@amsterdamdatalabs/adl-agent-control-linux-x64 0.1.12 → 0.1.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/adl +2 -2
- package/bin/git +16 -17
- package/bin/git-ado +25 -24
- package/bin/git-defaults +173 -0
- package/bin/health-check +8 -1
- package/bin/kimi-hooks +1 -1
- package/bin/lib/adl-package.sh +257 -0
- package/bin/lib/fleet-host.sh +8 -5
- package/bin/reconcile +482 -232
- package/bin/reconcile-host +30 -20
- package/bin/setup +20 -17
- package/bin/shell-path-policy +15 -5
- package/bin/sync-and-reconcile +62 -64
- package/bin/validate-manifest +33 -9
- package/package.json +2 -10
- package/packages/agent-hooks/README.md +14 -9
- package/packages/agent-hooks/assets/hooks.json +0 -20
- package/packages/agent-hooks/src/cli/args.ts +1 -1
- package/packages/agent-hooks/src/cli/doctor.ts +6 -58
- package/packages/agent-hooks/src/deploy/deploy.ts +12 -41
- package/packages/agent-hooks/src/deploy/doctor.ts +8 -11
- package/packages/agent-hooks/src/deploy/index.ts +14 -14
- package/packages/agent-hooks/src/deploy/json-merge.ts +7 -8
- package/packages/agent-hooks/src/deploy/legacy-lock.ts +2 -2
- package/packages/agent-hooks/src/deploy/list.ts +1 -1
- package/packages/agent-hooks/src/deploy/lock.ts +31 -12
- package/packages/agent-hooks/src/deploy/profile.ts +3 -4
- package/packages/agent-hooks/src/deploy/source.ts +1 -1
- package/packages/agent-hooks/src/gating/config.ts +12 -24
- package/packages/agent-hooks/src/gating/root.ts +3 -3
- package/packages/agent-hooks/src/hooks/briefing/handler.ts +2 -2
- package/packages/agent-hooks/src/hooks/briefing/index.ts +27 -287
- package/packages/agent-hooks/src/hooks/contract.ts +17 -17
- package/packages/agent-hooks/src/hooks/crg/background.ts +27 -0
- package/packages/agent-hooks/src/hooks/crg/index.ts +7 -6
- package/packages/agent-hooks/src/hooks/log.ts +8 -10
- package/packages/agent-hooks/src/hooks/user-prompt-submit/match.ts +1 -1
- package/packages/agent-hooks/src/hooks/user-prompt-submit/tokenizer.ts +1 -1
- package/packages/agent-hooks/src/hooks/user-prompt-submit/vector.ts +6 -5
- package/packages/agent-hooks/src/hosts/registry.ts +1 -1
- package/packages/agent-hooks/src/log/adl-dir.ts +44 -0
- package/packages/agent-hooks/src/log/writer.ts +16 -2
- package/packages/agent-hooks/src/main.ts +7 -41
- package/packages/agent-hooks/src/pre-tool-use/handler.ts +71 -82
- package/packages/agent-hooks/src/rules/engine.ts +13 -17
- package/packages/agent-hooks/src/rules/impl/adl-build-run-denied.ts +3 -3
- package/packages/agent-hooks/src/rules/impl/adl-git-credential-bypass.ts +12 -14
- package/packages/agent-hooks/src/rules/impl/adl-git-identity.ts +28 -28
- package/packages/agent-hooks/src/rules/impl/adl-git-push-policy.ts +8 -9
- package/packages/agent-hooks/src/rules/impl/adl-human-azdo-bypass.ts +56 -59
- package/packages/agent-hooks/src/rules/impl/adl-identity.ts +16 -23
- package/packages/agent-hooks/src/rules/impl/adl-mcp-cli.ts +19 -16
- package/packages/agent-hooks/src/rules/impl/adl-pr-complete-pending.ts +2 -2
- package/packages/agent-hooks/src/rules/impl/adl-pr-review-role.ts +9 -12
- package/packages/agent-hooks/src/rules/impl/adl-pr-role.ts +5 -7
- package/packages/agent-hooks/src/rules/impl/adl-run-required.ts +411 -0
- package/packages/agent-hooks/src/rules/impl/adl-token-minting-role.ts +4 -5
- package/packages/agent-hooks/src/rules/impl/adl-workitem-role.ts +6 -7
- package/packages/agent-hooks/src/rules/impl/agent-tamper-protection.ts +77 -70
- package/packages/agent-hooks/src/rules/impl/deny-allowlist.ts +131 -0
- package/packages/agent-hooks/src/rules/impl/git-helpers.ts +21 -23
- package/packages/agent-hooks/src/rules/impl/git-worktree.ts +14 -28
- package/packages/agent-hooks/src/rules/impl/mcp-tool.ts +3 -3
- package/packages/agent-hooks/src/rules/impl/messages.ts +1 -1
- package/packages/agent-hooks/src/rules/impl/pr-completion.ts +1 -1
- package/packages/agent-hooks/src/rules/impl/tool-azure-devops.ts +35 -46
- package/packages/agent-hooks/src/rules/impl/tool-find.ts +34 -7
- package/packages/agent-hooks/src/rules/impl/tool-grep.ts +33 -12
- package/packages/agent-hooks/src/rules/impl/tool-native-search.ts +52 -9
- package/packages/agent-hooks/src/rules/ports.ts +5 -7
- package/packages/agent-hooks/src/rules/registry.ts +4 -6
- package/packages/agent-hooks/src/rules/shell/git-identity.ts +86 -101
- package/packages/agent-hooks/src/rules/shell/git-internals.ts +1 -1
- package/packages/agent-hooks/src/rules/shell/invocation.ts +24 -118
- package/packages/agent-hooks/src/rules/shell/piped-script.ts +1 -1
- package/packages/agent-hooks/src/rules/shell/prefixes.ts +1 -1
- package/packages/agent-hooks/src/rules/shell/protected-carrier-writes.ts +11 -10
- package/packages/agent-hooks/src/rules/shell/protected-carriers.ts +26 -26
- package/packages/agent-hooks/src/rules/shell/substitution.ts +1 -1
- package/packages/agent-hooks/src/rules/shell/xargs.ts +2 -2
- package/packages/agent-hooks/src/rules/spec.ts +2 -2
- package/packages/agent-settings/README.md +287 -0
- package/packages/agent-settings/assets/GLOBAL-AGENTS.md +14 -16
- package/packages/agent-settings/assets/agents/architect.toml +2 -0
- package/packages/agent-settings/assets/agents/code-reviewer.toml +2 -0
- package/packages/agent-settings/assets/agents/executor.toml +2 -0
- package/packages/agent-settings/assets/agents/explore.toml +2 -0
- package/packages/agent-settings/assets/agents/planner.toml +2 -0
- package/packages/agent-settings/assets/mcp.json +0 -4
- package/packages/agent-settings/deploy-profile.json +139 -0
- package/packages/agent-settings/deploy-profile.schema.json +147 -0
- package/packages/agent-settings/managed/README.md +29 -30
- package/packages/agent-settings/managed/codex-requirements.toml +9 -9
- package/packages/agent-settings/package.json +20 -0
- package/packages/agent-settings/src/deploy/agent-render.ts +2 -2
- package/packages/agent-settings/src/deploy/agent-toml.ts +1 -1
- package/packages/agent-settings/src/deploy/agents-deploy.ts +17 -3
- package/packages/agent-settings/src/deploy/doctor.ts +3 -83
- package/packages/agent-settings/src/deploy/index.ts +6 -33
- package/packages/agent-settings/src/deploy/legacy-lock.ts +6 -6
- package/packages/agent-settings/src/deploy/list.ts +5 -19
- package/packages/agent-settings/src/deploy/lock.ts +8 -18
- package/packages/agent-settings/src/deploy/mcp-deploy.ts +10 -5
- package/packages/agent-settings/src/deploy/mcp-merge.ts +22 -3
- package/packages/agent-settings/src/deploy/mcp-source.ts +1 -1
- package/packages/agent-settings/src/deploy/profile.ts +11 -35
- package/packages/agent-settings/src/deploy/retire-lean-ctx.ts +184 -0
- package/packages/agent-settings/src/deploy/settings.ts +17 -22
- package/packages/agent-settings/src/global-surface-sweep.ts +0 -2
- package/packages/agent-settings/src/kimi-hooks.ts +339 -192
- package/packages/agent-settings/src/opencode-hooks.ts +1 -1
- package/packages/agent-settings/tsconfig.json +23 -0
- package/packages/agent-skills/assets/agent-search-tool-audit/SKILL.md +120 -0
- package/packages/agent-skills/assets/agent-search-tool-audit/scripts/audit.sh +276 -0
- package/packages/agent-skills/assets/debug-issue/SKILL.md +8 -7
- package/packages/agent-skills/assets/explore-codebase/SKILL.md +13 -13
- package/packages/agent-skills/assets/refactor-safely/SKILL.md +12 -11
- package/packages/agent-skills/assets/review-changes/SKILL.md +7 -7
- package/packages/agent-skills/assets/testing/references/e2e.md +37 -0
- package/packages/agent-skills/assets/testing/references/integration.md +37 -0
- package/packages/agent-skills/assets/testing/references/unit.md +32 -0
- package/packages/agent-skills/dist/deploy.d.ts +2 -0
- package/packages/agent-skills/dist/deploy.d.ts.map +1 -1
- package/packages/agent-skills/dist/deploy.js +27 -1
- package/packages/agent-skills/dist/deploy.js.map +1 -1
- package/packages/agent-skills/dist/doctor.d.ts +0 -2
- package/packages/agent-skills/dist/doctor.d.ts.map +1 -1
- package/packages/agent-skills/dist/doctor.js +1 -1
- package/packages/agent-skills/dist/doctor.js.map +1 -1
- package/packages/agent-skills/dist/fs-utils.d.ts +0 -1
- package/packages/agent-skills/dist/fs-utils.d.ts.map +1 -1
- package/packages/agent-skills/dist/fs-utils.js +1 -1
- package/packages/agent-skills/dist/fs-utils.js.map +1 -1
- package/packages/agent-skills/src/deploy.ts +29 -1
- package/packages/agent-skills/src/doctor.ts +1 -1
- package/packages/agent-skills/src/fs-utils.ts +1 -1
- package/packages/azdo/README.md +10 -9
- package/packages/azdo/package.json +1 -3
- package/packages/azdo/scripts/probe-ado-rules.ts +311 -0
- package/packages/azdo/src/azdo-pl.ts +2 -54
- package/packages/azdo/src/azdo-pr-review.ts +4 -4
- package/packages/azdo/src/azdo-repo-doctor.ts +101 -52
- package/packages/azdo/src/azdo-wit.ts +44 -2
- package/packages/azdo/src/lib/agent-identity.ts +12 -14
- package/packages/azdo/src/lib/agent-token.ts +2 -2
- package/packages/azdo/src/lib/client.ts +0 -5
- package/packages/azdo/src/lib/graph-identity.ts +4 -4
- package/packages/azdo/src/workflow-ladder.csv +241 -0
- package/packages/azdo/src/workflow-rules-matrix.csv +85 -0
- package/packages/azdo/src/workflow-rules.ts +194 -0
- package/packages/fleet/manifest.json +35 -11
- package/packages/fleet/manifest.schema.json +62 -10
- package/packages/fleet/src/default-agent-file.ts +3 -3
- package/packages/fleet/src/install-adl-package.ts +73 -15
- package/packages/fleet/src/install-embedding-model.ts +13 -13
- package/packages/fleet/src/managed-settings.ts +7 -7
- package/packages/fleet/src/repo-maintain.ts +91 -55
- package/packages/fleet/src/scratch-reap.ts +5 -5
- package/packages/fleet/src/vscode-settings.ts +5 -5
- package/packages/repo-controls/README.md +141 -43
- package/packages/repo-controls/assets/promote.ts +4 -4
- package/packages/repo-controls/assets/reconcile-guard.sh +10 -46
- package/packages/repo-controls/assets/version-bump.sh +31 -84
- package/packages/repo-controls/bunfig.toml +6 -7
- package/packages/repo-controls/package/adl-compliance/AGENTS.md +5 -6
- package/packages/repo-controls/package/adl-compliance/conftest.py +3 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/__init__.py +4 -16
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/test_check.py +9 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/notes.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/test_check.py +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/__init__.py +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/check.py +266 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/.drafts/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/.drafts/d.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/.hidden.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/data.csv +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/diagram.png +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/mock.png +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/sub/nested.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p1.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p2.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p3.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p4.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p5.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/architecture/build.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/architecture/overview.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/guide/install.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/guide/start.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/adr-001-tenancy.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/adr-002-carrier.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/adr-003-cli.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/archive/adr-000-old.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/archive/adr-000-older.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-01.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-02.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-03.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-04.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-05.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-06.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-07.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-08.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-09.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-10.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-11.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-12.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-13.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-14.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-15.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-16.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/d.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/e.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/docs/short/only.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/d.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/shrunk/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/shrunk/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/grants.yaml +6 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/grants.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/test_check.py +345 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/check.py +18 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/test_check.py +35 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/__init__.py +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/check.py +91 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/AGENTS.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/CLAUDE.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/-leading-hyphen.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/AGENTS.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/double--hyphen.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/getting started.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/nested/page-here.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/trailing-hyphen-.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/ui-contract.md +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/user_profile.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/assets/UI-CONTRACT.png +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/assets/diagram.png +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/index.md +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/notes.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/reference.html +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/research/2026-10-experiment.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/research/UI-CONTRACT.md +6 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs.md +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/test_check.py +194 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/check.py +14 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/docs-knowledge-indexes.yaml +5 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-shipped-register-legacy/docs/compliance/index.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-shipped-register-type/docs/compliance/index.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/test_check.py +58 -6
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/test_check.py +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/check.py +64 -17
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/docs-okf-profiles.yaml +60 -9
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-ledger-clean/docs/notes.md +17 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-ledger-no-lines/docs/notes.md +13 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-clean/docs/architecture/demo.md +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-clean/docs-okf-profiles.yaml +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/no-type.md +9 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/typed-experiment.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/typed-research.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs-okf-profiles.yaml +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-violation/docs/architecture/bad-status.md +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-violation/docs-okf-profiles.yaml +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/experiment-ok.md +15 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/extra-key.md +15 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/extra-keys.md +16 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-created.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-description.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-last-update.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-sources.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-status.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-title.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/optional-keys.md +16 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/research-ok.md +14 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research-neighbours/docs/architecture/created-date.md +21 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research-neighbours/docs/architecture/research-shaped.md +19 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research-neighbours/docs/operations/runbook.md +26 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/test_check.py +228 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/register.py +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/test_check.py +11 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/__init__.py +5 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/check.py +160 -44
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-clean/grants.yaml +0 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-empty-register/frontend/packages/desktop/src/a.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-empty-register/frontend/packages/desktop/src/b.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-empty-register/grants.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/grants.yaml +0 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-missing-tree/frontend/packages/desktop/src/renderer/solo/item.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-missing-tree/grants.yaml +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/frontend/packages/desktop/src/a.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/frontend/packages/desktop/src/b.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/frontend/packages/desktop/src/c.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-stale-entry/frontend/packages/desktop/src/renderer/solo/item.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-stale-entry/grants.yaml +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/grants.yaml +0 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unusable-register/frontend/packages/desktop/src/renderer/solo/item.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unusable-register/grants.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/register.py +127 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/test_check.py +265 -29
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/check.py +75 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/test_check.py +194 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/check.py +56 -10
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/test_check.py +258 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/check.py +40 -12
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/test_check.py +108 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plan_metadata.py +9 -4
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/check.py +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/items/az351-restore-entrypoint.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/test_check.py +3 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/check.py +2 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/check.py +23 -6
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/test_check.py +76 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/check.py +58 -17
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/test_check.py +161 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/check.py +35 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/test_check.py +108 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/check.py +281 -61
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/absolute-path.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/backslash-path.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/baseline-is-a-list.yaml +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/boolean-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/dot-segment.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/duplicate-path.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/empty-file.yaml +0 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/empty-segment.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/float-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/negative-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/no-over-limit-baseline.yaml +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/no-schema-version.yaml +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/non-string-path.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/not-yaml.yaml +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/null-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/parent-segment.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/string-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/top-level-is-a-list.yaml +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/trailing-slash.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/unknown-key.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/wrong-schema-version.yaml +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/zero-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/valid.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/test_check.py +758 -45
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/check.py +4 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/test_check.py +2 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/cargo_lock.py +490 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/check.py +368 -55
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_check.py +4 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_declared_paths.py +523 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_stale_lock.py +1179 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/cli.py +122 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/check.py +33 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/constants.py +0 -11
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/context.py +16 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/config.py +1 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/docs_shape.py +12 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.alt.yaml +133 -147
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.yaml +133 -147
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/registry.py +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/root_shape.py +52 -10
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/runner.py +23 -4
- package/packages/repo-controls/package.json +2 -9
- package/packages/repo-controls/scripts/hooks/post-merge +13 -0
- package/packages/repo-controls/scripts/hooks/pre-push +3 -3
- package/packages/repo-controls/src/azdo-push.ts +64 -36
- package/packages/repo-controls/src/azure-devops-governance.ts +7 -9
- package/packages/repo-controls/src/azure-devops-remote.ts +1 -1
- package/packages/repo-controls/src/cli.ts +29 -8
- package/packages/repo-controls/src/compliance-config.ts +410 -2
- package/packages/repo-controls/src/config.ts +133 -60
- package/packages/repo-controls/src/constants.ts +13 -27
- package/packages/repo-controls/src/coverage-ratchet.ts +4 -4
- package/packages/repo-controls/src/doctor.ts +46 -19
- package/packages/repo-controls/src/gitignore-block.ts +5 -29
- package/packages/repo-controls/src/hook-log.ts +1 -2
- package/packages/repo-controls/src/hook.ts +201 -45
- package/packages/repo-controls/src/install.ts +14 -8
- package/packages/repo-controls/src/integrity.ts +3 -3
- package/packages/repo-controls/src/lfs.ts +111 -0
- package/packages/repo-controls/src/promote.ts +8 -8
- package/packages/repo-controls/src/runtime.ts +9 -1
- package/packages/repo-controls/src/workflows-drift.ts +4 -5
- package/packages/repo-controls/src/worktree-guard.ts +3 -3
package/bin/reconcile
CHANGED
|
@@ -110,9 +110,7 @@ failed_tools=()
|
|
|
110
110
|
# block at the very end, just before "global-tools: reconciliation complete"
|
|
111
111
|
# (Tarun, 2026-09-28). Collected from every step that backs something up
|
|
112
112
|
# before overwriting/removing a file: kimi-hooks (parsed from its own
|
|
113
|
-
# captured "backed up previous config to <path>" note),
|
|
114
|
-
# (2026-09-29, STATUS.md 12p item 13 final scope -- same note shape, parsed
|
|
115
|
-
# by collect_lean_ctx_observe_strip_backups), the global surface sweep
|
|
113
|
+
# captured "backed up previous config to <path>" note), the global surface sweep
|
|
116
114
|
# (parsed from ITS OWN already-printed "global-surface-sweep: backups
|
|
117
115
|
# this run:" block -- never recomputed here, per Tarun's instruction not to
|
|
118
116
|
# duplicate that package's backup logic), and write_one_repo_script below
|
|
@@ -157,39 +155,6 @@ collect_kimi_hooks_backups() {
|
|
|
157
155
|
done <<<"$text"
|
|
158
156
|
}
|
|
159
157
|
|
|
160
|
-
# Same shape as collect_kimi_hooks_backups, for bin/lean-ctx-observe-strip's
|
|
161
|
-
# own "lean-ctx-observe-strip: backed up previous config to <path>" note --
|
|
162
|
-
# unlike kimi-hooks (always exactly one config file), this step can strip
|
|
163
|
-
# multiple JSON/shell-rc targets in one run, so the loop below (like
|
|
164
|
-
# collect_sweep_backups) records every match, not just the first.
|
|
165
|
-
#
|
|
166
|
-
# A skill-directory backup gets a SECOND, distinct line shape: "backed up
|
|
167
|
-
# previous skill directory <original> to <backup>" (final review finding
|
|
168
|
-
# 1: its backup path is a SIBLING of the scanned skills/ directory, e.g.
|
|
169
|
-
# ".codex/skills.pre-lean-ctx-observe-strip-<ts>/lean-ctx" -- it no longer
|
|
170
|
-
# ends in ".pre-<label>-<timestamp>", so strip_backup_suffix's regex can't
|
|
171
|
-
# recover the original path from it; that note states BOTH paths directly
|
|
172
|
-
# instead, and is matched here as its own case rather than forced through
|
|
173
|
-
# the single-path regex above).
|
|
174
|
-
collect_lean_ctx_observe_strip_backups() {
|
|
175
|
-
local text="$1" line backup original
|
|
176
|
-
while IFS= read -r line; do
|
|
177
|
-
if [[ "$line" =~ ^lean-ctx-observe-strip:\ backed\ up\ previous\ config\ to\ (.+)$ ]]; then
|
|
178
|
-
backup="${BASH_REMATCH[1]}"
|
|
179
|
-
record_backup "$(strip_backup_suffix "$backup")" "$backup"
|
|
180
|
-
elif [[ "$line" =~ ^lean-ctx-observe-strip:\ backed\ up\ previous\ skill\ directory\ (.+)\ to\ (.+)$ ]]; then
|
|
181
|
-
original="${BASH_REMATCH[1]}"
|
|
182
|
-
backup="${BASH_REMATCH[2]}"
|
|
183
|
-
record_backup "$original" "$backup"
|
|
184
|
-
elif [[ "$line" =~ ^lean-ctx-observe-strip:\ backed\ up\ previous\ hook\ script\ (.+)\ to\ (.+)$ ]]; then
|
|
185
|
-
# ~/.claude/hooks/lean-ctx-* scripts: same two-path shape as a skill
|
|
186
|
-
# directory (sibling "hooks.pre-lean-ctx-observe-strip-<ts>/" backup).
|
|
187
|
-
original="${BASH_REMATCH[1]}"
|
|
188
|
-
backup="${BASH_REMATCH[2]}"
|
|
189
|
-
record_backup "$original" "$backup"
|
|
190
|
-
fi
|
|
191
|
-
done <<<"$text"
|
|
192
|
-
}
|
|
193
158
|
|
|
194
159
|
# Folds the global-surface-sweep's OWN already-computed and already-printed
|
|
195
160
|
# backup lines into this run's combined summary, without recomputing
|
|
@@ -223,7 +188,9 @@ repo_root="$(cd "$script_dir/.." && pwd)"
|
|
|
223
188
|
manifest="${manifest:-$repo_root/packages/fleet/manifest.json}"
|
|
224
189
|
# shellcheck source=lib/bun-compile-build.sh
|
|
225
190
|
source "$script_dir/lib/bun-compile-build.sh"
|
|
226
|
-
|
|
191
|
+
# shellcheck source=lib/adl-package.sh
|
|
192
|
+
source "$script_dir/lib/adl-package.sh"
|
|
193
|
+
"$BASH" "$script_dir/validate-manifest" "$manifest" >/dev/null
|
|
227
194
|
if [[ "${RECONCILE_SOURCE_ONLY:-0}" != "1" ]]; then
|
|
228
195
|
if [[ "$source_mode" == npm && -e "$repo_root/.git" ]]; then
|
|
229
196
|
echo "ERROR npm source mode requires an installed package root; use --source checkout for a Git checkout" >&2
|
|
@@ -331,9 +298,24 @@ run_brew() {
|
|
|
331
298
|
return 0
|
|
332
299
|
fi
|
|
333
300
|
[[ "$(id -u)" -eq 0 ]] || { echo "ERROR apply mode must run as root" >&2; exit 1; }
|
|
301
|
+
if [[ -n "${brew_noninteractive_dir:-}" ]]; then
|
|
302
|
+
# The upgrade step: no sudo Homebrew spawns may prompt (see run_brew_upgrade_all).
|
|
303
|
+
(cd /tmp && sudo -u "$brew_owner" -H env -u SUDO_ASKPASS NONINTERACTIVE=1 HOMEBREW_NO_SUDO=1 HOMEBREW_NO_ENV_HINTS=1 PATH="$brew_noninteractive_dir:${brew_bin%/*}:/usr/bin:/bin" "$brew_bin" "$@" </dev/null)
|
|
304
|
+
return
|
|
305
|
+
fi
|
|
334
306
|
(cd /tmp && sudo -u "$brew_owner" -H env NONINTERACTIVE=1 PATH="${brew_bin%/*}:/usr/bin:/bin" "$brew_bin" "$@" </dev/null)
|
|
335
307
|
}
|
|
336
308
|
|
|
309
|
+
# A directory holding a `sudo` that can never prompt: it execs /usr/bin/sudo -n. Put first on the
|
|
310
|
+
# PATH of the brew upgrade step, for anything that calls sudo by name.
|
|
311
|
+
make_brew_noninteractive_shim() {
|
|
312
|
+
local dir
|
|
313
|
+
dir="$(mktemp -d "${TMPDIR:-/tmp}/adl-brew-sudo-shim.XXXXXX")" || return 1
|
|
314
|
+
printf '#!/bin/sh\nexec /usr/bin/sudo -n "$@"\n' >"$dir/sudo"
|
|
315
|
+
chmod 0755 "$dir" "$dir/sudo"
|
|
316
|
+
printf '%s\n' "$dir"
|
|
317
|
+
}
|
|
318
|
+
|
|
337
319
|
# Portable command timeout: neither GNU coreutils' `timeout` nor its `gtimeout`
|
|
338
320
|
# alias is installed by default on a fresh mac (this manifest installs
|
|
339
321
|
# neither), so a real `command -v timeout` gate would silently do nothing on
|
|
@@ -383,52 +365,126 @@ run_with_timeout() {
|
|
|
383
365
|
BREW_UPGRADE_ALL_TIMEOUT_SECONDS="${RECONCILE_BREW_UPGRADE_TIMEOUT_SECONDS:-1200}"
|
|
384
366
|
SURFACE_UPDATE_TIMEOUT_SECONDS="${RECONCILE_SURFACE_UPDATE_TIMEOUT_SECONDS:-300}"
|
|
385
367
|
|
|
386
|
-
#
|
|
387
|
-
#
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
#
|
|
393
|
-
#
|
|
368
|
+
# brew's output for a cask whose upgrade needed sudo but was not allowed to ask: Homebrew refusing
|
|
369
|
+
# ("sudo is disabled by HOMEBREW_NO_SUDO."), or sudo -n failing fast. It never blocks.
|
|
370
|
+
brew_output_needs_password() {
|
|
371
|
+
grep -Eiq 'sudo is disabled by HOMEBREW_NO_SUDO|sudo: .*(password|terminal|tty|askpass)|^Password:' <<<"$1"
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
# Upgrades the outdated Homebrew formulae and casks, from ONE `brew outdated --json=v2` (the
|
|
375
|
+
# formulae and casks, with installed and available versions). A formula outdated for reasons
|
|
376
|
+
# unrelated to this manifest (installed once by hand, or a transitive dependency of a manifest
|
|
377
|
+
# formula) still converges instead of accumulating outdated versions forever (item 1,
|
|
378
|
+
# 2026-09-28: `brew update` alone, the only brew-wide step that ran before this, never upgrades
|
|
379
|
+
# anything). Gated by the manifest's own brew_upgrade_all switch at the call site below, not
|
|
380
|
+
# inside this function -- this function always does the real (or plan-mode preview) work when
|
|
381
|
+
# called.
|
|
382
|
+
#
|
|
383
|
+
# Two rules from the live tests (Tarun, 2026-10-01):
|
|
384
|
+
# - config.brew_upgrade_exclude names packages that are never upgraded here (git: every Homebrew
|
|
385
|
+
# git upgrade installs an ad-hoc-signed binary at a new Cellar path and re-prompts the
|
|
386
|
+
# osxkeychain ACL). Not a `brew pin`, not a version pin: an outdated excluded package is one
|
|
387
|
+
# info line, and the rest is upgraded BY NAME.
|
|
388
|
+
# - a reconcile NEVER prompts, terminal or not (m5, 2026-10-01: an interactive `sudo adl setup`
|
|
389
|
+
# got a nested, echoing `Password:` from the visual-studio-code cask's sudo inside brew inside
|
|
390
|
+
# our sudo -u). Every brew call here runs with stdin /dev/null, SUDO_ASKPASS unset,
|
|
391
|
+
# HOMEBREW_NO_SUDO=1 (brew refuses before spawning sudo) and a PATH-shimmed `sudo -n`. Casks are
|
|
392
|
+
# upgraded one at a time; one that needs a password is reported as a WARN with the command to
|
|
393
|
+
# run by hand and is not a failed tool. A failing formula, or a cask that fails for any other
|
|
394
|
+
# reason, still fails loud.
|
|
394
395
|
run_brew_upgrade_all() {
|
|
396
|
+
if [[ "$mode" != apply ]]; then
|
|
397
|
+
run_brew_upgrade_all_body
|
|
398
|
+
return
|
|
399
|
+
fi
|
|
400
|
+
local status=0
|
|
401
|
+
brew_noninteractive_dir="$(make_brew_noninteractive_shim)" || { echo "ERROR could not create the brew sudo shim" >&2; return 1; }
|
|
402
|
+
run_brew_upgrade_all_body || status=$?
|
|
403
|
+
command rm -rf -- "$brew_noninteractive_dir"
|
|
404
|
+
brew_noninteractive_dir=""
|
|
405
|
+
return "$status"
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
run_brew_upgrade_all_body() {
|
|
395
409
|
if [[ "$mode" != apply ]]; then
|
|
396
410
|
echo "would run: brew upgrade (all outdated formulae and casks)"
|
|
411
|
+
local planned_excludes
|
|
412
|
+
planned_excludes="$(jq -r '(.config.brew_upgrade_exclude // []) | join(", ")' "$manifest")"
|
|
413
|
+
if [[ -n "$planned_excludes" ]]; then
|
|
414
|
+
echo "brew upgrade excludes (config.brew_upgrade_exclude): $planned_excludes"
|
|
415
|
+
fi
|
|
397
416
|
return 0
|
|
398
417
|
fi
|
|
399
418
|
[[ "$(id -u)" -eq 0 ]] || { echo "ERROR apply mode must run as root" >&2; exit 1; }
|
|
400
|
-
local
|
|
401
|
-
|
|
402
|
-
|
|
419
|
+
local outdated_json excluded_names line kind name installed available
|
|
420
|
+
local -a formulae=() casks=()
|
|
421
|
+
local skipped=0
|
|
422
|
+
outdated_json="$(brew_query outdated --json=v2)" || {
|
|
423
|
+
echo "ERROR brew outdated check failed" >&2
|
|
403
424
|
return 1
|
|
404
425
|
}
|
|
405
|
-
|
|
406
|
-
echo "ERROR brew outdated --
|
|
426
|
+
jq -e '(.formulae | type == "array") and (.casks | type == "array")' >/dev/null 2>&1 <<<"$outdated_json" || {
|
|
427
|
+
echo "ERROR brew outdated --json=v2 did not print formulae and casks" >&2
|
|
407
428
|
return 1
|
|
408
429
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
430
|
+
excluded_names="$(jq -r '(.config.brew_upgrade_exclude // [])[]' "$manifest")"
|
|
431
|
+
while IFS=$'\t' read -r kind name installed available; do
|
|
432
|
+
[[ -n "$name" ]] || continue
|
|
433
|
+
if [[ -n "$excluded_names" ]] && grep -Fxq -- "$name" <<<"$excluded_names"; then
|
|
434
|
+
echo "global-tools: brew upgrade skips excluded: $name ($installed → $available)"
|
|
435
|
+
skipped=$((skipped + 1))
|
|
436
|
+
continue
|
|
437
|
+
fi
|
|
438
|
+
if [[ "$kind" == formula ]]; then formulae+=("$name"); else casks+=("$name"); fi
|
|
439
|
+
done < <(jq -r '
|
|
440
|
+
def versions: if type == "array" then join(", ") else tostring end;
|
|
441
|
+
(.formulae[]? | ["formula", .name, (.installed_versions | versions), .current_version]),
|
|
442
|
+
(.casks[]? | ["cask", .name, (.installed_versions | versions), .current_version]) | @tsv
|
|
443
|
+
' <<<"$outdated_json")
|
|
444
|
+
local formulae_count="${#formulae[@]}" casks_count="${#casks[@]}"
|
|
413
445
|
if [[ "$formulae_count" -eq 0 && "$casks_count" -eq 0 ]]; then
|
|
414
|
-
|
|
446
|
+
if [[ "$skipped" -gt 0 ]]; then
|
|
447
|
+
echo "brew upgrade: nothing left to upgrade after $skipped excluded"
|
|
448
|
+
else
|
|
449
|
+
echo "brew upgrade: nothing outdated"
|
|
450
|
+
fi
|
|
415
451
|
return 0
|
|
416
452
|
fi
|
|
417
|
-
local upgrade_status=0
|
|
418
453
|
# Routed through run_brew itself (same owner/cwd/stdin wiring as every
|
|
419
454
|
# other brew mutation in this file), bounded by run_with_timeout so a
|
|
420
455
|
# network-stalled `brew upgrade` cannot hang the rest of this run forever.
|
|
421
456
|
# brew's output streams live -- never captured and printed at the end,
|
|
422
457
|
# which left a long upgrade silent for minutes and looking stuck.
|
|
423
458
|
echo "brew upgrade: $formulae_count formulae, $casks_count casks outdated; upgrading (timeout ${BREW_UPGRADE_ALL_TIMEOUT_SECONDS}s)"
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
459
|
+
local upgrade_status=0
|
|
460
|
+
local failed=0 cask cask_output
|
|
461
|
+
if [[ "$formulae_count" -gt 0 ]]; then
|
|
462
|
+
run_with_timeout "$BREW_UPGRADE_ALL_TIMEOUT_SECONDS" run_brew upgrade --formula "${formulae[@]}" 2>&1 || upgrade_status=$?
|
|
463
|
+
if [[ "$upgrade_status" -eq 124 ]]; then
|
|
464
|
+
echo "ERROR brew upgrade timed out after ${BREW_UPGRADE_ALL_TIMEOUT_SECONDS}s" >&2
|
|
465
|
+
return 1
|
|
466
|
+
elif [[ "$upgrade_status" -ne 0 ]]; then
|
|
467
|
+
echo "ERROR brew upgrade failed (exit $upgrade_status)" >&2
|
|
468
|
+
failed=1
|
|
469
|
+
fi
|
|
431
470
|
fi
|
|
471
|
+
for cask in ${casks[@]+"${casks[@]}"}; do
|
|
472
|
+
upgrade_status=0
|
|
473
|
+
cask_output="$(run_with_timeout "$BREW_UPGRADE_ALL_TIMEOUT_SECONDS" run_brew upgrade --cask "$cask" 2>&1)" || upgrade_status=$?
|
|
474
|
+
[[ -z "$cask_output" ]] || printf '%s\n' "$cask_output"
|
|
475
|
+
if [[ "$upgrade_status" -eq 124 ]]; then
|
|
476
|
+
echo "ERROR brew upgrade timed out after ${BREW_UPGRADE_ALL_TIMEOUT_SECONDS}s ($cask)" >&2
|
|
477
|
+
return 1
|
|
478
|
+
elif [[ "$upgrade_status" -ne 0 ]]; then
|
|
479
|
+
if brew_output_needs_password "$cask_output"; then
|
|
480
|
+
echo "WARN brew: $cask needs an interactive password to upgrade; run: brew upgrade --cask $cask" >&2
|
|
481
|
+
else
|
|
482
|
+
echo "ERROR brew upgrade failed (exit $upgrade_status): $cask" >&2
|
|
483
|
+
failed=1
|
|
484
|
+
fi
|
|
485
|
+
fi
|
|
486
|
+
done
|
|
487
|
+
[[ "$failed" -eq 0 ]] || return 1
|
|
432
488
|
echo "brew upgrade: $formulae_count formulae, $casks_count casks were outdated before upgrade"
|
|
433
489
|
return 0
|
|
434
490
|
}
|
|
@@ -582,6 +638,22 @@ npm_package_owns_executable() {
|
|
|
582
638
|
}
|
|
583
639
|
}
|
|
584
640
|
|
|
641
|
+
# The published package is installed with bun (Tarun, 2026-10-01). Package mode
|
|
642
|
+
# proves the administrator's `adl` IS this package (bin/lib/adl-package.sh, the
|
|
643
|
+
# check bin/setup runs too): a different adl earlier on the administrator's PATH
|
|
644
|
+
# -- a legacy compiled /usr/local/bin/adl from before the package existed -- would
|
|
645
|
+
# keep running instead of the package this job updates, so it fails loud here with
|
|
646
|
+
# the one-line fix instead of being silently tolerated.
|
|
647
|
+
adl_package_owns_executable() {
|
|
648
|
+
local os package_real
|
|
649
|
+
case "$platform" in
|
|
650
|
+
mac) os=Darwin ;;
|
|
651
|
+
*) os=Linux ;;
|
|
652
|
+
esac
|
|
653
|
+
package_real="$(cd -P -- "$repo_root" && pwd -P)" || return 1
|
|
654
|
+
adl_check_adl_not_shadowed "$administrator" "$os" "$administrator_home" "$package_real" "global-tools"
|
|
655
|
+
}
|
|
656
|
+
|
|
585
657
|
run_pip() {
|
|
586
658
|
if [[ "$mode" != apply ]]; then
|
|
587
659
|
printf 'would run pip as %s: python3 -m pip' "$administrator"
|
|
@@ -752,7 +824,7 @@ run_embedding_model() {
|
|
|
752
824
|
local package="$1"
|
|
753
825
|
local spec_json="$2"
|
|
754
826
|
if [[ "$mode" != apply ]]; then
|
|
755
|
-
printf 'would install embedding model: %s as %s -> ~/.cache/
|
|
827
|
+
printf 'would install embedding model: %s as %s -> ~/.cache/enact-embedding/model\n' "$package" "$administrator"
|
|
756
828
|
return 0
|
|
757
829
|
fi
|
|
758
830
|
[[ "$(id -u)" -eq 0 ]] || { echo "ERROR apply mode must run as root" >&2; exit 1; }
|
|
@@ -763,9 +835,8 @@ run_embedding_model() {
|
|
|
763
835
|
|
|
764
836
|
# Installs $src as $dest via a same-directory temp-file + rename, never a
|
|
765
837
|
# direct in-place write -- so a concurrent reader (including the next agent
|
|
766
|
-
# shell's `command -v $dest`,
|
|
767
|
-
# in-place
|
|
768
|
-
# "binary not found" for ~44s on every scheduled reconcile) can never observe
|
|
838
|
+
# shell's `command -v $dest`, which could otherwise observe an executable
|
|
839
|
+
# partway through an in-place rewrite) can never observe
|
|
769
840
|
# $dest existing but only partially written. `mv` within the same directory
|
|
770
841
|
# is a single rename(2) on both Darwin and Linux -- atomic by construction,
|
|
771
842
|
# not by scheduling luck.
|
|
@@ -796,8 +867,8 @@ install_surface_policy_file() {
|
|
|
796
867
|
|
|
797
868
|
# A resolved release version against the first line of a release-archive-
|
|
798
869
|
# latest tool's own `--version` output. Different tools format that line
|
|
799
|
-
# differently --
|
|
800
|
-
#
|
|
870
|
+
# differently -- some include parenthetical metadata; agent-vault prints
|
|
871
|
+
# "agent-vault version 0.39.3" (flush
|
|
801
872
|
# against the end of the line, no trailing space); a plain "vX.Y.Z" line
|
|
802
873
|
# with no separating space before the version at all -- so the LEFT boundary
|
|
803
874
|
# is a string start or a real space, with an OPTIONAL literal "v" directly
|
|
@@ -927,7 +998,7 @@ resolve_surface_mode() {
|
|
|
927
998
|
# root") is a real environment fault, not a flaky install, and still
|
|
928
999
|
# aborts immediately -- `exit` is unconditional and is never caught here.
|
|
929
1000
|
install_one_tool() {
|
|
930
|
-
local tool_id="$1" manager package executable previous_executable migrating_from_bun=0 rc=0 npm_spec npm_allow_scripts npm_target_version npm_installed_ver brew_outdated_output brew_installed_version
|
|
1001
|
+
local tool_id="$1" manager package executable previous_executable migrating_from_bun=0 rc=0 npm_spec npm_allow_scripts npm_target_version npm_installed_ver brew_outdated_output brew_installed_version trust_kind
|
|
931
1002
|
manager="$(jq -r --arg id "$tool_id" '.[$id].manager' "$resolved_file")"
|
|
932
1003
|
package="$(jq -r --arg id "$tool_id" '.[$id].package' "$resolved_file")"
|
|
933
1004
|
executable="$(jq -r --arg id "$tool_id" '.[$id].executable' "$resolved_file")"
|
|
@@ -941,19 +1012,76 @@ install_one_tool() {
|
|
|
941
1012
|
fi
|
|
942
1013
|
if [[ "$tool_id" == adl && "$source_mode" == npm ]]; then
|
|
943
1014
|
if [[ "$mode" != apply ]]; then
|
|
944
|
-
echo "would use installed
|
|
1015
|
+
echo "would use installed package payload: $repo_root"
|
|
945
1016
|
return 0
|
|
946
1017
|
fi
|
|
947
1018
|
if is_in_place_bun_to_npm_migration "$tool_id"; then
|
|
948
1019
|
prepare_in_place_bun_to_npm_migration "$tool_id" || return 1
|
|
949
1020
|
fi
|
|
950
|
-
|
|
951
|
-
echo "using installed
|
|
1021
|
+
adl_package_owns_executable || return 1
|
|
1022
|
+
echo "using installed package payload: $repo_root"
|
|
952
1023
|
return 0
|
|
953
1024
|
fi
|
|
954
1025
|
echo "ensure latest stable: $tool_id ($manager:$package)"
|
|
955
1026
|
case "$manager" in
|
|
956
1027
|
brew)
|
|
1028
|
+
# Optional declared tap (manifest .tap, owner/repo): fully-qualified
|
|
1029
|
+
# package names (e.g. stablyai/orca/orca) refuse to resolve until their
|
|
1030
|
+
# tap exists, and Homebrew will not auto-tap a non-core tap for a
|
|
1031
|
+
# noninteractive caller — so reconcile taps it first, idempotently.
|
|
1032
|
+
# Tarun 2026-10-02: orca is brew-managed from Stably's own tap; that
|
|
1033
|
+
# cask is auto_updates, so the per-tool path installs-if-missing and
|
|
1034
|
+
# the in-app updater owns versioning — no version is ever pinned here.
|
|
1035
|
+
tap="$(jq -r --arg id "$tool_id" '.[$id].tap // ""' "$resolved_file")"
|
|
1036
|
+
if [[ "$rc" -eq 0 && -n "$tap" ]]; then
|
|
1037
|
+
[[ "$tap" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]] || {
|
|
1038
|
+
echo "ERROR refusing unsafe brew tap name for $tool_id: $tap" >&2
|
|
1039
|
+
rc=1
|
|
1040
|
+
}
|
|
1041
|
+
fi
|
|
1042
|
+
if [[ "$rc" -eq 0 && -n "$tap" && "$mode" == apply ]]; then
|
|
1043
|
+
brew_query tap | grep -Fqx "$tap" || run_brew tap "$tap" || {
|
|
1044
|
+
echo "ERROR $tool_id: brew tap $tap failed" >&2
|
|
1045
|
+
rc=1
|
|
1046
|
+
}
|
|
1047
|
+
fi
|
|
1048
|
+
# Homebrew >=6 tap trust (brew 7.0.7 on this fleet; the 2026-10 orca
|
|
1049
|
+
# install failure was exactly this refusal): a command that must load an
|
|
1050
|
+
# untrusted non-core tap FAILS until trust is granted, noninteractively
|
|
1051
|
+
# or not. Grant ITEM-level trust for the declared package only --
|
|
1052
|
+
# brew's own automation guidance is `brew trust --formula|--cask
|
|
1053
|
+
# owner/repo/item`, never the whole tap. Gated on the same declared
|
|
1054
|
+
# .tap as the tap step above: that manifest field is the reviewed trust
|
|
1055
|
+
# boundary, and a bare core package (curl, ripgrep) needs no grant.
|
|
1056
|
+
if [[ "$rc" -eq 0 && -n "$tap" && "$mode" == apply ]]; then
|
|
1057
|
+
# The kind is resolved, never guessed: a fully-qualified name is
|
|
1058
|
+
# loadable exactly as one of formula/cask once its tap exists.
|
|
1059
|
+
if brew_query info --formula "$package" >/dev/null 2>&1; then
|
|
1060
|
+
trust_kind=formula
|
|
1061
|
+
elif brew_query info --cask "$package" >/dev/null 2>&1; then
|
|
1062
|
+
trust_kind=cask
|
|
1063
|
+
else
|
|
1064
|
+
echo "ERROR $tool_id: cannot determine whether $package is a formula or a cask — refusing to guess its trust kind" >&2
|
|
1065
|
+
rc=1
|
|
1066
|
+
fi
|
|
1067
|
+
# `brew trust` (list) prints each granted item on its own line,
|
|
1068
|
+
# indented under a "Trusted formulae:"/"Trusted casks:" header
|
|
1069
|
+
# (verified on brew 7.0.7) -- trim, then exact-line match so a
|
|
1070
|
+
# whole-tap grant ("Trusted taps: owner/repo") can never satisfy the
|
|
1071
|
+
# item check.
|
|
1072
|
+
if [[ "$rc" -eq 0 ]]; then
|
|
1073
|
+
brew_query trust | awk '{$1=$1};1' | grep -Fqx "$package" || run_brew trust "--$trust_kind" "$package" || {
|
|
1074
|
+
echo "ERROR $tool_id: brew trust --$trust_kind $package failed" >&2
|
|
1075
|
+
rc=1
|
|
1076
|
+
}
|
|
1077
|
+
fi
|
|
1078
|
+
elif [[ "$rc" -eq 0 && -n "$tap" ]]; then
|
|
1079
|
+
# Plan mode: brew_query is apply-only (see its own header comment),
|
|
1080
|
+
# so the kind is not resolved for a preview -- name the grant anyway.
|
|
1081
|
+
echo "would trust Homebrew item: $package (formula|cask)"
|
|
1082
|
+
fi
|
|
1083
|
+
if [[ "$rc" -ne 0 ]]; then
|
|
1084
|
+
:
|
|
957
1085
|
# Plan mode's message is intentionally unconditional (see brew_query's
|
|
958
1086
|
# own comment for why: a real up-to-date check is slow enough on a
|
|
959
1087
|
# loaded box to defeat the point of a quick preview). Apply mode pays
|
|
@@ -961,7 +1089,7 @@ install_one_tool() {
|
|
|
961
1089
|
# run `brew upgrade` on an already-current formula -- which brew itself
|
|
962
1090
|
# accepts silently (prints "Warning: <pkg> <ver> already installed" and
|
|
963
1091
|
# exits 0), the exact per-run noise this replaces.
|
|
964
|
-
|
|
1092
|
+
elif [[ "$mode" != apply ]]; then
|
|
965
1093
|
echo "would install or upgrade Homebrew formula: $package"
|
|
966
1094
|
elif brew_query list --formula "$package" >/dev/null 2>&1; then
|
|
967
1095
|
if brew_outdated_output="$(brew_query outdated --formula --quiet "$package")"; then
|
|
@@ -1054,10 +1182,8 @@ install_one_tool() {
|
|
|
1054
1182
|
latest_tag="$(resolve_latest_release_tag "$repo")" || { rc=1; latest_tag=""; }
|
|
1055
1183
|
if [[ "$rc" -eq 0 ]]; then
|
|
1056
1184
|
latest_version="${latest_tag#v}"
|
|
1057
|
-
# A release whose asset filename bakes in the version
|
|
1058
|
-
#
|
|
1059
|
-
# .asset/.checksums_asset; lean-ctx's own asset names carry no
|
|
1060
|
-
# version at all, so this is a no-op substring replace for it.
|
|
1185
|
+
# A release whose asset filename bakes in the version declares
|
|
1186
|
+
# "{version}" in .asset/.checksums_asset; otherwise this is a no-op.
|
|
1061
1187
|
resolved_asset="${asset//\{version\}/$latest_version}"
|
|
1062
1188
|
resolved_checksums_asset="${checksums_asset//\{version\}/$latest_version}"
|
|
1063
1189
|
if [[ -x "$executable" ]] &&
|
|
@@ -1129,10 +1255,17 @@ prepare_in_place_bun_to_npm_migration() {
|
|
|
1129
1255
|
if [[ -L "$migration_path" ]]; then
|
|
1130
1256
|
package="$(jq -r --arg id "$tool_id" '.[$id].package' "$resolved_file")"
|
|
1131
1257
|
executable="$(jq -r --arg id "$tool_id" '.[$id].executable' "$resolved_file")"
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1258
|
+
if [[ "$tool_id" == adl && "$source_mode" == npm ]]; then
|
|
1259
|
+
adl_package_owns_executable || {
|
|
1260
|
+
echo "ERROR refusing to remove an executable symlink not owned by the installed package: $previous_executable" >&2
|
|
1261
|
+
return 1
|
|
1262
|
+
}
|
|
1263
|
+
else
|
|
1264
|
+
npm_package_owns_executable "$package" "$executable" || {
|
|
1265
|
+
echo "ERROR refusing to remove an executable symlink not owned by npm: $previous_executable" >&2
|
|
1266
|
+
return 1
|
|
1267
|
+
}
|
|
1268
|
+
fi
|
|
1136
1269
|
hash_file="$(bun_source_hash_file "$tool_id")"
|
|
1137
1270
|
rm -f -- "$hash_file" || return 1
|
|
1138
1271
|
echo "retained npm-owned executable and removed retired Bun marker: $previous_executable ($hash_file)"
|
|
@@ -1214,7 +1347,7 @@ build_checkout_adl() {
|
|
|
1214
1347
|
return "$rc"
|
|
1215
1348
|
}
|
|
1216
1349
|
|
|
1217
|
-
# embedding-model installs the
|
|
1350
|
+
# embedding-model installs the enact-embedding static (Model2Vec) artifact
|
|
1218
1351
|
# that adl hook's (the folded-in hook engine's) skill-match hook loads
|
|
1219
1352
|
# from the administrator's cache.
|
|
1220
1353
|
# It runs as the declared administrator (root on Linux) so the hook and
|
|
@@ -1284,7 +1417,7 @@ managed_repo_script_marker='# Managed by adl global-tools.'
|
|
|
1284
1417
|
# real, previously-self-installed files as "unmanaged", so apply mode refused
|
|
1285
1418
|
# to update them ("refusing to replace unmanaged or symlinked managed script
|
|
1286
1419
|
# target") instead of replacing them with the renamed source -- seen live on
|
|
1287
|
-
# M3's `fleet-cutover.sh --apply` for /usr/local/bin/git and
|
|
1420
|
+
# M3's `packages/fleet/scripts/fleet-cutover.sh --apply` for /usr/local/bin/git and
|
|
1288
1421
|
# /usr/local/bin/git-ado. A target carrying EITHER line is this writer's own
|
|
1289
1422
|
# prior output and must still be treated as managed; a target carrying
|
|
1290
1423
|
# neither (or a symlink) must keep being refused.
|
|
@@ -1325,8 +1458,10 @@ write_one_repo_script() {
|
|
|
1325
1458
|
return 1
|
|
1326
1459
|
}
|
|
1327
1460
|
source_path="$repo_root/$source"
|
|
1328
|
-
|
|
1329
|
-
|
|
1461
|
+
# -f, not -x: bun leaves every shipped file but the `bin` targets 0644, and the
|
|
1462
|
+
# copy below is installed 0755.
|
|
1463
|
+
[[ -f "$source_path" && ! -L "$source_path" ]] || {
|
|
1464
|
+
echo "ERROR managed script source must be a regular non-symlink file: $source_path" >&2
|
|
1330
1465
|
return 1
|
|
1331
1466
|
}
|
|
1332
1467
|
if [[ "$mode" != apply ]]; then
|
|
@@ -1681,6 +1816,27 @@ executable_claimed_by_current_manifest() {
|
|
|
1681
1816
|
# into its own function, like install_one_tool, so
|
|
1682
1817
|
# packages/fleet/tests/test-manifest.sh can exercise it directly through the
|
|
1683
1818
|
# RECONCILE_SOURCE_ONLY seam instead of only through a real apply run.
|
|
1819
|
+
remove_release_archive_executable() {
|
|
1820
|
+
local executable="$1" label="$2" target="$executable"
|
|
1821
|
+
[[ "$executable" =~ ^/usr/local/bin/[A-Za-z0-9][A-Za-z0-9._-]*$ ]] || {
|
|
1822
|
+
echo "ERROR refusing unsafe release archive removal target: $executable" >&2
|
|
1823
|
+
return 1
|
|
1824
|
+
}
|
|
1825
|
+
if [[ "${RECONCILE_SOURCE_ONLY:-0}" == 1 && -n "${RECONCILE_TEST_COMMAND_ROOT:-}" ]]; then
|
|
1826
|
+
target="${RECONCILE_TEST_COMMAND_ROOT%/}/${executable##*/}"
|
|
1827
|
+
fi
|
|
1828
|
+
if [[ "$mode" == apply ]]; then
|
|
1829
|
+
rm -f -- "$target" || return 1
|
|
1830
|
+
[[ ! -e "$target" && ! -L "$target" ]] || {
|
|
1831
|
+
echo "ERROR release archive executable remains after removal: $target" >&2
|
|
1832
|
+
return 1
|
|
1833
|
+
}
|
|
1834
|
+
echo "removed $label release executable: $executable"
|
|
1835
|
+
else
|
|
1836
|
+
echo "would remove $label release executable: $executable"
|
|
1837
|
+
fi
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1684
1840
|
remove_one_manifest_entry() {
|
|
1685
1841
|
local tool_id="$1" manager package executable removed_repo_dir_target
|
|
1686
1842
|
if jq -e --arg id "$tool_id" '.config.protected_tools | index($id)' "$manifest" >/dev/null; then
|
|
@@ -1735,26 +1891,10 @@ remove_one_manifest_entry() {
|
|
|
1735
1891
|
# still cleanly uninstall it the next time it reconciles; previous
|
|
1736
1892
|
# state is read straight from disk, never re-validated.
|
|
1737
1893
|
release-archive)
|
|
1738
|
-
|
|
1739
|
-
echo "ERROR refusing unsafe release archive removal target: $executable" >&2
|
|
1740
|
-
exit 1
|
|
1741
|
-
}
|
|
1742
|
-
if [[ "$mode" == apply ]]; then
|
|
1743
|
-
rm -f -- "$executable"
|
|
1744
|
-
else
|
|
1745
|
-
echo "would remove pinned release executable: $executable"
|
|
1746
|
-
fi
|
|
1894
|
+
remove_release_archive_executable "$executable" pinned
|
|
1747
1895
|
;;
|
|
1748
1896
|
release-archive-latest)
|
|
1749
|
-
|
|
1750
|
-
echo "ERROR refusing unsafe release archive removal target: $executable" >&2
|
|
1751
|
-
exit 1
|
|
1752
|
-
}
|
|
1753
|
-
if [[ "$mode" == apply ]]; then
|
|
1754
|
-
rm -f -- "$executable"
|
|
1755
|
-
else
|
|
1756
|
-
echo "would remove latest release executable: $executable"
|
|
1757
|
-
fi
|
|
1897
|
+
remove_release_archive_executable "$executable" latest
|
|
1758
1898
|
;;
|
|
1759
1899
|
shim)
|
|
1760
1900
|
[[ "$executable" == /usr/local/bin/* ]] || {
|
|
@@ -1808,29 +1948,13 @@ remove_one_manifest_entry() {
|
|
|
1808
1948
|
(cd /tmp && sudo -u "$administrator" -H env PATH="${brew_bin%/*}:/usr/bin:/bin" \
|
|
1809
1949
|
bun "$repo_root/packages/fleet/src/install-embedding-model.ts" uninstall </dev/null)
|
|
1810
1950
|
else
|
|
1811
|
-
echo "would remove embedding model cache: ~/.cache/
|
|
1951
|
+
echo "would remove embedding model cache: ~/.cache/enact-embedding/model (as $administrator)"
|
|
1812
1952
|
fi
|
|
1813
1953
|
;;
|
|
1814
1954
|
*) echo "ERROR unsupported manager in previous manifest: $manager" >&2; exit 1 ;;
|
|
1815
1955
|
esac
|
|
1816
1956
|
}
|
|
1817
1957
|
|
|
1818
|
-
# config.git_global_config: global git config for the administrator (the
|
|
1819
|
-
# account whose HOME the per-user deployers below also write to). Apply runs git as
|
|
1820
|
-
# that user (sudo -u -H) so ~/.gitconfig stays user-owned; plan/audit only
|
|
1821
|
-
# read, as whoever invoked reconcile. Motivating entries: Azure DevOps SSH
|
|
1822
|
-
# has no Git LFS support, and git-lfs's default pure-SSH `git-lfs-transfer`
|
|
1823
|
-
# probe hangs forever against ssh.dev.azure.com, stalling every `git push` in
|
|
1824
|
-
# the LFS pre-push hook.
|
|
1825
|
-
run_git_config_global() {
|
|
1826
|
-
if [[ "$mode" == apply ]]; then
|
|
1827
|
-
[[ "$(id -u)" -eq 0 ]] || { echo "ERROR apply mode must run as root" >&2; exit 1; }
|
|
1828
|
-
(cd /tmp && sudo -u "$git_config_user" -H git config --global "$@" </dev/null)
|
|
1829
|
-
else
|
|
1830
|
-
git config --global "$@" </dev/null
|
|
1831
|
-
fi
|
|
1832
|
-
}
|
|
1833
|
-
|
|
1834
1958
|
# One-release migration for Linux state written by the retired two-user
|
|
1835
1959
|
# contract. The previous applied manifest is the authority for the former
|
|
1836
1960
|
# account and home, so no legacy identity remains configured after a successful
|
|
@@ -1875,49 +1999,18 @@ cleanup_legacy_linux_git_config() {
|
|
|
1875
1999
|
done
|
|
1876
2000
|
}
|
|
1877
2001
|
|
|
1878
|
-
#
|
|
1879
|
-
#
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
return 0
|
|
1885
|
-
fi
|
|
1886
|
-
[[ "$rc" -eq 0 ]] || { echo "ERROR git config --global --get $key failed (exit $rc)" >&2; return "$rc"; }
|
|
1887
|
-
printf '%s\n' "$value"
|
|
1888
|
-
}
|
|
1889
|
-
|
|
2002
|
+
# config.git_global_config + <platform>.common.git_global_config + the device's
|
|
2003
|
+
# git_user: the administrator's global git config, identical on every host
|
|
2004
|
+
# (Tarun, 2026-10-01). All logic lives in bin/git-defaults; undeclared keys are
|
|
2005
|
+
# never touched. Motivating entries: Azure DevOps SSH has no Git LFS support
|
|
2006
|
+
# (git-lfs's pure-SSH probe hangs against ssh.dev.azure.com), and GCM is the
|
|
2007
|
+
# credential helper on every host.
|
|
1890
2008
|
reconcile_git_global_config() {
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
echo "global git config already set: $key=$value"
|
|
1897
|
-
elif [[ "$mode" != apply ]]; then
|
|
1898
|
-
echo "would set global git config: $key=$value"
|
|
1899
|
-
else
|
|
1900
|
-
run_git_config_global "$key" "$value" || return 1
|
|
1901
|
-
echo "set global git config: $key=$value"
|
|
1902
|
-
fi
|
|
1903
|
-
done < <(jq -r '.config.git_global_config | to_entries[] | [.key, .value] | @tsv' "$manifest")
|
|
1904
|
-
|
|
1905
|
-
[[ "$have_previous" -eq 1 ]] || return 0
|
|
1906
|
-
while IFS= read -r key; do
|
|
1907
|
-
[[ -n "$key" ]] || continue
|
|
1908
|
-
current="$(git_global_config_value "$key")" || return 1
|
|
1909
|
-
[[ -n "$current" ]] || continue
|
|
1910
|
-
if [[ "$mode" != apply ]]; then
|
|
1911
|
-
echo "would unset global git config (explicit manifest deletion): $key"
|
|
1912
|
-
else
|
|
1913
|
-
run_git_config_global --unset-all "$key" || return 1
|
|
1914
|
-
echo "explicit manifest deletion: unset global git config $key"
|
|
1915
|
-
fi
|
|
1916
|
-
done < <(jq -r --slurpfile current "$manifest" '
|
|
1917
|
-
(.config.git_global_config // {}) | keys[] as $key
|
|
1918
|
-
| select(($current[0].config.git_global_config | has($key)) | not)
|
|
1919
|
-
| $key
|
|
1920
|
-
' "$applied_manifest")
|
|
2009
|
+
if [[ "$mode" == apply ]]; then
|
|
2010
|
+
[[ "$(id -u)" -eq 0 ]] || { echo "ERROR apply mode must run as root" >&2; exit 1; }
|
|
2011
|
+
fi
|
|
2012
|
+
"$BASH" "$repo_root/bin/git-defaults" --manifest "$manifest" --platform "$platform" \
|
|
2013
|
+
--device "$device" --mode "$mode" --administrator "$git_config_user"
|
|
1921
2014
|
}
|
|
1922
2015
|
|
|
1923
2016
|
# default-agent-file.ts and managed-settings.ts (Claude/Codex) MUST run
|
|
@@ -1946,9 +2039,11 @@ require_bun_for_identity_files() {
|
|
|
1946
2039
|
# The PATH searched for a surface command intentionally extends past the
|
|
1947
2040
|
# usual brew/system directories into the per-user install locations these
|
|
1948
2041
|
# specific CLIs' own installers use (claude's and cursor's native installers,
|
|
1949
|
-
# kimi's
|
|
1950
|
-
#
|
|
1951
|
-
|
|
2042
|
+
# kimi's curl-script installer) -- none of those are on the plain system PATH
|
|
2043
|
+
# this file uses elsewhere for brew/npm/pip. opencode is the exception (Tarun,
|
|
2044
|
+
# 2026-10-01): it comes from the npm registry through bun, so bun's global bin
|
|
2045
|
+
# directory is searched instead of the retired native ~/.opencode/bin.
|
|
2046
|
+
surface_cli_search_path="$administrator_home/.local/bin:$administrator_home/.kimi-code/bin:$administrator_home/.bun/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin:/usr/local/bin:/usr/bin:/bin"
|
|
1952
2047
|
|
|
1953
2048
|
# Resolves a surface to the real executable that will be run: an explicit
|
|
1954
2049
|
# manifest `executable` (a fixed, known path -- e.g. hostinger's report-only
|
|
@@ -2017,6 +2112,173 @@ surface_update_error_reason() {
|
|
|
2017
2112
|
fi
|
|
2018
2113
|
}
|
|
2019
2114
|
|
|
2115
|
+
# bun-managed surface (Tarun, 2026-10-01, "we are not on GitHub"): opencode is installed and updated
|
|
2116
|
+
# from the npm registry package `opencode-ai` with `bun add -g opencode-ai@latest`, run as the
|
|
2117
|
+
# administrator -- never `opencode upgrade`, which asks the unauthenticated GitHub REST API for its
|
|
2118
|
+
# latest release and 403s under the fleet's shared-IP rate limit. Named so tests can stub the one
|
|
2119
|
+
# boundary that touches the machine; adl_bun_add_global (bin/lib/adl-package.sh) is the same call
|
|
2120
|
+
# the adl package install uses (the administrator's own ~/.bun, bun found through Homebrew).
|
|
2121
|
+
run_surface_bun_add() {
|
|
2122
|
+
local spec="$1" os
|
|
2123
|
+
case "$platform" in
|
|
2124
|
+
mac) os=Darwin ;;
|
|
2125
|
+
linux) os=Linux ;;
|
|
2126
|
+
*) echo "ERROR unsupported platform for a bun surface: $platform" >&2; return 1 ;;
|
|
2127
|
+
esac
|
|
2128
|
+
adl_bun_add_global "$administrator" "$os" "$administrator_home" "$spec" </dev/null
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
# Finds every OTHER copy of a bun-managed surface command: each directory on the surface search
|
|
2132
|
+
# path plus the native installer's ~/.opencode/bin. Prints one TAB-separated record per distinct
|
|
2133
|
+
# copy, `kind<TAB>path<TAB>detail`, where kind is
|
|
2134
|
+
# native <home>/.opencode/bin/<command> (a regular executable the native installer wrote;
|
|
2135
|
+
# path is the bin DIRECTORY that is moved aside)
|
|
2136
|
+
# brew a symlink into <this host's Homebrew prefix>/Cellar/<command>/<version>/bin/<command>
|
|
2137
|
+
# npm a symlink into <prefix>/lib/node_modules/<package>/bin/<command>.exe whose
|
|
2138
|
+
# package.json names <package> (detail is the prefix)
|
|
2139
|
+
# unrecognised anything else (detail is where it really points)
|
|
2140
|
+
# A copy is retired only when it is positively one of the first three; the bun install itself is
|
|
2141
|
+
# skipped. Several PATH entries that reach one real file (/bin -> usr/bin) count once.
|
|
2142
|
+
classify_surface_copies() {
|
|
2143
|
+
local command_name="$1" package="$2" bun_exe="$3"
|
|
2144
|
+
local dirs=() dir path real bun_real seen=" " native_bin="$administrator_home/.opencode/bin" prefix pkg_dir brew_prefix
|
|
2145
|
+
brew_prefix="$(cd -P -- "${brew_bin%/bin/brew}" 2>/dev/null && pwd -P)" || brew_prefix="${brew_bin%/bin/brew}"
|
|
2146
|
+
IFS=: read -r -a dirs <<<"$surface_cli_search_path"
|
|
2147
|
+
dirs+=("$native_bin")
|
|
2148
|
+
bun_real="$(adl_realpath "$bun_exe" 2>/dev/null)" || bun_real="$bun_exe"
|
|
2149
|
+
for dir in "${dirs[@]}"; do
|
|
2150
|
+
[[ -n "$dir" ]] || continue
|
|
2151
|
+
path="$dir/$command_name"
|
|
2152
|
+
[[ -e "$path" || -L "$path" ]] || continue
|
|
2153
|
+
real="$(adl_realpath "$path" 2>/dev/null)" || real="$path"
|
|
2154
|
+
[[ "$real" != "$bun_real" ]] || continue
|
|
2155
|
+
case "$seen" in *" $real "*) continue ;; esac
|
|
2156
|
+
seen="$seen$real "
|
|
2157
|
+
if [[ "$path" == "$native_bin/$command_name" && -f "$path" && ! -L "$path" && -x "$path" ]]; then
|
|
2158
|
+
printf 'native\t%s\t%s\n' "$native_bin" "$path"
|
|
2159
|
+
elif [[ "$real" =~ ^(.*)/Cellar/${command_name}/[^/]+/bin/${command_name}$ && "${BASH_REMATCH[1]}" == "$brew_prefix" ]]; then
|
|
2160
|
+
printf 'brew\t%s\t%s\n' "$path" "${BASH_REMATCH[1]}"
|
|
2161
|
+
elif [[ "$real" =~ ^(.*)/lib/node_modules/${package}/bin/${command_name}\.exe$ ]]; then
|
|
2162
|
+
prefix="${BASH_REMATCH[1]}"
|
|
2163
|
+
pkg_dir="$prefix/lib/node_modules/$package"
|
|
2164
|
+
if [[ -f "$pkg_dir/package.json" ]] && jq -e --arg name "$package" '.name == $name' "$pkg_dir/package.json" >/dev/null 2>&1; then
|
|
2165
|
+
printf 'npm\t%s\t%s\n' "$path" "$prefix"
|
|
2166
|
+
else
|
|
2167
|
+
printf 'unrecognised\t%s\t%s\n' "$path" "$real"
|
|
2168
|
+
fi
|
|
2169
|
+
else
|
|
2170
|
+
printf 'unrecognised\t%s\t%s\n' "$path" "$real"
|
|
2171
|
+
fi
|
|
2172
|
+
done
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
# Retires every other copy of a bun-managed surface so the host has exactly one, idempotently:
|
|
2176
|
+
# the native installer's ~/.opencode/bin is moved ASIDE under <state dir>/retired-opencode/<UTC
|
|
2177
|
+
# stamp>/native-bin (never deleted; ~/.opencode's own plugin files and ~/.config/opencode are not
|
|
2178
|
+
# touched), a Homebrew formula goes through `brew uninstall` as the Homebrew owner (run_brew, never
|
|
2179
|
+
# sudo brew), and an npm global goes through `npm uninstall -g --prefix <its real prefix>`. Anything
|
|
2180
|
+
# not positively identified is an ERROR and NOTHING is removed. Plan mode lists what apply would do.
|
|
2181
|
+
retire_other_surface_copies() {
|
|
2182
|
+
local name="$1" command_name="$2" package="$3" bun_exe="$4"
|
|
2183
|
+
local kinds=() paths=() details=() kind path detail i unrecognised=0 aside=""
|
|
2184
|
+
while IFS=$'\t' read -r kind path detail; do
|
|
2185
|
+
[[ -n "$kind" ]] || continue
|
|
2186
|
+
kinds+=("$kind"); paths+=("$path"); details+=("$detail")
|
|
2187
|
+
done < <(classify_surface_copies "$command_name" "$package" "$bun_exe")
|
|
2188
|
+
[[ "${#kinds[@]}" -gt 0 ]] || return 0
|
|
2189
|
+
for ((i = 0; i < ${#kinds[@]}; i++)); do
|
|
2190
|
+
[[ "${kinds[i]}" == unrecognised ]] || continue
|
|
2191
|
+
unrecognised=1
|
|
2192
|
+
if [[ "$mode" != apply ]]; then
|
|
2193
|
+
echo "global-tools: would FAIL: unrecognised $command_name at ${paths[i]} (-> ${details[i]}); not a copy reconcile knows how to retire"
|
|
2194
|
+
else
|
|
2195
|
+
echo "ERROR surface $name: unrecognised $command_name at ${paths[i]} (-> ${details[i]}); not a copy reconcile knows how to retire, so nothing was removed" >&2
|
|
2196
|
+
fi
|
|
2197
|
+
done
|
|
2198
|
+
if [[ "$unrecognised" -eq 1 ]]; then
|
|
2199
|
+
[[ "$mode" != apply ]] || return 1
|
|
2200
|
+
return 0
|
|
2201
|
+
fi
|
|
2202
|
+
if [[ "$mode" != apply ]]; then
|
|
2203
|
+
for ((i = 0; i < ${#kinds[@]}; i++)); do
|
|
2204
|
+
case "${kinds[i]}" in
|
|
2205
|
+
native) echo "global-tools: would retire $command_name copy: move ${paths[i]} aside (native installer)" ;;
|
|
2206
|
+
brew) echo "global-tools: would retire $command_name copy: brew uninstall $command_name (Homebrew formula, ${paths[i]})" ;;
|
|
2207
|
+
npm) echo "global-tools: would retire $command_name copy: npm uninstall -g --prefix ${details[i]} $package (${paths[i]})" ;;
|
|
2208
|
+
esac
|
|
2209
|
+
done
|
|
2210
|
+
return 0
|
|
2211
|
+
fi
|
|
2212
|
+
for ((i = 0; i < ${#kinds[@]}; i++)); do
|
|
2213
|
+
case "${kinds[i]}" in
|
|
2214
|
+
native)
|
|
2215
|
+
[[ -n "$aside" ]] || aside="$state_dir/retired-$command_name/$(date -u +%Y%m%dT%H%M%SZ)"
|
|
2216
|
+
mkdir -p -- "$aside" || return 1
|
|
2217
|
+
mv -- "${paths[i]}" "$aside/native-bin" || { echo "ERROR surface $name: could not move ${paths[i]} aside to $aside" >&2; return 1; }
|
|
2218
|
+
echo "global-tools: retiring $command_name copy: moved ${paths[i]} aside to $aside/native-bin"
|
|
2219
|
+
;;
|
|
2220
|
+
brew)
|
|
2221
|
+
run_brew uninstall "$command_name" || { echo "ERROR surface $name: brew uninstall $command_name failed" >&2; return 1; }
|
|
2222
|
+
[[ ! -e "${paths[i]}" && ! -L "${paths[i]}" ]] || { echo "ERROR surface $name: ${paths[i]} is still present after brew uninstall $command_name" >&2; return 1; }
|
|
2223
|
+
echo "global-tools: retiring $command_name copy: brew uninstalled $command_name (${paths[i]})"
|
|
2224
|
+
;;
|
|
2225
|
+
npm)
|
|
2226
|
+
run_npm uninstall -g --prefix "${details[i]}" "$package" || { echo "ERROR surface $name: npm uninstall -g $package failed" >&2; return 1; }
|
|
2227
|
+
[[ ! -e "${paths[i]}" && ! -L "${paths[i]}" ]] || { echo "ERROR surface $name: ${paths[i]} is still present after npm uninstall -g $package" >&2; return 1; }
|
|
2228
|
+
echo "global-tools: retiring $command_name copy: npm uninstalled $package from ${details[i]} (${paths[i]})"
|
|
2229
|
+
;;
|
|
2230
|
+
esac
|
|
2231
|
+
done
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2234
|
+
# Installs or updates a bun-managed surface (see run_surface_bun_add): one `bun add -g
|
|
2235
|
+
# <package>@latest` covers both "absent" and "present", then the other copies are retired and the
|
|
2236
|
+
# command the administrator's PATH resolves is checked to be bun's. Fails loud at every step; a
|
|
2237
|
+
# version is never pinned.
|
|
2238
|
+
reconcile_bun_surface_cli() {
|
|
2239
|
+
local name="$1" command_name="$2" package="$3"
|
|
2240
|
+
local bun_exe="$administrator_home/.bun/bin/$command_name" spec="$package@latest"
|
|
2241
|
+
local old_version="" new_version update_output update_status=0 resolved
|
|
2242
|
+
if [[ "$mode" != apply ]]; then
|
|
2243
|
+
echo "would install or update surface from the npm registry: $name (bun add -g $spec as $administrator)"
|
|
2244
|
+
retire_other_surface_copies "$name" "$command_name" "$package" "$bun_exe"
|
|
2245
|
+
return 0
|
|
2246
|
+
fi
|
|
2247
|
+
[[ "$(id -u)" -eq 0 ]] || { echo "ERROR apply mode must run as root" >&2; exit 1; }
|
|
2248
|
+
if [[ -x "$bun_exe" ]]; then old_version="$(surface_cli_version "$bun_exe")"; fi
|
|
2249
|
+
update_output="$(run_with_timeout "$SURFACE_UPDATE_TIMEOUT_SECONDS" run_surface_bun_add "$spec" 2>&1)" || update_status=$?
|
|
2250
|
+
printf '%s\n' "$update_output"
|
|
2251
|
+
if [[ "$update_status" -eq 124 ]]; then
|
|
2252
|
+
echo "ERROR surface update timed out: $name" >&2
|
|
2253
|
+
return 1
|
|
2254
|
+
elif [[ "$update_status" -ne 0 ]]; then
|
|
2255
|
+
echo "ERROR surface update failed: $name (exit $update_status)" >&2
|
|
2256
|
+
return 1
|
|
2257
|
+
fi
|
|
2258
|
+
# opencode-ai's bin is a stub that exits 1 until its postinstall puts the platform binary in
|
|
2259
|
+
# place, and bun skips an untrusted package's postinstall: a bun add that "succeeded" but left
|
|
2260
|
+
# a command that cannot report its version is not an install.
|
|
2261
|
+
new_version="$(surface_cli_version "$bun_exe")"
|
|
2262
|
+
if [[ -z "$new_version" ]]; then
|
|
2263
|
+
echo "ERROR surface $name: bun add -g $spec succeeded but '$bun_exe --version' printed nothing; the package's postinstall did not run (check 'bun pm default-trusted' lists $package, or add it to the global trustedDependencies)" >&2
|
|
2264
|
+
return 1
|
|
2265
|
+
fi
|
|
2266
|
+
retire_other_surface_copies "$name" "$command_name" "$package" "$bun_exe" || return 1
|
|
2267
|
+
resolved="$(resolve_surface_executable "$command_name" "")"
|
|
2268
|
+
if [[ "$resolved" != "$bun_exe" ]]; then
|
|
2269
|
+
echo "ERROR surface $name: $command_name on ${administrator}'s PATH is ${resolved:-missing}, not the bun-installed $bun_exe" >&2
|
|
2270
|
+
return 1
|
|
2271
|
+
fi
|
|
2272
|
+
if [[ -z "$old_version" ]]; then
|
|
2273
|
+
echo "surface $name: installed $new_version ($package from the npm registry)"
|
|
2274
|
+
elif [[ "$old_version" != "$new_version" ]]; then
|
|
2275
|
+
echo "surface $name: $old_version -> $new_version"
|
|
2276
|
+
else
|
|
2277
|
+
echo "surface $name: already latest ($new_version)"
|
|
2278
|
+
fi
|
|
2279
|
+
return 0
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2020
2282
|
# Reconciles one declared surface_clis entry. report_only (hostinger's loose
|
|
2021
2283
|
# /root/codex, unknown install method) is version-reported only -- run_surface_update
|
|
2022
2284
|
# is never called for it, by construction (this branch returns before
|
|
@@ -2028,12 +2290,30 @@ reconcile_one_surface_cli() {
|
|
|
2028
2290
|
local name="$1" command_name="$2" executable_override="$3" report_only="$4" manager="$5"
|
|
2029
2291
|
shift 5
|
|
2030
2292
|
local update_args=("$@")
|
|
2293
|
+
if [[ "$manager" == bun ]]; then
|
|
2294
|
+
# For a bun surface the one trailing argument is the npm registry package, not an update argv.
|
|
2295
|
+
reconcile_bun_surface_cli "$name" "$command_name" "${update_args[0]}"
|
|
2296
|
+
return
|
|
2297
|
+
fi
|
|
2031
2298
|
if [[ "$manager" == brew ]]; then
|
|
2032
2299
|
if [[ "$mode" != apply ]]; then
|
|
2300
|
+
if [[ "$name" == */* ]]; then
|
|
2301
|
+
echo "would trust Homebrew item: $name (cask)"
|
|
2302
|
+
fi
|
|
2033
2303
|
echo "would ensure Homebrew cask: $name (brew install --cask $name; brew upgrade --cask $name)"
|
|
2034
2304
|
return 0
|
|
2035
2305
|
fi
|
|
2036
2306
|
[[ "$(id -u)" -eq 0 ]] || { echo "ERROR apply mode must run as root" >&2; exit 1; }
|
|
2307
|
+
# A fully-qualified cask name comes from a non-core tap, which Homebrew
|
|
2308
|
+
# >=6 refuses to load until the ITEM is trusted (same tap-trust grant as
|
|
2309
|
+
# the per-tool brew path in install_one_tool; the kind is certain here).
|
|
2310
|
+
# Bare names are core casks, trusted by default -- no grant.
|
|
2311
|
+
if [[ "$name" == */* ]]; then
|
|
2312
|
+
brew_query trust | awk '{$1=$1};1' | grep -Fqx "$name" || run_brew trust --cask "$name" || {
|
|
2313
|
+
echo "ERROR surface $name: brew trust --cask $name failed" >&2
|
|
2314
|
+
return 1
|
|
2315
|
+
}
|
|
2316
|
+
fi
|
|
2037
2317
|
local installed_casks query_status=0 cask_action=() update_output update_status=0
|
|
2038
2318
|
installed_casks="$(brew_query list --cask --versions 2>&1)" || query_status=$?
|
|
2039
2319
|
if [[ "$query_status" -ne 0 ]]; then
|
|
@@ -2181,10 +2461,15 @@ reconcile_surface_clis() {
|
|
|
2181
2461
|
report_only="$(jq -r --argjson i "$i" --arg platform "$platform" --arg device "$device" \
|
|
2182
2462
|
'.[$platform].devices[$device].surface_clis[$i].report_only // false' "$manifest")"
|
|
2183
2463
|
update_args=()
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2464
|
+
if [[ "$manager" == bun ]]; then
|
|
2465
|
+
update_args+=("$(jq -r --argjson i "$i" --arg platform "$platform" --arg device "$device" \
|
|
2466
|
+
'.[$platform].devices[$device].surface_clis[$i].package // empty' "$manifest")")
|
|
2467
|
+
else
|
|
2468
|
+
while IFS= read -r arg; do
|
|
2469
|
+
[[ -n "$arg" ]] && update_args+=("$arg")
|
|
2470
|
+
done < <(jq -r --argjson i "$i" --arg platform "$platform" --arg device "$device" \
|
|
2471
|
+
'.[$platform].devices[$device].surface_clis[$i].update_args // [] | .[]' "$manifest")
|
|
2472
|
+
fi
|
|
2188
2473
|
if ! reconcile_one_surface_cli "$name" "$command_name" "$executable_override" "$report_only" "$manager" ${update_args[@]+"${update_args[@]}"}; then
|
|
2189
2474
|
echo "ERROR global-tools: TOOL INSTALL FAILED: surface-$name" >&2
|
|
2190
2475
|
failed_tools+=("surface-$name")
|
|
@@ -2483,7 +2768,7 @@ if [[ "$(jq -r '.config.scratch_reap.enabled // false' "$manifest")" == true ]];
|
|
|
2483
2768
|
# REFUSE to remove worktrees. That is the safe direction, so it must not
|
|
2484
2769
|
# abort the fleet's update -- but it must not vanish either, or the
|
|
2485
2770
|
# published-HEAD gate rots with nothing ever reporting it.
|
|
2486
|
-
"$script_dir/scratch-reap" \
|
|
2771
|
+
"$BASH" "$script_dir/scratch-reap" \
|
|
2487
2772
|
"${scratch_reap_args[@]}" \
|
|
2488
2773
|
--mode "$scratch_reap_mode" \
|
|
2489
2774
|
--idle-days "$scratch_reap_idle_days" \
|
|
@@ -2512,15 +2797,10 @@ if [[ "$have_previous" -eq 1 ]]; then
|
|
|
2512
2797
|
[[ -n "$tool_id" ]] || continue
|
|
2513
2798
|
remove_one_manifest_entry "$tool_id"
|
|
2514
2799
|
# Selects an id when it was deleted outright (absent from the current
|
|
2515
|
-
# manifest) OR retained but migrated to a different manager/package
|
|
2516
|
-
# lean-ctx moving from npm:lean-ctx-bin to release-archive-latest:lean-ctx)
|
|
2800
|
+
# manifest) OR retained but migrated to a different manager/package
|
|
2517
2801
|
# -- a plain "id no longer present" check would silently leave the OLD
|
|
2518
2802
|
# manager's install in place forever whenever an id survives a manager
|
|
2519
|
-
# change,
|
|
2520
|
-
# /opt/homebrew/bin/lean-ctx shim it owns) would never be uninstalled, and
|
|
2521
|
-
# that shim's earlier position on PATH than /usr/local/bin would keep
|
|
2522
|
-
# `command -v lean-ctx` resolving to it instead of the new release binary
|
|
2523
|
-
# no matter how many times reconcile ran.
|
|
2803
|
+
# change, even though the current declaration points to a different install.
|
|
2524
2804
|
done < <(jq -r --slurpfile current "$resolved_file" '
|
|
2525
2805
|
keys[] as $id
|
|
2526
2806
|
| ($current[0][$id]) as $cur
|
|
@@ -2547,6 +2827,9 @@ project_adl_package_payload() {
|
|
|
2547
2827
|
echo "would build agent-skills payload from checkout"
|
|
2548
2828
|
fi
|
|
2549
2829
|
echo "would project Adl package payload from $repo_root to /usr/local/libexec/adl and /usr/local/bin/git{,-ado}"
|
|
2830
|
+
if [[ "$source_mode" == npm ]]; then
|
|
2831
|
+
echo "would link /usr/local/bin/adl to $repo_root/bin/adl"
|
|
2832
|
+
fi
|
|
2550
2833
|
return 0
|
|
2551
2834
|
fi
|
|
2552
2835
|
bun_bin="$(command -v bun || true)"
|
|
@@ -2561,6 +2844,12 @@ project_adl_package_payload() {
|
|
|
2561
2844
|
if [[ -n "${RECONCILE_TEST_SYSTEM_ROOT:-}" ]]; then
|
|
2562
2845
|
system_root_args+=(--system-root "$RECONCILE_TEST_SYSTEM_ROOT")
|
|
2563
2846
|
fi
|
|
2847
|
+
# Package mode also links /usr/local/bin/adl to this package's own bin/adl:
|
|
2848
|
+
# bun links adl into the owner's ~/.bun/bin only, yet bin/git-ado, the MCP
|
|
2849
|
+
# server command and the managed surface hooks run a bare `adl`.
|
|
2850
|
+
if [[ "$source_mode" == npm ]]; then
|
|
2851
|
+
system_root_args+=(--link-adl)
|
|
2852
|
+
fi
|
|
2564
2853
|
"$bun_bin" "$repo_root/packages/fleet/src/install-adl-package.ts" install \
|
|
2565
2854
|
--package-root "$repo_root" ${system_root_args[@]+"${system_root_args[@]}"}
|
|
2566
2855
|
}
|
|
@@ -2572,7 +2861,7 @@ fi
|
|
|
2572
2861
|
|
|
2573
2862
|
# Same continue-on-failure contract as the tool passes above: runs after git
|
|
2574
2863
|
# itself is installed/upgraded, and a failure is recorded, not fatal.
|
|
2575
|
-
if ! "$repo_root/bin/shell-path-policy" --home "$administrator_home" --platform "$platform" --mode "$mode" --owner "$administrator"; then
|
|
2864
|
+
if ! "$BASH" "$repo_root/bin/shell-path-policy" --home "$administrator_home" --platform "$platform" --mode "$mode" --owner "$administrator"; then
|
|
2576
2865
|
echo "ERROR global-tools: TOOL INSTALL FAILED: shell-path-policy" >&2
|
|
2577
2866
|
failed_tools+=("shell-path-policy")
|
|
2578
2867
|
fi
|
|
@@ -2596,7 +2885,7 @@ if ! retire_git_maintain; then
|
|
|
2596
2885
|
fi
|
|
2597
2886
|
|
|
2598
2887
|
if [[ "$mode" == apply ]]; then
|
|
2599
|
-
"$script_dir/health-check" "$device"
|
|
2888
|
+
"$BASH" "$script_dir/health-check" "$device"
|
|
2600
2889
|
fi
|
|
2601
2890
|
|
|
2602
2891
|
if [[ "$(jq -r '.config.global_surface_sweep.enabled' "$manifest")" == true ]]; then
|
|
@@ -2609,7 +2898,7 @@ if [[ "$(jq -r '.config.global_surface_sweep.enabled' "$manifest")" == true ]];
|
|
|
2609
2898
|
# recomputes the sweep's own backupPath() logic. stderr is left
|
|
2610
2899
|
# unredirected so a real failure still streams live as before.
|
|
2611
2900
|
sweep_status=0
|
|
2612
|
-
sweep_output="$("$script_dir/global-surface-sweep" \
|
|
2901
|
+
sweep_output="$("$BASH" "$script_dir/global-surface-sweep" \
|
|
2613
2902
|
--home "$administrator_home" \
|
|
2614
2903
|
--mode "$surface_mode" \
|
|
2615
2904
|
--state-dir "$state_dir")" || sweep_status=$?
|
|
@@ -2647,7 +2936,7 @@ if [[ "$kimi_hooks_enabled" == true ]]; then
|
|
|
2647
2936
|
echo "global-tools: kimi-hooks skipped: kimi not installed"
|
|
2648
2937
|
elif [[ "$mode" != apply ]]; then
|
|
2649
2938
|
echo "global-tools: kimi hooks mode=plan home=$administrator_home"
|
|
2650
|
-
"$script_dir/kimi-hooks" --home "$administrator_home" --mode plan
|
|
2939
|
+
"$BASH" "$script_dir/kimi-hooks" --home "$administrator_home" --mode plan
|
|
2651
2940
|
else
|
|
2652
2941
|
# Ordering: adl (bun-compile pass, above) must already resolve as
|
|
2653
2942
|
# a bare command before we write TOML entries that reference it -- Kimi
|
|
@@ -2657,12 +2946,12 @@ if [[ "$kimi_hooks_enabled" == true ]]; then
|
|
|
2657
2946
|
# docs/specs/two-branch-standard-2026-09-27.md) -- hard cut, no compat
|
|
2658
2947
|
# shim: there is no standalone hook executable to resolve any more.
|
|
2659
2948
|
adl_executable="$(jq -r '."adl".executable' "$resolved_file")"
|
|
2660
|
-
if ! adl_resolved="$(sudo -u "$administrator" -H env PATH="/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin:/usr/local/bin:/usr/bin:/bin" /bin/sh -c "command -v '$adl_executable'" 2>/dev/null)"; then
|
|
2949
|
+
if ! adl_resolved="$(sudo -u "$administrator" -H env PATH="/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin:/usr/local/bin:$administrator_home/.bun/bin:/usr/bin:/bin" /bin/sh -c "command -v '$adl_executable'" 2>/dev/null)"; then
|
|
2661
2950
|
echo "ERROR global-tools: could not resolve adl from the administrator PATH" >&2
|
|
2662
2951
|
exit 1
|
|
2663
2952
|
fi
|
|
2664
2953
|
[[ -n "$adl_resolved" && -x "$adl_resolved" ]] || {
|
|
2665
|
-
echo "ERROR global-tools: kimi-hooks requires adl on PATH ($adl_executable);
|
|
2954
|
+
echo "ERROR global-tools: kimi-hooks requires adl on PATH ($adl_executable); the adl package installation must succeed first" >&2
|
|
2666
2955
|
exit 1
|
|
2667
2956
|
}
|
|
2668
2957
|
echo "global-tools: kimi hooks mode=apply home=$administrator_home (as $administrator)"
|
|
@@ -2679,7 +2968,7 @@ if [[ "$kimi_hooks_enabled" == true ]]; then
|
|
|
2679
2968
|
# streams live exactly as before.
|
|
2680
2969
|
kimi_hooks_status=0
|
|
2681
2970
|
kimi_hooks_output="$(cd /tmp && sudo -u "$administrator" -H env PATH="${brew_bin%/*}:/usr/bin:/bin" \
|
|
2682
|
-
"$script_dir/kimi-hooks" --home "$administrator_home" --mode apply)" || kimi_hooks_status=$?
|
|
2971
|
+
"$BASH" "$script_dir/kimi-hooks" --home "$administrator_home" --mode apply)" || kimi_hooks_status=$?
|
|
2683
2972
|
printf '%s\n' "$kimi_hooks_output"
|
|
2684
2973
|
collect_kimi_hooks_backups "$kimi_hooks_output"
|
|
2685
2974
|
[[ "$kimi_hooks_status" -eq 0 ]] || exit "$kimi_hooks_status"
|
|
@@ -2692,50 +2981,11 @@ fi
|
|
|
2692
2981
|
# run the same hook contract twice. The exact old path remains Enact-owned.
|
|
2693
2982
|
if [[ "$mode" != apply ]]; then
|
|
2694
2983
|
echo "global-tools: retired OpenCode carrier mode=plan home=$administrator_home"
|
|
2695
|
-
"$script_dir/opencode-hooks" --home "$administrator_home" --mode plan
|
|
2984
|
+
"$BASH" "$script_dir/opencode-hooks" --home "$administrator_home" --mode plan
|
|
2696
2985
|
else
|
|
2697
2986
|
echo "global-tools: retired OpenCode carrier mode=remove home=$administrator_home (as $administrator)"
|
|
2698
2987
|
(cd /tmp && sudo -u "$administrator" -H env PATH="${brew_bin%/*}:/usr/bin:/bin" \
|
|
2699
|
-
"$script_dir/opencode-hooks" --home "$administrator_home" --mode remove)
|
|
2700
|
-
fi
|
|
2701
|
-
|
|
2702
|
-
# STATUS.md 12p item 13, final scope (2026-09-29): lean-ctx hooks are "moved
|
|
2703
|
-
# to repo level" and must be REMOVED FROM GLOBAL -- the per-repo carrier
|
|
2704
|
-
# (`adl hook lean-ctx pre-tool-use|post-tool-use --host=<x>`, written by
|
|
2705
|
-
# `adl hooks deploy`) already provides them with the repo's own config, so
|
|
2706
|
-
# any raw, unwrapped `lean-ctx hook <subcommand>` entry left in a per-user
|
|
2707
|
-
# config (observe, rewrite, redirect, read-dedup, any other) is retracted
|
|
2708
|
-
# global wiring, never the per-repo carrier or Orca's own hooks -- see
|
|
2709
|
-
# bin/lib/lean-ctx-observe-hooks.sh's header for the full decision trail and
|
|
2710
|
-
# exactly which per-user files can carry one. Unconditional, like the
|
|
2711
|
-
# retired OpenCode carrier cleanup just above: not a manifest-gated optional
|
|
2712
|
-
# feature, a standing cleanup that runs every reconciliation so a
|
|
2713
|
-
# hand-edited or Orca-reinstalled per-user config never lets this creep back
|
|
2714
|
-
# in unnoticed.
|
|
2715
|
-
if [[ "$mode" != apply ]]; then
|
|
2716
|
-
echo "global-tools: lean-ctx observe/raw-hook strip mode=plan home=$administrator_home"
|
|
2717
|
-
# Plan runs either unprivileged (the administrator's own shell) or under
|
|
2718
|
-
# sudo (fleet-cutover.sh's plan). As root it must drop to the administrator
|
|
2719
|
-
# exactly like apply: lean-ctx-observe-strip refuses root against a
|
|
2720
|
-
# non-root home (m5 cutover plan, 2026-09-29).
|
|
2721
|
-
if [[ "$EUID" -eq 0 && "$administrator" != root ]]; then
|
|
2722
|
-
(cd /tmp && sudo -u "$administrator" -H env PATH="${brew_bin%/*}:/usr/bin:/bin" \
|
|
2723
|
-
"$script_dir/lean-ctx-observe-strip" --home "$administrator_home" --mode plan)
|
|
2724
|
-
else
|
|
2725
|
-
"$script_dir/lean-ctx-observe-strip" --home "$administrator_home" --mode plan
|
|
2726
|
-
fi
|
|
2727
|
-
else
|
|
2728
|
-
echo "global-tools: lean-ctx observe/raw-hook strip mode=apply home=$administrator_home (as $administrator)"
|
|
2729
|
-
# stdout captured (then re-printed) so its own "backed up previous config
|
|
2730
|
-
# to ..." note(s) can be folded into this run's combined backups list,
|
|
2731
|
-
# exactly like kimi-hooks above; stderr left unredirected so a real
|
|
2732
|
-
# failure (a file that fails to parse) still streams live.
|
|
2733
|
-
lean_ctx_observe_strip_status=0
|
|
2734
|
-
lean_ctx_observe_strip_output="$(cd /tmp && sudo -u "$administrator" -H env PATH="${brew_bin%/*}:/usr/bin:/bin" \
|
|
2735
|
-
"$script_dir/lean-ctx-observe-strip" --home "$administrator_home" --mode apply)" || lean_ctx_observe_strip_status=$?
|
|
2736
|
-
printf '%s\n' "$lean_ctx_observe_strip_output"
|
|
2737
|
-
collect_lean_ctx_observe_strip_backups "$lean_ctx_observe_strip_output"
|
|
2738
|
-
[[ "$lean_ctx_observe_strip_status" -eq 0 ]] || exit "$lean_ctx_observe_strip_status"
|
|
2988
|
+
"$BASH" "$script_dir/opencode-hooks" --home "$administrator_home" --mode remove)
|
|
2739
2989
|
fi
|
|
2740
2990
|
|
|
2741
2991
|
# surface-policy re-asserts each host's permission MODE from the single source
|
|
@@ -2758,11 +3008,11 @@ fi
|
|
|
2758
3008
|
if [[ "$surface_policy_enabled" == true ]]; then
|
|
2759
3009
|
if [[ "$mode" != apply ]]; then
|
|
2760
3010
|
echo "global-tools: surface policy mode=plan home=$administrator_home"
|
|
2761
|
-
"$script_dir/surface-policy" --home "$administrator_home" --mode plan
|
|
3011
|
+
"$BASH" "$script_dir/surface-policy" --home "$administrator_home" --mode plan
|
|
2762
3012
|
else
|
|
2763
3013
|
echo "global-tools: surface policy mode=apply home=$administrator_home (as $administrator)"
|
|
2764
3014
|
(cd /tmp && sudo -u "$administrator" -H env PATH="${brew_bin%/*}:/usr/bin:/bin" \
|
|
2765
|
-
"$script_dir/surface-policy" --home "$administrator_home" --mode apply)
|
|
3015
|
+
"$BASH" "$script_dir/surface-policy" --home "$administrator_home" --mode apply)
|
|
2766
3016
|
fi
|
|
2767
3017
|
fi
|
|
2768
3018
|
|
|
@@ -2774,24 +3024,24 @@ fi
|
|
|
2774
3024
|
if [[ "$vscode_settings_enabled" == true ]]; then
|
|
2775
3025
|
if [[ "$mode" != apply ]]; then
|
|
2776
3026
|
echo "global-tools: VS Code settings mode=plan home=$administrator_home"
|
|
2777
|
-
"$script_dir/vscode-settings" --home "$administrator_home" --platform "$platform" --mode plan
|
|
3027
|
+
"$BASH" "$script_dir/vscode-settings" --home "$administrator_home" --platform "$platform" --mode plan
|
|
2778
3028
|
else
|
|
2779
3029
|
echo "global-tools: VS Code settings mode=apply home=$administrator_home (as $administrator)"
|
|
2780
3030
|
(cd /tmp && sudo -u "$administrator" -H env PATH="${brew_bin%/*}:/usr/bin:/bin" \
|
|
2781
|
-
"$script_dir/vscode-settings" --home "$administrator_home" --platform "$platform" --mode apply)
|
|
3031
|
+
"$BASH" "$script_dir/vscode-settings" --home "$administrator_home" --platform "$platform" --mode apply)
|
|
2782
3032
|
fi
|
|
2783
3033
|
fi
|
|
2784
3034
|
|
|
2785
3035
|
if [[ "$global_agents_enabled" == true ]]; then
|
|
2786
3036
|
if [[ "$mode" != apply ]]; then
|
|
2787
3037
|
echo "global-tools: global agents mode=status home=$administrator_home"
|
|
2788
|
-
"$script_dir/global-agents" --home "$administrator_home" --mode status
|
|
3038
|
+
"$BASH" "$script_dir/global-agents" --home "$administrator_home" --mode status
|
|
2789
3039
|
else
|
|
2790
3040
|
echo "global-tools: global agents mode=deploy home=$administrator_home (as $administrator)"
|
|
2791
3041
|
# The exact target files are authoritative global artifacts. Drift is
|
|
2792
3042
|
# replaced from GLOBAL-AGENTS.md with no backup or leave-in-place branch.
|
|
2793
3043
|
(cd /tmp && sudo -u "$administrator" -H env PATH="${brew_bin%/*}:/usr/bin:/bin" \
|
|
2794
|
-
"$script_dir/global-agents" --home "$administrator_home" --mode deploy)
|
|
3044
|
+
"$BASH" "$script_dir/global-agents" --home "$administrator_home" --mode deploy)
|
|
2795
3045
|
fi
|
|
2796
3046
|
fi
|
|
2797
3047
|
|