@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
package/bin/adl CHANGED
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: package/bin/adl
3
- size: 82925024 bytes
4
- sha256: bf72c4f43099dc33afd161d5e8205d2fbfc5607e4b3aafac4ac0644224b75337
3
+ size: 82912736 bytes
4
+ sha256: 09177fe24ffc58ce3e4224020a520a03d35e9cb77882aa86c1b0e9396a84f6b9
package/bin/git CHANGED
@@ -117,7 +117,7 @@ done
117
117
  (( command_index >= 0 )) || exec "$real_git" ${args[@]+"${args[@]}"}
118
118
  command_name="${args[command_index]}"
119
119
 
120
- # L1 worktree guard (STATUS.md item 2, docs/operations/worktree-guard.md): refuse
120
+ # L1 worktree guard (docs/operations/worktree-guard.md): refuse
121
121
  # `git worktree add` when the repository already has 3 checkouts, including
122
122
  # the main folder. Runs BEFORE the network-command routing below because it
123
123
  # applies to every command line, not only Azure DevOps ones, and to humans
@@ -435,7 +435,7 @@ case "$command_name" in
435
435
  # "whatever the schedule says" -- "Otherwise, the tasks are determined
436
436
  # by which maintenance.<task>.enabled config options are true. By
437
437
  # default, only maintenance.gc.enabled is true." A bare `run` (the
438
- # shape a human, a GUI, or the git-maintain LaunchAgent's own
438
+ # shape a human, a GUI, or a scheduled repository-maintenance job's own
439
439
  # background gc actually calls) therefore almost never touches the
440
440
  # network at all -- routing it unconditionally, as this used to,
441
441
  # refused every one of those local-only callers once git-ado went
@@ -567,22 +567,21 @@ case "$command_name" in
567
567
  done
568
568
  ;;
569
569
  lfs)
570
- # GAP (second independent review, 2026-09-29), fix REVISED (third
571
- # independent review, 2026-09-29, item 3): `git lfs push|pull|fetch`
572
- # against an Azure DevOps remote used to reach the real `git-lfs`
573
- # binary (a SEPARATE executable git dispatches to via PATH, never
574
- # through THIS controller's own real_git exec) with no identity at all.
575
- # The FIRST fix refused this outright here in bin/git -- but that also
576
- # refused it in Tarun's OWN marked human terminal, a regression: his
577
- # real credential helper has always handled `git lfs` fine, and the
578
- # human path never involved git-ado's unverified header mechanism in
579
- # the first place. Routing through git-ado instead lets IT apply the
580
- # SAME policy it applies to every other verb: human (TTY+marker) passes
581
- # through unchanged (unaffected by any of this); the agent identity
582
- # path refuses with a clear message (git-lfs's own HTTP credential
583
- # resolution has not been verified to honor git-ado's
584
- # `http.<url>.extraHeader` mechanism); no identity and no human marker
585
- # refuses, exactly as for every other verb.
570
+ # GAP (second independent review, 2026-09-29): `git lfs push|pull|fetch`
571
+ # against an Azure DevOps remote reaches the real `git-lfs` binary (a
572
+ # SEPARATE executable git dispatches to via PATH, never through THIS
573
+ # controller's own real_git exec) with no identity at all, so it is routed
574
+ # through git-ado like every other network verb. git-ado applies the one
575
+ # policy: human (TTY+marker) passes through unchanged; an agent identity
576
+ # authenticates with the same `http.<url>.extraHeader` GIT_CONFIG_*
577
+ # mechanism as `git push` (proved to be honored by git-lfs, with no fallback
578
+ # to the human credential helper, in packages/repo-controls/tests/
579
+ # lfs-credential-boundary.test.ts -- it was refused for agents until that
580
+ # proof existed); no identity and no human marker is refused, as for every
581
+ # other verb. Other `git lfs` subcommands -- notably `pre-push`,
582
+ # `post-checkout`, `post-commit` and `post-merge`, which the projected hooks
583
+ # run inside a `git push` that already carries the header -- never reach
584
+ # the network through here and are not routed.
586
585
  lfs_sub=''
587
586
  lfs_sub_index=-1
588
587
  for ((index = command_index + 1; index < ${#args[@]}; index += 1)); do
package/bin/git-ado CHANGED
@@ -15,16 +15,17 @@
15
15
  # three Entra service principals: agent-tarun, agent-vivek, agent-reviewer.
16
16
  # Agents never see a secret.
17
17
  #
18
- # HUMAN PATH (STATUS.md 12p decision 1: fail closed, the human opts in).
18
+ # HUMAN PATH (fail closed: the human opts in; Tarun, 2026-09-29).
19
19
  # An unset/empty ADL_AGENT_ID_AGENT is passed through to the human's own
20
20
  # credential helper (Git Credential Manager, etc.) ONLY when BOTH stdin is
21
21
  # a real terminal AND ADL_HUMAN_AZDO is the exact string "1" -- Tarun
22
- # exports it from his own `.zshrc` (decision 1c: "its not only git, its
23
- # azdo" -- the marker governs every human Azure DevOps path, not only this
24
- # script). Otherwise this script refuses outright, by name, before
22
+ # exports it from his own `.zshrc` ("its not only git, its azdo": the
23
+ # marker governs every human Azure DevOps path, not only this script;
24
+ # `adl run` strips it from a child's environment and the adl hook denies
25
+ # any agent command that sets it). Otherwise this script refuses outright, by name, before
25
26
  # touching git at all: the earlier "unset means human" rule relied
26
27
  # entirely on the adl hook denying an agent's Azure DevOps network git
27
- # command that omits ADL_AGENT_ID_AGENT (H2 rule 1) -- a host the hook
28
+ # command that omits ADL_AGENT_ID_AGENT -- a host the hook
28
29
  # cannot rewrite on, or a chained/opaque shell shape the hook's walker
29
30
  # misses, reached THIS script with no agent identity and no TTY, and used
30
31
  # to be treated as human regardless. `adl id whoami`
@@ -53,7 +54,7 @@
53
54
  # NEVER a fallback to another identity: an unrecognized agent name is
54
55
  # refused, by name, before anything reaches adl-agent-id.
55
56
  #
56
- # HOST AUTOMATION (sync-and-reconcile, scratch-reap, git-maintain) is not one
57
+ # HOST AUTOMATION (sync-and-reconcile, scratch-reap, `adl maintain`) is not one
57
58
  # of the three named agents and is not a human terminal either, but it goes
58
59
  # through THIS script's ordinary agent path as agent-tarun, the machine's own
59
60
  # default agent (2026-09-27 decision 5). THIS SCRIPT NEVER READS THE
@@ -64,7 +65,7 @@
64
65
  # (packages/fleet/src/default-agent-file.ts owns the WRITE side), and sets
65
66
  # ADL_AGENT_ID_AGENT in the child env before it ever reaches this script --
66
67
  # see e.g. packages/fleet/src/scratch-reap.ts and
67
- # packages/fleet/jobs/git-maintain/src/main.ts. The separate host-only
68
+ # packages/fleet/src/repo-maintain.ts. The separate host-only
68
69
  # credentialed path (git-ado-host) is retired: the old DevOps vault
69
70
  # credentials it used were deleted, so it was dead regardless.
70
71
  set -euo pipefail
@@ -311,10 +312,10 @@ ado_host="$(printf '%s' "$remote_url" | tr '[:upper:]' '[:lower:]')"
311
312
  ado_host="${ado_host#https://}"
312
313
  ado_host="${ado_host%%/*}"
313
314
 
314
- # HUMAN PASS-THROUGH (STATUS.md 12p decision 1: fail closed, the human opts
315
- # in). Unset or empty ADL_AGENT_ID_AGENT passes through to the real git
315
+ # HUMAN PASS-THROUGH (fail closed: the human opts in; Tarun, 2026-09-29).
316
+ # Unset or empty ADL_AGENT_ID_AGENT passes through to the real git
316
317
  # UNCHANGED only when this is also a marked human terminal: stdin is a real
317
- # tty AND ADL_HUMAN_AZDO is the exact string "1" (decision 1b/1c). Anything
318
+ # tty AND ADL_HUMAN_AZDO is the exact string "1". Anything
318
319
  # else with no agent identity -- no marker, no tty, or both -- is refused
319
320
  # outright, by name, before touching git at all. This is the ONE place that
320
321
  # check is made in bash; `isMarkedHumanAzdoCaller` in
@@ -333,22 +334,22 @@ fi
333
334
  # AGENT PATH.
334
335
  require_agent_identity "$ADL_AGENT_ID_AGENT" || exit 1
335
336
 
336
- # THIRD independent review (2026-09-29), item 3: `git lfs push|pull|fetch`
337
- # reaches here too now that `is_network_command_name` includes `lfs` (fixing
338
- # the live bug above) -- but git-lfs is a SEPARATE binary whose HTTP
339
- # credential resolution has not been verified to honor the
340
- # `http.<url>.extraHeader` mechanism the agent path below relies on (unlike
341
- # git itself, which this script's own tests prove reads it). Minting a
342
- # token and injecting a header git-lfs might silently ignore -- falling
343
- # back to ITS OWN Basic-auth `git credential fill` flow, bypassing the
344
- # identity model entirely -- is worse than refusing outright. The human
345
- # path above is UNAFFECTED: it execs the real git unchanged regardless of
346
- # `$git_command`, exactly like every other verb, so Tarun's own marked
347
- # terminal keeps using `git lfs` via his real credential helper as before.
348
- if [[ "$git_command" == "lfs" ]]; then
349
- printf 'git-ado: git lfs against Azure DevOps remote %s is refused for the agent identity path (fail closed): git-lfs is a separate binary whose HTTP credential resolution has not been verified to honor this header mechanism. Run the underlying git fetch/push through git-ado directly, or ask Tarun to confirm LFS support before removing this refusal.\n' "$remote_url" >&2
350
- exit 1
351
- fi
337
+ # `git lfs push|pull|fetch` reaches here too (`is_network_command_name`
338
+ # includes `lfs`) and takes the SAME agent path as every other verb. It used to
339
+ # be refused (independent review, 2026-09-29, item 3) because git-lfs is a
340
+ # SEPARATE binary whose HTTP credential resolution had never been verified to
341
+ # honor the `http.<url>.extraHeader` mechanism below; if it ignored the header
342
+ # it would fall back to `git credential fill`, i.e. Git Credential Manager,
343
+ # i.e. the HUMAN. That doubt is settled by a test, not an assumption:
344
+ # packages/repo-controls/tests/lfs-credential-boundary.test.ts runs real
345
+ # git-lfs (3.8.0) against a local LFS endpoint that requires the Bearer token
346
+ # and a credential helper that records every call, with exactly this
347
+ # GIT_CONFIG_COUNT/KEY_n/VALUE_n mechanism: every request carried the header
348
+ # and the helper was never called (and, as the control, was called when the
349
+ # header was absent). The same proof covers the pre-push hook's
350
+ # `git lfs pre-push` (packages/repo-controls/src/lfs.ts), which inherits this
351
+ # environment from the `git push` this script runs. Had it failed, this would
352
+ # still be a refusal; it must become one again if that test ever goes red.
352
353
 
353
354
  # adl-agent-id mints the session and runs `agent-vault run -- <child>`. The
354
355
  # child asks `adl id token` for this agent's Entra token over the proxy
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env bash
2
+ # Managed by adl global-tools.
3
+ #
4
+ # Every host's human git setup is identical and kept that way by the 12-hourly
5
+ # reconcile (Tarun, 2026-10-01): no manual `git config` on any machine. This
6
+ # script sets the administrator's GLOBAL git config from the manifest:
7
+ #
8
+ # config.git_global_config shared by every host
9
+ # <platform>.common.git_global_config added for that platform only
10
+ # <platform>.devices.<device>.git_user user.name / user.email
11
+ #
12
+ # A value is a string (single-valued key) or an ordered array of strings
13
+ # (multi-valued key: the empty-reset-then-helper pattern of credential.helper).
14
+ # A key is rewritten only when its current values differ from the declared
15
+ # ordered list: single-valued via `git config --global KEY VALUE`, multi-valued
16
+ # via `--unset-all` then `--add` for each value in order. Keys the manifest does
17
+ # not declare (including any GitHub or gist credential helper a human set) are
18
+ # never read, changed or removed.
19
+ #
20
+ # Git Credential Manager is installed by the human (macOS: `brew install --cask
21
+ # git-credential-manager`; Linux: the .deb or tarball) -- reconcile never
22
+ # installs it. The one placeholder a value may carry, {git-credential-manager},
23
+ # is resolved at run time as the administrator (`command -v` on the explicit
24
+ # PATH below, which covers /usr/local/bin, /usr/local/share/gcm-core and the
25
+ # Homebrew/linuxbrew bins). When it is not installed, every key that needs it is
26
+ # skipped and left as it is, with one loud WARN; the next reconcile after the
27
+ # install sets it. Nothing is ever written that points at a missing executable.
28
+ #
29
+ # Headless Linux has no keychain, so the manifest's Linux common config sets
30
+ # GCM's credentialStore=cache (an in-memory credential cache daemon) with a
31
+ # one-week timeout instead of the macOS keychain.
32
+ #
33
+ # Git runs as the administrator (`sudo -u ADMIN -H env PATH=... git ...`) so
34
+ # ~/.gitconfig stays user-owned. Apply is invoked by bin/reconcile as root. Plan
35
+ # mode only reads, through sudo when run as root and as the caller otherwise.
36
+ set -euo pipefail
37
+
38
+ usage() {
39
+ echo 'usage: git-defaults --manifest FILE --platform mac|linux --device NAME --mode plan|apply --administrator USER [--path-dirs DIR:DIR...]' >&2
40
+ exit 2
41
+ }
42
+
43
+ manifest=''
44
+ platform=''
45
+ device=''
46
+ mode=''
47
+ administrator=''
48
+ # /usr/local/share/gcm-core comes first so a macOS cask install resolves to the
49
+ # real GCM path rather than its /usr/local/bin symlink. --path-dirs exists for
50
+ # tests; a real run never passes it.
51
+ path_dirs='/usr/local/share/gcm-core:/usr/local/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin:/usr/bin:/bin:/usr/sbin:/sbin'
52
+ while [[ $# -gt 0 ]]; do
53
+ case "$1" in
54
+ --manifest) manifest="${2:-}"; shift 2 ;;
55
+ --platform) platform="${2:-}"; shift 2 ;;
56
+ --device) device="${2:-}"; shift 2 ;;
57
+ --mode) mode="${2:-}"; shift 2 ;;
58
+ --administrator) administrator="${2:-}"; shift 2 ;;
59
+ --path-dirs) path_dirs="${2:-}"; shift 2 ;;
60
+ *) usage ;;
61
+ esac
62
+ done
63
+ [[ -n "$manifest" && -f "$manifest" ]] || usage
64
+ [[ "$platform" == mac || "$platform" == linux ]] || usage
65
+ [[ -n "$device" && -n "$administrator" && -n "$path_dirs" ]] || usage
66
+ [[ "$mode" == plan || "$mode" == apply ]] || usage
67
+
68
+ as_administrator() {
69
+ if [[ "$mode" == apply || "$(id -u)" -eq 0 ]]; then
70
+ (cd /tmp && sudo -u "$administrator" -H env PATH="$path_dirs" "$@" </dev/null)
71
+ else
72
+ (cd /tmp && env PATH="$path_dirs" "$@" </dev/null)
73
+ fi
74
+ }
75
+
76
+ scratch="$(mktemp -d "${TMPDIR:-/tmp}/git-defaults.XXXXXX")"
77
+ trap 'rm -rf -- "$scratch"' EXIT
78
+
79
+ # Current values of $1 into the global `current` array, in file order. Exit 1
80
+ # from git means the key is unset; any other failure is real and propagates.
81
+ read_current() {
82
+ local key="$1" rc=0 value
83
+ current=()
84
+ as_administrator git config --global -z --get-all "$key" >"$scratch/values" || rc=$?
85
+ if [[ "$rc" -eq 1 ]]; then
86
+ return 0
87
+ fi
88
+ [[ "$rc" -eq 0 ]] || { echo "ERROR git-config: git config --global --get-all $key failed (exit $rc)" >&2; return "$rc"; }
89
+ while IFS= read -r -d '' value; do
90
+ current+=("$value")
91
+ done <"$scratch/values"
92
+ }
93
+
94
+ gcm_path=''
95
+ gcm_resolved=0
96
+ resolve_gcm() {
97
+ [[ "$gcm_resolved" -eq 0 ]] || return 0
98
+ gcm_resolved=1
99
+ local found rc=0
100
+ found="$(as_administrator sh -c 'command -v git-credential-manager')" || rc=$?
101
+ if [[ "$rc" -eq 0 && "$found" == /* ]]; then
102
+ gcm_path="$found"
103
+ return 0
104
+ fi
105
+ echo "WARN git-config: git-credential-manager not installed on $device; credential helper not changed (install it, then the next reconcile sets it)" >&2
106
+ }
107
+
108
+ declared="$(jq -r --arg platform "$platform" --arg device "$device" '
109
+ . as $m
110
+ | ($m[$platform].devices[$device].git_user // error("git-config: device \($device) has no git_user in the manifest")) as $user
111
+ | ($m.config.git_global_config + ($m[$platform].common.git_global_config // {})
112
+ + {"user.name": $user.name, "user.email": $user.email})
113
+ | to_entries[]
114
+ | [.key, (.value | if type == "array" then . else [.] end | tojson)]
115
+ | @tsv
116
+ ' "$manifest")"
117
+
118
+ changed=0
119
+ while IFS=$'\t' read -r key values_json; do
120
+ [[ -n "$key" ]] || continue
121
+ wanted=()
122
+ needs_gcm=0
123
+ while IFS= read -r value; do
124
+ [[ "$value" != *'{git-credential-manager}'* ]] || needs_gcm=1
125
+ wanted+=("$value")
126
+ done < <(jq -r '.[]' <<<"$values_json")
127
+ if [[ "$needs_gcm" -eq 1 ]]; then
128
+ resolve_gcm
129
+ [[ -n "$gcm_path" ]] || continue
130
+ for index in "${!wanted[@]}"; do
131
+ wanted[index]="${wanted[index]//'{git-credential-manager}'/"$gcm_path"}"
132
+ done
133
+ fi
134
+
135
+ read_current "$key"
136
+ same=0
137
+ if [[ "${#current[@]}" -eq "${#wanted[@]}" ]]; then
138
+ same=1
139
+ for index in "${!wanted[@]}"; do
140
+ [[ "${current[index]}" == "${wanted[index]}" ]] || same=0
141
+ done
142
+ fi
143
+ if [[ "$same" -eq 1 ]]; then
144
+ echo "git-config: already set $key"
145
+ continue
146
+ fi
147
+
148
+ if [[ "${#wanted[@]}" -eq 1 ]]; then
149
+ shown="${wanted[0]}"
150
+ else
151
+ shown="$(jq -nc '$ARGS.positional' --args -- "${wanted[@]}")"
152
+ fi
153
+ if [[ "$mode" != apply ]]; then
154
+ echo "git-config: would set $key=$shown"
155
+ continue
156
+ fi
157
+ if [[ "${#wanted[@]}" -eq 1 && "${#current[@]}" -le 1 ]]; then
158
+ as_administrator git config --global "$key" "${wanted[0]}"
159
+ else
160
+ if [[ "${#current[@]}" -gt 0 ]]; then
161
+ as_administrator git config --global --unset-all "$key"
162
+ fi
163
+ for value in "${wanted[@]}"; do
164
+ as_administrator git config --global --add "$key" "$value"
165
+ done
166
+ fi
167
+ echo "git-config: set $key=$shown"
168
+ changed=$((changed + 1))
169
+ done <<<"$declared"
170
+
171
+ if [[ "$mode" == apply ]]; then
172
+ echo "git-config: $changed key(s) changed on $device"
173
+ fi
package/bin/health-check CHANGED
@@ -21,7 +21,14 @@ case "$device" in
21
21
  grep -q 'state = running'
22
22
  ;;
23
23
  hostinger-vps-1)
24
- systemctl is-active --quiet docker tailscaled enact-agent-vault
24
+ # One unit per call: `systemctl is-active` given several units exits 0 when at
25
+ # least one is active, so a combined call cannot see a single unit being down.
26
+ for unit_name in docker tailscaled; do
27
+ systemctl is-active --quiet "$unit_name" || {
28
+ echo "required service is not active: $unit_name" >&2
29
+ exit 1
30
+ }
31
+ done
25
32
  for container_name in nordvpn-exit-gluetun-1 nordvpn-exit-tailscale-1 traefik-traefik-1; do
26
33
  [[ "$(docker inspect -f '{{.State.Running}}' "$container_name" 2>/dev/null)" == true ]] || {
27
34
  echo "required container is not running: $container_name" >&2
package/bin/kimi-hooks CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
- export PATH="/usr/local/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin:/usr/bin:/bin:/usr/sbin:/sbin"
4
+ export PATH="/usr/local/bin:${HOME:-}/.bun/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin:/usr/bin:/bin:/usr/sbin:/sbin"
5
5
 
6
6
  script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
7
  repo_root="$(cd "$script_dir/.." && pwd)"
@@ -0,0 +1,257 @@
1
+ # Where the published adl package lives on a host, and how to prove it is the
2
+ # `adl` the owner gets. Sourced (never executed) by bin/sync-and-reconcile,
3
+ # bin/setup, bin/reconcile-host and bin/reconcile, so the scheduled job, the
4
+ # onboarding command and the reconcile itself all ask the same question the
5
+ # same way.
6
+ #
7
+ # Hosts install with bun (Tarun, 2026-10-01): `bun install -g
8
+ # @amsterdamdatalabs/adl-agent-control`, run as the device's `administrator`.
9
+ # Measured with bun 1.4.2 (packages: workflows/scripts/release/tests/
10
+ # bun-global-install.test.ts): bun HOISTS the platform package as a SIBLING of
11
+ # the wrapper, unlike npm, which nests it inside the wrapper:
12
+ #
13
+ # $HOME/.bun/install/global/node_modules/@amsterdamdatalabs/
14
+ # adl-agent-control/ the wrapper (bin/adl.js)
15
+ # adl-agent-control-<os>-<arch>/ the platform package this job runs from
16
+ # $HOME/.bun/bin/adl -> the wrapper's bin/adl.js
17
+ #
18
+ # bun marks ONLY `bin`-field targets executable; every other shipped file stays
19
+ # 0644, so nothing here ever executes a shipped script directly (always
20
+ # `bash <script>`) or checks it with -x.
21
+ #
22
+ # The owner's bun is found through Homebrew (macOS /opt/homebrew, Linux
23
+ # /home/linuxbrew/.linuxbrew), exactly as the owner's other global tools are.
24
+
25
+ adl_wrapper_package='@amsterdamdatalabs/adl-agent-control'
26
+
27
+ adl_brew_bin_dir() {
28
+ case "$1" in
29
+ Darwin) printf '%s\n' /opt/homebrew/bin ;;
30
+ Linux) printf '%s\n' /home/linuxbrew/.linuxbrew/bin ;;
31
+ *) echo "ERROR unsupported operating system for the adl package: $1" >&2; return 1 ;;
32
+ esac
33
+ }
34
+
35
+ # PATH for the bun calls the job makes as the owner (install, nothing else).
36
+ adl_bun_path() {
37
+ local brew
38
+ brew="$(adl_brew_bin_dir "$1")" || return 1
39
+ printf '%s:/usr/bin:/bin\n' "$brew"
40
+ }
41
+
42
+ # PATH the owner gets when it runs `adl` (the repo step, and the shadow check).
43
+ # /usr/local/bin stays FIRST: git must resolve to the managed front controller,
44
+ # which routes Azure DevOps traffic through the agent identity; Homebrew's git
45
+ # would bypass it. The owner's bun bin directory comes next, then Homebrew.
46
+ adl_owner_path() {
47
+ local os="$1" home="$2" brew
48
+ brew="$(adl_brew_bin_dir "$os")" || return 1
49
+ printf '/usr/local/bin:%s/.bun/bin:%s:/usr/bin:/bin\n' "${home%/}" "$brew"
50
+ }
51
+
52
+ # The owner's home directory, asked of the owner (never guessed from the name).
53
+ adl_owner_home() {
54
+ local owner="$1" home
55
+ home="$(cd /tmp && sudo -u "$owner" -H /bin/sh -c 'printf "%s" "$HOME"')" || return 1
56
+ [[ "$home" == /* ]] || { echo "ERROR cannot resolve the home directory of $owner" >&2; return 1; }
57
+ printf '%s\n' "${home%/}"
58
+ }
59
+
60
+ # bun's global package directory for an owner home. `bun pm bin -g` errors on a
61
+ # host that has never run `bun add -g`, so the path is derived, and pinned in
62
+ # the install call below with an explicit BUN_INSTALL.
63
+ adl_global_node_modules() {
64
+ printf '%s/.bun/install/global/node_modules\n' "${1%/}"
65
+ }
66
+
67
+ adl_platform_package_dir() {
68
+ local global_node_modules="$1" os="$2" arch="$3" platform
69
+ case "$os:$arch" in
70
+ Darwin:arm64) platform=darwin-arm64 ;;
71
+ Linux:x86_64) platform=linux-x64 ;;
72
+ *) echo "ERROR unsupported platform for the adl package: $os $arch" >&2; return 1 ;;
73
+ esac
74
+ # bun hoists the platform package next to the wrapper; it is not nested.
75
+ printf '%s/%s-%s\n' "${global_node_modules%/}" "$adl_wrapper_package" "$platform"
76
+ }
77
+
78
+ # Real path of a file, following every symlink (macOS has no `readlink -f` on
79
+ # older releases, and the owner's command is always a symlink).
80
+ adl_realpath() {
81
+ local path="$1" link dir
82
+ while [[ -L "$path" ]]; do
83
+ link="$(readlink "$path")" || return 1
84
+ case "$link" in
85
+ /*) path="$link" ;;
86
+ *) path="$(dirname -- "$path")/$link" ;;
87
+ esac
88
+ done
89
+ dir="$(cd -P -- "$(dirname -- "$path")" 2>/dev/null && pwd -P)" || return 1
90
+ printf '%s/%s\n' "$dir" "$(basename -- "$path")"
91
+ }
92
+
93
+ # The registry's `latest` for the package, asked of the owner. `bun pm view`
94
+ # needs a package.json in its working directory (measured with bun 1.4.2), and the
95
+ # owner's bun global directory always has one once the package is installed.
96
+ # Prints the version, or an error and a non-zero status: a failed lookup is never
97
+ # guessed around.
98
+ adl_registry_latest() {
99
+ local owner="$1" os="$2" home="$3" bun_path answer
100
+ bun_path="$(adl_bun_path "$os")" || return 1
101
+ answer="$(sudo -u "$owner" -H env PATH="$bun_path" BUN_INSTALL="${home%/}/.bun" /bin/sh -c 'cd "$1" && bun pm view "$2" version' sh "${home%/}/.bun/install/global" "$adl_wrapper_package")" || return 1
102
+ answer="$(printf '%s' "$answer" | tr -d '[:space:]')"
103
+ [[ "$answer" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]] || {
104
+ echo "ERROR the registry answered '$answer' for $adl_wrapper_package, which is not a release version" >&2
105
+ return 1
106
+ }
107
+ printf '%s\n' "$answer"
108
+ }
109
+
110
+ # Compares two release versions (x.y.z with an optional -prerelease): prints -1, 0
111
+ # or 1 for A older than, equal to, or newer than B. Semver ordering: components
112
+ # numerically (0.1.9 < 0.1.10), a pre-release is older than its release, and
113
+ # pre-release identifiers compare numerically when both are numbers, numbers
114
+ # before words, else by text. A value that is not a version is an error.
115
+ adl_semver_compare() {
116
+ local a="$1" b="$2" re='^([0-9]+)\.([0-9]+)\.([0-9]+)(-([0-9A-Za-z.-]+))?$' i x y pre_a pre_b
117
+ local -a core_a core_b ids_a ids_b
118
+ [[ "$a" =~ $re ]] || { echo "ERROR not a release version: '$a'" >&2; return 1; }
119
+ core_a=("${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}")
120
+ pre_a="${BASH_REMATCH[5]:-}"
121
+ [[ "$b" =~ $re ]] || { echo "ERROR not a release version: '$b'" >&2; return 1; }
122
+ core_b=("${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}")
123
+ pre_b="${BASH_REMATCH[5]:-}"
124
+ for i in 0 1 2; do
125
+ if ((10#${core_a[i]} > 10#${core_b[i]})); then printf '1\n'; return 0; fi
126
+ if ((10#${core_a[i]} < 10#${core_b[i]})); then printf -- '-1\n'; return 0; fi
127
+ done
128
+ if [[ -z "$pre_a" && -z "$pre_b" ]]; then printf '0\n'; return 0; fi
129
+ if [[ -z "$pre_a" ]]; then printf '1\n'; return 0; fi
130
+ if [[ -z "$pre_b" ]]; then printf -- '-1\n'; return 0; fi
131
+ IFS=. read -r -a ids_a <<<"$pre_a"
132
+ IFS=. read -r -a ids_b <<<"$pre_b"
133
+ for ((i = 0; i < ${#ids_a[@]} || i < ${#ids_b[@]}; i++)); do
134
+ if ((i >= ${#ids_a[@]})); then printf -- '-1\n'; return 0; fi
135
+ if ((i >= ${#ids_b[@]})); then printf '1\n'; return 0; fi
136
+ x="${ids_a[i]}"
137
+ y="${ids_b[i]}"
138
+ if [[ "$x" =~ ^[0-9]+$ && "$y" =~ ^[0-9]+$ ]]; then
139
+ if ((10#$x > 10#$y)); then printf '1\n'; return 0; fi
140
+ if ((10#$x < 10#$y)); then printf -- '-1\n'; return 0; fi
141
+ elif [[ "$x" =~ ^[0-9]+$ ]]; then
142
+ printf -- '-1\n'; return 0
143
+ elif [[ "$y" =~ ^[0-9]+$ ]]; then
144
+ printf '1\n'; return 0
145
+ elif [[ "$x" < "$y" ]]; then
146
+ printf -- '-1\n'; return 0
147
+ elif [[ "$x" > "$y" ]]; then
148
+ printf '1\n'; return 0
149
+ fi
150
+ done
151
+ printf '0\n'
152
+ }
153
+
154
+ # Runs `bun add --global SPEC` as the owner, pinned to the owner's ~/.bun.
155
+ adl_bun_add_global() {
156
+ local owner="$1" os="$2" home="$3" spec="$4" bun_path
157
+ bun_path="$(adl_bun_path "$os")" || return 1
158
+ # cd /tmp: the caller's working directory may be unreadable to the owner (root's home), and sudo then fails.
159
+ (cd /tmp && sudo -u "$owner" -H env PATH="$bun_path" BUN_INSTALL="${home%/}/.bun" bun add --global "$spec")
160
+ }
161
+
162
+ # The `adl` the owner gets must be THIS package: a different one earlier on the
163
+ # owner's PATH (a legacy compiled /usr/local/bin/adl from before the package
164
+ # existed is the real case) would keep running instead of the package the job
165
+ # keeps up to date. Accepts the package's own bin/adl, or the wrapper's
166
+ # bin/adl.js that sits beside it (the link `bun install -g` puts on PATH).
167
+ # adl_check_adl_not_shadowed OWNER OS OWNER_HOME PACKAGE_REAL_DIR CONTEXT
168
+ adl_check_adl_not_shadowed() {
169
+ local owner="$1" os="$2" home="$3" package_real="$4" context="$5" path resolved real wrapper_real
170
+ path="$(adl_owner_path "$os" "$home")" || return 1
171
+ resolved="$(cd /tmp && sudo -u "$owner" -H env PATH="$path" /bin/sh -c 'command -v adl' 2>/dev/null)" || resolved=""
172
+ if [[ -z "$resolved" ]]; then
173
+ {
174
+ echo "ERROR $context: $owner has no 'adl' on PATH ($path)."
175
+ echo "ERROR $context: expected ${home%/}/.bun/bin/adl from: bun install -g $adl_wrapper_package (run as $owner)"
176
+ } >&2
177
+ return 1
178
+ fi
179
+ real="$(adl_realpath "$resolved")" || real="$resolved"
180
+ wrapper_real="$(adl_realpath "$(dirname -- "$package_real")/$(basename -- "$adl_wrapper_package")/bin/adl.js" 2>/dev/null)" || wrapper_real=""
181
+ if [[ "$real" == "$package_real/bin/adl" || ( -n "$wrapper_real" && "$real" == "$wrapper_real" ) ]]; then
182
+ return 0
183
+ fi
184
+ {
185
+ echo "ERROR $context: $owner's 'adl' is $resolved (-> $real), not this package's ($package_real/bin/adl)."
186
+ echo "ERROR $context: a different adl shadows the package, so the job would keep updating one adl while $owner runs another."
187
+ echo "ERROR $context: move it aside (never delete it), then run this again:"
188
+ echo "ERROR $context: sudo mv $resolved $resolved.legacy-$(date +%Y%m%d)"
189
+ } >&2
190
+ return 1
191
+ }
192
+
193
+ # ---------------------------------------------------------------------------------------------
194
+ # The two reconcile locks (/var/run/adl-reconcile.lock, /var/run/adl-sync.lock) are mkdir locks.
195
+ # A run that is killed or hangs used to leave the directory behind, and every later `adl setup` /
196
+ # `adl reconcile` then refused "another reconcile is running" forever (m5, 2026-10-01). The holder
197
+ # now records its pid and start time in the lock directory:
198
+ # - pid running with the same start time -> refused, naming the pid;
199
+ # - pid gone, or running with a different start time (the pid was reused) -> stale;
200
+ # - no pid file (the old format, or a holder killed between mkdir and the write) -> stale only
201
+ # when older than the longest a run may take, 3 hours (the systemd unit's TimeoutStartSec).
202
+ # A stale lock is renamed aside and only then re-created with mkdir, so two takers cannot both win.
203
+ # Prints WARN on stderr when it takes over; returns 1 (after an ERROR naming the holder) when the
204
+ # lock is held. The caller removes the directory on exit.
205
+ # adl_lock_acquire LOCK_DIR "what is running"
206
+ adl_lock_max_age_seconds=10800
207
+
208
+ adl_lock_start_time() {
209
+ ps -p "$1" -o lstart= 2>/dev/null | sed -e 's/^ *//' -e 's/ *$//'
210
+ }
211
+
212
+ adl_lock_mtime() {
213
+ stat -c %Y "$1" 2>/dev/null || stat -f %m "$1" 2>/dev/null
214
+ }
215
+
216
+ adl_lock_write_holder() {
217
+ printf '%s\n' "$$" >"$1/pid"
218
+ printf '%s\n' "$(adl_lock_start_time "$$")" >"$1/started"
219
+ }
220
+
221
+ adl_lock_acquire() {
222
+ local lock="$1" running="$2" pid="" recorded_start="" actual_start reason="" now mtime aside
223
+ if mkdir "$lock" 2>/dev/null; then
224
+ adl_lock_write_holder "$lock"
225
+ return 0
226
+ fi
227
+ [[ -d "$lock" ]] && pid="$(tr -d '[:space:]' 2>/dev/null <"$lock/pid" || true)"
228
+ if [[ "$pid" =~ ^[0-9]+$ ]]; then
229
+ if kill -0 "$pid" 2>/dev/null; then
230
+ recorded_start="$(tr -d '\n' <"$lock/started" 2>/dev/null | sed -e 's/^ *//' -e 's/ *$//' || true)"
231
+ actual_start="$(adl_lock_start_time "$pid")"
232
+ if [[ -z "$recorded_start" || "$recorded_start" == "$actual_start" ]]; then
233
+ echo "ERROR $running (lock: $lock, pid $pid)" >&2
234
+ return 1
235
+ fi
236
+ fi
237
+ reason="pid $pid not running"
238
+ else
239
+ now="$(date +%s)"
240
+ mtime="$(adl_lock_mtime "$lock")" || mtime="$now"
241
+ if (( now - mtime < adl_lock_max_age_seconds )); then
242
+ echo "ERROR $running (lock: $lock, no pid recorded; it is treated as stale after 3h)" >&2
243
+ return 1
244
+ fi
245
+ reason="no pid recorded, older than 3h"
246
+ fi
247
+ echo "WARN adl reconcile: removing stale lock $lock ($reason)" >&2
248
+ aside="$lock.stale.$$"
249
+ mv -- "$lock" "$aside" 2>/dev/null || true
250
+ command rm -rf -- "$aside"
251
+ if mkdir "$lock" 2>/dev/null; then
252
+ adl_lock_write_holder "$lock"
253
+ return 0
254
+ fi
255
+ echo "ERROR $running (lock: $lock, taken by another run while removing the stale one)" >&2
256
+ return 1
257
+ }
@@ -21,7 +21,7 @@ bun_compile_build() {
21
21
  local bun_bin="$1"
22
22
  local entry_path="$2"
23
23
  local target="$3"
24
- [[ -f "$entry_path" ]] || { echo "bun-compile entry missing: $entry_path" >&2; exit 1; }
24
+ [[ -f "$entry_path" ]] || { echo "ERROR bun-compile entry missing: $entry_path" >&2; exit 1; }
25
25
  (
26
26
  build_dir="$(mktemp -d)"
27
27
  trap 'rm -rf "$build_dir"' EXIT