Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
186 commits
Select commit Hold shift + click to select a range
68404a0
chore: stop tracking AI-assistant config and internal docs
hakeemRash Jul 7, 2026
fca4231
Merge pull request #6 from AlfaCode-Team/chore/remove-ai-docs
hakeemRash Jul 7, 2026
fe07980
feat(cli): show Sentinel banner on bare hkm and hkm help
hakeemRash Jul 7, 2026
58fe2c5
Merge pull request #7 from AlfaCode-Team/feat/banner-on-help
hakeemRash Jul 7, 2026
10c8f37
feat(upgrade): auto-download and install updates per OS
hakeemRash Jul 7, 2026
562a344
Merge pull request #8 from AlfaCode-Team/feat/hkm-upgrade-autoinstall
hakeemRash Jul 7, 2026
bacb6e8
fix(cli): self-locate installed kernel + real hkm-config + load confi…
hakeemRash Jul 7, 2026
7a01a63
Merge pull request #9 from AlfaCode-Team/fix/kernel-self-location
hakeemRash Jul 7, 2026
f367603
fix(templates): move templates out of tools/ so they ship in the kernel
hakeemRash Jul 7, 2026
2e05a8f
Merge pull request #10 from AlfaCode-Team/fix/ship-templates
hakeemRash Jul 7, 2026
e60838b
chore(release): v1.0.3
hakeemRash Jul 7, 2026
dfd65fa
Merge pull request #11 from AlfaCode-Team/release/v1.0.3
hakeemRash Jul 7, 2026
1b085b4
chore(cli): empty the committed project registry + auto-clear hook + …
hakeemRash Jul 7, 2026
e28c233
Merge pull request #12 from AlfaCode-Team/chore/registry-privacy-and-…
hakeemRash Jul 7, 2026
a1531b3
chore: refresh contributor statistics
hakeemRash Jul 7, 2026
ead0a18
feat(userdata): HKM_USERDATA_DIR for persistent registry across updates
hakeemRash Jul 7, 2026
feb8e60
Merge pull request #13 from AlfaCode-Team/feat/userdata-dir
hakeemRash Jul 7, 2026
6bf2b11
feat(config): hkm-config sets up the full environment (kernel + userd…
hakeemRash Jul 7, 2026
54cd260
Merge pull request #14 from AlfaCode-Team/feat/hkm-config-full-setup
hakeemRash Jul 7, 2026
3a4f9e0
security: harden scaffolding defaults
hakeemRash Jul 7, 2026
639c468
Merge pull request #15 from AlfaCode-Team/sec/harden-scaffolding
hakeemRash Jul 7, 2026
2559aa1
chore(release): v1.0.4
hakeemRash Jul 7, 2026
e0f907a
Merge pull request #16 from AlfaCode-Team/release/v1.0.4
hakeemRash Jul 7, 2026
95110aa
feat(scaffold): ship an Apache vhost sample alongside nginx
hakeemRash Jul 7, 2026
775df28
Merge pull request #17 from AlfaCode-Team/feat/apache-config-sample
hakeemRash Jul 7, 2026
98cd91b
chore(release): v1.0.5
hakeemRash Jul 8, 2026
badf5b1
docs: rewrite README for the native hkm CLI; fix broken doc links
hakeemRash Jul 8, 2026
0ba721e
Merge pull request #19 from AlfaCode-Team/docs/refresh-readme
hakeemRash Jul 8, 2026
2193ccc
feat(routes,cli): project routePolicy.disable + hkm --dev environment
hakeemRash Jul 9, 2026
8502721
chore(release): v1.0.6
hakeemRash Jul 9, 2026
5ce6f01
docs: document hkm --dev + HKM_DEV_HOME in README and CLI usage guide
hakeemRash Jul 9, 2026
aa0fadd
ci: bump actions to v5 (checkout, upload/download-artifact) for Node 24
hakeemRash Jul 9, 2026
92519ea
feat(tools): hkm plugins upgrade — split-safe project upgrade
hakeemRash Jul 10, 2026
f52df19
chore(release): v1.0.7
hakeemRash Jul 10, 2026
84d0112
test(feedback): fix FeedbackServiceTest namespace after User→Feedback…
hakeemRash Jul 10, 2026
1da84a4
refactor(plugins): complete Feedback/Mail/Validation split
hakeemRash Jul 10, 2026
e9d79e7
Merge pull request #22 from AlfaCode-Team/feat/complete-feedback-mail…
hakeemRash Jul 10, 2026
e0a6bb3
chore(githooks): strip AI-authored trailers in commit-msg hook
hakeemRash Jul 11, 2026
9758c97
docs: rewrite README as a full framework guide (concepts, lifecycle, …
hakeemRash Jul 11, 2026
eed6473
docs: rewrite README as a full framework guide (concepts, lifecycle, …
hakeemRash Jul 11, 2026
be30ad5
chore: stop tracking tools/zig-out build output (rebuilt by zig build…
hakeemRash Jul 11, 2026
58acbd9
fix(cli,tenancy): resolve tenant:migrate command collision + project-…
hakeemRash Jul 11, 2026
631400d
feat(audit,auth,social,tenancy,cli): audit plugin, device/mobile auth…
hakeemRash Jul 13, 2026
3844272
chore(release): v1.0.9
hakeemRash Jul 13, 2026
772ab4e
feat(auth,session,tenancy,user): display identity, previous-page logi…
hakeemRash Jul 14, 2026
73ea31f
chore(release): v1.0.10
hakeemRash Jul 14, 2026
8cee6bd
feat(kernel,tenancy,pageflow,auth): project essentials, strict tenant…
hakeemRash Jul 16, 2026
a7d6701
chore(release): v1.0.11
hakeemRash Jul 16, 2026
e784933
fix(security-filters): RequireAuthStage only redirects real page navi…
hakeemRash Jul 16, 2026
aba77eb
build(bundle): pin bundle dependencies to the PHP 8.4 series
Alshatri Jul 16, 2026
8005f2d
Merge branch 'main'
hakeemRash Jul 16, 2026
26e2765
ci(release): auto-tag new CHANGELOG version on merge to main -> trigg…
hakeemRash Jul 16, 2026
3ddff8e
ci(release): auto-release on merge to main via workflow_call (no PAT)…
hakeemRash Jul 16, 2026
9933839
docs(readme): document master->main branch model and automatic CHANGE…
hakeemRash Jul 16, 2026
d67f916
ci(security): CODEOWNERS + main branch protection script (required re…
hakeemRash Jul 16, 2026
47c2cd6
feat(edge): host-aware web-server config plugin (nginx SNI stream spl…
hakeemRash Jul 16, 2026
27250f4
feat(edge): classify .local/.test as local domains — exclude from ser…
hakeemRash Jul 17, 2026
e4d41b5
fix(edge): resolve project registry from global kernel home (not proj…
hakeemRash Jul 17, 2026
916fc95
feat(edge): project-aware config — per-project vhosts (docroot app/pu…
hakeemRash Jul 17, 2026
15a0f08
feat(edge): default commands to the CURRENT project (base_path/proj.j…
hakeemRash Jul 17, 2026
9506d89
feat(edge): auto-resolve PHP-FPM socket to match the CLI PHP version …
hakeemRash Jul 17, 2026
9a10dcf
feat(userconfig): resolve config path for non-root sudo users
hakeemRash Jul 17, 2026
cdfe728
Adopt master→main branch model, automated releases, and main branch p…
hakeemRash Jul 17, 2026
4b1b62e
Adopt master→main branch model, automated releases, and main branch p…
hakeemRash Jul 17, 2026
cb5446b
feat(edge): enhance hosts management with dev mode checks and force o…
hakeemRash Jul 17, 2026
7f7feda
chore(release): v1.0.13 — Edge plugin, PSP_PROJECTS_DIR export, front…
hakeemRash Jul 17, 2026
f328798
Merge remote-tracking branch 'origin/main'
hakeemRash Jul 17, 2026
bcc74b8
chore(release): bump to v1.0.14 (v1.0.13 tag already exists from an e…
hakeemRash Jul 17, 2026
0d70969
chore(release): reclaim v1.0.13 (stale mis-tagged v1.0.13 release/tag…
hakeemRash Jul 17, 2026
c0c59e0
Release v1.0.13 — Edge plugin + launcher/frontend fixes (#24)
hakeemRash Jul 17, 2026
f7e0ce5
Release v1.0.13 — Edge plugin + launcher/frontend fixes (#24)
hakeemRash Jul 17, 2026
c61dc40
chore(release): v1.0.14
hakeemRash Jul 17, 2026
8dc8479
chore: align CHANGELOG to released v1.0.13 (drop phantom 1.0.14)
hakeemRash Jul 17, 2026
e4b640e
fix(edge): serve local .local/.test domains in dev mode (--dev)
hakeemRash Jul 17, 2026
1175d87
Merge origin/main into master (squash-merge of #24; master already co…
hakeemRash Jul 17, 2026
d556935
Release v1.0.15 — Edge serves local domains in dev (#25)
hakeemRash Jul 17, 2026
8a7a3cc
Release v1.0.15 — Edge serves local domains in dev (#25)
hakeemRash Jul 17, 2026
6da6b61
Merge branch 'main' of github.com:AlfaCode-Team/php-service-platform
Alshatri Jul 18, 2026
7b30fc5
Merge branch 'master' of github.com:AlfaCode-Team/php-service-platform
Alshatri Jul 18, 2026
75fb403
feat(edge): TLS modes, APP_ENV cache profiles and OpenSwoole runtime …
hakeemRash Jul 18, 2026
0fed361
feat(edge): TLS modes, APP_ENV cache profiles and OpenSwoole runtime …
hakeemRash Jul 18, 2026
ae29055
Merge origin/main into master (PR #26: Edge TLS modes, APP_ENV cache …
hakeemRash Jul 18, 2026
5ab7050
feat(tenancy): add control plane support and enhance tenant migration…
hakeemRash Jul 20, 2026
4b084c1
feat(cli): hkm discover — find and register projects on disk
hakeemRash Jul 20, 2026
19ea1e5
Release v1.0.17 — hkm discover: find & register projects on disk (#27)
hakeemRash Jul 20, 2026
a4810b3
feat(cli): plugins recover + discover restores runtime dirs
hakeemRash Jul 20, 2026
e343c55
Merge remote-tracking branch 'origin/main'
hakeemRash Jul 20, 2026
fbce22c
Release v1.0.18 — plugins recover + discover restores runtime dirs (#28)
hakeemRash Jul 20, 2026
cff5a95
feat(edge): stream reuse/merge, force strategy, security hardening; r…
hakeemRash Jul 21, 2026
62d72b3
Merge remote-tracking branch 'origin/main'
hakeemRash Jul 21, 2026
5102572
test(edge): make nginx -t check portable across nginx versions
hakeemRash Jul 21, 2026
52c7791
test(edge): make nginx -t syntax check runnable as non-root in CI
hakeemRash Jul 21, 2026
73ce696
chore: auto-wire git hooks to strip AI co-author trailers
hakeemRash Jul 21, 2026
45bf72c
chore: drop pulse-engine + module-template modules, patch guzzle, wir…
hakeemRash Jul 21, 2026
a8f098a
feat: add issue and pull request templates, contributing guide, secur…
hakeemRash Jul 21, 2026
120805d
feat: add issue templates for documentation and plugin proposals
hakeemRash Jul 21, 2026
38c27c2
Merge branch 'main' of github.com:AlfaCode-Team/php-service-platform
hakeemRash Jul 21, 2026
cbbcc43
Merge branch 'main' of github.com:AlfaCode-Team/php-service-platform
hakeemRash Jul 21, 2026
ab9d39e
Merge branch 'main' of github.com:AlfaCode-Team/php-service-platform
hakeemRash Jul 21, 2026
e9f129e
ci: add CodeQL (JS/TS + Actions) and PHP analysis (composer audit, Se…
hakeemRash Jul 21, 2026
cfbe6d5
ci: drop custom CodeQL workflow — repo uses CodeQL default setup (avo…
hakeemRash Jul 21, 2026
9428e63
ci(phpstan): add level-5 config + baseline, make analysis a blocking …
hakeemRash Jul 21, 2026
45f21b2
fix: repair MigrateListCommand parent + OutboxWriter port contract
hakeemRash Jul 21, 2026
ed0f0cb
ci: fix PHPStan (ignore optional Swoole/OpenSwoole coroutine calls) +…
hakeemRash Jul 21, 2026
9b3a4a5
Merge branch 'main' of github.com:AlfaCode-Team/php-service-platform
hakeemRash Jul 21, 2026
8ae7317
chore(oss): open-source readiness — license, composer metadata, .env.…
hakeemRash Jul 21, 2026
d821af4
chore: add craftdevscommunity as code owner (required PR reviewers fo…
hakeemRash Jul 21, 2026
79f4bd6
Refactor Pageflow stages and consolidate functionality
hakeemRash Jul 22, 2026
e7010ae
Depend on alfacode-team/http ^1.0 (dev-master in monorepo, v1.0.0 for…
hakeemRash Jul 22, 2026
06cdf90
feat(module): add `hkm module` command for managing first-party kerne…
hakeemRash Jul 22, 2026
ae40be7
chore: update subproject commit for http module
hakeemRash Jul 22, 2026
613c67e
Point http submodule at latest master (dev-master, v1.0.0 release for…
hakeemRash Jul 22, 2026
9120c18
refactor(PageflowResponderTest): consolidate stage classes into a sin…
hakeemRash Jul 22, 2026
1f6252c
Refactor code structure for improved readability and maintainability
hakeemRash Jul 22, 2026
26c8f74
Merge branch 'main' into master
hakeemRash Jul 22, 2026
5223f73
docs: update README to enhance clarity and structure, add new sections
hakeemRash Jul 22, 2026
6adb862
Merge branch 'master' of github.com:AlfaCode-Team/hkm-kernel
hakeemRash Jul 22, 2026
a25eae4
Merge #36; rebrand to HKM Kernel, publish docs/guides, README rewrite…
hakeemRash Jul 22, 2026
bc87acd
Merge branch 'main' of github.com:AlfaCode-Team/hkm-kernel
hakeemRash Jul 22, 2026
43b0034
feat: add MailDemoController for testing routes and implement preview…
hakeemRash Jul 27, 2026
c6912c9
feat: add OAuth2 consent and simulation pages
hakeemRash Jul 27, 2026
e34313d
Merge branch 'main' of github.com:AlfaCode-Team/hkm-kernel
hakeemRash Jul 27, 2026
2959d56
feat: update OAuth2 module routes and remove mobile authentication en…
hakeemRash Jul 31, 2026
f0f9432
refactor: update references from "Sentinel" to "HKM" in upgrade and b…
Alshatri Jul 31, 2026
20091e4
chore: remove unused submodules for module-template and pulse-engine
Alshatri Jul 31, 2026
2372fb9
Merge branch 'master' of github.com:AlfaCode-Team/hkm-kernel
Alshatri Jul 31, 2026
145c6c6
feat(kernel): add config repository, logger port, locks, typed routes…
Alshatri Aug 6, 2026
08cbd62
feat(plugins): adopt the new kernel ports; add Logger plugin
Alshatri Aug 6, 2026
77cff02
docs: reconcile drift and document the kernel additions
Alshatri Aug 6, 2026
b86e5ff
fix(tests): repair three OAuth2 fakes drifted from their interfaces
Alshatri Aug 6, 2026
09f1b44
refactor!: decouple plugins from the kernel into standalone packages
Alshatri Aug 6, 2026
d784f91
refactor!: kernel depends on no plugins; plugin tests move to their o…
Alshatri Aug 6, 2026
9be0a62
fix(deps): pin phpshots/bind-it instead of accepting any version
Alshatri Aug 6, 2026
ba15d5b
feat(boot): compile a translation catalogue cascade so plugins can sh…
Alshatri Aug 6, 2026
5a54acd
fix(tools): make defers run at exit; wire the memory inspector; repai…
Alshatri Aug 6, 2026
2b40610
feat(tools): install, update and lock plugins from their git remotes
Alshatri Aug 6, 2026
df53379
fix(tools): a git-describe build must not sort below the tag it came …
Alshatri Aug 6, 2026
fe9d288
feat(tools): stamp the build version into composer.json; fix the upgr…
Alshatri Aug 6, 2026
28dbe3e
feat(tools): hkm upgrade --local — install the local checkout over th…
Alshatri Aug 6, 2026
b705713
fix(tools): a pre-release tag must not be offered as the latest update
Alshatri Aug 7, 2026
9d648de
docs: changelog for 1.1.0-dev.1
Alshatri Aug 7, 2026
c685bb8
fix: PHPStan could not run at all; clear the kernel's own findings
Alshatri Aug 7, 2026
64b14a1
fix(tools): `**` array-repeat was removed in Zig 0.17 — the release b…
Alshatri Aug 7, 2026
33871fd
fix(ci): releases published with no binaries attached
Alshatri Aug 7, 2026
cd8d203
docs: changelog for 1.1.0-dev.2
Alshatri Aug 7, 2026
59f9316
fix(ci): auto-release skipped pre-release versions and picked an olde…
Alshatri Aug 7, 2026
6933376
fix: PHPStan green — fix the real finding, scope out plugin-bound sca…
Alshatri Aug 7, 2026
c78606c
docs: changelog for 1.1.0-dev.3
Alshatri Aug 7, 2026
91c999f
fix(tools): stamping an invalid version broke composer install on eve…
Alshatri Aug 7, 2026
74b72e6
docs: release 1.1.0-beta.1 — the first installable pre-release
Alshatri Aug 7, 2026
2c2c32a
Merge branch 'main' into master
hakeemRash Aug 7, 2026
378c40d
fix(tools): restore the composer version fix lost in the main->master…
Alshatri Aug 7, 2026
373e390
Merge branch 'main' of github.com:AlfaCode-Team/hkm-kernel
Alshatri Aug 7, 2026
5362dad
fix(.gitignore): add 'var' to ignored files
Alshatri Aug 7, 2026
9cc18f6
fix(tools): a new project could not boot — hkm new never installed it…
Alshatri Aug 8, 2026
b3d6fb6
feat(routing): groups, domain grouping, safer parameters and a boot c…
Alshatri Aug 11, 2026
a98d822
chore: release 1.2.0
Alshatri Aug 11, 2026
d92450e
fix(release): point modules/let-migrate back at its published commit
Alshatri Aug 11, 2026
7d15d1d
feat: add plugin domains and store management
Alshatri Aug 11, 2026
a74024d
fix(release): drop the version field from the checked-in composer.json
Alshatri Aug 11, 2026
e8079dd
fix(release): actually pin let-migrate to its published commit
Alshatri Aug 11, 2026
32fa889
fix(ci,stamp): stop duplicate PR checks and reject a version that cor…
Alshatri Aug 11, 2026
1aac9df
Merge branch 'main' of github.com:AlfaCode-Team/hkm-kernel
hakeemRash Aug 12, 2026
fb3f74d
chore: update subproject commits for http and php-io-cli modules
hakeemRash Aug 12, 2026
d7c645e
Merge branch 'master' of github.com:AlfaCode-Team/hkm-kernel
hakeemRash Aug 12, 2026
16c60d1
feat(routing): accept a LIST of domains at every level
Alshatri Aug 12, 2026
fe93826
feat(plugins): seed a plugin's declared env into .env on enable
Alshatri Aug 12, 2026
f98011b
feat(install): a user-local tarball install that needs no root
Alshatri Aug 12, 2026
58985dc
feat(template): wire the scaffold up to @pageflow/admin
Alshatri Aug 12, 2026
e64b903
fix(release): pin php-io-cli back to its last loadable commit
Alshatri Aug 12, 2026
5454df2
chore: release 1.3.0
Alshatri Aug 12, 2026
e819444
chore: release 1.3.1
Alshatri Aug 12, 2026
d037923
update
hakeemRash Aug 13, 2026
8e26c96
feat: initialize projects configuration with shop, hkmcode, and hkmvo…
Alshatri Aug 14, 2026
884dd7d
fix(cli): scope-aware install, upgrade and version reporting
hakeemRash Aug 17, 2026
7bdd4c9
fix(upgrade): ensure failed .deb installs are reported correctly
hakeemRash Aug 17, 2026
5b67430
update
hakeemRash Aug 17, 2026
9a729ba
feat(cli): hkm uninstall, and fix how commands talk to the shell
hakeemRash Aug 18, 2026
18da323
Merge main into release/v1.3.3
hakeemRash Aug 18, 2026
38587fb
ci: move off the deprecated Node 20 action runtime, and keep it that way
hakeemRash Aug 18, 2026
73826ca
Merge master (CI Node 24 bumps) into release/v1.3.3
hakeemRash Aug 18, 2026
10e92ac
fix(modules): pin php-io-cli to the unknown-option parser fix
hakeemRash Aug 18, 2026
8d94c5b
docs(changelog): record the php-io-cli parser fix
hakeemRash Aug 18, 2026
58ce3c3
Merge master into release/v1.3.3
hakeemRash Aug 18, 2026
720c2cd
fix(cli): close the review findings on uninstall and the output split
hakeemRash Aug 18, 2026
45e926b
Merge master into release/v1.3.3
hakeemRash Aug 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Keeps GitHub Actions current so a runtime deprecation is a pull request, not a
# warning nobody sees.
#
# The Node 20 deprecation is the case this exists for: five actions kept working
# while the runners forced them onto Node 24, and the only signal was a notice in
# the log of a workflow that still passed. Pinned majors do not rot loudly — they
# rot silently until the forced runtime is withdrawn and every workflow fails at
# once. A weekly PR turns that into something reviewable.
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
commit-message:
# Matches the Conventional Commits style the rest of the history uses, so
# these land in the CHANGELOG tooling like anything else.
prefix: ci
labels:
- dependencies
groups:
# One PR for all of them: they are bumped together in practice (upload and
# download artifact must stay compatible), and five separate PRs for the
# same deprecation is five reviews of the same decision.
actions:
patterns:
- "*"
2 changes: 1 addition & 1 deletion .github/workflows/php-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ jobs:
SEMGREP_RULES: "p/php p/security-audit p/secrets"
- name: Upload SARIF to code scanning
if: always()
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: semgrep.sarif
category: semgrep
14 changes: 7 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,12 @@ jobs:
# TWO artifacts. The tarball is the DEFAULT install path — user-local,
# no root (tools/install.sh). The .deb is for multi-user machines and CI
# images where a system-wide install and apt-managed PHP are the point.
- uses: actions/upload-artifact@v5
- uses: actions/upload-artifact@v7
with: { name: linux-tarball, path: dist/*linux*.tar.gz }
- uses: actions/upload-artifact@v5
- uses: actions/upload-artifact@v7
with: { name: linux-deb, path: dist/*.deb }
# Published alongside the assets so `curl | sh` works without a checkout.
- uses: actions/upload-artifact@v5
- uses: actions/upload-artifact@v7
with: { name: installer, path: tools/install.sh }

# ── Windows: .zip (x86_64, cross-compiled) ────────────────────────────────
Expand All @@ -89,7 +89,7 @@ jobs:
with: { php-version: "8.4", tools: composer }
- name: Bundle (windows)
run: VERSION="${RELEASE_VERSION:-${GITHUB_REF_NAME#v}}" ./tools/bundle.sh windows
- uses: actions/upload-artifact@v5
- uses: actions/upload-artifact@v7
with: { name: windows-zip, path: dist/*.zip }

# ── macOS: universal .app tarball (arm64 + x86_64), built ON LINUX ─────────
Expand All @@ -109,7 +109,7 @@ jobs:
with: { php-version: "8.4", tools: composer }
- name: Bundle (macos)
run: VERSION="${RELEASE_VERSION:-${GITHUB_REF_NAME#v}}" ./tools/bundle.sh macos
- uses: actions/upload-artifact@v5
- uses: actions/upload-artifact@v7
with: { name: macos-app, path: dist/*.tar.gz }

# ── Publish GitHub Release with all artifacts ─────────────────────────────
Expand All @@ -119,7 +119,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v5 # need CHANGELOG.md at the checked-out commit
- uses: actions/download-artifact@v5
- uses: actions/download-artifact@v8
with: { path: artifacts/ }
- name: Resolve version + extract CHANGELOG section
id: notes
Expand All @@ -137,7 +137,7 @@ jobs:
else
echo "No CHANGELOG entry for $VERSION — using auto-generated notes only."
fi
- uses: softprops/action-gh-release@v2
- uses: softprops/action-gh-release@v3
with:
# When called from auto-release the ref is a branch, so name the tag
# explicitly; on a tag push this matches GITHUB_REF_NAME anyway.
Expand Down
99 changes: 99 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,105 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.3.3] - 2026-08-18

Follows 1.3.2 within a day, and the theme is narrower: 1.3.2 fixed *which*
kernel a command acts on, this one fixes *how* commands talk to the shell around
them, plus a full uninstall. An audit of the Zig toolchain drove it — every item
below was reproduced against the shipped `--release=small` binary.

### Added
- **`hkm uninstall`** — removes every hkm install on the machine (both kernels,
both pairs of launchers, the pre-1.4 user kernel, `~/.config/hkm` and the
shared plugin store) and deregisters the `.deb` from dpkg, while keeping **your
projects and the project registry**. Those two are protected by construction,
not by a filter: every path it can delete is computed from the install layout,
so a project directory cannot enter the plan at all; and `projects.json` +
`platform.json` are rescued out of a kernel tree into the userdata directory
*before* anything is deleted, so the registry survives even when its only copy
was inside the tree being removed. `--dry-run` prints the plan and exits;
system paths are reported rather than silently skipped when not root.

### Changed
- `hkm doctor` and `hkm version` share one PATH lookup with the launcher
passthrough (`util.findOnPath`). Three private copies of "which binary would
actually run" is three chances to disagree.
- **CI actions moved off the deprecated Node 20 runtime.** `upload-artifact`
v5→v7, `download-artifact` v5→v8, `codeql-action/upload-sarif` v3→v4 and
`action-gh-release` v2→v3 all declared `node20`, which the runners were
already forcing onto Node 24. A `.github/dependabot.yml` now watches the
`github-actions` ecosystem weekly and groups the bumps into one PR, so the
next runtime deprecation arrives as a reviewable change rather than a notice
in the log of a workflow that still passes.

### Fixed
- **Command output went to stderr, so nothing could be piped.** The whole
`prompt` renderer used `std.debug.print`, which writes to stderr — so
`hkm list > projects.txt` produced an empty file and a command's results were
indistinguishable from its errors. Results (`intro`/`section`/`item`/`ok`/
`muted`/`note`/`table`/`outro`) now go to **stdout**; `err`/`warn` and every
interactive prompt stay on **stderr**. This was found once before and fixed a
single function wide (`banner.printShort`); the cause was in the shared
renderer all along.
- **ANSI escapes were emitted unconditionally and `NO_COLOR` was ignored**, so
colour codes landed in redirected output, log files and CI transcripts.
Colour is now decided per stream from the rule `tools/install.sh` already
applied: off when `NO_COLOR` is set, when `TERM=dumb`, or when that stream is
not a terminal.
- **Tables truncated to 80 columns when redirected.** `termCols()` falls back to
80 whenever the `ioctl` fails — exactly the non-TTY case — so piping cut the
end off every long path, with the `…` as the only clue. Truncation now applies
only when stdout really is a terminal.
- **A mistyped command printed a raw Zig error.** Anything not handled natively
is forwarded to the PHP CLI, and a spawn failure propagated out of `main` as
`error: FileNotFound` — no filename, no mention of PHP, no pointer to
`hkm doctor`. The three causes (no PHP, no kernel CLI, an unknown command) are
now told apart and each names its own fix.
- **Unknown flags were silently ignored, which inverted a destructive command.**
Every command parsed the flags it knew and dropped the rest. The token most
likely to be misspelled is the one that makes a command safe, so
`hkm uninstall --dryrun --yes` parsed as "no dry run, and don't ask" and
deleted the install without a prompt. `uninstall` and `upgrade` now reject
anything they do not recognise before acting on anything they do.
- **`projects.json` and `plugins.lock.json` were written non-atomically.**
`writeFile` truncates before writing, so a process killed part way through — or
a full disk — left a truncated registry rather than the previous one. Both now
write a sibling temp file and `rename()` over the target, the same pattern
`install.sh` and the launcher install already used.
- **Every unknown long option crashed the CLI parser.** `php-io-cli`'s
long-option branch recorded a different array shape than its two siblings, and
`rejectUnknownOptions()` reads the key it omitted — so the feature meant to
suggest a correction raised `TypeError: suggestOption(): Argument #1 ($name)
must be of type string, null given` on every unknown `--flag`. Fixed upstream
(php-io-cli `b1dd657`) rather than pinned back, so the handling stays in.
- **`hkm uninstall` could destroy the registry it promises to keep** (found in
review). Two holes: `HKM_USERDATA_DIR` may point INSIDE a deletion target —
`/opt/hkm-kernel/projects` is the obvious case — so the plan listed it under
"Will KEEP" and deleted its parent moments later; and `rescueRegistry`
swallowed every write failure, so a failed rescue was followed by the delete
anyway while the command reported success. It now refuses the first layout
outright and aborts before removing anything if the rescue fails. Rescued
files are written atomically.
- **Output fixes that had gaps of their own** (found in review): `hkm-config
print` still wrote the config to stderr; a line longer than 8 KiB fell back to
`std.debug.print` and silently changed stream; remediation text printed after
an error went to stdout, splitting one message across two streams;
`writeFileAtomic` used a fixed temp name two processes could collide on;
`findOnPath` skipped empty `PATH` entries, which POSIX defines as the current
directory; the passthrough blamed a missing PHP for a missing kernel CLI; and
`--` ended flag VALIDATION but not flag PARSING, so `hkm upgrade -- --system`
still selected the system scope.
- **A failed `.deb` install could still report success.** The fallback path
treated `apt-get -f install` exiting 0 as evidence the package had landed, but
it exits 0 whenever it finds nothing to repair — so a `dpkg -i` that failed for
any non-dependency reason (a truncated download, a corrupt `.deb`) was reported
as "updated" with the previous kernel still installed. The dependency repair is
now followed by a second `dpkg -i`, and that result alone is the verdict.
- **`prompt.item` padded by byte count**, so a key containing any multi-byte
glyph shifted its description column left — a single `→` misaligned the row by
two. It now measures display width using the helper already written for
`table()`.

## [1.3.2] - 2026-08-17

Fixes a class of failure that made installing or upgrading on a machine with an
Expand Down
2 changes: 1 addition & 1 deletion modules/php-io-cli
34 changes: 34 additions & 0 deletions tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,40 @@ So a pin still works wherever it was actually needed; it no longer overrides an
install sitting next to the binary. `hkm-config check` writes one only when
self-location failed, and `hkm-config unset HKM_KERNEL_HOME` clears a stale one.

### `hkm uninstall` — remove everything, keep the projects

```sh
hkm uninstall --dry-run # print the plan, delete nothing
hkm uninstall # everything this user can remove
sudo hkm uninstall # …including the .deb under /opt + /usr/bin
```

| Removed | Kept |
|---|---|
| `/opt/hkm-kernel`, `~/.local/lib/hkm-kernel`, the pre-1.4 user kernel | **your projects**, wherever they live |
| `/usr/bin/{hkm,hkm-config}`, `~/.local/bin/{hkm,hkm-config}` | **`projects.json`** + **`platform.json`** |
| `~/.config/hkm` (config.env), the shared plugin store | |
| the `hkm-kernel` dpkg registration (`remove`, never `purge`) | |

The two kept items are protected **by construction, not by a filter**:

- Every path the command can delete is *computed* from the install layout. None
is read from the registry, the working directory, or an argument — so a
project directory cannot appear in the plan at all.
- `projects.json` and `platform.json` are **rescued into the userdata directory
before anything is deleted**, so the registry survives even when its only copy
was inside the kernel tree being removed. Reinstall later and `hkm list` still
shows every project.

Two rules in the rescue exist because testing found them the hard way: it only
copies from a tree it is *actually removing*, and it prefers the user's kernel
over the system one. The `.deb` ships `projects/projects.json` as `{}` (a
packaged conffile), and without both rules that empty default won the race to the
destination and shadowed the user's real project list.

`tools/install.sh --uninstall` remains deliberately narrow — it removes only what
that script installed, at that prefix. `hkm uninstall` is the full removal.

### `hkm upgrade --local`

Installs the current checkout over an installed kernel, obeying the same scope
Expand Down
9 changes: 8 additions & 1 deletion tools/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,20 @@ done

# ── uninstall ───────────────────────────────────────────────────────────────
if [ "$DO_UNINSTALL" -eq 1 ]; then
# Deliberately NARROW: this removes only what this script installed, at this
# prefix. It does not touch a system (.deb) install, the pre-1.4 user kernel,
# the config file or the plugin cache — `hkm uninstall` does all of that, and
# rescues the project registry out of any kernel tree before deleting it.
say "Removing $DEST"
rm -rf "$DEST"
rm -f "$BINDIR/hkm" "$BINDIR/hkm-config"
ok "Removed. Your data was left alone:"
printf ' %s\n %s\n' "${XDG_CONFIG_HOME:-$HOME/.config}/hkm" \
"${XDG_DATA_HOME:-$HOME/.local/share}/hkm"
printf ' Delete those too if you want a clean slate.\n'
printf '\n For a FULL removal — every install on this machine, the config and\n'
printf ' the plugin cache, while keeping your projects and projects.json:\n'
printf ' hkm uninstall --dry-run # see the plan first\n'
printf ' hkm uninstall # then do it (sudo for the .deb too)\n'
exit 0
fi

Expand Down
30 changes: 5 additions & 25 deletions tools/src/commands/doctor.zig
Original file line number Diff line number Diff line change
Expand Up @@ -56,31 +56,11 @@ fn mark(present: bool) []const u8 {
return if (present) OK else MISSING;
}

/// Locate an executable by walking PATH. Returns the FIRST match, which is the
/// one that would actually run.
fn findOnPath(allocator: std.mem.Allocator, io: Io, env: *EnvMap, name: []const u8) ?[]const u8 {
const path = env.get("PATH") orelse return null;
var it = std.mem.splitScalar(u8, path, ':');
while (it.next()) |dir| {
if (dir.len == 0) continue;
const cand = std.fs.path.join(allocator, &.{ dir, name }) catch continue;
if (util.fileExists(io, cand)) return cand;
}
return null;
}

/// Every match on PATH, in order — used to detect one install shadowing another.
fn countOnPath(allocator: std.mem.Allocator, io: Io, env: *EnvMap, name: []const u8) usize {
const path = env.get("PATH") orelse return 0;
var n: usize = 0;
var it = std.mem.splitScalar(u8, path, ':');
while (it.next()) |dir| {
if (dir.len == 0) continue;
const cand = std.fs.path.join(allocator, &.{ dir, name }) catch continue;
if (util.fileExists(io, cand)) n += 1;
}
return n;
}
// findOnPath / countOnPath now live in lib/util.zig — doctor, version and the
// passthrough diagnostic in main.zig all needed the same walk, and three copies
// of "which binary would actually run" is three chances to disagree.
const findOnPath = util.findOnPath;
const countOnPath = util.countOnPath;

fn dirOnPath(env: *EnvMap, dir: []const u8) bool {
const path = env.get("PATH") orelse return false;
Expand Down
Loading