@amsterdamdatalabs/adl-agent-control-linux-x64 0.1.37 → 0.1.47
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/reconcile +10 -13
- package/bin/setup +15 -15
- package/package.json +1 -1
- package/packages/agent-hooks/package.json +1 -1
- package/packages/agent-hooks/src/main.ts +23 -2
- package/packages/agent-hooks/src/rules/impl/adl-mcp-cli.ts +12 -8
- package/packages/agent-hooks/src/rules/impl/adl-run-required.ts +11 -5
- package/packages/agent-hooks/src/rules/impl/adl-workitem-role.ts +18 -5
- package/packages/agent-hooks/src/rules/impl/agent-tamper-protection.ts +30 -26
- package/packages/agent-hooks/src/rules/impl/git-branch.ts +1 -1
- package/packages/agent-hooks/src/rules/impl/git-target.ts +5 -0
- package/packages/agent-hooks/src/rules/impl/mcp-tool.ts +3 -1
- package/packages/agent-hooks/src/rules/impl/tool-frontend.ts +230 -11
- package/packages/agent-hooks/src/rules/shell/git-identity.ts +1 -1
- package/packages/agent-hooks/src/rules/shell/invocation.ts +14 -2
- package/packages/agent-hooks/src/rules/shell/protected-carriers.ts +10 -11
- package/packages/agent-settings/assets/TARUN-GLOBAL-AGENTS-INSTRUCTIONS.md +2 -2
- package/packages/agent-settings/package.json +1 -1
- package/packages/agent-settings/src/deploy/agents-deploy.ts +19 -1
- package/packages/agent-settings/src/deploy/index.ts +1 -0
- package/packages/agent-skills/assets/agent-search-tool-audit/SKILL.md +4 -6
- package/packages/agent-skills/assets/finalize-feature/SKILL.md +3 -3
- package/packages/agent-skills/assets/implement-feature/SKILL.md +17 -20
- package/packages/agent-skills/assets/implement-feature/references/briefs.md +3 -3
- package/packages/agent-skills/assets/implement-item/SKILL.md +3 -3
- package/packages/agent-skills/assets/mechanics/SKILL.md +1 -1
- package/packages/agent-skills/assets/plan-feature/SKILL.md +10 -10
- package/packages/agent-skills/assets/prepare-promotion/SKILL.md +3 -4
- package/packages/agent-skills/assets/report-bug/SKILL.md +2 -2
- package/packages/agent-skills/assets/review-change/SKILL.md +3 -3
- package/packages/agent-skills/assets/review-plan/SKILL.md +4 -4
- package/packages/agent-skills/assets/triage-workitems/SKILL.md +4 -4
- package/packages/agent-skills/assets/validate-design/SKILL.md +6 -12
- package/packages/agent-skills/assets/verify-item/SKILL.md +5 -5
- package/packages/agent-skills/assets/wayfinder/SKILL.md +1 -1
- package/packages/agent-skills/assets/workitems-process/SKILL.md +19 -21
- package/packages/agent-skills/assets/workitems-process/references/ado-and-git.md +36 -3
- package/packages/agent-skills/assets/workitems-process/references/evidence.md +4 -4
- package/packages/agent-skills/assets/write-feature/SKILL.md +15 -18
- package/packages/agent-skills/dist/deploy.d.ts +45 -0
- package/packages/agent-skills/dist/deploy.d.ts.map +1 -1
- package/packages/agent-skills/dist/deploy.js +167 -3
- package/packages/agent-skills/dist/deploy.js.map +1 -1
- package/packages/agent-skills/dist/index.d.ts +1 -1
- package/packages/agent-skills/dist/index.d.ts.map +1 -1
- package/packages/agent-skills/dist/index.js +1 -1
- package/packages/agent-skills/dist/index.js.map +1 -1
- package/packages/agent-skills/package.json +1 -1
- package/packages/agent-skills/src/deploy.ts +241 -3
- package/packages/agent-skills/src/index.ts +10 -1
- package/packages/azdo/README.md +13 -4
- package/packages/azdo/bunfig.toml +6 -0
- package/packages/azdo/package.json +1 -1
- package/packages/azdo/src/azdo-attachments.ts +2 -1
- package/packages/azdo/src/azdo-pr.ts +182 -6
- package/packages/azdo/src/azdo-wit.ts +290 -41
- package/packages/azdo/src/cli.ts +79 -12
- package/packages/azdo/src/lib/client.ts +88 -16
- package/packages/azdo/src/mcp-server.ts +75 -10
- package/packages/azdo/src/tool-dispatch.ts +61 -26
- package/packages/fleet/src/install-adl-package.ts +4 -3
- package/packages/repo-controls/assets/promote.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/no-type.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/typed-experiment.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/typed-research.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/extra-key.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/extra-keys.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-created.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-description.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-last-update.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-status.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-title.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/optional-keys.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/research-ok.md +1 -1
- package/packages/repo-controls/package.json +1 -1
- package/packages/repo-controls/src/config.ts +21 -2
- package/packages/repo-controls/src/doctor.ts +9 -14
- package/packages/repo-controls/src/findings-ratchet.ts +12 -0
- package/packages/repo-controls/src/hook.ts +61 -4
- package/bin/lean-ctx-observe-strip +0 -434
- package/bin/lib/lean-ctx-observe-hooks.sh +0 -634
- package/bin/update-azure-agent-pool +0 -29
- package/packages/agent-hooks/src/hooks/lean-ctx/handler.ts +0 -22
- package/packages/agent-hooks/src/hooks/lean-ctx/index.ts +0 -173
- package/packages/agent-hooks/src/hooks/lean-ctx/mapping.ts +0 -121
- package/packages/agent-hooks/src/hooks/lean-ctx/scope-rewrite.ts +0 -207
- package/packages/agent-hooks/src/lean-ctx/env.ts +0 -123
- package/packages/agent-hooks/src/lean-ctx/mcp.ts +0 -142
- package/packages/agent-hooks/src/rules/impl/adl-build-run-denied.ts +0 -51
- package/packages/agent-hooks/src/rules/impl/adl-session-required.ts +0 -403
- package/packages/agent-hooks/src/rules/impl/tool-lean-ctx-global.ts +0 -594
- package/packages/agent-settings/assets/GLOBAL-AGENTS.md +0 -112
- package/packages/agent-settings/assets/lean-ctx/config.toml +0 -42
- package/packages/agent-settings/assets/lean-ctx/gitignore +0 -10
- package/packages/agent-settings/assets/lean-ctx/layout.toml +0 -7
- package/packages/agent-settings/src/deploy/lean-ctx-deploy.ts +0 -230
- package/packages/agent-settings/src/deploy/lean-ctx-merge.ts +0 -580
- package/packages/agent-skills/assets/adl-mechanics/SKILL.md +0 -38
- package/packages/agent-skills/assets/codebase-design/SKILL.md +0 -98
- package/packages/agent-skills/assets/codebase-design/references/DEEPENING.md +0 -37
- package/packages/agent-skills/assets/codebase-design/references/DESIGN-IT-TWICE.md +0 -44
- package/packages/agent-skills/assets/codebase-design/references/TESTABILITY.md +0 -29
- package/packages/agent-skills/assets/debug-issue/SKILL.md +0 -41
- package/packages/agent-skills/assets/domain-modeling/SKILL.md +0 -86
- package/packages/agent-skills/assets/domain-modeling/references/ADR-FORMAT.md +0 -47
- package/packages/agent-skills/assets/domain-modeling/references/CONTEXT-FORMAT.md +0 -60
- package/packages/agent-skills/assets/implement/SKILL.md +0 -28
- package/packages/agent-skills/assets/review-changes/SKILL.md +0 -45
- package/packages/agent-skills/assets/tdd/SKILL.md +0 -49
- package/packages/agent-skills/assets/tdd/references/mocking.md +0 -59
- package/packages/agent-skills/assets/tdd/references/tests.md +0 -77
- package/packages/agent-skills/assets/testing/SKILL.md +0 -54
- package/packages/agent-skills/assets/testing/references/e2e.md +0 -37
- package/packages/agent-skills/assets/testing/references/integration.md +0 -37
- package/packages/agent-skills/assets/testing/references/unit.md +0 -32
- package/packages/agent-skills/assets/to-feature/SKILL.md +0 -91
- package/packages/agent-skills/assets/to-feature/references/FEATURE-SPEC-TEMPLATE.md +0 -88
- package/packages/agent-skills/assets/to-workitems/SKILL.md +0 -90
- package/packages/agent-skills/assets/to-workitems/references/AZURE-DEVOPS-HIERARCHY.md +0 -121
- package/packages/agent-skills/assets/to-workitems/references/TICKET-TEMPLATES.md +0 -70
- package/packages/azdo/src/workflow-rules-matrix.csv +0 -85
- package/packages/fleet/src/launch-agents.ts +0 -649
- package/packages/repo-controls/assets/GLOBAL-INVARIANTS.md +0 -21
- package/packages/repo-controls/assets/enable-integration-auto-complete.mjs +0 -79
- package/packages/repo-controls/assets/scaffold/docs/notes.md +0 -20
- package/packages/repo-controls/assets/scaffold/plans/GAPS-AND-FINDINGS.md +0 -12
- package/packages/repo-controls/azure-pipelines.yml +0 -274
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/notes.md +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/fixtures/excluded/frontend/mobile/src/i18n/locales/zh-CN/strings.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-ledger-clean/docs/notes.md +0 -17
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-ledger-no-lines/docs/notes.md +0 -13
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/product/stable-delivery.md +0 -10
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/product/stable-recommendation.md +0 -12
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/product/target-narration.md +0 -10
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-clean/frontend/packages/desktop/src/renderer/solo/item.ts +0 -1
- 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 +0 -1
- 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 +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/fresh/fresh.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub1/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub10/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub11/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub2/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub3/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub4/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub5/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub6/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub7/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub8/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub9/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/services/i18n/locales/de/common.json +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/solo/item.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/vendored-crate/Cargo.toml +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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/fresh/fresh.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub1/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub10/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub11/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub2/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub3/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub4/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub5/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub6/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub7/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub8/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub9/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/solo/item.ts +0 -1
- 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 +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/fixtures/open-work-cap-clean/plans/GAPS-AND-FINDINGS.md +0 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/fixtures/open-work-cap-clean/plans/features/az601-clean/spec.md +0 -10
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/agent/crates/enact-providers/src/snapshots/README.md +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/backend/crates/enact-app/assets/builtin-assistants/avatars/assistant.jpg +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/backend/crates/enact-assets/assets/logos/tools/coding/tool.png +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/backend/crates/enact-session/src/backend/codex_init_prompt.md +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/mobile/assets/images/icon.png +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/packages/desktop/src/renderer/assets/logos/brand/app.png +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/packages/desktop/src/renderer/assets/themes/default-theme.png +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/public/pwa/icon-192.png +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/resources/product.png +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-stray/backend/crates/enact-session/src/backend/README.md +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/spec.md +0 -12
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-violation/plans/features/az347-test-coverage/spec.md +0 -12
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/__init__.py +0 -11
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/check.py +0 -62
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/NotAMigration.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/0001_long_prefix.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/001_init.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/002_add_index.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/003-dashed-slug.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/004_MixedCase.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/005_trailing space.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/01_short_prefix.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/not-a-migration.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/test_check.py +0 -116
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-broken/docs/architecture/product/links.md +0 -20
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-broken/docs/architecture/product/route-target.md +0 -8
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-clean/docs/architecture/product/links.md +0 -20
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-clean/docs/architecture/product/route-target.md +0 -8
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.changeset/declared.txt +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/INDEPENDENT-VERIFICATION.md +0 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/attribute-without-conversion/.gitattributes +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/attribute-without-conversion/large file.bin +0 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/clean/.gitattributes +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/clean/large file.bin +0 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/clean/small.txt +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/missing-filter/large file.bin +0 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/unmatched-extension/.gitattributes +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/unmatched-extension/payload.dat +0 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/__init__.py +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/__init__.py +0 -12
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/check.py +0 -129
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/fixtures/disjoint/gate-registry.yaml +0 -13
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/fixtures/empty/gate-registry.yaml +0 -7
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/fixtures/overlapping/gate-registry.yaml +0 -13
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/test_check.py +0 -109
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/__init__.py +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/__init__.py +0 -11
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/check.py +0 -149
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/fixtures/clean/docs/readme.md +0 -4
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/fixtures/relevant/VERSION +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/test_check.py +0 -151
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/__init__.py +0 -11
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/check.py +0 -202
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/aligned/.workflows/changesets/package.json +0 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/aligned/.workflows/package.json +0 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/aligned/CHANGELOG.md +0 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/aligned/VERSION +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/mismatched/.workflows/changesets/package.json +0 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/mismatched/.workflows/package.json +0 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/mismatched/CHANGELOG.md +0 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/mismatched/VERSION +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/test_check.py +0 -162
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/check.py +0 -103
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/backend/Cargo.lock +0 -7
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/backend/Cargo.toml +0 -4
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/backend/rust-toolchain.toml +0 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/backend/src/main.rs +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/frontend/bun.lock +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/backend/Cargo.lock +0 -7
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/backend/Cargo.toml +0 -4
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/backend/rust-toolchain.toml +0 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/backend/src/main.rs +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/frontend/bun.lock +0 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/grants-registry.yaml +0 -112
- package/packages/repo-controls/workflows/scripts/release/verify-npm-artifact.ts +0 -119
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `main.ts`-facing entry point for the `lean-ctx` hook kind's
|
|
3
|
-
* `pre-tool-use` / `post-tool-use` subcommands.
|
|
4
|
-
*
|
|
5
|
-
* Thin wiring only, mirroring `../briefing/handler.ts` and `../crg/handler.ts`:
|
|
6
|
-
* the actual logic lives in `./index.ts`, built against an injectable
|
|
7
|
-
* `Runner` so it can be unit-tested without a real `lean-ctx` binary. This
|
|
8
|
-
* file wires that logic to the production, timeout-enforcing `bunRunner`.
|
|
9
|
-
*
|
|
10
|
-
* `main.ts` never routes a `subcommand: 'mcp'` invocation here — see
|
|
11
|
-
* `../../lean-ctx/mcp.ts`'s header for why that subcommand is dispatched
|
|
12
|
-
* entirely separately, before `main.ts`'s standard JSON-payload flow.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import type { HookInvocation, HookResult } from '../contract.ts'
|
|
16
|
-
import { bunRunner, createLeanCtxHandler } from './index.ts'
|
|
17
|
-
|
|
18
|
-
const leanCtxHandler = createLeanCtxHandler({ run: bunRunner })
|
|
19
|
-
|
|
20
|
-
export async function handleLeanCtx(inv: HookInvocation): Promise<HookResult> {
|
|
21
|
-
return leanCtxHandler(inv)
|
|
22
|
-
}
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The `lean-ctx` hook kind's `pre-tool-use` / `post-tool-use` subcommands:
|
|
3
|
-
* `adl hook lean-ctx pre-tool-use --host=X` / `post-tool-use --host=X`
|
|
4
|
-
* (work item A.2). The `mcp` subcommand is NOT handled here — it is a true
|
|
5
|
-
* stdio-passthrough, long-running MCP server, dispatched straight out of
|
|
6
|
-
* `main.ts` (see `../../lean-ctx/mcp.ts`) before the standard
|
|
7
|
-
* read-stdin-as-one-JSON-payload / `HookHandler` machinery this file uses
|
|
8
|
-
* ever runs.
|
|
9
|
-
*
|
|
10
|
-
* Gating (managed repo + `[hooks] enabled`, silent no-op otherwise) is
|
|
11
|
-
* `main.ts`'s job, identical to every other kind — see its header. This
|
|
12
|
-
* handler only has to:
|
|
13
|
-
*
|
|
14
|
-
* 1. Read the invoking tool's name out of the payload (the same field every
|
|
15
|
-
* host spells `tool_name` for a PreToolUse/PostToolUse call — see
|
|
16
|
-
* `../../pre-tool-use/handler.ts`'s `toDecideInput` for the reference
|
|
17
|
-
* this mirrors).
|
|
18
|
-
* 2. Map (host, direction, tool name) to a `lean-ctx hook <subcommand>` via
|
|
19
|
-
* `./mapping.ts`. No match (kimi/opencode always; any host+tool this
|
|
20
|
-
* task's mapping table does not name) is a SILENT no-op — exit 0, empty
|
|
21
|
-
* stdout/stderr, no `lean-ctx` spawn at all.
|
|
22
|
-
* 3. Spawn `lean-ctx hook <subcommand>` with the payload JSON on stdin and
|
|
23
|
-
* the shared `LEAN_CTX_*` env (`../../lean-ctx/env.ts`), and relay its
|
|
24
|
-
* stdout/stderr/exit code VERBATIM — lean-ctx speaks each host's own
|
|
25
|
-
* hook protocol (deny/rewrite/redirect envelopes) itself, so this must
|
|
26
|
-
* not reinterpret or reshape what it returns.
|
|
27
|
-
*
|
|
28
|
-
* Two exceptions to "relay verbatim":
|
|
29
|
-
*
|
|
30
|
-
* - A hung or missing `lean-ctx` (`status: null` — see `Runner`'s doc) must
|
|
31
|
-
* never block the calling host's tool-call loop, so that degrades to exit 0
|
|
32
|
-
* with a stderr note instead of whatever `lean-ctx` would have returned had
|
|
33
|
-
* it run — same fail-open shape `../briefing/index.ts` and
|
|
34
|
-
* `../crg/index.ts` already use for their own subprocess calls.
|
|
35
|
-
* - A `rewrite` envelope's REPLACEMENT command is re-scoped by
|
|
36
|
-
* `./scope-rewrite.ts` (G1). lean-ctx rewrites the host's command into one
|
|
37
|
-
* that re-execs lean-ctx by absolute path, and the host runs that in the
|
|
38
|
-
* HOST's env — which carries none of the four `LEAN_CTX_*` dir vars set for
|
|
39
|
-
* the child above, so the process that actually ENFORCES silently falls back
|
|
40
|
-
* to built-in defaults instead of the repo's `config.toml`. Prefixing the
|
|
41
|
-
* four assignments onto that command is the narrowest place to fix it: the
|
|
42
|
-
* envelope's shape, decision and every other field are untouched, and any
|
|
43
|
-
* non-rewrite output is returned as the identical string.
|
|
44
|
-
*/
|
|
45
|
-
|
|
46
|
-
import type { HookHandler, HookInvocation, HookResult } from '../contract.ts'
|
|
47
|
-
import { leanCtxEnvFor } from '../../lean-ctx/env.ts'
|
|
48
|
-
import { spawnWithTimeout } from '../../lib/spawn-with-timeout.ts'
|
|
49
|
-
import { leanCtxSubcommand, type LeanCtxDirection } from './mapping.ts'
|
|
50
|
-
import { scopeRewrittenCommand, sessionIdentityOf } from './scope-rewrite.ts'
|
|
51
|
-
|
|
52
|
-
export interface RunResult {
|
|
53
|
-
readonly status: number | null
|
|
54
|
-
readonly stdout: string
|
|
55
|
-
readonly stderr: string
|
|
56
|
-
/** `true` only when the spawn was killed for exceeding `timeoutMs`. */
|
|
57
|
-
readonly timedOut?: boolean
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export interface RunOptions {
|
|
61
|
-
readonly cwd: string
|
|
62
|
-
readonly env: Readonly<Record<string, string | undefined>>
|
|
63
|
-
readonly input?: string
|
|
64
|
-
readonly timeoutMs?: number
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** Process spawning, injected so tests never need a real `lean-ctx` binary. */
|
|
68
|
-
export type Runner = (cmd: string, args: readonly string[], opts: RunOptions) => Promise<RunResult>
|
|
69
|
-
|
|
70
|
-
const BIN = 'lean-ctx'
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* lean-ctx's own PreToolUse/PostToolUse hook subcommands (rewrite, redirect,
|
|
74
|
-
* deny, read-dedup, codex-pretooluse) are simple synchronous lookups/string
|
|
75
|
-
* transforms in the real binary — generous, but well under the host's own
|
|
76
|
-
* tool-call timeout, matching `../crg/index.ts`'s reasoning for its own
|
|
77
|
-
* default.
|
|
78
|
-
*/
|
|
79
|
-
const DEFAULT_TIMEOUT_MS = 10_000
|
|
80
|
-
|
|
81
|
-
/** The tool-name field every host's PreToolUse/PostToolUse payload carries — see `../../pre-tool-use/handler.ts`'s `toDecideInput`. */
|
|
82
|
-
function toolNameOf(payload: Record<string, unknown>): string | null {
|
|
83
|
-
const name = payload.tool_name
|
|
84
|
-
return typeof name === 'string' && name.length > 0 ? name : null
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function directionOf(subcommand: string | undefined): LeanCtxDirection | null {
|
|
88
|
-
if (subcommand === 'pre-tool-use') return 'pre'
|
|
89
|
-
if (subcommand === 'post-tool-use') return 'post'
|
|
90
|
-
return null
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function silentNoop(): HookResult {
|
|
94
|
-
return { stdout: '', stderr: '', exitCode: 0 }
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export function createLeanCtxHandler(deps: { run: Runner }): HookHandler {
|
|
98
|
-
return async (inv: HookInvocation): Promise<HookResult> => {
|
|
99
|
-
const direction = directionOf(inv.subcommand)
|
|
100
|
-
if (direction === null) {
|
|
101
|
-
return {
|
|
102
|
-
stdout: '',
|
|
103
|
-
stderr: `adl hook: lean-ctx: unknown subcommand: ${String(inv.subcommand)} (expected mcp | pre-tool-use | post-tool-use)\n`,
|
|
104
|
-
exitCode: 1,
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const toolName = toolNameOf(inv.payload)
|
|
109
|
-
if (toolName === null) {
|
|
110
|
-
inv.record?.({ reason: 'SKIP no tool_name in payload' })
|
|
111
|
-
return silentNoop()
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const subcommand = leanCtxSubcommand(inv.host, direction, toolName)
|
|
115
|
-
if (subcommand === null) {
|
|
116
|
-
inv.record?.({ reason: `SKIP no lean-ctx hook for ${toolName}` })
|
|
117
|
-
return silentNoop()
|
|
118
|
-
}
|
|
119
|
-
const downstream = `${BIN} hook ${subcommand}`
|
|
120
|
-
|
|
121
|
-
const result = await deps.run(BIN, ['hook', subcommand], {
|
|
122
|
-
cwd: inv.root,
|
|
123
|
-
env: leanCtxEnvFor(inv.root, inv.env),
|
|
124
|
-
input: JSON.stringify(inv.payload),
|
|
125
|
-
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
if (result.status === null) {
|
|
129
|
-
const reason = result.stderr.trim() || (result.timedOut ? `${BIN} timed out after ${DEFAULT_TIMEOUT_MS}ms` : `${BIN} not found on PATH`)
|
|
130
|
-
const stderr = `lean-ctx ${inv.subcommand} (${subcommand}): ${reason}\n`
|
|
131
|
-
inv.record?.({ reason: `${result.timedOut ? 'TIMEOUT' : 'ERROR'} ${downstream}`, message: stderr.trim(), downstream })
|
|
132
|
-
return { stdout: '', stderr, exitCode: 0 }
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
inv.record?.({ reason: result.status === 0 ? 'PASS' : `ERROR exit=${result.status}`, message: result.stderr.trim(), downstream })
|
|
136
|
-
// 2026-09-28: the session identity rides into the rewrite envelope too —
|
|
137
|
-
// see `./scope-rewrite.ts`'s header for the two-envelope race this closes.
|
|
138
|
-
return { stdout: scopeRewrittenCommand(result.stdout, inv.root, sessionIdentityOf(inv.env)), stderr: result.stderr, exitCode: result.status }
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* The production `Runner`: a real, timeout-enforcing subprocess via
|
|
144
|
-
* `spawnWithTimeout` (see `../../lib/spawn-with-timeout.ts`), resolving
|
|
145
|
-
* `lean-ctx` off `PATH` — the same shape `../briefing/index.ts` and
|
|
146
|
-
* `../crg/index.ts` already use for their own production runners.
|
|
147
|
-
*/
|
|
148
|
-
export const bunRunner: Runner = async (cmd, args, opts) => {
|
|
149
|
-
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS
|
|
150
|
-
try {
|
|
151
|
-
const result = await spawnWithTimeout(cmd, args, {
|
|
152
|
-
cwd: opts.cwd,
|
|
153
|
-
env: opts.env,
|
|
154
|
-
timeoutMs,
|
|
155
|
-
...(opts.input !== undefined ? { stdin: opts.input } : {}),
|
|
156
|
-
})
|
|
157
|
-
if (result.timedOut) {
|
|
158
|
-
return {
|
|
159
|
-
status: null,
|
|
160
|
-
stdout: result.stdout,
|
|
161
|
-
stderr: result.stderr.trim() || `${cmd} timed out after ${timeoutMs}ms`,
|
|
162
|
-
timedOut: true,
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
return { status: result.exitCode, stdout: result.stdout, stderr: result.stderr }
|
|
166
|
-
} catch (error) {
|
|
167
|
-
const message = error instanceof Error ? error.message : String(error)
|
|
168
|
-
return { status: null, stdout: '', stderr: message }
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export const handleLeanCtx: HookHandler = createLeanCtxHandler({ run: bunRunner })
|
|
173
|
-
export default handleLeanCtx
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* (host, direction, tool name) → `lean-ctx hook <subcommand>` mapping.
|
|
3
|
-
*
|
|
4
|
-
* Ported 1:1 from enact-m5's real wiring — the source of truth is each
|
|
5
|
-
* host's own hooks config, read directly (this session, 2026-09-14):
|
|
6
|
-
*
|
|
7
|
-
* - `.claude/settings.json`: `PreToolUse` matcher `"Bash|bash"` →
|
|
8
|
-
* `lean-ctx-local hook rewrite`; matcher
|
|
9
|
-
* `"Read|read|ReadFile|read_file|View|view|Grep|grep|Search|search|
|
|
10
|
-
* ListFiles|list_files|ListDirectory|list_directory|Glob|glob"` →
|
|
11
|
-
* `hook redirect`. `PostToolUse` matcher `"Read"` → `hook read-dedup`.
|
|
12
|
-
* - `.cursor/hooks.json`: see the CURSOR CORRECTION note below — the
|
|
13
|
-
* original port's matcher strings here were wrong; this describes the
|
|
14
|
-
* corrected mapping actually implemented in `CURSOR` below.
|
|
15
|
-
* `preToolUse` matcher `"Shell"` → `hook rewrite`; matcher `"Grep"` →
|
|
16
|
-
* `hook deny`; matcher `"Read"` → `hook redirect`; matcher `"Write"` →
|
|
17
|
-
* `hook deny`. No `postToolUse` bucket at all.
|
|
18
|
-
* - `.codex/hooks.json`: `PreToolUse` matcher `"Bash|Read|Grep|Glob"` →
|
|
19
|
-
* `lean-ctx-local hook codex-pretooluse`. No `PostToolUse` lean-ctx entry.
|
|
20
|
-
* - kimi, opencode: no lean-ctx wiring in either host's config at all — a
|
|
21
|
-
* lean-ctx pre/post-tool-use invocation for these hosts is always a
|
|
22
|
-
* no-op.
|
|
23
|
-
*
|
|
24
|
-
* Each host's matcher is a regex tested against the payload's tool name; the
|
|
25
|
-
* task's own wording ("match anchored as those hosts do") reflects that
|
|
26
|
-
* every one of these host matchers is an untagged alternation with no
|
|
27
|
-
* partial-match intent (`Bash|bash`, not `.*Bash.*`) — every spelling below
|
|
28
|
-
* is therefore matched as an exact, case-sensitive string against the tool
|
|
29
|
-
* name, never a substring or prefix test.
|
|
30
|
-
*
|
|
31
|
-
* CURSOR CORRECTION (this session, 2026-09-14, verified against
|
|
32
|
-
* https://cursor.com/docs/agent/hooks): the `CURSOR` table below used to
|
|
33
|
-
* carry Claude-vocabulary tool names — `Glob` alongside `Grep`, and
|
|
34
|
-
* `StrReplace`/`Write`/`Edit`/`EditNotebook`/`MultiEdit` all denied — none of
|
|
35
|
-
* which are real Cursor tool names. The docs' "Matcher Patterns" section
|
|
36
|
-
* states verbatim: "preToolUse / postToolUse / postToolUseFailure: Filter by
|
|
37
|
-
* tool type. Values include Shell, Read, Write, Grep, Delete, Task, and MCP
|
|
38
|
-
* tools using the MCP:<tool_name> format." That is Cursor's *complete*
|
|
39
|
-
* `tool_name` vocabulary for these two events — there is no `Glob`,
|
|
40
|
-
* `StrReplace`, `Edit`, `EditNotebook`, or `MultiEdit` in it. `CURSOR` below
|
|
41
|
-
* is corrected to that vocabulary: `Shell` → rewrite, `Grep` → deny (no
|
|
42
|
-
* separate glob-like tool exists to also deny), `Read` → redirect, `Write` →
|
|
43
|
-
* deny (the one edit-like tool Cursor actually has). `Delete`, `Task`, and
|
|
44
|
-
* any `MCP:<tool_name>` call are intentionally left unmapped (no-op, same as
|
|
45
|
-
* any tool name absent from a route's set) — enact-m5's real wiring never
|
|
46
|
-
* named them for lean-ctx.
|
|
47
|
-
*
|
|
48
|
-
* A `preToolUse` payload's `tool_name` field (matched above) is documented
|
|
49
|
-
* alongside `tool_input`, e.g. `{"tool_name": "Shell", "tool_input":
|
|
50
|
-
* {"command": "npm install", "working_directory": "/project"}, ...}` — see
|
|
51
|
-
* `../../pre-tool-use/handler.ts`'s `toDecideInput` for where the sibling
|
|
52
|
-
* `tool_input.command` field (and `beforeShellExecution`'s top-level
|
|
53
|
-
* `command`) get read.
|
|
54
|
-
*/
|
|
55
|
-
|
|
56
|
-
import type { HostId } from '../contract.ts'
|
|
57
|
-
|
|
58
|
-
export type LeanCtxDirection = 'pre' | 'post'
|
|
59
|
-
|
|
60
|
-
interface ToolRoute {
|
|
61
|
-
readonly subcommand: string
|
|
62
|
-
readonly tools: ReadonlySet<string>
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
type HostRoutes = Readonly<Record<LeanCtxDirection, readonly ToolRoute[]>>
|
|
66
|
-
|
|
67
|
-
const CLAUDE: HostRoutes = {
|
|
68
|
-
pre: [
|
|
69
|
-
{ subcommand: 'rewrite', tools: new Set(['Bash', 'bash']) },
|
|
70
|
-
{
|
|
71
|
-
subcommand: 'redirect',
|
|
72
|
-
tools: new Set([
|
|
73
|
-
'Read', 'read', 'ReadFile', 'read_file', 'View', 'view',
|
|
74
|
-
'Grep', 'grep', 'Search', 'search',
|
|
75
|
-
'ListFiles', 'list_files', 'ListDirectory', 'list_directory',
|
|
76
|
-
'Glob', 'glob',
|
|
77
|
-
]),
|
|
78
|
-
},
|
|
79
|
-
],
|
|
80
|
-
post: [{ subcommand: 'read-dedup', tools: new Set(['Read']) }],
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const CURSOR: HostRoutes = {
|
|
84
|
-
pre: [
|
|
85
|
-
{ subcommand: 'rewrite', tools: new Set(['Shell']) },
|
|
86
|
-
{ subcommand: 'deny', tools: new Set(['Grep']) },
|
|
87
|
-
{ subcommand: 'redirect', tools: new Set(['Read']) },
|
|
88
|
-
{ subcommand: 'deny', tools: new Set(['Write']) },
|
|
89
|
-
],
|
|
90
|
-
post: [],
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const CODEX: HostRoutes = {
|
|
94
|
-
pre: [{ subcommand: 'codex-pretooluse', tools: new Set(['Bash', 'Read', 'Grep', 'Glob']) }],
|
|
95
|
-
post: [],
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const NONE: HostRoutes = { pre: [], post: [] }
|
|
99
|
-
|
|
100
|
-
const ROUTES: Readonly<Record<HostId, HostRoutes>> = {
|
|
101
|
-
claude: CLAUDE,
|
|
102
|
-
cursor: CURSOR,
|
|
103
|
-
codex: CODEX,
|
|
104
|
-
kimi: NONE,
|
|
105
|
-
opencode: NONE,
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Resolve which `lean-ctx hook <subcommand>` a (host, direction, tool name)
|
|
110
|
-
* triple maps to, or `null` when nothing matches — the caller's no-op case
|
|
111
|
-
* (kimi/opencode always, and any tool name not named in the host's own
|
|
112
|
-
* matcher above, e.g. an Edit under Claude, which has no lean-ctx PreToolUse
|
|
113
|
-
* entry at all).
|
|
114
|
-
*/
|
|
115
|
-
export function leanCtxSubcommand(host: HostId, direction: LeanCtxDirection, toolName: string): string | null {
|
|
116
|
-
const routes = ROUTES[host][direction]
|
|
117
|
-
for (const route of routes) {
|
|
118
|
-
if (route.tools.has(toolName)) return route.subcommand
|
|
119
|
-
}
|
|
120
|
-
return null
|
|
121
|
-
}
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* G1 — carry this package's `LEAN_CTX_*` scope across lean-ctx's own rewrite.
|
|
3
|
-
*
|
|
4
|
-
* `lean-ctx hook rewrite` does not return a decision about the host's command;
|
|
5
|
-
* it returns a REPLACEMENT command that re-execs lean-ctx by its own absolute
|
|
6
|
-
* path, e.g. `/usr/local/bin/lean-ctx -c 'trash /tmp/x'` or
|
|
7
|
-
* `/usr/local/bin/lean-ctx read README.md`. The host then runs that string in
|
|
8
|
-
* the HOST's environment.
|
|
9
|
-
*
|
|
10
|
-
* That is the whole bug. `./index.ts` spawns its own child with the four dir
|
|
11
|
-
* vars from `../../lean-ctx/env.ts`, so the child that makes the DECISION sees
|
|
12
|
-
* the repo's `config.toml` (249 commands). But the replacement command is
|
|
13
|
-
* executed by the host, whose environment carries only `LEAN_CTX_ACTIVE=1` and
|
|
14
|
-
* `LEAN_CTX_WRAPPED=1` — the two the wrapper sets for itself, measured on this
|
|
15
|
-
* machine — and never the four dir vars. So the process that ENFORCES resolves
|
|
16
|
-
* the global XDG path, finds no `config.toml`, and silently falls back to
|
|
17
|
-
* lean-ctx's 223 built-in defaults.
|
|
18
|
-
*
|
|
19
|
-
* The visible symptom is a deadlock between the two guards: `../../rules/` denies
|
|
20
|
-
* `rm` and directs the caller to `trash`, and `trash` is in the repo allowlist —
|
|
21
|
-
* but the unscoped re-exec answers "[BLOCKED — DO NOT RETRY] 'trash' is not in
|
|
22
|
-
* the shell allowlist", so neither verb works. Both halves were measured
|
|
23
|
-
* directly, 2026-09-15.
|
|
24
|
-
*
|
|
25
|
-
* Rooted at the caller's resolved git root, never `$PWD`. A `$PWD`-derived
|
|
26
|
-
* scope reports 249 at the repo root and 223 from `<repo>/.agents` with no
|
|
27
|
-
* error — one `cd` and the gate reverts to built-ins.
|
|
28
|
-
*
|
|
29
|
-
* Deliberately NOT solved with an env carrier in host config
|
|
30
|
-
* (`.claude/settings.local.json` and friends): Cursor's project config is
|
|
31
|
-
* permissions-only, Kimi reads a single user-level file, and Codex ignores
|
|
32
|
-
* `[shell_environment_policy] set` for untrusted projects — so a carrier
|
|
33
|
-
* cannot cover the hosts that need it. Rewriting the command reaches every
|
|
34
|
-
* host that honours the rewrite, which is exactly the set that has the bug.
|
|
35
|
-
*/
|
|
36
|
-
|
|
37
|
-
import { basename } from 'node:path'
|
|
38
|
-
import { leanCtxEnvFor } from '../../lean-ctx/env.ts'
|
|
39
|
-
import { resolveFromEnvOrFile } from '../../rules/impl/adl-identity.ts'
|
|
40
|
-
import { rewriteGitNetworkCommands } from '../../rules/shell/git-identity.ts'
|
|
41
|
-
|
|
42
|
-
/** The four dir vars, in the order they are prefixed. See `../../lean-ctx/env.ts`. */
|
|
43
|
-
const SCOPED_VARS = [
|
|
44
|
-
'LEAN_CTX_CONFIG_DIR',
|
|
45
|
-
'LEAN_CTX_DATA_DIR',
|
|
46
|
-
'LEAN_CTX_STATE_DIR',
|
|
47
|
-
'LEAN_CTX_CACHE_DIR',
|
|
48
|
-
] as const
|
|
49
|
-
|
|
50
|
-
/** Basename the replacement command must invoke for it to be lean-ctx's own re-exec. */
|
|
51
|
-
const WRAPPER = 'lean-ctx'
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* The three keys lean-ctx emits the replacement input under — one per host
|
|
55
|
-
* protocol dialect, all three in every rewrite envelope. Captured verbatim
|
|
56
|
-
* from the real v3.9.20 binary; all three must be scoped or a host reading
|
|
57
|
-
* the shape we skipped would run the command unscoped.
|
|
58
|
-
*/
|
|
59
|
-
const INPUT_PATHS: readonly (readonly string[])[] = [
|
|
60
|
-
['hookSpecificOutput', 'updatedInput'],
|
|
61
|
-
['modifiedArgs'],
|
|
62
|
-
['updated_input'],
|
|
63
|
-
]
|
|
64
|
-
|
|
65
|
-
/** POSIX single-quoting: wrap in `'…'`, and close/escape/reopen around any embedded `'`. */
|
|
66
|
-
function shellQuote(value: string): string {
|
|
67
|
-
return `'${value.replaceAll("'", "'\\''")}'`
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** `VAR='…' VAR='…' …` for `root`, derived from the one shared env helper so there is a single source of truth. */
|
|
71
|
-
function scopePrefix(root: string): string {
|
|
72
|
-
const env = leanCtxEnvFor(root, {})
|
|
73
|
-
return SCOPED_VARS.map((name) => `${name}=${shellQuote(env[name] ?? '')}`).join(' ')
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
77
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Whether `command` is lean-ctx re-execing itself, and so ours to scope.
|
|
82
|
-
*
|
|
83
|
-
* Matched on the first token's BASENAME, not a fixed `/usr/local/bin` path, so
|
|
84
|
-
* a non-standard install location still scopes. An already-scoped command
|
|
85
|
-
* fails this test — its first token is a `VAR=…` assignment — which is what
|
|
86
|
-
* makes this function idempotent; the explicit guard in `scopeRewrittenCommand`
|
|
87
|
-
* does not rely on that, so this can be relaxed without silently double-scoping.
|
|
88
|
-
*/
|
|
89
|
-
function isWrapperReexec(command: string): boolean {
|
|
90
|
-
const first = command.trimStart().split(/\s+/, 1)[0]
|
|
91
|
-
return first !== undefined && first.length > 0 && basename(first) === WRAPPER
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* The EFFECTIVE identity to carry into git network commands inside a
|
|
96
|
-
* rewritten command — L3 (STATUS.md 12p): steps
|
|
97
|
-
* 2-3 of the standard, `../../rules/impl/adl-identity.ts`'s
|
|
98
|
-
* `resolveFromEnvOrFile` (the session env `ADL_AGENT_ID_AGENT`, else the
|
|
99
|
-
* machine default-agent file), not the session env var alone. This used to
|
|
100
|
-
* read only `currentAgent` — the raw env var — which meant a session whose
|
|
101
|
-
* identity resolved from the machine default-agent file (no
|
|
102
|
-
* `ADL_AGENT_ID_AGENT` in the environment at all, e.g. a surface without an
|
|
103
|
-
* `adl run --as` session) never got its lean-ctx `-c` re-exec's git network
|
|
104
|
-
* commands carried, even though every OTHER identity-bearing surface in
|
|
105
|
-
* this package (`../../pre-tool-use/handler.ts`'s rewrite, `../../rules/engine.ts`'s
|
|
106
|
-
* own rewrite stage) already falls back to that file. The lean-ctx hook
|
|
107
|
-
* kind runs in the same process the host spawned for `adl hook`, so
|
|
108
|
-
* `inv.env` is the session env `adl run` set — the same environment the
|
|
109
|
-
* rule engine resolves from.
|
|
110
|
-
*/
|
|
111
|
-
export function sessionIdentityOf(env: Readonly<Record<string, string | undefined>>): string | null {
|
|
112
|
-
const resolution = resolveFromEnvOrFile({ get: (name) => env[name] })
|
|
113
|
-
return resolution.ok ? resolution.agent : null
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* The machine-generated re-exec shapes lean-ctx emits for shell commands:
|
|
118
|
-
* `<binary> -c '<script>'` (single- or double-quoted, `-c` or `--command`,
|
|
119
|
-
* `=` or space separated). A non-shell rewrite (`lean-ctx read <path>`) has
|
|
120
|
-
* no script and is not matched.
|
|
121
|
-
*/
|
|
122
|
-
const REEXEC_SCRIPT_SINGLE = /^(\S+)\s+(?:-c|--command)(?:=|\s+)'((?:\\'|[^'])*)'\s*$/
|
|
123
|
-
const REEXEC_SCRIPT_DOUBLE = /^(\S+)\s+(?:-c|--command)(?:=|\s+)"((?:\\"|[^"])*)"\s*$/
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Carry `identity` into the git network commands of the script inside a
|
|
127
|
-
* lean-ctx `-c` re-exec — one scanner (`rewriteGitNetworkCommands`), so the
|
|
128
|
-
* prefix is byte-identical to the one `adl hook pre-tool-use` puts on the
|
|
129
|
-
* native command. Returns the rebuilt command, or null when there is nothing
|
|
130
|
-
* to carry (no script, non-git script, already-carried idempotently, or a
|
|
131
|
-
* DENY outcome — a conflicting/unsafe inline identity is the pre-tool-use
|
|
132
|
-
* guard's deny, never rewritten over here).
|
|
133
|
-
*/
|
|
134
|
-
function carryIdentityIntoReexec(command: string, identity: string): string | null {
|
|
135
|
-
const match = REEXEC_SCRIPT_SINGLE.exec(command) ?? REEXEC_SCRIPT_DOUBLE.exec(command)
|
|
136
|
-
if (match === null) return null
|
|
137
|
-
const binary = match[1] as string
|
|
138
|
-
const script = match[2] as string
|
|
139
|
-
const outcome = rewriteGitNetworkCommands(script, identity)
|
|
140
|
-
if (outcome.kind !== 'rewrite') return null
|
|
141
|
-
return `${binary} -c ${shellQuote(outcome.command)}`
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Prefix the four dir vars onto every replacement command in a `lean-ctx hook`
|
|
146
|
-
* stdout envelope, so the re-exec'd lean-ctx resolves the same `config.toml`
|
|
147
|
-
* its parent did.
|
|
148
|
-
*
|
|
149
|
-
* Fail-open by construction: anything that is not a rewrite envelope carrying a
|
|
150
|
-
* lean-ctx re-exec — a deny, a plain allow, a non-JSON line, empty output — is
|
|
151
|
-
* returned as the IDENTICAL string. This sits in the hook's verbatim relay
|
|
152
|
-
* path, so it must never be the reason a host's tool call breaks.
|
|
153
|
-
*
|
|
154
|
-
* 2026-09-28 — the two-envelope race: on Claude/Codex/Cursor a native shell
|
|
155
|
-
* call gets TWO PreToolUse rewrites (this scope rewrite and the git-identity
|
|
156
|
-
* rewrite in `../../pre-tool-use`), and the host applies only one of them
|
|
157
|
-
* (Claude's hooks guide: "the last one to finish takes effect … the order is
|
|
158
|
-
* non-deterministic"; Codex/Cursor specify no arbitration). So when the
|
|
159
|
-
* session has an identity, the git network commands inside the `-c` script
|
|
160
|
-
* are prefixed here too — whichever envelope the host picks authenticates
|
|
161
|
-
* the push. Everything else about the envelope is unchanged.
|
|
162
|
-
*/
|
|
163
|
-
export function scopeRewrittenCommand(stdout: string, root: string, identity: string | null = null): string {
|
|
164
|
-
if (stdout.trim().length === 0) return stdout
|
|
165
|
-
|
|
166
|
-
let parsed: unknown
|
|
167
|
-
try {
|
|
168
|
-
parsed = JSON.parse(stdout)
|
|
169
|
-
} catch {
|
|
170
|
-
return stdout
|
|
171
|
-
}
|
|
172
|
-
if (!isRecord(parsed)) return stdout
|
|
173
|
-
|
|
174
|
-
const prefix = scopePrefix(root)
|
|
175
|
-
let changed = false
|
|
176
|
-
|
|
177
|
-
for (const path of INPUT_PATHS) {
|
|
178
|
-
let node: unknown = parsed
|
|
179
|
-
for (const segment of path) {
|
|
180
|
-
if (!isRecord(node)) {
|
|
181
|
-
node = undefined
|
|
182
|
-
break
|
|
183
|
-
}
|
|
184
|
-
node = node[segment]
|
|
185
|
-
}
|
|
186
|
-
if (!isRecord(node)) continue
|
|
187
|
-
|
|
188
|
-
const command = node.command
|
|
189
|
-
if (typeof command !== 'string' || command.length === 0) continue
|
|
190
|
-
if (command.startsWith(`${SCOPED_VARS[0]}=`)) continue
|
|
191
|
-
if (!isWrapperReexec(command)) continue
|
|
192
|
-
|
|
193
|
-
let next = command
|
|
194
|
-
if (identity !== null) {
|
|
195
|
-
const carried = carryIdentityIntoReexec(next, identity)
|
|
196
|
-
if (carried !== null) next = carried
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
node.command = `${prefix} ${next}`
|
|
200
|
-
changed = true
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (!changed) return stdout
|
|
204
|
-
|
|
205
|
-
const trailing = stdout.slice(stdout.trimEnd().length)
|
|
206
|
-
return `${JSON.stringify(parsed)}${trailing}`
|
|
207
|
-
}
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared `LEAN_CTX_*` environment for every subprocess this package spawns
|
|
3
|
-
* into the global `lean-ctx` binary (installed fleet-wide on `PATH` by
|
|
4
|
-
* global-tools — see `../hooks/briefing/index.ts`'s header for why the
|
|
5
|
-
* binary itself is never repo-local here).
|
|
6
|
-
*
|
|
7
|
-
* `lean-ctx` reads four env vars to root its own config/data/state/cache
|
|
8
|
-
* per-invocation (confirmed directly against the real v3.9.20 binary via
|
|
9
|
-
* `strings` and `lean-ctx doctor --json`, this session, 2026-09-14 — they do
|
|
10
|
-
* not appear in `lean-ctx --help`'s documented list, which only advertises
|
|
11
|
-
* the unrelated `LEAN_CTX_DISABLED`/`LEAN_CTX_RAW`/... shell-hook toggles):
|
|
12
|
-
*
|
|
13
|
-
* - `LEAN_CTX_CONFIG_DIR` — directly the app's own config dir (i.e. already
|
|
14
|
-
* including the trailing `lean-ctx` segment, mirroring
|
|
15
|
-
* `XDG_CONFIG_HOME/lean-ctx`'s resolved value, not `XDG_CONFIG_HOME`
|
|
16
|
-
* itself) — `lean-ctx doctor --json` reports `config.toml exists` at
|
|
17
|
-
* exactly `<this>/config.toml`.
|
|
18
|
-
* - `LEAN_CTX_DATA_DIR`, `LEAN_CTX_STATE_DIR`, `LEAN_CTX_CACHE_DIR` — same
|
|
19
|
-
* shape, for lean-ctx's data/state/cache.
|
|
20
|
-
*
|
|
21
|
-
* Verified end-to-end this session: pointing these four vars at
|
|
22
|
-
* `enact-m5`'s real `.agents/lean-ctx/{config/lean-ctx,data,state,cache}`
|
|
23
|
-
* (which carries a real `config.toml`) makes `lean-ctx doctor --json` report
|
|
24
|
-
* "Shell allowlist 249 command(s) enforced"; the same binary with these vars
|
|
25
|
-
* pointed at an empty scratch directory (no config.toml at all) reports 223 —
|
|
26
|
-
* proof the binary actually reads these vars to resolve its per-repo config,
|
|
27
|
-
* not just a coincidence of directory layout.
|
|
28
|
-
*
|
|
29
|
-
* HARDCUT (work item A.3): this replaces the plain `XDG_CONFIG_HOME`/
|
|
30
|
-
* `XDG_DATA_HOME`/`XDG_STATE_HOME`/`XDG_CACHE_HOME` vars `../hooks/briefing/index.ts`
|
|
31
|
-
* used to set for the same purpose — those are a generic Unix convention
|
|
32
|
-
* lean-ctx does not actually key its own dir resolution on (its shell-hook
|
|
33
|
-
* script derives ITS OWN unrelated `_LEAN_CTX_STATE_DIR` from
|
|
34
|
-
* `XDG_STATE_HOME`, but the compiled binary invoked here never consults it).
|
|
35
|
-
* Every call site that used to build its own `XDG_*` env now imports this
|
|
36
|
-
* one helper instead, so config/data/state/cache resolution for lean-ctx
|
|
37
|
-
* lives in exactly one place.
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
import { existsSync, readFileSync } from 'node:fs'
|
|
41
|
-
import { join } from 'node:path'
|
|
42
|
-
|
|
43
|
-
import { decodeConfig } from '../gating/config.ts'
|
|
44
|
-
import { MARKER } from '../gating/root.ts'
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Repo-relative root every lean-ctx call's config/data/state/cache lives
|
|
48
|
-
* under, when `adl-config.toml`'s `[hooks] lean_ctx_dir` does not say
|
|
49
|
-
* otherwise.
|
|
50
|
-
*/
|
|
51
|
-
export const DEFAULT_LEAN_CTX_DIR = '.agents/lean-ctx'
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Resolve `[hooks] lean_ctx_dir` for `root`.
|
|
55
|
-
*
|
|
56
|
-
* Mirrors `../hooks/user-prompt-submit/handler.ts`'s `resolveSkillsDir`: an
|
|
57
|
-
* explicit key wins; a missing `adl-config.toml` falls back to the default
|
|
58
|
-
* (handlers are callable directly from tests, without the gating `main.ts`
|
|
59
|
-
* normally performs); a file that exists but fails to decode throws, so a
|
|
60
|
-
* typo'd key is a loud error rather than a silent revert to the default.
|
|
61
|
-
*/
|
|
62
|
-
export function resolveLeanCtxDir(root: string): string {
|
|
63
|
-
const configPath = join(root, MARKER)
|
|
64
|
-
if (!existsSync(configPath)) return DEFAULT_LEAN_CTX_DIR
|
|
65
|
-
|
|
66
|
-
const decoded = decodeConfig(readFileSync(configPath, 'utf8'))
|
|
67
|
-
if (!decoded.ok) {
|
|
68
|
-
throw new Error(`invalid ${configPath} at ${decoded.issue.pointer}: ${decoded.issue.message}`)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return decoded.value.hooks.leanCtxDir ?? DEFAULT_LEAN_CTX_DIR
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Set on EVERY `lean-ctx` child this package spawns, managed repo or not.
|
|
76
|
-
*
|
|
77
|
-
* lean-ctx 3.10.5's MCP `initialize` handler runs a startup maintenance
|
|
78
|
-
* block that calls `refresh_installed_hooks()`, re-writing raw
|
|
79
|
-
* `lean-ctx hook …` entries into the GLOBAL `~/.claude/settings.json`
|
|
80
|
-
* (upstream `rust/src/server/server_handler.rs` ~L180-209, issue #1879).
|
|
81
|
-
* `[setup] auto_inject_*` does not gate it; the only switch in that release
|
|
82
|
-
* is `LEAN_CTX_HEADLESS` (any value), checked first in that block. Measured
|
|
83
|
-
* 2026-09-30 on a real $HOME: unset → nine global hook entries re-appeared
|
|
84
|
-
* seconds after start; set → none, and the same 12 MCP tools are served.
|
|
85
|
-
* Those global hooks are what put lean-ctx's global shell allowlist in front
|
|
86
|
-
* of agents in unrelated, unmanaged folders — lean-ctx stays repo-local only.
|
|
87
|
-
*/
|
|
88
|
-
export const LEAN_CTX_HEADLESS_ENV: Readonly<Record<'LEAN_CTX_HEADLESS', string>> = { LEAN_CTX_HEADLESS: '1' }
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Build the env for a `lean-ctx` subprocess rooted at repository `root`,
|
|
92
|
-
* merged over `base` (normally `inv.env`/`process.env`) so every other
|
|
93
|
-
* ambient var — `PATH` included — still reaches the child.
|
|
94
|
-
*/
|
|
95
|
-
export function leanCtxEnv(
|
|
96
|
-
root: string,
|
|
97
|
-
base: Readonly<Record<string, string | undefined>>,
|
|
98
|
-
leanCtxDir: string = DEFAULT_LEAN_CTX_DIR,
|
|
99
|
-
): Record<string, string | undefined> {
|
|
100
|
-
return {
|
|
101
|
-
...base,
|
|
102
|
-
LEAN_CTX_CONFIG_DIR: join(root, leanCtxDir, 'config/lean-ctx'),
|
|
103
|
-
LEAN_CTX_DATA_DIR: join(root, leanCtxDir, 'data'),
|
|
104
|
-
LEAN_CTX_STATE_DIR: join(root, leanCtxDir, 'state'),
|
|
105
|
-
LEAN_CTX_CACHE_DIR: join(root, leanCtxDir, 'cache'),
|
|
106
|
-
...LEAN_CTX_HEADLESS_ENV,
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* `leanCtxEnv` with the dir root read from `root`'s own `adl-config.toml`.
|
|
112
|
-
*
|
|
113
|
-
* Every production call site uses THIS rather than the pure form above, so
|
|
114
|
-
* the process that DECIDES and the process that ENFORCES derive their scope
|
|
115
|
-
* from one configured value — the single source of truth this module exists
|
|
116
|
-
* for, and the invariant G1 turned on.
|
|
117
|
-
*/
|
|
118
|
-
export function leanCtxEnvFor(
|
|
119
|
-
root: string,
|
|
120
|
-
base: Readonly<Record<string, string | undefined>>,
|
|
121
|
-
): Record<string, string | undefined> {
|
|
122
|
-
return leanCtxEnv(root, base, resolveLeanCtxDir(root))
|
|
123
|
-
}
|