@amsterdamdatalabs/adl-agent-control-linux-x64 0.1.10 → 0.1.26

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.
Files changed (413) hide show
  1. package/bin/adl +2 -2
  2. package/bin/git +17 -18
  3. package/bin/git-ado +27 -26
  4. package/bin/git-defaults +173 -0
  5. package/bin/health-check +8 -1
  6. package/bin/kimi-hooks +1 -1
  7. package/bin/lib/adl-package.sh +257 -0
  8. package/bin/lib/bun-compile-build.sh +1 -1
  9. package/bin/lib/fleet-host.sh +62 -0
  10. package/bin/lib/lean-ctx-observe-hooks.sh +9 -9
  11. package/bin/reconcile +693 -470
  12. package/bin/reconcile-host +121 -0
  13. package/bin/setup +219 -0
  14. package/bin/shell-path-policy +15 -5
  15. package/bin/sync-and-reconcile +79 -68
  16. package/bin/validate-manifest +46 -51
  17. package/package.json +2 -12
  18. package/packages/agent-hooks/README.md +14 -9
  19. package/packages/agent-hooks/assets/hooks.json +0 -20
  20. package/packages/agent-hooks/package.json +1 -2
  21. package/packages/agent-hooks/src/cli/args.ts +1 -1
  22. package/packages/agent-hooks/src/cli/doctor.ts +6 -58
  23. package/packages/agent-hooks/src/deploy/deploy.ts +12 -41
  24. package/packages/agent-hooks/src/deploy/doctor.ts +8 -11
  25. package/packages/agent-hooks/src/deploy/index.ts +14 -14
  26. package/packages/agent-hooks/src/deploy/json-merge.ts +7 -8
  27. package/packages/agent-hooks/src/deploy/legacy-lock.ts +2 -2
  28. package/packages/agent-hooks/src/deploy/list.ts +1 -1
  29. package/packages/agent-hooks/src/deploy/lock.ts +31 -12
  30. package/packages/agent-hooks/src/deploy/profile.ts +3 -4
  31. package/packages/agent-hooks/src/deploy/source.ts +1 -1
  32. package/packages/agent-hooks/src/gating/config.ts +10 -24
  33. package/packages/agent-hooks/src/gating/root.ts +3 -3
  34. package/packages/agent-hooks/src/hooks/briefing/handler.ts +2 -2
  35. package/packages/agent-hooks/src/hooks/briefing/index.ts +27 -287
  36. package/packages/agent-hooks/src/hooks/contract.ts +17 -17
  37. package/packages/agent-hooks/src/hooks/crg/background.ts +27 -0
  38. package/packages/agent-hooks/src/hooks/crg/index.ts +7 -6
  39. package/packages/agent-hooks/src/hooks/log.ts +8 -10
  40. package/packages/agent-hooks/src/hooks/user-prompt-submit/match.ts +1 -1
  41. package/packages/agent-hooks/src/hooks/user-prompt-submit/tokenizer.ts +1 -1
  42. package/packages/agent-hooks/src/hooks/user-prompt-submit/vector.ts +6 -5
  43. package/packages/agent-hooks/src/hosts/registry.ts +1 -1
  44. package/packages/agent-hooks/src/log/adl-dir.ts +44 -0
  45. package/packages/agent-hooks/src/log/writer.ts +16 -2
  46. package/packages/agent-hooks/src/main.ts +7 -41
  47. package/packages/agent-hooks/src/pre-tool-use/handler.ts +71 -82
  48. package/packages/agent-hooks/src/rules/engine.ts +13 -17
  49. package/packages/agent-hooks/src/rules/impl/adl-build-run-denied.ts +3 -3
  50. package/packages/agent-hooks/src/rules/impl/adl-git-credential-bypass.ts +12 -14
  51. package/packages/agent-hooks/src/rules/impl/adl-git-identity.ts +28 -28
  52. package/packages/agent-hooks/src/rules/impl/adl-git-push-policy.ts +8 -9
  53. package/packages/agent-hooks/src/rules/impl/adl-human-azdo-bypass.ts +56 -59
  54. package/packages/agent-hooks/src/rules/impl/adl-identity.ts +16 -23
  55. package/packages/agent-hooks/src/rules/impl/adl-mcp-cli.ts +19 -16
  56. package/packages/agent-hooks/src/rules/impl/adl-pr-complete-pending.ts +2 -2
  57. package/packages/agent-hooks/src/rules/impl/adl-pr-review-role.ts +9 -12
  58. package/packages/agent-hooks/src/rules/impl/adl-pr-role.ts +5 -7
  59. package/packages/agent-hooks/src/rules/impl/adl-run-required.ts +411 -0
  60. package/packages/agent-hooks/src/rules/impl/adl-token-minting-role.ts +4 -5
  61. package/packages/agent-hooks/src/rules/impl/adl-workitem-role.ts +6 -7
  62. package/packages/agent-hooks/src/rules/impl/agent-tamper-protection.ts +77 -70
  63. package/packages/agent-hooks/src/rules/impl/deny-allowlist.ts +159 -0
  64. package/packages/agent-hooks/src/rules/impl/fs-trash.ts +2 -2
  65. package/packages/agent-hooks/src/rules/impl/git-helpers.ts +21 -23
  66. package/packages/agent-hooks/src/rules/impl/git-worktree.ts +14 -28
  67. package/packages/agent-hooks/src/rules/impl/mcp-tool.ts +3 -3
  68. package/packages/agent-hooks/src/rules/impl/messages.ts +1 -1
  69. package/packages/agent-hooks/src/rules/impl/pr-completion.ts +1 -1
  70. package/packages/agent-hooks/src/rules/impl/tool-azure-devops.ts +35 -46
  71. package/packages/agent-hooks/src/rules/impl/tool-find.ts +34 -7
  72. package/packages/agent-hooks/src/rules/impl/tool-grep.ts +34 -12
  73. package/packages/agent-hooks/src/rules/impl/tool-native-search.ts +52 -9
  74. package/packages/agent-hooks/src/rules/ports.ts +5 -7
  75. package/packages/agent-hooks/src/rules/registry.ts +4 -6
  76. package/packages/agent-hooks/src/rules/shell/git-identity.ts +86 -101
  77. package/packages/agent-hooks/src/rules/shell/git-internals.ts +1 -1
  78. package/packages/agent-hooks/src/rules/shell/invocation.ts +24 -118
  79. package/packages/agent-hooks/src/rules/shell/piped-script.ts +1 -1
  80. package/packages/agent-hooks/src/rules/shell/prefixes.ts +1 -1
  81. package/packages/agent-hooks/src/rules/shell/protected-carrier-writes.ts +11 -10
  82. package/packages/agent-hooks/src/rules/shell/protected-carriers.ts +26 -26
  83. package/packages/agent-hooks/src/rules/shell/substitution.ts +1 -1
  84. package/packages/agent-hooks/src/rules/shell/xargs.ts +2 -2
  85. package/packages/agent-hooks/src/rules/spec.ts +2 -2
  86. package/packages/agent-settings/README.md +287 -0
  87. package/packages/agent-settings/assets/GLOBAL-AGENTS.md +18 -18
  88. package/packages/agent-settings/assets/agents/architect.toml +2 -0
  89. package/packages/agent-settings/assets/agents/code-reviewer.toml +2 -0
  90. package/packages/agent-settings/assets/agents/executor.toml +2 -0
  91. package/packages/agent-settings/assets/agents/explore.toml +2 -0
  92. package/packages/agent-settings/assets/agents/planner.toml +2 -0
  93. package/packages/agent-settings/assets/mcp.json +0 -4
  94. package/packages/agent-settings/deploy-profile.json +139 -0
  95. package/packages/agent-settings/deploy-profile.schema.json +147 -0
  96. package/packages/agent-settings/managed/README.md +29 -30
  97. package/packages/agent-settings/managed/codex-requirements.toml +9 -9
  98. package/packages/agent-settings/package.json +20 -0
  99. package/packages/agent-settings/src/deploy/agent-render.ts +2 -2
  100. package/packages/agent-settings/src/deploy/agent-toml.ts +1 -1
  101. package/packages/agent-settings/src/deploy/agents-deploy.ts +17 -3
  102. package/packages/agent-settings/src/deploy/doctor.ts +3 -83
  103. package/packages/agent-settings/src/deploy/index.ts +6 -33
  104. package/packages/agent-settings/src/deploy/legacy-lock.ts +6 -6
  105. package/packages/agent-settings/src/deploy/list.ts +5 -19
  106. package/packages/agent-settings/src/deploy/lock.ts +8 -18
  107. package/packages/agent-settings/src/deploy/mcp-deploy.ts +10 -5
  108. package/packages/agent-settings/src/deploy/mcp-merge.ts +22 -3
  109. package/packages/agent-settings/src/deploy/mcp-source.ts +1 -1
  110. package/packages/agent-settings/src/deploy/profile.ts +11 -35
  111. package/packages/agent-settings/src/deploy/retire-lean-ctx.ts +184 -0
  112. package/packages/agent-settings/src/deploy/settings.ts +17 -22
  113. package/packages/agent-settings/src/global-surface-sweep.ts +5 -17
  114. package/packages/agent-settings/src/kimi-hooks.ts +339 -192
  115. package/packages/agent-settings/src/opencode-hooks.ts +1 -1
  116. package/packages/agent-settings/tsconfig.json +23 -0
  117. package/packages/agent-skills/assets/agent-search-tool-audit/SKILL.md +120 -0
  118. package/packages/agent-skills/assets/agent-search-tool-audit/scripts/audit.sh +276 -0
  119. package/packages/agent-skills/assets/debug-issue/SKILL.md +8 -7
  120. package/packages/agent-skills/assets/explore-codebase/SKILL.md +13 -13
  121. package/packages/agent-skills/assets/refactor-safely/SKILL.md +12 -11
  122. package/packages/agent-skills/assets/review-changes/SKILL.md +7 -7
  123. package/packages/agent-skills/assets/testing/references/e2e.md +37 -0
  124. package/packages/agent-skills/assets/testing/references/integration.md +37 -0
  125. package/packages/agent-skills/assets/testing/references/unit.md +32 -0
  126. package/packages/agent-skills/dist/deploy.d.ts +2 -0
  127. package/packages/agent-skills/dist/deploy.d.ts.map +1 -1
  128. package/packages/agent-skills/dist/deploy.js +27 -1
  129. package/packages/agent-skills/dist/deploy.js.map +1 -1
  130. package/packages/agent-skills/dist/doctor.d.ts +0 -2
  131. package/packages/agent-skills/dist/doctor.d.ts.map +1 -1
  132. package/packages/agent-skills/dist/doctor.js +1 -1
  133. package/packages/agent-skills/dist/doctor.js.map +1 -1
  134. package/packages/agent-skills/dist/fs-utils.d.ts +0 -1
  135. package/packages/agent-skills/dist/fs-utils.d.ts.map +1 -1
  136. package/packages/agent-skills/dist/fs-utils.js +1 -1
  137. package/packages/agent-skills/dist/fs-utils.js.map +1 -1
  138. package/packages/agent-skills/package.json +1 -1
  139. package/packages/agent-skills/src/deploy.ts +29 -1
  140. package/packages/agent-skills/src/doctor.ts +1 -1
  141. package/packages/agent-skills/src/fs-utils.ts +1 -1
  142. package/packages/azdo/README.md +10 -9
  143. package/packages/azdo/package.json +2 -5
  144. package/packages/azdo/src/azdo-pl.ts +2 -54
  145. package/packages/azdo/src/azdo-pr-review.ts +4 -4
  146. package/packages/azdo/src/azdo-repo-doctor.ts +101 -52
  147. package/packages/azdo/src/azdo-wit.ts +41 -2
  148. package/packages/azdo/src/lib/agent-identity.ts +12 -14
  149. package/packages/azdo/src/lib/agent-token.ts +2 -2
  150. package/packages/azdo/src/lib/client.ts +0 -5
  151. package/packages/azdo/src/lib/graph-identity.ts +4 -4
  152. package/packages/azdo/src/workflow-rules-matrix.csv +85 -0
  153. package/packages/azdo/src/workflow-rules.ts +128 -0
  154. package/packages/fleet/manifest.json +38 -33
  155. package/packages/fleet/manifest.schema.json +67 -65
  156. package/packages/fleet/src/default-agent-file.ts +3 -3
  157. package/packages/fleet/src/install-adl-package.ts +73 -15
  158. package/packages/fleet/src/install-embedding-model.ts +14 -14
  159. package/packages/fleet/src/managed-settings.ts +7 -7
  160. package/packages/fleet/src/repo-maintain.ts +439 -0
  161. package/packages/fleet/src/scratch-reap.ts +6 -6
  162. package/packages/fleet/src/vscode-settings.ts +5 -5
  163. package/packages/repo-controls/README.md +141 -43
  164. package/packages/repo-controls/assets/promote.ts +4 -4
  165. package/packages/repo-controls/assets/reconcile-guard.sh +10 -46
  166. package/packages/repo-controls/assets/version-bump.sh +31 -84
  167. package/packages/repo-controls/bunfig.toml +6 -7
  168. package/packages/repo-controls/package/adl-compliance/AGENTS.md +5 -6
  169. package/packages/repo-controls/package/adl-compliance/conftest.py +3 -1
  170. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/__init__.py +4 -16
  171. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/test_check.py +9 -2
  172. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/notes.md +1 -0
  173. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/test_check.py +11 -0
  174. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/__init__.py +7 -0
  175. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/check.py +266 -0
  176. 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
  177. 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
  178. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/.hidden.md +1 -0
  179. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/a.md +1 -0
  180. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/b.md +1 -0
  181. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/data.csv +1 -0
  182. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/diagram.png +1 -0
  183. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/mock.png +1 -0
  184. 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
  185. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs.md +1 -0
  186. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/grants.yaml +4 -0
  187. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p1.md +1 -0
  188. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p2.md +1 -0
  189. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p3.md +1 -0
  190. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p4.md +1 -0
  191. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p5.md +1 -0
  192. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/architecture/build.md +1 -0
  193. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/architecture/overview.md +1 -0
  194. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/guide/install.md +1 -0
  195. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/guide/start.md +1 -0
  196. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/grants.yaml +4 -0
  197. 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
  198. 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
  199. 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
  200. 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
  201. 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
  202. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/guide/a.md +1 -0
  203. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/guide/b.md +1 -0
  204. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/guide/c.md +1 -0
  205. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/grants.yaml +4 -0
  206. 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
  207. 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
  208. 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
  209. 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
  210. 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
  211. 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
  212. 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
  213. 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
  214. 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
  215. 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
  216. 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
  217. 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
  218. 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
  219. 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
  220. 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
  221. 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
  222. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/grants.yaml +4 -0
  223. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/docs/guide/a.md +1 -0
  224. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/docs/guide/b.md +1 -0
  225. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/docs/guide/c.md +1 -0
  226. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/grants.yaml +4 -0
  227. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/docs/guide/a.md +1 -0
  228. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/docs/guide/b.md +1 -0
  229. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/docs/guide/c.md +1 -0
  230. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/grants.yaml +4 -0
  231. 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
  232. 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
  233. 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
  234. 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
  235. 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
  236. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/grants.yaml +4 -0
  237. 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
  238. 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
  239. 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
  240. 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
  241. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/grants.yaml +4 -0
  242. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/a.md +1 -0
  243. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/b.md +1 -0
  244. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/c.md +1 -0
  245. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/d.md +1 -0
  246. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/shrunk/a.md +1 -0
  247. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/shrunk/b.md +1 -0
  248. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/grants.yaml +6 -0
  249. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/docs/guide/a.md +1 -0
  250. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/docs/guide/b.md +1 -0
  251. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/docs/guide/c.md +1 -0
  252. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/grants.yaml +3 -0
  253. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/test_check.py +345 -0
  254. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/check.py +18 -5
  255. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/test_check.py +35 -0
  256. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/__init__.py +7 -0
  257. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/check.py +91 -0
  258. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/AGENTS.md +3 -0
  259. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/CLAUDE.md +3 -0
  260. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/-leading-hyphen.md +3 -0
  261. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/AGENTS.md +3 -0
  262. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/double--hyphen.md +3 -0
  263. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/getting started.md +3 -0
  264. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/nested/page-here.md +3 -0
  265. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/trailing-hyphen-.md +3 -0
  266. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/ui-contract.md +4 -0
  267. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/user_profile.md +3 -0
  268. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/assets/UI-CONTRACT.png +2 -0
  269. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/assets/diagram.png +1 -0
  270. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/index.md +4 -0
  271. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/notes.md +3 -0
  272. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/reference.html +1 -0
  273. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/research/2026-10-experiment.md +3 -0
  274. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/research/UI-CONTRACT.md +6 -0
  275. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs.md +5 -0
  276. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/test_check.py +194 -0
  277. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/check.py +14 -2
  278. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/docs-knowledge-indexes.yaml +5 -5
  279. 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
  280. 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
  281. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/test_check.py +58 -6
  282. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/test_check.py +0 -1
  283. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/check.py +64 -17
  284. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/docs-okf-profiles.yaml +60 -9
  285. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-ledger-clean/docs/notes.md +17 -0
  286. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-ledger-no-lines/docs/notes.md +13 -0
  287. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-clean/docs/architecture/demo.md +0 -1
  288. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-clean/docs-okf-profiles.yaml +0 -1
  289. 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
  290. 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
  291. 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
  292. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs-okf-profiles.yaml +5 -0
  293. 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
  294. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-violation/docs-okf-profiles.yaml +0 -1
  295. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/experiment-ok.md +15 -0
  296. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/extra-key.md +15 -0
  297. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/extra-keys.md +16 -0
  298. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-created.md +11 -0
  299. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-description.md +11 -0
  300. 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
  301. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-sources.md +10 -0
  302. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-status.md +11 -0
  303. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-title.md +11 -0
  304. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/optional-keys.md +16 -0
  305. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/research-ok.md +14 -0
  306. 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
  307. 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
  308. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research-neighbours/docs/operations/runbook.md +26 -0
  309. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/test_check.py +228 -2
  310. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/register.py +5 -0
  311. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/test_check.py +11 -2
  312. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/__init__.py +5 -3
  313. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/check.py +160 -44
  314. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-clean/grants.yaml +0 -2
  315. 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
  316. 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
  317. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-empty-register/grants.yaml +3 -0
  318. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/grants.yaml +0 -2
  319. 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
  320. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-missing-tree/grants.yaml +5 -0
  321. 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
  322. 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
  323. 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
  324. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/grants.yaml +4 -0
  325. 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
  326. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-stale-entry/grants.yaml +5 -0
  327. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/grants.yaml +0 -2
  328. 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
  329. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unusable-register/grants.yaml +3 -0
  330. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/register.py +127 -0
  331. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/test_check.py +265 -29
  332. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/check.py +75 -2
  333. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/test_check.py +194 -0
  334. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/check.py +56 -10
  335. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/test_check.py +256 -0
  336. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/check.py +40 -12
  337. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/test_check.py +108 -0
  338. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/test_check.py +1 -1
  339. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/check.py +2 -3
  340. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/check.py +23 -6
  341. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/test_check.py +76 -0
  342. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/check.py +58 -17
  343. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/test_check.py +161 -0
  344. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/check.py +35 -3
  345. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/test_check.py +108 -1
  346. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/check.py +281 -61
  347. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/absolute-path.yaml +3 -0
  348. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/backslash-path.yaml +3 -0
  349. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/baseline-is-a-list.yaml +2 -0
  350. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/boolean-size.yaml +3 -0
  351. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/dot-segment.yaml +3 -0
  352. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/duplicate-path.yaml +4 -0
  353. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/empty-file.yaml +0 -0
  354. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/empty-segment.yaml +3 -0
  355. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/float-size.yaml +3 -0
  356. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/negative-size.yaml +3 -0
  357. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/no-over-limit-baseline.yaml +1 -0
  358. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/no-schema-version.yaml +1 -0
  359. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/non-string-path.yaml +3 -0
  360. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/not-yaml.yaml +2 -0
  361. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/null-size.yaml +3 -0
  362. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/parent-segment.yaml +3 -0
  363. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/string-size.yaml +3 -0
  364. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/top-level-is-a-list.yaml +2 -0
  365. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/trailing-slash.yaml +3 -0
  366. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/unknown-key.yaml +3 -0
  367. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/wrong-schema-version.yaml +2 -0
  368. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/zero-size.yaml +3 -0
  369. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/valid.yaml +4 -0
  370. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/test_check.py +758 -45
  371. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/check.py +4 -3
  372. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/test_check.py +2 -2
  373. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/cargo_lock.py +490 -0
  374. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/check.py +368 -55
  375. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_check.py +4 -2
  376. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_declared_paths.py +523 -0
  377. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_stale_lock.py +1179 -0
  378. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/cli.py +122 -3
  379. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/check.py +33 -1
  380. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/constants.py +0 -11
  381. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/context.py +16 -1
  382. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/config.py +1 -2
  383. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/docs_shape.py +12 -1
  384. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.alt.yaml +133 -147
  385. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.yaml +133 -147
  386. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/registry.py +1 -1
  387. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/root_shape.py +52 -10
  388. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/runner.py +23 -4
  389. package/packages/repo-controls/package.json +2 -10
  390. package/packages/repo-controls/scripts/hooks/post-merge +13 -0
  391. package/packages/repo-controls/scripts/hooks/pre-push +3 -3
  392. package/packages/repo-controls/src/azdo-push.ts +64 -36
  393. package/packages/repo-controls/src/azure-devops-governance.ts +7 -9
  394. package/packages/repo-controls/src/azure-devops-remote.ts +1 -1
  395. package/packages/repo-controls/src/cli.ts +29 -8
  396. package/packages/repo-controls/src/compliance-config.ts +410 -2
  397. package/packages/repo-controls/src/config.ts +133 -60
  398. package/packages/repo-controls/src/constants.ts +13 -27
  399. package/packages/repo-controls/src/coverage-ratchet.ts +4 -4
  400. package/packages/repo-controls/src/doctor.ts +46 -19
  401. package/packages/repo-controls/src/gitignore-block.ts +5 -29
  402. package/packages/repo-controls/src/hook-log.ts +1 -2
  403. package/packages/repo-controls/src/hook.ts +201 -45
  404. package/packages/repo-controls/src/install.ts +14 -8
  405. package/packages/repo-controls/src/integrity.ts +3 -3
  406. package/packages/repo-controls/src/lfs.ts +111 -0
  407. package/packages/repo-controls/src/promote.ts +8 -8
  408. package/packages/repo-controls/src/runtime.ts +9 -1
  409. package/packages/repo-controls/src/workflows-drift.ts +4 -5
  410. package/packages/repo-controls/src/worktree-guard.ts +3 -3
  411. package/packages/fleet/jobs/git-maintain/src/main.ts +0 -848
  412. package/packages/fleet/systemd/adl-azure-agent-update.service +0 -13
  413. package/packages/fleet/systemd/adl-azure-agent-update.timer +0 -10
@@ -1,46 +1,48 @@
1
1
  /**
2
- * Editing the files that wire the host's hooks or un-manage this repo.
2
+ * Editing the files that wire the host's hooks.
3
3
  *
4
4
  * Handoff 5, rule 5: deny Write/Edit/MultiEdit/NotebookEdit on
5
- * `.claude/settings.json`, `.claude/settings.local.json`,
6
- * `.codex/config.toml`, or `adl-config.toml`. These are the files that
7
- * either install the hook into the host (`.claude/settings.json`,
8
- * `.codex/config.toml`, including the `.local.json` overrides) or arm the
9
- * gate in this repo (`adl-config.toml`'s `[hooks] enabled = false`
10
- * silently no-ops every kind — see `main.ts`'s `runHook`). Editing any
11
- * of them is a way to switch the gate off without anyone noticing.
5
+ * `.claude/settings.json`, `.claude/settings.local.json`, or
6
+ * `.codex/config.toml`. These are the files that install the hook into the
7
+ * host (including the `.local.json` overrides). Editing any of them is a way
8
+ * to switch the gate off without anyone noticing.
12
9
  *
13
- * Decision 13 (STATUS.md 12p, 2026-09-29): the managed-
14
- * hooks lock is off, so these per-repo carrier files are now the ONLY
10
+ * `adl-config.toml` was the fourth file until 2026-10-01 (Tarun: "nobody
11
+ * should stop editing adl-config.toml"). It is no longer on the list, so an
12
+ * agent can edit, move or delete it. Two things follow, both accepted by the
13
+ * owner: (1) every hook run re-reads it, so `[hooks] enabled = false` (a
14
+ * silent no-op, `main.ts`'s `runHook`) or a `[rules."<id>"] enabled = false`
15
+ * takes effect on the agent's next tool call, ahead of any commit — the
16
+ * commit-time layers (`git.protected-tree-commit`, repo-controls' integrity
17
+ * gate) are the only review left; (2) the carriers that stayed on the list
18
+ * below are only as strong as that file, since it can also switch THIS rule
19
+ * off.
20
+ *
21
+ * Hooks are local-repo-first (Tarun, 2026-09-29): there is no managed-hooks
22
+ * lock and no global carrier, so these per-repo carrier files are the ONLY
15
23
  * enforcement layer for the hosts that read them — three more joined the
16
24
  * set for exactly that reason: `.codex/hooks.json`, `.cursor/hooks.json`,
17
25
  * and `.opencode/plugins/adl-repo.ts` (the generated OpenCode plugin IS
18
- * its own carrier; there is no separate settings file for that host).
19
- * Measured against the real engine before this fix: Write
20
- * `.codex/hooks.json` / Edit `.cursor/hooks.json` / Write
21
- * `.opencode/plugins/adl-repo.ts` all had `blocked: false`, while the
22
- * original four's own control case (`.claude/settings.json`) already had
23
- * `blocked: true`.
26
+ * its own carrier; there is no separate settings file for that host). The
27
+ * single source of the list is `PROTECTED_CARRIER_PATHS` in
28
+ * `../shell/protected-carriers.ts`, which also names Kimi's one global
29
+ * carrier, `~/.kimi-code/config.toml`.
24
30
  *
25
- * The list is hard-coded here on purpose. `adl-config.toml`'s own
26
- * `[hooks] enabled` already lets a repo switch the whole hook system
27
- * off; allowing `[rules."agent.tamper-protection"] enabled = false` in
28
- * the same file is the same switch wearing a different hat. A repo that
29
- * legitimately needs a different allowlist should patch this file in a
30
- * PR, not in a session.
31
+ * The list is hard-coded here on purpose: a per-repo allowlist in
32
+ * `adl-config.toml` would be one more switch in a file the repo controls.
33
+ * A repo that legitimately needs a different allowlist should patch this
34
+ * file in a PR, not in a session.
31
35
  *
32
36
  * The file names match against the FULL path and against the basename so
33
37
  * `Write .claude/settings.json` AND `Write /Users/x/repo/.claude/settings.json`
34
38
  * both fire, but `Write .claude/SETTINGS.json.bak` does NOT (the
35
39
  * case-sensitive suffix check rejects it).
36
40
  *
37
- * Shell-write coverage (STATUS.md 12p, decision 13 follow-up, 2026-09-29):
38
- * the tool-call gate above never saw a shell command at all — `echo x >
39
- * .cursor/hooks.json`, `tee`, `mv`/`cp`/`install`/`ln -sf`, `sed -i`/
40
- * `perl -pi`, `truncate`, `trash`/`rm`/`unlink`/`shred`, and `dd of=` were
41
- * every one of them `{blocked: false}` against all seven protected files,
42
- * measured directly against the real engine before this fix. Closed via
43
- * three additional match() branches:
41
+ * Shell-write coverage: the tool-call gate above never sees a shell
42
+ * command, so `echo x > .cursor/hooks.json`, `tee`, `mv`/`cp`/`install`/
43
+ * `ln -sf`, `sed -i`/`perl -pi`, `truncate`, `trash`/`rm`/`unlink`/`shred`,
44
+ * and `dd of=` against a protected file are covered by three additional
45
+ * match() branches:
44
46
  * - `inv.kind === 'protected-carrier-write'` — the generic-command half
45
47
  * (redirection/tee/mv/cp/install/ln/sed/perl/truncate/trash/rm/unlink/
46
48
  * shred/dd), classified by `shell/protected-carrier-writes.ts` and wired
@@ -88,14 +90,14 @@ function logicalToolName(tool: string): string {
88
90
  /**
89
91
  * Tools whose `input.file_path` / `input.notebook_path` / `input.path` /
90
92
  * `input.filePath` decides what the edit targets — matched case-insensitively
91
- * (F4, independent review, 2026-09-29): OpenCode's own plugin
93
+ * (independent review, 2026-09-29): OpenCode's own plugin
92
94
  * (`.opencode/plugins/adl-repo.ts`'s `tool.execute.before`) sends its OWN
93
95
  * lowercase tool names (`edit`, `write`), not Claude/Codex/Kimi's
94
96
  * capitalized ones, and its `tool_input` (`output.args`) carries the target
95
97
  * as camelCase `filePath`, not `file_path`.
96
98
  */
97
99
  /**
98
- * P2 (independent review, 2026-09-29): widened beyond Claude/Codex/Kimi's
100
+ * Widened beyond Claude/Codex/Kimi's
99
101
  * own capitalized names — one normalized (lowercase) list covering every
100
102
  * edit-tool spelling a supported host actually sends:
101
103
  * - `strreplace`/`str_replace_editor`/`edit_file`/`str_replace`/
@@ -139,7 +141,7 @@ function readStringField(input: Readonly<Record<string, unknown>>, key: string):
139
141
  }
140
142
 
141
143
  /**
142
- * Codex's `apply_patch` (F4): its patch body lives in `input.command`
144
+ * Codex's `apply_patch`: its patch body lives in `input.command`
143
145
  * (`handler.ts`'s `toDecideInput` special-cases this tool to a `tool-call`
144
146
  * precisely so it reaches here instead of being walked as shell text), and
145
147
  * the path it targets is named in a `*** Add File:`/`*** Update File:`/
@@ -161,13 +163,13 @@ function toolCallTarget(inv: Invocation & { kind: 'tool-call' }): string | null
161
163
  const name = logicalToolName(inv.tool).toLowerCase()
162
164
  // apply_patch / OpenCode's own `patch` tool: the patch body is
163
165
  // `input.command` (Codex) or `input.patchText` (OpenCode's own field
164
- // name for the same shape, P2) — never a `file_path`-shaped field.
166
+ // name for the same shape) — never a `file_path`-shaped field.
165
167
  if (name === 'apply_patch' || name === 'patch') {
166
168
  const body = readStringField(inv.input, 'command') + readStringField(inv.input, 'patchText')
167
169
  if (body.length > 0) return applyPatchTarget(body)
168
170
  }
169
171
  if (!EDIT_TOOL_NAMES.has(name)) return null
170
- // F8 (fourth independent review, 2026-09-29): Cursor's real `edit_file`
172
+ // Cursor's real `edit_file`
171
173
  // schema names its path argument `target_file` (confirmed via Cursor's
172
174
  // own published tool schema/system-prompt documentation).
173
175
  const filePath =
@@ -194,8 +196,8 @@ function nonOptionValues(rest: readonly Token[]): readonly string[] {
194
196
  /**
195
197
  * `git checkout` ALWAYS restores the WORKTREE for a named path — there is no
196
198
  * staged-only variant (that is `git restore --staged`'s job) — so every
197
- * shape is checked: `git checkout -- <path>` and, P1 (second independent
198
- * review, 2026-09-29), the equally real `git checkout <rev> <path>` form
199
+ * shape is checked: `git checkout -- <path>` and the equally real
200
+ * `git checkout <rev> <path>` form
199
201
  * with no `--` at all (>= 2 non-option operands; the LAST one is the path).
200
202
  */
201
203
  function checkoutTarget(rest: readonly Token[]): string | null {
@@ -215,7 +217,7 @@ function checkoutTarget(rest: readonly Token[]): string | null {
215
217
  /**
216
218
  * `git restore` touches the WORKTREE by default; `--staged`/`-S` makes it an
217
219
  * index-only unstage UNLESS `--worktree`/`-W` is ALSO given (both flags
218
- * together restore both). P1 (second independent review, 2026-09-29): a
220
+ * together restore both). A
219
221
  * plain `git restore --staged -- <path>` must be ALLOWED — it never
220
222
  * touches the file this rule exists to protect from being overwritten.
221
223
  */
@@ -242,8 +244,7 @@ function restoreTarget(rest: readonly Token[]): string | null {
242
244
  * `--hard`/`--merge`/`--keep`, none of which accepts a pathspec in real
243
245
  * git (a bare `git reset --hard` with no path at all is `git.reset`'s own
244
246
  * unconditional deny to catch, not this rule's — there is no specific
245
- * carrier PATH for this function to find there). P1 (second independent
246
- * review, 2026-09-29): `git reset -- <path>` and `git reset HEAD --
247
+ * carrier PATH for this function to find there). `git reset -- <path>` and `git reset HEAD --
247
248
  * <path>` must be ALLOWED — they only unstage.
248
249
  */
249
250
  function resetTouchesWorktree(rest: readonly Token[]): boolean {
@@ -267,7 +268,7 @@ function anyOperandTarget(rest: readonly Token[]): string | null {
267
268
  for (const token of rest) {
268
269
  const value = tokenValue(token)
269
270
  if (value === '--' || value.startsWith('-')) continue
270
- // F5 (fourth independent review, 2026-09-29): `git mv .claude
271
+ // `git mv .claude
271
272
  // .claude-old` moves the WHOLE carrier directory away — file-level
272
273
  // `protectedCarrierMatch` alone never saw this.
273
274
  const hit = protectedCarrierMatch(value) ?? protectedCarrierDirMatch(value)
@@ -277,13 +278,13 @@ function anyOperandTarget(rest: readonly Token[]): string | null {
277
278
  }
278
279
 
279
280
  function gitTarget(inv: Invocation & { kind: 'git' }): string | null {
280
- // P2 (independent review, 2026-09-29): `git mv` of a carrier (either
281
+ // `git mv` of a carrier (either
281
282
  // operand — moving it away, or overwriting it with something else).
282
283
  if (inv.subcommand === 'rm' || inv.subcommand === 'mv') return anyOperandTarget(inv.rest)
283
284
  if (inv.subcommand === 'checkout') return checkoutTarget(inv.rest)
284
285
  if (inv.subcommand === 'restore') return restoreTarget(inv.rest)
285
286
  if (inv.subcommand === 'reset') return resetTarget(inv.rest)
286
- // P2: `git checkout-index` writes working-tree files from the index for
287
+ // `git checkout-index` writes working-tree files from the index for
287
288
  // named paths — the plumbing sibling of `git checkout -- <path>`. `-a`/
288
289
  // `--all` (every staged file, no specific path named) is a known,
289
290
  // documented gap — not handled here.
@@ -292,8 +293,7 @@ function gitTarget(inv: Invocation & { kind: 'git' }): string | null {
292
293
  }
293
294
 
294
295
  /**
295
- * `git apply`/the standalone `patch` utility (P2, independent review,
296
- * 2026-09-29): the path a patch actually modifies lives INSIDE the patch
296
+ * `git apply`/the standalone `patch` utility: the path a patch actually modifies lives INSIDE the patch
297
297
  * file's own headers, not (usually) as a command-line operand at all —
298
298
  * `git apply some.patch` names the PATCH FILE, never its target. Coarse,
299
299
  * whole-command (same tradeoff `interpreterTarget`/`coarsePathMention`
@@ -303,29 +303,38 @@ function gitTarget(inv: Invocation & { kind: 'git' }): string | null {
303
303
  * static, pre-execution hook (it would need to read the file from disk,
304
304
  * which this hook does not do for any other check either).
305
305
  */
306
- /** `git apply` flags that inspect a patch without applying anything (F7, fourth independent review, 2026-09-29). */
306
+ /** `git apply` flags that inspect a patch without applying anything. */
307
307
  const DRY_RUN_GIT_APPLY_FLAGS: ReadonlySet<string> = new Set(['--check', '--stat', '--numstat', '--summary'])
308
308
 
309
+ /**
310
+ * `name` as a whole file name: not glued to a longer name on either side. A bare
311
+ * substring test matched `config.toml` inside `adl-config.toml`,
312
+ * `enact-config.toml` and `my.config.toml`, denying any `git apply`/`patch`
313
+ * that named them as "rewriting .codex/config.toml".
314
+ */
315
+ function mentionsWholeName(command: string, name: string): boolean {
316
+ const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
317
+ return new RegExp(`(?<![\\w.-])${escaped}(?![\\w.-])`).test(command)
318
+ }
319
+
309
320
  function coarsePathMention(command: string): string | null {
310
321
  for (const protectedPath of PROTECTED_CARRIER_PATHS) {
311
322
  if (command.includes(protectedPath)) return protectedPath
312
323
  const base = protectedPath.slice(protectedPath.lastIndexOf('/') + 1)
313
- if (command.includes(base)) return protectedPath
324
+ if (mentionsWholeName(command, base)) return protectedPath
314
325
  }
315
326
  return null
316
327
  }
317
328
 
318
329
  /**
319
- * Live false positive (third independent review, 2026-09-29): the OLD check
320
- * paired "some write call anywhere in the command" (`WRITE_CALL_RE.test`)
321
- * with "a carrier path anywhere in the command text" (`coarsePathMention`)
322
- * — two UNCORRELATED checks. A heredoc-fed `python3 - <<'EOF'` writing an
323
- * unrelated file (e.g. `STATUS.md`) whose own written TEXT merely mentioned
330
+ * Correlated detection, not two independent checks. Pairing "some write call
331
+ * anywhere in the command" with "a carrier path anywhere in the command
332
+ * text" (`coarsePathMention`) was a live false positive (independent review,
333
+ * 2026-09-29): a heredoc-fed `python3 - <<'EOF'` writing an unrelated file
334
+ * (e.g. `notes.md`) whose own written TEXT merely mentioned
324
335
  * `.codex/config.toml` (a docstring, a log line, a commit message) was
325
336
  * wrongly denied — the mention and the write had nothing to do with each
326
- * other.
327
- *
328
- * Replaced with CORRELATED detection: each pattern below captures the
337
+ * other. So each pattern below captures the
329
338
  * WRITE-CALL'S OWN TARGET ARGUMENT specifically (group 1) — `open(TARGET,
330
339
  * 'w'|'a'|'x'…)`, `Path(TARGET).write_text/write_bytes(...)`,
331
340
  * `os.remove/unlink(TARGET)`, `os.rename(SRC, TARGET)`,
@@ -344,7 +353,7 @@ function coarsePathMention(command: string): string | null {
344
353
  * expression (neither a literal nor a bare identifier — string
345
354
  * concatenation, a function call, …) cannot be correlated at all and is
346
355
  * left alone (allowed), the same "cannot resolve, so cannot deny" stance
347
- * `adl.session-required-for-writes`'s own destination classification takes
356
+ * `adl.run-required-for-writes`'s own destination classification takes
348
357
  * for an unresolved git push remote.
349
358
  *
350
359
  * `ARG` allows one level of nested parens (`os.path.join(a, b)` as a
@@ -354,7 +363,7 @@ function coarsePathMention(command: string): string | null {
354
363
  const ARG = `((?:[^,()]|\\([^()]*\\))+)`
355
364
  /** `fs.X(...)`, `require('fs').X(...)`, or `require('fs').promises.X(...)` (no literal `fs.` substring exists in the `require(...)` forms — `'fs')` breaks it — so all three are matched explicitly rather than relying on a bare `fs\.` prefix). Required (not optional) for the async, non-Sync names below — `rename`/`unlink`/`rm` are common-enough verbs that an UNqualified bare call risks a real collision with an unrelated same-named function. */
356
365
  const FS_QUALIFIED_PREFIX = `(?:\\bfs|require\\(\\s*['"]fs['"]\\s*\\))\\s*\\.\\s*(?:promises\\s*\\.\\s*)?`
357
- /** The SAME prefix, but OPTIONAL — F6 (fourth independent review, 2026-09-29): `const { writeFileSync } = require('fs'); writeFileSync(...)` calls it BARE, with no qualifying prefix on the call site itself. Only for the `*Sync` names, distinctive enough on their own that an unqualified bare call is still almost certainly this Node API. */
366
+ /** The SAME prefix, but OPTIONAL: `const { writeFileSync } = require('fs'); writeFileSync(...)` calls it BARE, with no qualifying prefix on the call site itself. Only for the `*Sync` names, distinctive enough on their own that an unqualified bare call is still almost certainly this Node API. */
358
367
  const FS_SYNC_OPTIONAL_PREFIX = `(?:${FS_QUALIFIED_PREFIX})?`
359
368
  const WRITE_TARGET_PATTERNS: readonly RegExp[] = [
360
369
  new RegExp(`\\bopen\\s*\\(\\s*${ARG}\\s*,\\s*['"][wax]`, 'g'),
@@ -364,7 +373,7 @@ const WRITE_TARGET_PATTERNS: readonly RegExp[] = [
364
373
  new RegExp(`\\bshutil\\.(?:move|copy2?|copyfile)\\s*\\(\\s*${ARG}\\s*,\\s*${ARG}\\s*\\)`, 'g'),
365
374
  new RegExp(`${FS_SYNC_OPTIONAL_PREFIX}(?:writeFileSync|appendFileSync|rmSync|unlinkSync|copyFileSync|truncateSync)\\s*\\(\\s*${ARG}`, 'g'),
366
375
  new RegExp(`${FS_SYNC_OPTIONAL_PREFIX}renameSync\\s*\\(\\s*${ARG}\\s*,\\s*${ARG}`, 'g'),
367
- // F6: the async (non-Sync) forms, prefix REQUIRED.
376
+ // The async (non-Sync) forms, prefix REQUIRED.
368
377
  new RegExp(`${FS_QUALIFIED_PREFIX}(?:writeFile|appendFile|rm|unlink|copyFile)\\s*\\(\\s*${ARG}`, 'g'),
369
378
  new RegExp(`${FS_QUALIFIED_PREFIX}rename\\s*\\(\\s*${ARG}\\s*,\\s*${ARG}`, 'g'),
370
379
  new RegExp(`\\bBun\\.write\\s*\\(\\s*${ARG}`, 'g'),
@@ -414,7 +423,7 @@ export const agentTamperProtection: RuleSpec = {
414
423
  category: 'tool-call',
415
424
  severity: 'deny',
416
425
  enabledByDefault: true,
417
- summary: 'Deny edits (tool, shell write, or git rewrite) to the host hook config or the repo gate marker.',
426
+ summary: "Deny edits (tool, shell write, or git rewrite) to the files that wire a host's hooks.",
418
427
  params: noParams,
419
428
  match(inv: Invocation, ctx: RuleContext<Record<string, never>>): Finding | null {
420
429
  if (inv.kind === 'tool-call') {
@@ -431,10 +440,10 @@ export const agentTamperProtection: RuleSpec = {
431
440
  if (target !== null) {
432
441
  return { ruleId: 'agent.tamper-protection', severity: 'deny', detail: { path: target, via: 'git', command: `git ${inv.subcommand}` } }
433
442
  }
434
- // P2: `git apply` — coarse, whole-command (see `coarsePathMention`'s
443
+ // `git apply` — coarse, whole-command (see `coarsePathMention`'s
435
444
  // own doc for why: the target path is inside the patch's own
436
445
  // headers, not an operand `gitTarget`'s per-operand scan would see).
437
- // F7 (fourth independent review, 2026-09-29): a dry-run/inspection
446
+ // A dry-run/inspection
438
447
  // flag applies NOTHING — `git apply --check/--stat/--numstat/
439
448
  // --summary` never touches the working tree, so naming a carrier is
440
449
  // harmless.
@@ -444,7 +453,7 @@ export const agentTamperProtection: RuleSpec = {
444
453
  }
445
454
  return null
446
455
  }
447
- // P2: the standalone `patch` utility — same coarse, whole-command
456
+ // The standalone `patch` utility — same coarse, whole-command
448
457
  // reasoning as `git apply` above.
449
458
  if (inv.kind === 'command' && inv.name === 'patch') {
450
459
  const hit = coarsePathMention(ctx.command ?? '')
@@ -469,21 +478,19 @@ export const agentTamperProtection: RuleSpec = {
469
478
  ? 'an interpreter one-liner writing'
470
479
  : 'editing'
471
480
  return {
472
- user: `Blocked ${via === 'tool-call' ? 'editing' : verb} ${path}. This file wires the host's hooks or un-manages this repo; ask the user to change it.`,
481
+ user: `Blocked ${via === 'tool-call' ? 'editing' : verb} ${path}. This file wires the host's hooks; ask the user to change it.`,
473
482
  agent:
474
483
  `DENIED ${verb} ${path}. This file is one of the tamper-protected files: ` +
475
484
  '`.claude/settings.json`, `.claude/settings.local.json`, `.codex/config.toml`, ' +
476
485
  '`.codex/hooks.json`, `.cursor/hooks.json`, `.opencode/plugins/adl-repo.ts`, ' +
477
- "`~/.kimi-code/config.toml`, or `adl-config.toml`. The first six install or override a " +
478
- "host's own hook contract (directly, or — for `.opencode/plugins/adl-repo.ts` — as the " +
479
- 'generated plugin THAT IS the carrier; `~/.kimi-code/config.toml` is Kimi\'s own single, ' +
480
- "globally-installed carrier — Kimi has no per-repo one); `adl-config.toml` is the repo's " +
481
- "own gate marker (`[hooks] enabled = false` silently no-ops every hook kind — see " +
482
- '`main.ts`). Editing, overwriting, moving over, truncating, ' +
486
+ "or `~/.kimi-code/config.toml`. Each installs or overrides a host's own hook contract " +
487
+ "(directly, or — for `.opencode/plugins/adl-repo.ts` — as the generated plugin THAT IS " +
488
+ "the carrier; `~/.kimi-code/config.toml` is Kimi's own single, globally-installed " +
489
+ 'carrier — Kimi has no per-repo one). Editing, overwriting, moving over, truncating, ' +
483
490
  'deleting, or rewriting any of them — by a tool call, a shell write, or a git checkout/ ' +
484
491
  'restore/reset/rm — is a way to switch the gate off without anyone noticing, the ONLY ' +
485
- 'enforcement layer for the hosts that read them (decision 13: the managed-hooks lock is ' +
486
- `off). If a legitimate change is needed, file a PR or ask the user to make it themselves. ` +
492
+ 'enforcement layer for the hosts that read them (there is no managed-hooks lock). ' +
493
+ `If a legitimate change is needed, file a PR or ask the user to make it themselves. ` +
487
494
  `Blocked call: ${ctx.snippet}`,
488
495
  }
489
496
  },
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Single source of truth for "which commands actually pass the lean-ctx
3
+ * shell allowlist", so the three search-tool deny rules (tool.grep,
4
+ * tool.find, tool.native-search) cannot lie about what's available.
5
+ *
6
+ * History (2026-10-02 research `research-2026-10-02-search-tool-usage-across-surfaces.md`
7
+ * finding #4):
8
+ *
9
+ * - `tool.grep`'s deny text claimed "search is allowed". It is not — the
10
+ * default lean-ctx allowlist has 223 commands and no `search` unless the
11
+ * repo's `.agents/lean-ctx/config/lean-ctx/config.toml` declares it under
12
+ * `shell_allowlist_extra`. Only a per-repo deploy with the seed list lands
13
+ * `search`/`crg`/etc. into the actual runtime allowlist.
14
+ * - `tool.find`'s deny text pointed at `search query "<text>"` for every
15
+ * path-pattern request, which is the wrong recommendation — `search`
16
+ * searches CONTENT, not paths; the right tool for `find -name '*.md'` is
17
+ * `rg --files -g '<glob>'` or `ctx_glob`.
18
+ * - `tool.native-search`'s deny text pointed at `ctx_search` /
19
+ * `ctx_compose` / `ctx_callgraph` / `rg / ast-grep`, never at `search
20
+ * query` — the docs-and-plans case that 11 of 25 kimi denials actually were.
21
+ *
22
+ * Every entry here is the canonical name (matches the binary on PATH); the
23
+ * rules import this and reference its shape from their deny messages, so a
24
+ * command added here appears in every deny message that recommends it, and a
25
+ * command removed here stops being recommended everywhere at once.
26
+ *
27
+ * The list is consumed by:
28
+ *
29
+ * - `tool.grep.ts` (Bash shape): pipe stdin filter / literal text search
30
+ * - `tool.find.ts` (Bash shape): path-pattern search
31
+ * - `tool.native-search.ts` (host-native tool shape): Grep / Glob / Search
32
+ *
33
+ * Each rule still owns its own denial text, but the recommendation rows are
34
+ * generated from `ALLOWED` so the texts cannot drift from the truth here.
35
+ */
36
+
37
+ export interface AllowedTool {
38
+ /** The binary name as it appears on PATH (no path prefix). */
39
+ readonly binary: string
40
+ /** A one-line description used by the deny rules' recommendation table. */
41
+ readonly purpose: string
42
+ /**
43
+ * A concrete command shape the model can copy verbatim. Used by the rules'
44
+ * deny messages so the message reads like documentation, not a hint.
45
+ * Multiple commands because some tools have multiple shapes (e.g. rg grep vs
46
+ * rg tree).
47
+ */
48
+ readonly examples: readonly string[]
49
+ }
50
+
51
+ /**
52
+ * The tools the deny messages recommend. Each row carries a single source of
53
+ * truth so the three rules' text cannot drift.
54
+ *
55
+ * Only the surface that's relevant to search-tool use is here. Bash itself
56
+ * is not "allowed" in this sense — it's the substrate the tools run in. `ls`,
57
+ * `cat`, `git`, etc. are not in this table because they are not search
58
+ * replacements.
59
+ */
60
+ export const ALLOWED_SEARCH_TOOLS: readonly AllowedTool[] = [
61
+ // Order matters — `rules-grep-message-order.test.ts` pins it as
62
+ // ast-grep, search, crg, rg, ctx_search, … (Tarun, 2026-09-30).
63
+ {
64
+ binary: 'ast-grep',
65
+ purpose: 'code STRUCTURE: shapes rather than strings',
66
+ examples: [
67
+ 'ast-grep -p "foo($A)" -l ts',
68
+ ],
69
+ },
70
+ {
71
+ binary: 'search',
72
+ purpose:
73
+ 'docs and plans by MEANING: hybrid semantic + keyword (enoted-search@0.2.2 at /usr/local/bin/search)',
74
+ examples: [
75
+ 'search query "how do I author a metric" # hybrid (default)',
76
+ 'search query "<text>" --mode keyword # when you only want literal matches',
77
+ 'search query "<text>" --mode semantic # when the doc talks about it, not the word',
78
+ ],
79
+ },
80
+ {
81
+ binary: 'crg',
82
+ purpose: 'the code GRAPH: callers, callees, impact (code-review-graph)',
83
+ examples: [
84
+ 'crg search "<text>" --kind File # find files matching a name/text',
85
+ 'crg query callers_of <fn> # who calls this function?',
86
+ 'crg query callees_of <fn> # what does this function call?',
87
+ 'crg impact # blast radius of staged changes',
88
+ 'crg architecture # module/structure overview',
89
+ ],
90
+ },
91
+ {
92
+ binary: 'rg',
93
+ purpose: 'literal text or regex, including stdin (`npm test 2>&1 | rg "pass|fail"`)',
94
+ examples: [
95
+ 'rg "TODO" src/',
96
+ 'rg --files -g "<glob>" # path patterns, NOT find',
97
+ 'rg "pass|fail" # stdin filter, NOT grep',
98
+ ],
99
+ },
100
+ {
101
+ binary: 'ctx_search',
102
+ purpose: 'lean-ctx MCP indexed code search (action=symbol for an exact symbol)',
103
+ examples: [
104
+ 'ctx_search(action=symbol, handle="path#name@Lstart")',
105
+ ],
106
+ },
107
+ {
108
+ binary: 'ctx_glob',
109
+ purpose: 'lean-ctx MCP indexed file search (path patterns only, not content)',
110
+ examples: ['ctx_glob(pattern, path)'],
111
+ },
112
+ {
113
+ binary: 'ctx_read',
114
+ purpose: 'lean-ctx MCP indexed file read (compressed output, no token tax)',
115
+ examples: ['ctx_read(path, mode)'],
116
+ },
117
+ {
118
+ binary: 'ctx_compose',
119
+ purpose: 'lean-ctx MCP context compose (orient on a task without reading whole files)',
120
+ examples: ['ctx_compose(task)'],
121
+ },
122
+ {
123
+ binary: 'ctx_callgraph',
124
+ purpose: 'lean-ctx MCP callers/impact for callers and engines (crg also answers these, but via shell)',
125
+ examples: ['ctx_callgraph(symbol)'],
126
+ },
127
+ ] as const
128
+
129
+ /**
130
+ * The rule's deny text needs to point at the right tool for the right
131
+ * surface. This helper produces a single recommendation block from
132
+ * `ALLOWED_SEARCH_TOOLS`, formatted as a multi-line bullet list the rules
133
+ * can paste into their `agent:` field. `filter` lets a rule narrow to the
134
+ * subset of tools that apply (e.g. only tools that work in a docs/plans
135
+ * tree).
136
+ */
137
+ export function recommendationBlock(filter?: (tool: AllowedTool) => boolean): string {
138
+ const rows = ALLOWED_SEARCH_TOOLS.filter(filter ?? (() => true))
139
+ return rows
140
+ .map((row) => {
141
+ const examples = row.examples.map((e) => ` ${e}`).join('\n')
142
+ return ` ${row.binary.padEnd(11)} ${row.purpose}\n${examples}`
143
+ })
144
+ .join('\n')
145
+ }
146
+
147
+ /**
148
+ * The set of paths where `search` (semantic + keyword) is the right tool
149
+ * over `rg`/`crg`/`ctx_search`. A native `Grep` whose `tool_input.path`
150
+ * starts with one of these should redirect to `search`, not to `rg` — the
151
+ * model is searching for the document that *talks* about X, not for the
152
+ * literal text X.
153
+ */
154
+ export const DOC_TREES: readonly string[] = [
155
+ 'docs/',
156
+ 'plans/',
157
+ '.scratchpad/',
158
+ ] as const
159
+
@@ -7,8 +7,8 @@
7
7
  *
8
8
  * The original's eighth predicate -- any path with an `.agents` segment --
9
9
  * was dropped by owner decision on 2026-09-15. `.agents/` is reconciled
10
- * centrally every six hours (global-tools `git-maintain` refreshes repo-local
11
- * surfaces in every managed repo), so a trashed copy is restored rather than
10
+ * centrally every 12 hours (`adl reconcile`'s repository step runs `adl install --repo`,
11
+ * which refreshes repo-local surfaces in every managed repo), so a trashed copy is restored rather than
12
12
  * lost, and `trash(1)` is itself recoverable from ~/.Trash. Protecting it here
13
13
  * blocked routine work to guard against something the fleet already repairs.
14
14
  *
@@ -90,7 +90,7 @@ export function flipsCoreBare(tokens: readonly Token[]): boolean {
90
90
  return tokens.some((token) => /core\.bare/i.test(tokenValue(token)))
91
91
  }
92
92
 
93
- export function pathIsInProtectedTree(rawPath: string, protectedTrees: readonly string[]): boolean {
93
+ function pathIsInProtectedTree(rawPath: string, protectedTrees: readonly string[]): boolean {
94
94
  const path = `/${rawPath.replace(/^\.\//, '').replace(/\/+$/, '')}/`
95
95
  return protectedTrees.some((tree) => path.includes(`/${tree}`))
96
96
  }
@@ -107,7 +107,7 @@ export function moveEscapesRepo(rest: readonly Token[], protectedTrees: readonly
107
107
 
108
108
  const WHOLE_TREE_PATHSPEC = new Set(['.', './', '..', '../', '*', ':', ':/', ':/*', ':(top)'])
109
109
 
110
- export function namedPathspecs(tokens: readonly Token[]): readonly string[] {
110
+ function namedPathspecs(tokens: readonly Token[]): readonly string[] {
111
111
  const paths: string[] = []
112
112
  for (let index = 0; index < tokens.length; index += 1) {
113
113
  const value = tokenValue(tokens[index] as Token)
@@ -121,7 +121,7 @@ export function namedPathspecs(tokens: readonly Token[]): readonly string[] {
121
121
  return paths
122
122
  }
123
123
 
124
- export function isNamedPathspecOnly(tokens: readonly Token[]): boolean {
124
+ function isNamedPathspecOnly(tokens: readonly Token[]): boolean {
125
125
  const paths = namedPathspecs(tokens)
126
126
  if (paths.length === 0) return false
127
127
  return paths.every((value) => !WHOLE_TREE_PATHSPEC.has(value))
@@ -152,23 +152,22 @@ export function updateIndexIsUnstageOnly(rest: readonly Token[]): boolean {
152
152
  }
153
153
 
154
154
  /**
155
- * `git push` destination classification shared by `adl.session-required-for-writes`
156
- * and `adl.git-push-branch-policy` — moved here (2026-09-27, docs/architecture/cli-design.md
157
- * decision 2 / docs/operations/agent-permissions.md) so the two rules cannot drift on what
155
+ * `git push` destination classification shared by `adl.run-required-for-writes`
156
+ * and `adl.git-push-branch-policy` — kept here (docs/architecture/cli-design.md §2 /
157
+ * docs/operations/agent-permissions.md) so the two rules cannot drift on what
158
158
  * counts as an Azure DevOps push. Both decide statically, off argv alone: no
159
159
  * `git remote get-url` subprocess (the deployed `bin/git` front controller can
160
160
  * do that; a pre-tool-use hook decides before the child runs).
161
161
  */
162
- export const ADO_HOST = 'dev.azure.com'
162
+ const ADO_HOST = 'dev.azure.com'
163
163
 
164
164
  /**
165
165
  * The second Azure DevOps host the one-agent-identity standard names
166
- * (STATUS.md 12p, "What the hook covers" — REST:
167
- * curl/wget/httpie/xh to `dev.azure.com` / `*.visualstudio.com`). Widened
168
- * 2026-09-28 alongside the identity-bearing command classes below;
169
- * `isAdoUrl` used to check `dev.azure.com` alone.
166
+ * (REST: curl/wget/httpie/xh to `dev.azure.com` / `*.visualstudio.com`);
167
+ * `isAdoUrl` checks both, alongside the identity-bearing command classes
168
+ * below.
170
169
  */
171
- export const ADO_VISUALSTUDIO_HOST = 'visualstudio.com'
170
+ const ADO_VISUALSTUDIO_HOST = 'visualstudio.com'
172
171
 
173
172
  export function isAdoUrl(value: string): boolean {
174
173
  const lower = value.toLowerCase()
@@ -177,13 +176,12 @@ export function isAdoUrl(value: string): boolean {
177
176
 
178
177
  /**
179
178
  * Identity-bearing `adl <...>` subcommand shapes
180
- * (STATUS.md 12p "What the hook covers" / W2 build
181
- * item 1): every one of these reaches Azure DevOps and needs the resolved
179
+ * (one-agent-identity standard): every one of these reaches Azure DevOps and needs the resolved
182
180
  * agent identity, exactly like a network git command. Matched positionally
183
181
  * against the words/tokens right after `adl` itself (case-insensitively,
184
182
  * dynamic values excluded by the caller) — shared by the shell scanner
185
183
  * (`../shell/git-identity.ts`, which needs the raw source span to rewrite)
186
- * and the ordinary invocation-based rules (`adl-session-required.ts`, which
184
+ * and the ordinary invocation-based rules (`adl-run-required.ts`, which
187
185
  * only needs a yes/no match) so the two classifications cannot drift apart.
188
186
  */
189
187
  export const ADL_IDENTITY_COMMAND_SHAPES: readonly (readonly string[])[] = [
@@ -202,7 +200,7 @@ export const ADL_AGENT_ID_BINARY_NAMES: ReadonlySet<string> = new Set(['adl-agen
202
200
 
203
201
  /**
204
202
  * curl/wget/httpie(`http`/`https`)/xh — the REST client family the standard
205
- * names. Shared with `adl-session-required.ts`'s own `HTTP_CLIENT_NAMES` so
203
+ * names. Shared with `adl-run-required.ts`'s own `HTTP_CLIENT_NAMES` so
206
204
  * the two classifications (this file's shape matcher vs. that rule's method
207
205
  * inspection) cannot name a different set of binaries.
208
206
  */
@@ -309,8 +307,8 @@ function httpieMethod(args: readonly Token[]): string {
309
307
  /**
310
308
  * The effective HTTP method for an `HTTP_CLIENT_BINARY_NAMES` invocation,
311
309
  * dispatched by binary name — curl/wget/httpie(`http`/`https`)/xh each spell
312
- * their method differently. M10 (STATUS.md 12p): shared
313
- * by `adl-session-required.ts` (deny with no identity, every method) and
310
+ * their method differently. Shared
311
+ * by `adl-run-required.ts` (deny with no identity, every method) and
314
312
  * `tool-azure-devops.ts` (deny a WRITE method outright, identity or not —
315
313
  * docs/operations/agent-permissions.md row 13) so the method-detection logic
316
314
  * cannot drift between the two.
@@ -334,8 +332,8 @@ export function matchesIdentityShape(values: readonly string[], shapes: readonly
334
332
  }
335
333
 
336
334
  /**
337
- * Drop leading dash-prefixed words — M5 (STATUS.md
338
- * 12p): `adl-agent-id`'s own global flags (e.g. `--verbose`/`--quiet`)
335
+ * Drop leading dash-prefixed words:
336
+ * `adl-agent-id`'s own global flags (e.g. `--verbose`/`--quiet`)
339
337
  * ahead of its `exec` subcommand, which `ADL_AGENT_ID_COMMAND_SHAPES`
340
338
  * (`[['exec']]`) would otherwise require sitting at position 0 exactly —
341
339
  * `adl-agent-id --verbose exec --agent agent-tarun -- ...` would not match
@@ -344,7 +342,7 @@ export function matchesIdentityShape(values: readonly string[], shapes: readonly
344
342
  * global flag is not a documented `adl-agent-id` shape today, so this does
345
343
  * not try to consume one — a bare `-` (stdin marker) is not treated as a
346
344
  * flag either. Shared by `../shell/git-identity.ts` (the rewrite scanner)
347
- * and `adl-session-required.ts` so the two classifications cannot drift on
345
+ * and `adl-run-required.ts` so the two classifications cannot drift on
348
346
  * this.
349
347
  */
350
348
  export function skipLeadingDashFlags(values: readonly string[]): readonly string[] {
@@ -380,9 +378,9 @@ export function classifyGitPushDestination(rest: readonly Token[]): GitPushDesti
380
378
  }
381
379
 
382
380
  /**
383
- * R3 (STATUS.md 12p): a coarse, TEXTUAL (not
381
+ * A coarse, TEXTUAL (not
384
382
  * shell-parsed) signal that some string holds an identity-bearing token —
385
- * used by `adl-session-required.ts`'s `identityBearingReason` for the two
383
+ * used by `adl-run-required.ts`'s `identityBearingReason` for the two
386
384
  * shapes the shell walker (`../shell/invocation.ts`) cannot see INTO at all:
387
385
  * an interpreter one-liner's `-c`/`-e` code string (`python3 -c
388
386
  * "...subprocess.run(['git','push'])..."` — the walker only re-parses