@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
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
1
|
+
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, existsSync } from 'node:fs'
|
|
2
2
|
import { tmpdir } from 'node:os'
|
|
3
3
|
import { join } from 'node:path'
|
|
4
|
-
import { loadComplianceConfig } from './compliance-config.ts'
|
|
4
|
+
import { LOCKFILE_KEYS, loadComplianceConfig } from './compliance-config.ts'
|
|
5
5
|
import { configEnv, type FindingsConfig, loadConfig, parseConfig, type StaticCheck } from './config.ts'
|
|
6
6
|
import { BUNDLE_ROOT, COMPLIANCE_ROOT, HOOK_NAMES, type HookName } from './constants.ts'
|
|
7
7
|
import { docFreshnessProblems, inScope } from './doc-freshness.ts'
|
|
8
8
|
import { azureDevOpsPromotionGovernanceChecks, type Check, doctor, type DoctorReport } from './doctor.ts'
|
|
9
9
|
import { commitRequiredProblems, integrityProblems } from './integrity.ts'
|
|
10
|
+
import { lfsChain } from './lfs.ts'
|
|
11
|
+
import { logHookEvent } from './hook-log.ts'
|
|
10
12
|
import { type CoverageSummary, coverageRegressions, readSummary } from './coverage-ratchet.ts'
|
|
11
13
|
import { type Floor, findingsProblems, parseCounterOutput, parseFloor } from './findings-ratchet.ts'
|
|
12
14
|
import { bashProblem, capture, childEnv, type Env, resolveRepo, which } from './runtime.ts'
|
|
@@ -45,7 +47,16 @@ export interface RunContext {
|
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
/** Runs one bundled script with the repository's config exported; returns its exit status. */
|
|
48
|
-
function runBundled(
|
|
50
|
+
function runBundled(
|
|
51
|
+
runtime: 'bash' | 'bun',
|
|
52
|
+
script: string,
|
|
53
|
+
args: string[],
|
|
54
|
+
repo: string,
|
|
55
|
+
workdir: string,
|
|
56
|
+
context: RunContext,
|
|
57
|
+
/** What to write to the script's stdin instead of {@link RunContext.stdin}: pre-push's already-captured ref lines. */
|
|
58
|
+
input?: string,
|
|
59
|
+
): number {
|
|
49
60
|
const problem = bashProblem(context.env)
|
|
50
61
|
if (problem) throw new Error(problem)
|
|
51
62
|
const env = { ...context.env, ...configEnv(repo, loadConfig(repo)) }
|
|
@@ -54,7 +65,7 @@ function runBundled(runtime: 'bash' | 'bun', script: string, args: string[], rep
|
|
|
54
65
|
const proc = Bun.spawnSync([executable, join(BUNDLE_ROOT, script), ...args], {
|
|
55
66
|
cwd: workdir,
|
|
56
67
|
env: childEnv(env),
|
|
57
|
-
stdin: context.stdin ?? 'inherit',
|
|
68
|
+
stdin: input === undefined ? (context.stdin ?? 'inherit') : Buffer.from(input),
|
|
58
69
|
stdout: 'inherit',
|
|
59
70
|
stderr: 'inherit',
|
|
60
71
|
})
|
|
@@ -83,6 +94,49 @@ function runUv(args: string[], repo: string, context: RunContext): number {
|
|
|
83
94
|
...Object.entries(config.trees).flatMap(([name, path]) => ['--tree', `${name}=${path}`]),
|
|
84
95
|
...Object.entries(config.inputs).flatMap(([name, path]) => ['--input', `${name}=${path}`]),
|
|
85
96
|
...Object.entries(config.declarations).flatMap(([name, value]) => ['--declare', `${name}=${value}`]),
|
|
97
|
+
// Extra root names this repository allows, as comma lists. An empty list is
|
|
98
|
+
// skipped, never sent: the engine rejects an empty `--declare` value. Names are
|
|
99
|
+
// validated comma-free in `parseRoot`, so the join is unambiguous.
|
|
100
|
+
...(config.root?.files.length ? ['--declare', `root-files=${config.root.files.join(',')}`] : []),
|
|
101
|
+
...(config.root?.dirs.length ? ['--declare', `root-dirs=${config.root.dirs.join(',')}`] : []),
|
|
102
|
+
// Engine limits this repository overrides. An unset key sends nothing, so the
|
|
103
|
+
// engine's own default stays in force; `parseLimits` already guaranteed a
|
|
104
|
+
// positive integer, which is what the engine will accept.
|
|
105
|
+
...(config.limits?.scripts_direct_files !== undefined
|
|
106
|
+
? ['--declare', `scripts-direct-files=${config.limits.scripts_direct_files}`]
|
|
107
|
+
: []),
|
|
108
|
+
...(config.limits?.open_gaps !== undefined ? ['--declare', `open-gaps=${config.limits.open_gaps}`] : []),
|
|
109
|
+
...(config.limits?.open_plans !== undefined ? ['--declare', `open-plans=${config.limits.open_plans}`] : []),
|
|
110
|
+
...(config.limits?.docs_pages_per_directory !== undefined
|
|
111
|
+
? ['--declare', `docs-pages-per-directory=${config.limits.docs_pages_per_directory}`]
|
|
112
|
+
: []),
|
|
113
|
+
// LAY-004's per-tree ceilings, as ONE comma list of `<path>:<n>` entries —
|
|
114
|
+
// the engine splits the list and refuses anything but a repo-relative
|
|
115
|
+
// path and a base-10 positive integer. Entries are sorted so the argv is
|
|
116
|
+
// deterministic whatever the TOML table's order. An empty or undeclared
|
|
117
|
+
// table sends nothing: no configuration, nothing to enforce.
|
|
118
|
+
...(() => {
|
|
119
|
+
const ceilings = config.directory_ratchet?.max_children ?? {}
|
|
120
|
+
const entries = Object.entries(ceilings)
|
|
121
|
+
if (entries.length === 0) return []
|
|
122
|
+
const joined = entries
|
|
123
|
+
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
124
|
+
.map(([path, n]) => `${path}:${n}`)
|
|
125
|
+
.join(',')
|
|
126
|
+
return ['--declare', `directory-ceilings=${joined}`]
|
|
127
|
+
})(),
|
|
128
|
+
// Extra Markdown roots, as one comma list. An empty list is skipped, never sent
|
|
129
|
+
// (the engine rejects an empty `--declare` value); `parseMarkdown` already
|
|
130
|
+
// guaranteed each root is comma-free, so the join is unambiguous.
|
|
131
|
+
...(config.markdown?.roots.length ? ['--declare', `markdown-roots=${config.markdown.roots.join(',')}`] : []),
|
|
132
|
+
// REP-002's declared manifest and lockfile paths, one comma list per key, in
|
|
133
|
+
// `LOCKFILE_KEYS` order (`bun-manifests`, `bun-lockfiles`, `cargo-manifests`,
|
|
134
|
+
// `cargo-lockfiles`). An empty list is skipped, never sent; `parseLockfiles` already
|
|
135
|
+
// guaranteed each entry is comma-free and that a half is set as a pair.
|
|
136
|
+
...LOCKFILE_KEYS.flatMap((key) => {
|
|
137
|
+
const entries = config.lockfiles?.[key] ?? []
|
|
138
|
+
return entries.length > 0 ? ['--declare', `${key.replace('_', '-')}=${entries.join(',')}`] : []
|
|
139
|
+
}),
|
|
86
140
|
]
|
|
87
141
|
const proc = Bun.spawnSync(
|
|
88
142
|
[executable, 'run', '--project', COMPLIANCE_ROOT, 'adl-compliance', '--root', repo, ...injected, ...args],
|
|
@@ -286,6 +340,45 @@ export function stagedCoverageStep(
|
|
|
286
340
|
return run.code
|
|
287
341
|
}
|
|
288
342
|
|
|
343
|
+
/**
|
|
344
|
+
* The coverage MEASUREMENT at push: the repository's declared push-phase
|
|
345
|
+
* command, not ours.
|
|
346
|
+
*
|
|
347
|
+
* The same division as `stagedCoverageStep`, one phase later: the repository
|
|
348
|
+
* says HOW to measure (`[controls.coverage].produce_push`), this package
|
|
349
|
+
* decides WHEN (pre-push, before the ratchet grades what the measurement
|
|
350
|
+
* wrote) and grades the exit status. The estate moved the measurement here
|
|
351
|
+
* because it serialises minutes of work; commits stay fast, and the push
|
|
352
|
+
* measures then grades in one gate.
|
|
353
|
+
*
|
|
354
|
+
* `produce_push` is a separate declaration from `produce` rather than a reuse:
|
|
355
|
+
* a commit-phase producer may stage a refreshed summary, while a push-phase
|
|
356
|
+
* command runs against an immutable HEAD — a check-mode run that never mutates
|
|
357
|
+
* the index is the shape.
|
|
358
|
+
*
|
|
359
|
+
* Absence is deliberately NOT a skip, same rule as at commit: with the gate
|
|
360
|
+
* armed and no command declared, this is could-not-run — a step that measures
|
|
361
|
+
* nothing is not a pass.
|
|
362
|
+
*/
|
|
363
|
+
export function coverageProduceStep(
|
|
364
|
+
producePush: string,
|
|
365
|
+
runCommand: (command: string) => { code: number; stdout: string; stderr: string },
|
|
366
|
+
err: (line: string) => void,
|
|
367
|
+
): number {
|
|
368
|
+
const declared = producePush.trim()
|
|
369
|
+
if (declared === '') {
|
|
370
|
+
err('pre-push: FAIL — pre_push.coverage_produce is on but [controls.coverage].produce_push declares no command.')
|
|
371
|
+
err(' A step that measures nothing is not a pass.')
|
|
372
|
+
return 1
|
|
373
|
+
}
|
|
374
|
+
const run = runCommand(declared)
|
|
375
|
+
if (run.code !== 0) {
|
|
376
|
+
err(`pre-push: FAIL — coverage.produce_push exited ${run.code}: ${declared}`)
|
|
377
|
+
if (run.stderr.trim() !== '') err(` ${run.stderr.trim().split('\n').slice(-3).join('\n ')}`)
|
|
378
|
+
}
|
|
379
|
+
return run.code
|
|
380
|
+
}
|
|
381
|
+
|
|
289
382
|
/**
|
|
290
383
|
* The coverage ratchet at push: did anything get worse between the baseline and
|
|
291
384
|
* what is being pushed.
|
|
@@ -365,6 +458,10 @@ export function declaredChecksFor(
|
|
|
365
458
|
// here, on purpose — see tests/declared-hook-scripts.test.ts.
|
|
366
459
|
case 'post-checkout':
|
|
367
460
|
return []
|
|
461
|
+
// `post-merge` exists only to chain Git LFS (scripts/hooks/lib/lfs.sh); like
|
|
462
|
+
// post-checkout it has no repository-declared seam.
|
|
463
|
+
case 'post-merge':
|
|
464
|
+
return []
|
|
368
465
|
}
|
|
369
466
|
}
|
|
370
467
|
|
|
@@ -524,7 +621,7 @@ export function doctorGate(readDoctor: () => DoctorReport, err: (line: string) =
|
|
|
524
621
|
* `loadConfig`) can throw on a malformed config; that is reported the same
|
|
525
622
|
* way as an unarmed check rather than crashing the hook process.
|
|
526
623
|
*/
|
|
527
|
-
|
|
624
|
+
function azureDevOpsPromotionGovernanceGate(readChecks: () => Check[], err: (line: string) => void): number {
|
|
528
625
|
let checks: Check[]
|
|
529
626
|
try {
|
|
530
627
|
checks = readChecks()
|
|
@@ -557,7 +654,7 @@ export function runHook(name: HookName, args: string[], context: RunContext): nu
|
|
|
557
654
|
const top = capture(['git', 'rev-parse', '--show-toplevel'], context.cwd, context.env)
|
|
558
655
|
if (top.code !== 0) throw new Error(`not inside a git work tree: ${context.cwd}`)
|
|
559
656
|
const repo = top.stdout.trim()
|
|
560
|
-
// The worktree-count backstop (
|
|
657
|
+
// The worktree-count backstop (docs/operations/worktree-guard.md). Git has no
|
|
561
658
|
// pre-worktree hook, so this cannot stop `git worktree add` from creating
|
|
562
659
|
// the checkout — it runs after, in the NEW worktree, and actively removes it
|
|
563
660
|
// when the repository is over the limit. See ./worktree-guard.ts for why
|
|
@@ -597,34 +694,41 @@ export function runHook(name: HookName, args: string[], context: RunContext): nu
|
|
|
597
694
|
// The armed compliance gates, before the bundled script. Until this existed
|
|
598
695
|
// `[controls.compliance].enabled` armed nothing that ever ran: no bundled hook
|
|
599
696
|
// mentions compliance and `runHook` never reached `runUv`, so a gate was
|
|
600
|
-
// "enabled" and dormant.
|
|
601
|
-
// `
|
|
697
|
+
// "enabled" and dormant. `compliance` defaults ON, but the step is a no-op
|
|
698
|
+
// when `[controls.compliance].enabled` is empty -- the same "wrapper on,
|
|
699
|
+
// work gated by configured state" shape as stagedCoverage/coverageRatchet/
|
|
700
|
+
// findingsRatchet above and the docFreshness floor's empty-files case.
|
|
602
701
|
if (name === 'pre-commit' && stagedComplianceEnabled(repo, context.env)) {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
702
|
+
if (loadComplianceConfig(repo).enabled.length > 0) {
|
|
703
|
+
const code = withStagedIndexSnapshot(repo, context.env, (snapshot) => {
|
|
704
|
+
// Activation is itself read from the candidate commit. An unstaged config
|
|
705
|
+
// edit cannot turn a staged gate off (or on), and a commit introducing the
|
|
706
|
+
// gate proves it is armed before it lands.
|
|
707
|
+
return complianceStep(() =>
|
|
708
|
+
runUv(['--files', snapshot.files, '--exhaustive'], snapshot.root, context),
|
|
709
|
+
)
|
|
710
|
+
})
|
|
711
|
+
if (code !== 0) return code
|
|
712
|
+
}
|
|
612
713
|
}
|
|
613
714
|
// Staged coverage, through the repository's declared command. Was a hardcoded
|
|
614
715
|
// shell-out inside the bundled pre-commit into this package's copy of the
|
|
615
716
|
// consumer's coverage code; see `stagedCoverageStep`.
|
|
717
|
+
// Safety gate: `stagedCoverage` defaults ON; a repository that has not declared
|
|
718
|
+
// `[controls.coverage].produce` has nothing to run, so the step is a no-op.
|
|
719
|
+
// Same shape as `compliance` below: the wrapper is on, the work is gated by
|
|
720
|
+
// whether the repository opted into the configuration it needs.
|
|
616
721
|
if (name === 'pre-commit' && loadConfig(repo).preCommit.stagedCoverage) {
|
|
617
722
|
const config = loadConfig(repo)
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
if (code !== 0) return code
|
|
723
|
+
if (config.coverage.produce.trim() !== '') {
|
|
724
|
+
const code = stagedCoverageStep(
|
|
725
|
+
config.coverage,
|
|
726
|
+
(command) => capture(['bash', '-c', command], repo, context.env),
|
|
727
|
+
null,
|
|
728
|
+
context.err,
|
|
729
|
+
)
|
|
730
|
+
if (code !== 0) return code
|
|
731
|
+
}
|
|
628
732
|
}
|
|
629
733
|
// The Azure DevOps promotion-governance checks, moved here from pre-commit
|
|
630
734
|
// (2026-09-28, Tarun): network access and a minted token are already
|
|
@@ -639,49 +743,101 @@ export function runHook(name: HookName, args: string[], context: RunContext): nu
|
|
|
639
743
|
)
|
|
640
744
|
if (code !== 0) return code
|
|
641
745
|
}
|
|
746
|
+
// The coverage MEASUREMENT at push, before the ratchet below grades what it
|
|
747
|
+
// wrote. Opt-in: `coverageProduce` defaults OFF (new gates opt in), unlike
|
|
748
|
+
// the ratchet's ON. Armed with no declared command, the step itself fails
|
|
749
|
+
// loud — a step that measures nothing is not a pass; off is a no-op.
|
|
750
|
+
if (name === 'pre-push' && loadConfig(repo).prePush.coverageProduce) {
|
|
751
|
+
const code = coverageProduceStep(
|
|
752
|
+
loadConfig(repo).coverage.producePush,
|
|
753
|
+
(command) => capture(['bash', '-c', command], repo, context.env),
|
|
754
|
+
context.err,
|
|
755
|
+
)
|
|
756
|
+
if (code !== 0) return code
|
|
757
|
+
}
|
|
642
758
|
// The coverage ratchet at push. Was `command.ts check-push` inside the bundled
|
|
643
759
|
// pre-push, running the package's copy of the consumer's coverage code.
|
|
760
|
+
// Safety gate: `coverageRatchet` defaults ON; the ratchet has no baseline
|
|
761
|
+
// unless the repository has staged a coverage summary file at the path
|
|
762
|
+
// `[controls.coverage].summary` declares. With no file on either side of the
|
|
763
|
+
// index, the step is a no-op — same shape as compliance below.
|
|
644
764
|
if (name === 'pre-push' && loadConfig(repo).prePush.coverageRatchet) {
|
|
645
765
|
const config = loadConfig(repo)
|
|
646
766
|
const rel = config.coverage.summary
|
|
647
|
-
|
|
648
|
-
const
|
|
649
|
-
|
|
767
|
+
if (rel !== '' && (existsSync(join(repo, rel)) || capture(['git', 'cat-file', '-e', `HEAD:${rel}`], repo, context.env).code === 0)) {
|
|
768
|
+
const at = (ref: string) => {
|
|
769
|
+
const shown = capture(['git', 'show', `${ref}:${rel}`], repo, context.env)
|
|
770
|
+
return shown.code === 0 ? shown.stdout : null
|
|
771
|
+
}
|
|
772
|
+
const code = coverageRatchetStep(
|
|
773
|
+
rel,
|
|
774
|
+
() => at('HEAD~1'),
|
|
775
|
+
() => at('HEAD') ?? readFileSync(join(repo, rel), 'utf8'),
|
|
776
|
+
context.err,
|
|
777
|
+
)
|
|
778
|
+
if (code !== 0) return code
|
|
650
779
|
}
|
|
651
|
-
const code = coverageRatchetStep(
|
|
652
|
-
rel,
|
|
653
|
-
() => at('HEAD~1'),
|
|
654
|
-
() => at('HEAD') ?? readFileSync(join(repo, rel), 'utf8'),
|
|
655
|
-
context.err,
|
|
656
|
-
)
|
|
657
|
-
if (code !== 0) return code
|
|
658
780
|
}
|
|
659
781
|
// The findings ratchet, before the bundled script, same shape as compliance
|
|
660
|
-
// above. `
|
|
661
|
-
//
|
|
662
|
-
//
|
|
782
|
+
// above. Safety gate: `findingsRatchet` defaults ON; the gate has nothing
|
|
783
|
+
// to grade unless `[controls.findings].floor` exists. With no floor file,
|
|
784
|
+
// the step is a no-op — same shape as compliance and coverageRatchet.
|
|
663
785
|
if (name === 'pre-push' && loadConfig(repo).prePush.findingsRatchet) {
|
|
664
|
-
const
|
|
665
|
-
if (
|
|
786
|
+
const floorPath = loadConfig(repo).findings.floor
|
|
787
|
+
if (floorPath !== '' && existsSync(join(repo, floorPath))) {
|
|
788
|
+
const code = runFindingsRatchet(repo, context)
|
|
789
|
+
if (code !== 0) return code
|
|
790
|
+
}
|
|
666
791
|
}
|
|
792
|
+
// git writes pre-push's ref lines on stdin exactly once. The bundled script
|
|
793
|
+
// reads them for the branch rules and `git lfs pre-push` needs them too, so
|
|
794
|
+
// they are read here, once, and fed to both. Every other hook has no stdin
|
|
795
|
+
// contract and passes none.
|
|
796
|
+
const pushUpdates = name === 'pre-push' && (context.stdin ?? 'inherit') === 'inherit' ? readFileSync(0, 'utf8') : ''
|
|
667
797
|
// The package's standard bash: the shared policy every repository gets.
|
|
668
|
-
const standard = runBundled(
|
|
798
|
+
const standard = runBundled(
|
|
799
|
+
'bash',
|
|
800
|
+
`hooks/${name}`,
|
|
801
|
+
args,
|
|
802
|
+
repo,
|
|
803
|
+
context.cwd,
|
|
804
|
+
context,
|
|
805
|
+
name === 'pre-push' ? pushUpdates : undefined,
|
|
806
|
+
)
|
|
669
807
|
if (standard !== 0) return standard
|
|
670
808
|
|
|
671
809
|
// pre-push owns its declared static checks inside the bundled script: it
|
|
672
810
|
// exports immutable HEAD, runs them there, and caches the pass by tree OID.
|
|
673
811
|
// Running them again here would grade the dirty checkout a second time.
|
|
674
|
-
|
|
812
|
+
// Git LFS comes last, after every adl check passed: a refused push uploads
|
|
813
|
+
// nothing. See ./lfs.ts for why this is here and not in the bash.
|
|
814
|
+
if (name === 'pre-push') return lfsStep(name, args, pushUpdates, repo, context)
|
|
675
815
|
|
|
676
816
|
// Then the repository's own script, on top (owner: "standard bash + script
|
|
677
817
|
// calling on top"). Declared per hook, run from the repo root, never named by
|
|
678
818
|
// this package. Absent means nothing runs -- there is no bundled default for
|
|
679
819
|
// a repository's own policy.
|
|
680
|
-
|
|
820
|
+
const declared = preCommitChecks(
|
|
681
821
|
declaredChecksFor(name, loadConfig(repo)),
|
|
682
822
|
(command) => capture(['bash', '-c', command], repo, context.env),
|
|
683
823
|
context.err,
|
|
684
824
|
)
|
|
825
|
+
const lfs = lfsStep(name, args, '', repo, context)
|
|
826
|
+
return declared !== 0 ? declared : lfs
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/** `lfsChain` plus the log row the bundled script cannot write: it has already logged PASS by the time git-lfs runs. */
|
|
830
|
+
function lfsStep(name: HookName, args: string[], input: string, repo: string, context: RunContext): number {
|
|
831
|
+
const failures: string[] = []
|
|
832
|
+
const code = lfsChain(name, args, input, repo, {
|
|
833
|
+
env: context.env,
|
|
834
|
+
err: (line) => {
|
|
835
|
+
failures.push(line)
|
|
836
|
+
context.err(line)
|
|
837
|
+
},
|
|
838
|
+
})
|
|
839
|
+
if (code !== 0) logHookEvent(name, `FAIL exit=${code}`, '', failures[0] ?? `git lfs ${name} failed`, repo)
|
|
840
|
+
return code
|
|
685
841
|
}
|
|
686
842
|
|
|
687
843
|
// `_tool` is unread on purpose. `compliance` is the only tool left, and it is a
|
|
@@ -48,7 +48,7 @@ interface GitignoreRecord {
|
|
|
48
48
|
created: boolean
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
type TableConfigRecord = { created: boolean; sha256: string } | null
|
|
52
52
|
|
|
53
53
|
export interface Lock {
|
|
54
54
|
lockVersion: 1
|
|
@@ -79,9 +79,9 @@ export function vendoredPromotePath(): string {
|
|
|
79
79
|
|
|
80
80
|
/**
|
|
81
81
|
* The stub execs `adl repo controls hook <name>`, not a standalone
|
|
82
|
-
* `adl-repo-controls` binary (
|
|
82
|
+
* `adl-repo-controls` binary (2026-09-27): this
|
|
83
83
|
* package is folded into the `adl` binary's `repo controls` namespace
|
|
84
|
-
* (docs/architecture/cli-design.md §6
|
|
84
|
+
* (docs/architecture/cli-design.md §6) — hard cut, no compat shim, the
|
|
85
85
|
* same decision `adl hook` already made for agent-hooks. `adl` is what a
|
|
86
86
|
* repository's hooks now require on PATH, and `adl` is what the fleet
|
|
87
87
|
* actually installs (bin/reconcile's `bun-compile` manager); see
|
|
@@ -335,15 +335,21 @@ function ownedTable(text: string, tableName: string): Table | null {
|
|
|
335
335
|
}
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
-
/**
|
|
338
|
+
/**
|
|
339
|
+
* Reject malformed text that declares itself to be this package's table, and the two
|
|
340
|
+
* array tables install owns outright: `[[controls]]` and `[[controls.compliance]]`.
|
|
341
|
+
* Array tables NESTED under an owned table (`[[controls.pre_push.static_checks]]`,
|
|
342
|
+
* what `adl migrate` writes) are ordinary user data: the same value as the inline
|
|
343
|
+
* form, kept byte-for-byte.
|
|
344
|
+
*/
|
|
339
345
|
function assertNoMalformedOwnedHeader(text: string): void {
|
|
340
346
|
for (const raw of text.split('\n')) {
|
|
341
347
|
const line = raw.trim()
|
|
342
|
-
const
|
|
343
|
-
if (
|
|
344
|
-
throw new Error(`${CONFIG_REL} declares unsupported owned array table: [[${
|
|
348
|
+
const arrayTable = /^\[\[\s*(controls(?:\.[A-Za-z0-9_-]+)*)\s*\]\]\s*(?:#.*)?$/.exec(line)
|
|
349
|
+
if (arrayTable !== null && (arrayTable[1] === 'controls' || arrayTable[1] === 'controls.compliance')) {
|
|
350
|
+
throw new Error(`${CONFIG_REL} declares unsupported owned array table: [[${arrayTable[1]}]]`)
|
|
345
351
|
}
|
|
346
|
-
if (/^\[\[\s*controls(?:\.|\]|\s)/.test(line)) {
|
|
352
|
+
if (arrayTable === null && /^\[\[\s*controls(?:\.|\]|\s)/.test(line)) {
|
|
347
353
|
throw new Error(`${CONFIG_REL} [controls] is invalid TOML: malformed table header`)
|
|
348
354
|
}
|
|
349
355
|
if (line === '[controls' || /^\[controls(?=\.|\])/.test(line) && !/^\[controls(?:\.[A-Za-z0-9_-]+)*\]$/.test(line)) {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* adl hook is responsible for refusing that escape hatch to agents.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
const WIRING: readonly string[] = ['adl-config.toml']
|
|
11
11
|
|
|
12
12
|
// Tarun, 2026-09-30: `.workflows/` and every agent surface root are protected
|
|
13
13
|
// like `workflows/` — a dirty path under any of them blocks a normal commit and
|
|
@@ -50,7 +50,7 @@ function patternToRegExp(pattern: string): RegExp {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/** Match the repository-declared portion of the protected set. */
|
|
53
|
-
|
|
53
|
+
function protectedMatchers(watched: readonly string[]): ((path: string) => boolean)[] {
|
|
54
54
|
const wiring = WIRING.map((name) => (path: string) => path === name)
|
|
55
55
|
const declared = watched.map((pattern) => {
|
|
56
56
|
const re = patternToRegExp(pattern)
|
|
@@ -62,7 +62,7 @@ export function protectedMatchers(watched: readonly string[]): ((path: string) =
|
|
|
62
62
|
const isUnderFixedRoot = (path: string): boolean => FIXED_ROOTS.some((root) => path === root || path.startsWith(`${root}/`))
|
|
63
63
|
|
|
64
64
|
/** Centrally managed repository files that must travel with the next commit. */
|
|
65
|
-
|
|
65
|
+
const isTopLevelDotPath = (path: string): boolean => path.startsWith('.')
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
68
|
* The single source of truth used for final-index and dirty-worktree checks.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git LFS chaining for the projected hooks.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS (live, 2026-10-01, enact-combined). `adl repo controls install`
|
|
5
|
+
* sets `core.hooksPath=.workflows/hooks`, so git never runs the
|
|
6
|
+
* `.git/hooks/{pre-push,post-checkout,post-commit,post-merge}` that
|
|
7
|
+
* `git lfs install` writes. adl's own hooks did not call git-lfs, so a push of a
|
|
8
|
+
* commit carrying an LFS pointer succeeded WITHOUT uploading the object and left
|
|
9
|
+
* a broken pointer on the remote. Each of those four hooks now chains to
|
|
10
|
+
* `git lfs <hook> "$@"` from `runHook`.
|
|
11
|
+
*
|
|
12
|
+
* Rules, in order:
|
|
13
|
+
* 1. A repository that does not use LFS never calls git lfs.
|
|
14
|
+
* 2. A repository that uses LFS with no `git-lfs` on PATH FAILS LOUD. There is
|
|
15
|
+
* no silent skip: a skipped pre-push is exactly the broken-pointer bug.
|
|
16
|
+
* 3. A failing `git lfs <hook>` is the hook's failure (for pre-push: the push
|
|
17
|
+
* fails).
|
|
18
|
+
*
|
|
19
|
+
* WHY THIS IS TYPESCRIPT, NOT THE BUNDLED BASH. bin/git-ado authenticates an
|
|
20
|
+
* agent's `git push` by exporting `GIT_CONFIG_COUNT` and a
|
|
21
|
+
* `GIT_CONFIG_KEY_n=http.https://<host>/.extraHeader` /
|
|
22
|
+
* `GIT_CONFIG_VALUE_n=Authorization: Bearer <token>` pair to the real git; git
|
|
23
|
+
* passes its environment to the hook. `runBundled` hands the bash scripts a
|
|
24
|
+
* `childEnv` with every `GIT_CONFIG_*` removed, on purpose, so adl's own checks
|
|
25
|
+
* never hold the token. git-lfs is the one child that must, and it must hold
|
|
26
|
+
* exactly the pairs the parent `git push` had -- the same mechanism, never a
|
|
27
|
+
* second mint, never the human's credential helper (tests/lfs-credential-
|
|
28
|
+
* boundary.test.ts proves git-lfs reads that header and does not fall back).
|
|
29
|
+
* `runHook` is the only place that still has the unstripped `context.env`, so
|
|
30
|
+
* the chaining lives here and only this one spawn is given it.
|
|
31
|
+
*/
|
|
32
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
33
|
+
import { join } from 'node:path'
|
|
34
|
+
import type { HookName } from './constants.ts'
|
|
35
|
+
import { capture, type Env, which } from './runtime.ts'
|
|
36
|
+
|
|
37
|
+
/** The hooks `git lfs install` writes -- and so the ones a controlled repository must chain. */
|
|
38
|
+
export const LFS_HOOKS: readonly HookName[] = ['pre-push', 'post-checkout', 'post-commit', 'post-merge']
|
|
39
|
+
|
|
40
|
+
const FILTER_LFS = /filter=lfs(\s|$)/m
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Whether the repository uses Git LFS: a `filter=lfs` attribute in any
|
|
44
|
+
* `.gitattributes` (tracked, or untracked and not ignored) or in
|
|
45
|
+
* `.git/info/attributes`, a `.lfsconfig`, or `lfs.*` in the repository's own git
|
|
46
|
+
* config. The git calls run through `capture`, whose env carries no
|
|
47
|
+
* `GIT_CONFIG_*`.
|
|
48
|
+
*/
|
|
49
|
+
export function repoUsesLfs(repo: string, env: Env): boolean {
|
|
50
|
+
if (existsSync(join(repo, '.lfsconfig'))) return true
|
|
51
|
+
const grep = capture(['git', 'grep', '-q', '--untracked', '-E', 'filter=lfs([[:space:]]|$)', '--', ':(glob)**/.gitattributes'], repo, env)
|
|
52
|
+
if (grep.code === 0) return true
|
|
53
|
+
const info = capture(['git', 'rev-parse', '--git-path', 'info/attributes'], repo, env)
|
|
54
|
+
if (info.code === 0) {
|
|
55
|
+
const path = join(repo, info.stdout.trim())
|
|
56
|
+
if (existsSync(path) && FILTER_LFS.test(readFileSync(path, 'utf8'))) return true
|
|
57
|
+
}
|
|
58
|
+
return capture(['git', 'config', '--local', '--name-only', '--get-regexp', '^lfs\\.'], repo, env).code === 0
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface LfsChainContext {
|
|
62
|
+
/** The environment git handed the hook, UNSTRIPPED: it is what authenticates git-lfs. */
|
|
63
|
+
env: Env
|
|
64
|
+
err: (line: string) => void
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Chains one hook to `git lfs <hook> <args...>`, feeding `input` on stdin
|
|
69
|
+
* (pre-push's ref lines; `''` for the others). Returns the hook's exit status.
|
|
70
|
+
*
|
|
71
|
+
* `run` is injected so the decision (skip / fail loud / propagate the status) is
|
|
72
|
+
* unit-testable without spawning git-lfs; production passes {@link spawnGitLfs}.
|
|
73
|
+
*/
|
|
74
|
+
export function lfsChain(
|
|
75
|
+
hook: HookName,
|
|
76
|
+
args: string[],
|
|
77
|
+
input: string,
|
|
78
|
+
repo: string,
|
|
79
|
+
context: LfsChainContext,
|
|
80
|
+
run: (hook: HookName, args: string[], input: string, repo: string, env: Env) => number = spawnGitLfs,
|
|
81
|
+
): number {
|
|
82
|
+
if (!LFS_HOOKS.includes(hook)) return 0
|
|
83
|
+
if (!repoUsesLfs(repo, context.env)) return 0
|
|
84
|
+
if (!which('git-lfs', context.env)) {
|
|
85
|
+
context.err(`${hook}: FAIL — this repository uses Git LFS but 'git-lfs' is not on PATH.`)
|
|
86
|
+
context.err(' Skipping it would leave LFS pointers without their objects; refusing instead.')
|
|
87
|
+
context.err(' Install git-lfs (macOS: brew install git-lfs; Debian/Ubuntu: apt install git-lfs), then retry.')
|
|
88
|
+
context.err(' If this repository no longer uses LFS, remove the filter=lfs lines from .gitattributes (and any .lfsconfig).')
|
|
89
|
+
return 1
|
|
90
|
+
}
|
|
91
|
+
const code = run(hook, args, input, repo, context.env)
|
|
92
|
+
if (code !== 0) context.err(`${hook}: FAIL — git lfs ${hook} exited ${code}.`)
|
|
93
|
+
return code
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* `git lfs <hook> <args...>` with the caller's whole environment, GIT_CONFIG_*
|
|
98
|
+
* included. This is deliberately NOT `childEnv`: see the header.
|
|
99
|
+
*/
|
|
100
|
+
function spawnGitLfs(hook: HookName, args: string[], input: string, repo: string, env: Env): number {
|
|
101
|
+
const git = which('git', env)
|
|
102
|
+
if (!git) throw new Error('git not found on PATH')
|
|
103
|
+
const proc = Bun.spawnSync([git, 'lfs', hook, ...args], {
|
|
104
|
+
cwd: repo,
|
|
105
|
+
env: { ...process.env, ...env },
|
|
106
|
+
stdin: Buffer.from(input),
|
|
107
|
+
stdout: 'inherit',
|
|
108
|
+
stderr: 'inherit',
|
|
109
|
+
})
|
|
110
|
+
return proc.exitCode ?? 1
|
|
111
|
+
}
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* repositories. Do not add a second implementation here.
|
|
7
7
|
*/
|
|
8
8
|
export {
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
MERGE_STRATEGIES,
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
ensurePromotionPullRequest,
|
|
13
13
|
main,
|
|
14
14
|
promotionPolicyReceipts,
|
|
@@ -16,10 +16,10 @@ export {
|
|
|
16
16
|
type FetchImpl,
|
|
17
17
|
type MergeStrategy,
|
|
18
18
|
type PolicyConfiguration,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
25
|
} from '../assets/promote.ts'
|
|
@@ -76,9 +76,17 @@ export function gitOrThrow(repo: string, args: string[]): string {
|
|
|
76
76
|
return result.stdout
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
/** The work tree root for `path`; `path` must be that root. */
|
|
79
|
+
/** The work tree root for `path`; `path` must be that root, or empty to default to cwd's git root. */
|
|
80
80
|
export function resolveRepo(path: string): string {
|
|
81
81
|
const absolute = resolve(path)
|
|
82
|
+
// An empty `path` defaults to cwd's git work tree root — `--repo` is no
|
|
83
|
+
// longer a typing tax when the caller is already inside the repository.
|
|
84
|
+
// All `--repo`-taking commands inherit this; the explicit flag still wins.
|
|
85
|
+
if (absolute === '' || (path === '' && !existsSync(absolute))) {
|
|
86
|
+
const cwdTop = capture(['git', 'rev-parse', '--show-toplevel'], process.cwd())
|
|
87
|
+
if (cwdTop.code !== 0) throw new Error(`not a git repository: ${process.cwd()} (cwd)`)
|
|
88
|
+
return cwdTop.stdout.trim()
|
|
89
|
+
}
|
|
82
90
|
if (!existsSync(absolute)) throw new Error(`repository path does not exist: ${absolute}`)
|
|
83
91
|
const result = capture(['git', 'rev-parse', '--show-toplevel'], absolute)
|
|
84
92
|
if (result.code !== 0) throw new Error(`not a git repository: ${absolute}`)
|
|
@@ -5,7 +5,7 @@ import { HOOK_NAMES, HOOKS_PATH, INSTALL_HINT, LOCK_REL, MANAGED_ASSETS, VERSION
|
|
|
5
5
|
import { checkGitignoreBlock } from './gitignore-block.ts'
|
|
6
6
|
import { readLock, stubText, type Lock } from './install.ts'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
interface WorkflowsDriftFinding {
|
|
9
9
|
/** Same ids `doctor()` uses for the same surface (`promote`, `hook:pre-commit`, `version`, ...). */
|
|
10
10
|
id: string
|
|
11
11
|
message: string
|
|
@@ -36,13 +36,12 @@ export interface WorkflowsDriftReport {
|
|
|
36
36
|
* Written for exactly the drift this package's own dogfood install had on
|
|
37
37
|
* 2026-09-27: adl-agent-control's root `.workflows/repo-controls.lock.json`
|
|
38
38
|
* claimed version 0.3.2 with only `promote.ts` and the four hook stubs
|
|
39
|
-
* recorded, while `version-bump.sh` and
|
|
39
|
+
* recorded, while `version-bump.sh` and the since-retired
|
|
40
40
|
* `scripts/enable-integration-auto-complete.mjs` existed on disk with no
|
|
41
41
|
* lock entry at all, and the `adl-config.toml` the lock's own `config`
|
|
42
42
|
* record claimed to have created did not exist. `checkWorkflowsDrift` would
|
|
43
|
-
* report
|
|
44
|
-
*
|
|
45
|
-
* mismatch — `doctor()` already does, but nothing outside a full `doctor`
|
|
43
|
+
* report a finding for each missing lock entry and a `version` finding for
|
|
44
|
+
* the lock/package mismatch — `doctor()` already does, but nothing outside a full `doctor`
|
|
46
45
|
* run could ask for just this until now.
|
|
47
46
|
*/
|
|
48
47
|
export function checkWorkflowsDrift(repoRoot: string): WorkflowsDriftReport {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The `post-checkout` worktree-count backstop (
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* The `post-checkout` worktree-count backstop (Tarun, 2026-09-27: "add a hook
|
|
3
|
+
* to detect existing worktrees and deny worktree creation — maximum worktrees
|
|
4
|
+
* allowed is 3 including the main folder"; see docs/operations/worktree-guard.md).
|
|
5
5
|
*
|
|
6
6
|
* Git has no pre-worktree hook: nothing runs BEFORE `git worktree add` creates
|
|
7
7
|
* the new checkout. What git DOES run is `post-checkout`, and — per git's own
|