coding-agent-skills 0.2.8

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 (357) hide show
  1. package/AGENTS.md +44 -0
  2. package/CHANGELOG.md +205 -0
  3. package/CONTRIBUTING.md +54 -0
  4. package/LICENSE +21 -0
  5. package/README.md +85 -0
  6. package/ROADMAP.md +87 -0
  7. package/RUNBOOK.md +47 -0
  8. package/bin/coding-agent-skills +75 -0
  9. package/contracts/evidence-pack/README.md +22 -0
  10. package/contracts/evidence-pack/evidence-pack.example.json +60 -0
  11. package/contracts/evidence-pack/evidence-pack.example.md +49 -0
  12. package/contracts/evidence-pack/evidence-pack.schema.json +156 -0
  13. package/docs/adapters/README.md +82 -0
  14. package/docs/adapters/discovery.md +50 -0
  15. package/docs/adapters/external-adapters.md +42 -0
  16. package/docs/adapters/project-installation.md +135 -0
  17. package/docs/adapters/real-project-adoption.md +193 -0
  18. package/docs/adapters/upgrade-evidence.md +67 -0
  19. package/docs/adapters/upgrades.md +83 -0
  20. package/docs/architecture/README.md +23 -0
  21. package/docs/authoring/README.md +54 -0
  22. package/docs/evidence-bundles/README.md +94 -0
  23. package/docs/privacy/README.md +26 -0
  24. package/docs/release/README.md +42 -0
  25. package/docs/release/npm-package.md +85 -0
  26. package/docs/safety/README.md +94 -0
  27. package/docs/testing/README.md +100 -0
  28. package/docs/usage/README.md +89 -0
  29. package/docs/versioning/README.md +30 -0
  30. package/docs/versioning/adapter-compatibility.md +54 -0
  31. package/examples/README.md +12 -0
  32. package/examples/adapters/README.md +9 -0
  33. package/examples/adapters/documentation-precedence.json +62 -0
  34. package/examples/adapters/narrow-repo-map.json +64 -0
  35. package/examples/adapters/runtime-status-hints.json +76 -0
  36. package/examples/command-policies/README.md +3 -0
  37. package/examples/command-policies/build-verify.json +57 -0
  38. package/examples/command-policies/git-preflight.json +44 -0
  39. package/examples/command-policies/llm-drift-control.json +45 -0
  40. package/examples/command-policies/repo-map.json +59 -0
  41. package/examples/command-policies/runtime-truth.json +59 -0
  42. package/examples/evidence-packs/README.md +3 -0
  43. package/examples/evidence-packs/build-verify.json +68 -0
  44. package/examples/evidence-packs/git-preflight.json +55 -0
  45. package/examples/evidence-packs/llm-drift-control.json +55 -0
  46. package/examples/evidence-packs/repo-map.json +55 -0
  47. package/examples/evidence-packs/runtime-truth.json +55 -0
  48. package/examples/manifests/README.md +3 -0
  49. package/examples/manifests/build-verify.json +14 -0
  50. package/examples/manifests/git-preflight.json +14 -0
  51. package/examples/manifests/llm-drift-control.json +14 -0
  52. package/examples/manifests/repo-map.json +14 -0
  53. package/examples/manifests/runtime-truth.json +14 -0
  54. package/examples/upgrade-evidence/README.md +14 -0
  55. package/examples/upgrade-evidence/chain-fail.evidence.json +155 -0
  56. package/examples/upgrade-evidence/chain-fail.evidence.md +14 -0
  57. package/examples/upgrade-evidence/chain-pass.evidence.json +156 -0
  58. package/examples/upgrade-evidence/stale-pin.evidence.json +117 -0
  59. package/examples/upgrade-evidence/unsafe-upgrade.evidence.json +128 -0
  60. package/examples/upgrade-evidence/valid-upgrade.evidence.json +105 -0
  61. package/examples/upgrade-evidence/valid-upgrade.evidence.md +13 -0
  62. package/examples/workflows/README.md +3 -0
  63. package/examples/workflows/build-verify.md +20 -0
  64. package/examples/workflows/git-preflight.md +18 -0
  65. package/examples/workflows/llm-drift-control.md +16 -0
  66. package/examples/workflows/repo-map.md +20 -0
  67. package/examples/workflows/runtime-truth.md +17 -0
  68. package/package.json +58 -0
  69. package/runs/skill-runs.md +162 -0
  70. package/schemas/adapter-upgrade-evidence.schema.json +443 -0
  71. package/schemas/archive-index.schema.json +174 -0
  72. package/schemas/archive-report.schema.json +322 -0
  73. package/schemas/command-policy.schema.json +125 -0
  74. package/schemas/evidence-bundle.schema.json +394 -0
  75. package/schemas/project-adapter-installation.schema.json +127 -0
  76. package/schemas/project-adapter.schema.json +328 -0
  77. package/schemas/skill-manifest.schema.json +40 -0
  78. package/scripts/check-adapter-upgrade-chain.mjs +32 -0
  79. package/scripts/check-adapter-upgrade.mjs +31 -0
  80. package/scripts/lib/adapter-discovery.mjs +441 -0
  81. package/scripts/lib/adapter-repo-map.mjs +358 -0
  82. package/scripts/lib/adapter-upgrade-chain.mjs +261 -0
  83. package/scripts/lib/adapter-upgrade.mjs +434 -0
  84. package/scripts/lib/evidence-bundle.mjs +831 -0
  85. package/scripts/lib/pack-rules.mjs +704 -0
  86. package/scripts/lib/project-adapter-installation.mjs +327 -0
  87. package/scripts/lib/safe-evidence-output.mjs +92 -0
  88. package/scripts/lib/schema-validator.mjs +146 -0
  89. package/scripts/lib/semver.mjs +54 -0
  90. package/scripts/lib/upgrade-evidence.mjs +276 -0
  91. package/scripts/render-adapter-repo-map.mjs +8 -0
  92. package/scripts/render-evidence-archive-report.mjs +18 -0
  93. package/scripts/run-next +220 -0
  94. package/scripts/test-pack.mjs +2232 -0
  95. package/scripts/validate-adapters.mjs +10 -0
  96. package/scripts/validate-maintainer-loop.mjs +146 -0
  97. package/scripts/validate-pack.mjs +950 -0
  98. package/scripts/validate-project-adapters.mjs +8 -0
  99. package/scripts/verify-evidence-bundle.mjs +18 -0
  100. package/skills/build-verify/SKILL.md +62 -0
  101. package/skills/build-verify/adapter-interface.md +7 -0
  102. package/skills/build-verify/agents/openai.yaml +4 -0
  103. package/skills/build-verify/checklist.md +12 -0
  104. package/skills/build-verify/evidence-template.md +11 -0
  105. package/skills/build-verify/examples.md +16 -0
  106. package/skills/build-verify/failure-modes.md +14 -0
  107. package/skills/git-preflight/SKILL.md +65 -0
  108. package/skills/git-preflight/adapter-interface.md +7 -0
  109. package/skills/git-preflight/agents/openai.yaml +4 -0
  110. package/skills/git-preflight/checklist.md +11 -0
  111. package/skills/git-preflight/evidence-template.md +10 -0
  112. package/skills/git-preflight/examples.md +18 -0
  113. package/skills/git-preflight/failure-modes.md +13 -0
  114. package/skills/llm-drift-control/SKILL.md +67 -0
  115. package/skills/llm-drift-control/adapter-interface.md +7 -0
  116. package/skills/llm-drift-control/agents/openai.yaml +4 -0
  117. package/skills/llm-drift-control/checklist.md +11 -0
  118. package/skills/llm-drift-control/evidence-template.md +13 -0
  119. package/skills/llm-drift-control/examples.md +15 -0
  120. package/skills/llm-drift-control/failure-modes.md +13 -0
  121. package/skills/repo-map/SKILL.md +71 -0
  122. package/skills/repo-map/adapter-interface.md +18 -0
  123. package/skills/repo-map/agents/openai.yaml +4 -0
  124. package/skills/repo-map/checklist.md +15 -0
  125. package/skills/repo-map/evidence-template.md +29 -0
  126. package/skills/repo-map/examples.md +19 -0
  127. package/skills/repo-map/failure-modes.md +16 -0
  128. package/skills/runtime-truth/SKILL.md +62 -0
  129. package/skills/runtime-truth/adapter-interface.md +7 -0
  130. package/skills/runtime-truth/agents/openai.yaml +4 -0
  131. package/skills/runtime-truth/checklist.md +11 -0
  132. package/skills/runtime-truth/evidence-template.md +12 -0
  133. package/skills/runtime-truth/examples.md +20 -0
  134. package/skills/runtime-truth/failure-modes.md +13 -0
  135. package/tests/README.md +44 -0
  136. package/tests/adapters/README.md +15 -0
  137. package/tests/completion/README.md +15 -0
  138. package/tests/evidence/README.md +15 -0
  139. package/tests/fixtures/README.md +23 -0
  140. package/tests/fixtures/adapters/allow-deploy.json +60 -0
  141. package/tests/fixtures/adapters/allow-git-push.json +60 -0
  142. package/tests/fixtures/adapters/expand-scope.json +53 -0
  143. package/tests/fixtures/adapters/expose-secrets.json +53 -0
  144. package/tests/fixtures/adapters/incompatible-version.json +53 -0
  145. package/tests/fixtures/adapters/override-audit-only.json +53 -0
  146. package/tests/fixtures/adapters/redefine-completion.json +53 -0
  147. package/tests/fixtures/adapters/remove-required-evidence.json +53 -0
  148. package/tests/fixtures/adapters/suppress-failures.json +53 -0
  149. package/tests/fixtures/adapters/valid-narrowing.json +53 -0
  150. package/tests/fixtures/adapters/valid-repo-map.json +53 -0
  151. package/tests/fixtures/adapters/weakening-repo-map.json +42 -0
  152. package/tests/fixtures/completion/cases.json +143 -0
  153. package/tests/fixtures/completion/false-complete.json +51 -0
  154. package/tests/fixtures/evidence-bundles/advisory-review-soon/archive/evidence-archive-index.json +52 -0
  155. package/tests/fixtures/evidence-bundles/advisory-review-soon/evidence/repo-map.evidence.json +68 -0
  156. package/tests/fixtures/evidence-bundles/advisory-review-soon/evidence/valid-upgrade.evidence.json +105 -0
  157. package/tests/fixtures/evidence-bundles/advisory-review-soon/evidence-bundle.json +109 -0
  158. package/tests/fixtures/evidence-bundles/invalid-archive/archive/evidence-archive-index.json +52 -0
  159. package/tests/fixtures/evidence-bundles/invalid-archive/evidence/repo-map.evidence.json +68 -0
  160. package/tests/fixtures/evidence-bundles/invalid-archive/evidence/valid-upgrade.evidence.json +105 -0
  161. package/tests/fixtures/evidence-bundles/invalid-archive/evidence-bundle.json +109 -0
  162. package/tests/fixtures/evidence-bundles/invalid-archive-index/archive/evidence-archive-index.json +52 -0
  163. package/tests/fixtures/evidence-bundles/invalid-archive-index/evidence/repo-map.evidence.json +68 -0
  164. package/tests/fixtures/evidence-bundles/invalid-archive-index/evidence/valid-upgrade.evidence.json +105 -0
  165. package/tests/fixtures/evidence-bundles/invalid-archive-index/evidence-bundle.json +109 -0
  166. package/tests/fixtures/evidence-bundles/invalid-hash/archive/evidence-archive-index.json +52 -0
  167. package/tests/fixtures/evidence-bundles/invalid-hash/evidence/repo-map.evidence.json +68 -0
  168. package/tests/fixtures/evidence-bundles/invalid-hash/evidence/valid-upgrade.evidence.json +105 -0
  169. package/tests/fixtures/evidence-bundles/invalid-hash/evidence-bundle.json +109 -0
  170. package/tests/fixtures/evidence-bundles/invalid-missing-entry/archive/evidence-archive-index.json +52 -0
  171. package/tests/fixtures/evidence-bundles/invalid-missing-entry/evidence/repo-map.evidence.json +68 -0
  172. package/tests/fixtures/evidence-bundles/invalid-missing-entry/evidence/valid-upgrade.evidence.json +105 -0
  173. package/tests/fixtures/evidence-bundles/invalid-missing-entry/evidence-bundle.json +109 -0
  174. package/tests/fixtures/evidence-bundles/invalid-path/archive/evidence-archive-index.json +52 -0
  175. package/tests/fixtures/evidence-bundles/invalid-path/evidence/repo-map.evidence.json +68 -0
  176. package/tests/fixtures/evidence-bundles/invalid-path/evidence/valid-upgrade.evidence.json +105 -0
  177. package/tests/fixtures/evidence-bundles/invalid-path/evidence-bundle.json +109 -0
  178. package/tests/fixtures/evidence-bundles/invalid-provenance/archive/evidence-archive-index.json +52 -0
  179. package/tests/fixtures/evidence-bundles/invalid-provenance/evidence/repo-map.evidence.json +68 -0
  180. package/tests/fixtures/evidence-bundles/invalid-provenance/evidence/valid-upgrade.evidence.json +105 -0
  181. package/tests/fixtures/evidence-bundles/invalid-provenance/evidence-bundle.json +109 -0
  182. package/tests/fixtures/evidence-bundles/invalid-regression/archive/evidence-archive-index.json +52 -0
  183. package/tests/fixtures/evidence-bundles/invalid-regression/evidence/repo-map.evidence.json +68 -0
  184. package/tests/fixtures/evidence-bundles/invalid-regression/evidence/valid-upgrade.evidence.json +105 -0
  185. package/tests/fixtures/evidence-bundles/invalid-regression/evidence-bundle.json +113 -0
  186. package/tests/fixtures/evidence-bundles/invalid-retention/archive/evidence-archive-index.json +52 -0
  187. package/tests/fixtures/evidence-bundles/invalid-retention/evidence/repo-map.evidence.json +68 -0
  188. package/tests/fixtures/evidence-bundles/invalid-retention/evidence/valid-upgrade.evidence.json +105 -0
  189. package/tests/fixtures/evidence-bundles/invalid-retention/evidence-bundle.json +109 -0
  190. package/tests/fixtures/evidence-bundles/invalid-signature-plan/archive/evidence-archive-index.json +52 -0
  191. package/tests/fixtures/evidence-bundles/invalid-signature-plan/evidence/repo-map.evidence.json +68 -0
  192. package/tests/fixtures/evidence-bundles/invalid-signature-plan/evidence/valid-upgrade.evidence.json +105 -0
  193. package/tests/fixtures/evidence-bundles/invalid-signature-plan/evidence-bundle.json +109 -0
  194. package/tests/fixtures/evidence-bundles/valid-bundle/archive/evidence-archive-index.json +52 -0
  195. package/tests/fixtures/evidence-bundles/valid-bundle/evidence/repo-map.evidence.json +68 -0
  196. package/tests/fixtures/evidence-bundles/valid-bundle/evidence/valid-upgrade.evidence.json +105 -0
  197. package/tests/fixtures/evidence-bundles/valid-bundle/evidence-bundle.json +109 -0
  198. package/tests/fixtures/external-adapters/empty/README.md +3 -0
  199. package/tests/fixtures/external-adapters/invalid-completion-override/.coding-agent/adapters/completion/adapter.json +53 -0
  200. package/tests/fixtures/external-adapters/invalid-deploy/.coding-agent/adapters/deploy/adapter.json +60 -0
  201. package/tests/fixtures/external-adapters/invalid-evidence-suppression/.coding-agent/adapters/evidence/adapter.json +53 -0
  202. package/tests/fixtures/external-adapters/invalid-failure-suppression/.coding-agent/adapters/failures/adapter.json +53 -0
  203. package/tests/fixtures/external-adapters/invalid-git-push/.coding-agent/adapters/publish/adapter.json +60 -0
  204. package/tests/fixtures/external-adapters/invalid-malformed/.coding-agent/adapters/malformed/adapter.json +1 -0
  205. package/tests/fixtures/external-adapters/invalid-malformed/malformed-adapter.txt +1 -0
  206. package/tests/fixtures/external-adapters/invalid-mode-escalation/.coding-agent/adapters/mode/adapter.json +53 -0
  207. package/tests/fixtures/external-adapters/invalid-path-traversal/.coding-agent/adapters/path/adapter.json +53 -0
  208. package/tests/fixtures/external-adapters/invalid-restriction-removal/.coding-agent/adapters/restrictions/adapter.json +52 -0
  209. package/tests/fixtures/external-adapters/invalid-scope-expansion/.coding-agent/adapters/scope/adapter.json +53 -0
  210. package/tests/fixtures/external-adapters/invalid-secret-exposure/.coding-agent/adapters/secrets/adapter.json +53 -0
  211. package/tests/fixtures/external-adapters/invalid-skill-id/.coding-agent/adapters/skill/adapter.json +53 -0
  212. package/tests/fixtures/external-adapters/invalid-skill-version/.coding-agent/adapters/skill-version/adapter.json +53 -0
  213. package/tests/fixtures/external-adapters/invalid-unknown-manifest/.coding-agent/adapters/unknown/manifest.json +1 -0
  214. package/tests/fixtures/external-adapters/invalid-version/.coding-agent/adapters/version/adapter.json +53 -0
  215. package/tests/fixtures/external-adapters/mixed/.coding-agent/adapters/invalid/adapter.json +60 -0
  216. package/tests/fixtures/external-adapters/mixed/.coding-agent/adapters/valid/adapter.json +53 -0
  217. package/tests/fixtures/external-adapters/valid-basic/.coding-agent/adapters/basic/adapter.json +53 -0
  218. package/tests/fixtures/external-adapters/valid-doc-precedence/coding-agent/adapters/docs/adapter.json +53 -0
  219. package/tests/fixtures/external-adapters/valid-runtime-status/adapters/coding-agent/runtime/adapter.json +65 -0
  220. package/tests/fixtures/mutation/cases.json +87 -0
  221. package/tests/fixtures/mutation/snapshot-target/README.md +3 -0
  222. package/tests/fixtures/mutation/snapshot-target/state.json +4 -0
  223. package/tests/fixtures/policy/commands.json +164 -0
  224. package/tests/fixtures/policy/properties.json +126 -0
  225. package/tests/fixtures/privacy/cases.json +47 -0
  226. package/tests/fixtures/project-adapter-installation/invalid-adapter-location/.agents/adapters/basic/adapter.json +53 -0
  227. package/tests/fixtures/project-adapter-installation/invalid-adapter-location/.coding-agent/skills.json +23 -0
  228. package/tests/fixtures/project-adapter-installation/invalid-adapter-schema-version/.coding-agent/adapters/basic/adapter.json +53 -0
  229. package/tests/fixtures/project-adapter-installation/invalid-adapter-schema-version/.coding-agent/skills.json +23 -0
  230. package/tests/fixtures/project-adapter-installation/invalid-adapter-version-mismatch/.coding-agent/adapters/basic/adapter.json +53 -0
  231. package/tests/fixtures/project-adapter-installation/invalid-adapter-version-mismatch/.coding-agent/skills.json +23 -0
  232. package/tests/fixtures/project-adapter-installation/invalid-bad-semver/.coding-agent/adapters/basic/adapter.json +53 -0
  233. package/tests/fixtures/project-adapter-installation/invalid-bad-semver/.coding-agent/skills.json +23 -0
  234. package/tests/fixtures/project-adapter-installation/invalid-completion-override/.coding-agent/adapters/basic/adapter.json +53 -0
  235. package/tests/fixtures/project-adapter-installation/invalid-completion-override/.coding-agent/skills.json +23 -0
  236. package/tests/fixtures/project-adapter-installation/invalid-failure-suppression/.coding-agent/adapters/basic/adapter.json +53 -0
  237. package/tests/fixtures/project-adapter-installation/invalid-failure-suppression/.coding-agent/skills.json +23 -0
  238. package/tests/fixtures/project-adapter-installation/invalid-missing-declaration/.coding-agent/adapters/basic/adapter.json +53 -0
  239. package/tests/fixtures/project-adapter-installation/invalid-mode-escalation/.coding-agent/adapters/basic/adapter.json +53 -0
  240. package/tests/fixtures/project-adapter-installation/invalid-mode-escalation/.coding-agent/skills.json +23 -0
  241. package/tests/fixtures/project-adapter-installation/invalid-path-traversal/.coding-agent/adapters/basic/adapter.json +53 -0
  242. package/tests/fixtures/project-adapter-installation/invalid-path-traversal/.coding-agent/skills.json +23 -0
  243. package/tests/fixtures/project-adapter-installation/invalid-scope-expansion/.coding-agent/adapters/basic/adapter.json +53 -0
  244. package/tests/fixtures/project-adapter-installation/invalid-scope-expansion/.coding-agent/skills.json +23 -0
  245. package/tests/fixtures/project-adapter-installation/invalid-secret-exposure/.coding-agent/adapters/basic/adapter.json +53 -0
  246. package/tests/fixtures/project-adapter-installation/invalid-secret-exposure/.coding-agent/skills.json +23 -0
  247. package/tests/fixtures/project-adapter-installation/invalid-skill-mismatch/.coding-agent/adapters/basic/adapter.json +53 -0
  248. package/tests/fixtures/project-adapter-installation/invalid-skill-mismatch/.coding-agent/skills.json +23 -0
  249. package/tests/fixtures/project-adapter-installation/invalid-unknown-skill/.coding-agent/adapters/basic/adapter.json +53 -0
  250. package/tests/fixtures/project-adapter-installation/invalid-unknown-skill/.coding-agent/skills.json +23 -0
  251. package/tests/fixtures/project-adapter-installation/invalid-unsupported-core-version/.coding-agent/adapters/basic/adapter.json +53 -0
  252. package/tests/fixtures/project-adapter-installation/invalid-unsupported-core-version/.coding-agent/skills.json +23 -0
  253. package/tests/fixtures/project-adapter-installation/invalid-weakens-restrictions/.coding-agent/adapters/basic/adapter.json +52 -0
  254. package/tests/fixtures/project-adapter-installation/invalid-weakens-restrictions/.coding-agent/skills.json +23 -0
  255. package/tests/fixtures/project-adapter-installation/valid-compatible-range/coding-agent/adapters/docs/adapter.json +53 -0
  256. package/tests/fixtures/project-adapter-installation/valid-compatible-range/coding-agent.skills.json +23 -0
  257. package/tests/fixtures/project-adapter-installation/valid-exact-pin/.coding-agent/adapters/basic/adapter.json +53 -0
  258. package/tests/fixtures/project-adapter-installation/valid-exact-pin/.coding-agent/skills.json +23 -0
  259. package/tests/fixtures/project-adapter-installation/valid-multiple-adapters/.coding-agent/skills.json +28 -0
  260. package/tests/fixtures/project-adapter-installation/valid-multiple-adapters/adapters/coding-agent/repo/adapter.json +53 -0
  261. package/tests/fixtures/project-adapter-installation/valid-multiple-adapters/adapters/coding-agent/runtime/adapter.json +58 -0
  262. package/tests/fixtures/project-adapter-upgrade-chains/broken-compatibility-chain/01-current/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  263. package/tests/fixtures/project-adapter-upgrade-chains/broken-compatibility-chain/01-current/.coding-agent/skills.json +27 -0
  264. package/tests/fixtures/project-adapter-upgrade-chains/broken-compatibility-chain/02-incompatible/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  265. package/tests/fixtures/project-adapter-upgrade-chains/broken-compatibility-chain/02-incompatible/.coding-agent/skills.json +27 -0
  266. package/tests/fixtures/project-adapter-upgrade-chains/broken-compatibility-chain/03-target/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  267. package/tests/fixtures/project-adapter-upgrade-chains/broken-compatibility-chain/03-target/.coding-agent/skills.json +27 -0
  268. package/tests/fixtures/project-adapter-upgrade-chains/schema-drift-chain/01-current/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  269. package/tests/fixtures/project-adapter-upgrade-chains/schema-drift-chain/01-current/.coding-agent/skills.json +27 -0
  270. package/tests/fixtures/project-adapter-upgrade-chains/schema-drift-chain/02-schema-drift/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  271. package/tests/fixtures/project-adapter-upgrade-chains/schema-drift-chain/02-schema-drift/.coding-agent/skills.json +27 -0
  272. package/tests/fixtures/project-adapter-upgrade-chains/skill-drift-chain/01-current/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  273. package/tests/fixtures/project-adapter-upgrade-chains/skill-drift-chain/01-current/.coding-agent/skills.json +27 -0
  274. package/tests/fixtures/project-adapter-upgrade-chains/skill-drift-chain/02-skill-drift/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  275. package/tests/fixtures/project-adapter-upgrade-chains/skill-drift-chain/02-skill-drift/.coding-agent/skills.json +27 -0
  276. package/tests/fixtures/project-adapter-upgrade-chains/stale-pin-chain/01-current/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  277. package/tests/fixtures/project-adapter-upgrade-chains/stale-pin-chain/01-current/.coding-agent/skills.json +27 -0
  278. package/tests/fixtures/project-adapter-upgrade-chains/stale-pin-chain/02-stale/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  279. package/tests/fixtures/project-adapter-upgrade-chains/stale-pin-chain/02-stale/.coding-agent/skills.json +27 -0
  280. package/tests/fixtures/project-adapter-upgrade-chains/stale-pin-chain/03-target/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  281. package/tests/fixtures/project-adapter-upgrade-chains/stale-pin-chain/03-target/.coding-agent/skills.json +27 -0
  282. package/tests/fixtures/project-adapter-upgrade-chains/unsafe-weakening-chain/01-current/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  283. package/tests/fixtures/project-adapter-upgrade-chains/unsafe-weakening-chain/01-current/.coding-agent/skills.json +27 -0
  284. package/tests/fixtures/project-adapter-upgrade-chains/unsafe-weakening-chain/02-safe/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  285. package/tests/fixtures/project-adapter-upgrade-chains/unsafe-weakening-chain/02-safe/.coding-agent/skills.json +27 -0
  286. package/tests/fixtures/project-adapter-upgrade-chains/unsafe-weakening-chain/03-weakens-restrictions/.coding-agent/adapters/fixture-chain-adapter/adapter.json +69 -0
  287. package/tests/fixtures/project-adapter-upgrade-chains/unsafe-weakening-chain/03-weakens-restrictions/.coding-agent/skills.json +27 -0
  288. package/tests/fixtures/project-adapter-upgrade-chains/valid-chain/01-current/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  289. package/tests/fixtures/project-adapter-upgrade-chains/valid-chain/01-current/.coding-agent/skills.json +27 -0
  290. package/tests/fixtures/project-adapter-upgrade-chains/valid-chain/02-upgrade/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  291. package/tests/fixtures/project-adapter-upgrade-chains/valid-chain/02-upgrade/.coding-agent/skills.json +27 -0
  292. package/tests/fixtures/project-adapter-upgrade-chains/valid-chain/03-upgrade/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  293. package/tests/fixtures/project-adapter-upgrade-chains/valid-chain/03-upgrade/.coding-agent/skills.json +27 -0
  294. package/tests/fixtures/project-adapter-upgrade-chains/valid-chain/04-upgrade/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  295. package/tests/fixtures/project-adapter-upgrade-chains/valid-chain/04-upgrade/.coding-agent/skills.json +27 -0
  296. package/tests/fixtures/project-adapter-upgrade-chains/valid-chain/05-upgrade/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  297. package/tests/fixtures/project-adapter-upgrade-chains/valid-chain/05-upgrade/.coding-agent/skills.json +27 -0
  298. package/tests/fixtures/project-adapter-upgrade-chains/valid-chain/06-upgrade/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  299. package/tests/fixtures/project-adapter-upgrade-chains/valid-chain/06-upgrade/.coding-agent/skills.json +27 -0
  300. package/tests/fixtures/project-adapter-upgrade-chains/valid-chain/07-upgrade/.coding-agent/adapters/fixture-chain-adapter/adapter.json +70 -0
  301. package/tests/fixtures/project-adapter-upgrade-chains/valid-chain/07-upgrade/.coding-agent/skills.json +27 -0
  302. package/tests/fixtures/project-adapter-upgrades/adapter-schema-drift/after/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  303. package/tests/fixtures/project-adapter-upgrades/adapter-schema-drift/after/.coding-agent/skills.json +27 -0
  304. package/tests/fixtures/project-adapter-upgrades/adapter-schema-drift/before/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  305. package/tests/fixtures/project-adapter-upgrades/adapter-schema-drift/before/.coding-agent/skills.json +27 -0
  306. package/tests/fixtures/project-adapter-upgrades/safe-upgrade-preserves-restrictions/after/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +71 -0
  307. package/tests/fixtures/project-adapter-upgrades/safe-upgrade-preserves-restrictions/after/.coding-agent/skills.json +27 -0
  308. package/tests/fixtures/project-adapter-upgrades/safe-upgrade-preserves-restrictions/before/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  309. package/tests/fixtures/project-adapter-upgrades/safe-upgrade-preserves-restrictions/before/.coding-agent/skills.json +27 -0
  310. package/tests/fixtures/project-adapter-upgrades/skill-compatibility-drift/after/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  311. package/tests/fixtures/project-adapter-upgrades/skill-compatibility-drift/after/.coding-agent/skills.json +27 -0
  312. package/tests/fixtures/project-adapter-upgrades/skill-compatibility-drift/before/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  313. package/tests/fixtures/project-adapter-upgrades/skill-compatibility-drift/before/.coding-agent/skills.json +27 -0
  314. package/tests/fixtures/project-adapter-upgrades/stale-compatible-range/after/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  315. package/tests/fixtures/project-adapter-upgrades/stale-compatible-range/after/.coding-agent/skills.json +27 -0
  316. package/tests/fixtures/project-adapter-upgrades/stale-compatible-range/before/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  317. package/tests/fixtures/project-adapter-upgrades/stale-compatible-range/before/.coding-agent/skills.json +27 -0
  318. package/tests/fixtures/project-adapter-upgrades/stale-exact-pin/after/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  319. package/tests/fixtures/project-adapter-upgrades/stale-exact-pin/after/.coding-agent/skills.json +27 -0
  320. package/tests/fixtures/project-adapter-upgrades/stale-exact-pin/before/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  321. package/tests/fixtures/project-adapter-upgrades/stale-exact-pin/before/.coding-agent/skills.json +27 -0
  322. package/tests/fixtures/project-adapter-upgrades/unsafe-upgrade-mode-escalation/after/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  323. package/tests/fixtures/project-adapter-upgrades/unsafe-upgrade-mode-escalation/after/.coding-agent/skills.json +27 -0
  324. package/tests/fixtures/project-adapter-upgrades/unsafe-upgrade-mode-escalation/before/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  325. package/tests/fixtures/project-adapter-upgrades/unsafe-upgrade-mode-escalation/before/.coding-agent/skills.json +27 -0
  326. package/tests/fixtures/project-adapter-upgrades/unsafe-upgrade-removes-evidence/after/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +69 -0
  327. package/tests/fixtures/project-adapter-upgrades/unsafe-upgrade-removes-evidence/after/.coding-agent/skills.json +27 -0
  328. package/tests/fixtures/project-adapter-upgrades/unsafe-upgrade-removes-evidence/before/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  329. package/tests/fixtures/project-adapter-upgrades/unsafe-upgrade-removes-evidence/before/.coding-agent/skills.json +27 -0
  330. package/tests/fixtures/project-adapter-upgrades/unsafe-upgrade-weakens-restrictions/after/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +69 -0
  331. package/tests/fixtures/project-adapter-upgrades/unsafe-upgrade-weakens-restrictions/after/.coding-agent/skills.json +27 -0
  332. package/tests/fixtures/project-adapter-upgrades/unsafe-upgrade-weakens-restrictions/before/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  333. package/tests/fixtures/project-adapter-upgrades/unsafe-upgrade-weakens-restrictions/before/.coding-agent/skills.json +27 -0
  334. package/tests/fixtures/project-adapter-upgrades/unsupported-future-core/after/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  335. package/tests/fixtures/project-adapter-upgrades/unsupported-future-core/after/.coding-agent/skills.json +27 -0
  336. package/tests/fixtures/project-adapter-upgrades/unsupported-future-core/before/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  337. package/tests/fixtures/project-adapter-upgrades/unsupported-future-core/before/.coding-agent/skills.json +27 -0
  338. package/tests/fixtures/project-adapter-upgrades/unsupported-old-core/after/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  339. package/tests/fixtures/project-adapter-upgrades/unsupported-old-core/after/.coding-agent/skills.json +27 -0
  340. package/tests/fixtures/project-adapter-upgrades/unsupported-old-core/before/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  341. package/tests/fixtures/project-adapter-upgrades/unsupported-old-core/before/.coding-agent/skills.json +27 -0
  342. package/tests/fixtures/project-adapter-upgrades/valid-upgrade/after/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  343. package/tests/fixtures/project-adapter-upgrades/valid-upgrade/after/.coding-agent/skills.json +27 -0
  344. package/tests/fixtures/project-adapter-upgrades/valid-upgrade/before/.coding-agent/adapters/fixture-upgrade-adapter/adapter.json +70 -0
  345. package/tests/fixtures/project-adapter-upgrades/valid-upgrade/before/.coding-agent/skills.json +27 -0
  346. package/tests/fixtures/sample-repo/.env.example +1 -0
  347. package/tests/fixtures/sample-repo/README.md +4 -0
  348. package/tests/fixtures/sample-repo/docs/architecture.md +3 -0
  349. package/tests/fixtures/sample-repo/package.json +11 -0
  350. package/tests/fixtures/sample-repo/src/index.js +3 -0
  351. package/tests/fixtures/sample-repo/test/index.test.js +8 -0
  352. package/tests/fixtures/triggers/cases.json +101 -0
  353. package/tests/policy/README.md +16 -0
  354. package/tests/privacy/README.md +14 -0
  355. package/tests/safety/README.md +17 -0
  356. package/tests/trigger/README.md +11 -0
  357. package/work-ledger.md +159 -0
@@ -0,0 +1,358 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ import {
7
+ ADAPTER_MANIFEST_FILENAME,
8
+ readSafeJsonFile,
9
+ } from "./adapter-discovery.mjs";
10
+ import { PILOT_VERSION, redactSensitiveText } from "./pack-rules.mjs";
11
+ import {
12
+ readProjectAdapterDeclaration,
13
+ validateProjectAdapters,
14
+ } from "./project-adapter-installation.mjs";
15
+
16
+ const DEFAULT_CORE_ROOT = path.resolve(
17
+ path.dirname(fileURLToPath(import.meta.url)),
18
+ "..",
19
+ "..",
20
+ );
21
+
22
+ const REFUSED_BEHAVIOR = [
23
+ "no target project builds",
24
+ "no target project tests",
25
+ "no package installs",
26
+ "no runtime checks",
27
+ "no deployments",
28
+ "no migrations",
29
+ "no secret-file reads",
30
+ "no project writes",
31
+ ];
32
+
33
+ function inside(root, candidate) {
34
+ const relative = path.relative(root, candidate);
35
+ return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
36
+ }
37
+
38
+ function unique(values) {
39
+ return [...new Set(values.filter((value) => typeof value === "string" && value))];
40
+ }
41
+
42
+ function describeApprovedPath(projectRoot, relativePath) {
43
+ if (
44
+ typeof relativePath !== "string" ||
45
+ !relativePath ||
46
+ relativePath.startsWith("/") ||
47
+ relativePath.split(/[\\/]+/).includes("..") ||
48
+ /(^|\/)\.env(?:\.|$)/.test(relativePath)
49
+ ) {
50
+ return {
51
+ path: String(relativePath),
52
+ status: "unsafe",
53
+ type: "unknown",
54
+ };
55
+ }
56
+
57
+ const absolute = path.resolve(projectRoot, relativePath);
58
+ if (!inside(projectRoot, absolute)) {
59
+ return {
60
+ path: relativePath,
61
+ status: "unsafe",
62
+ type: "unknown",
63
+ };
64
+ }
65
+
66
+ let current = projectRoot;
67
+ for (const segment of path.relative(projectRoot, absolute).split(path.sep).filter(Boolean)) {
68
+ current = path.join(current, segment);
69
+ if (!fs.existsSync(current)) {
70
+ return {
71
+ path: relativePath,
72
+ status: "missing",
73
+ type: "unknown",
74
+ };
75
+ }
76
+ if (fs.lstatSync(current).isSymbolicLink()) {
77
+ return {
78
+ path: relativePath,
79
+ status: "symlink",
80
+ type: "unknown",
81
+ };
82
+ }
83
+ }
84
+
85
+ const stat = fs.lstatSync(absolute);
86
+ return {
87
+ path: relativePath,
88
+ status: "present",
89
+ type: stat.isDirectory() ? "directory" : stat.isFile() ? "file" : "other",
90
+ };
91
+ }
92
+
93
+ function gitSummary(projectRoot) {
94
+ const summary = {
95
+ root: null,
96
+ branchState: null,
97
+ hasUncommittedChanges: false,
98
+ warnings: [],
99
+ };
100
+
101
+ const revParse = spawnSync("git", ["rev-parse", "--show-toplevel"], {
102
+ cwd: projectRoot,
103
+ encoding: "utf8",
104
+ stdio: ["ignore", "pipe", "pipe"],
105
+ });
106
+ if (revParse.status === 0) summary.root = revParse.stdout.trim();
107
+
108
+ const status = spawnSync("git", ["status", "--short", "--branch"], {
109
+ cwd: projectRoot,
110
+ encoding: "utf8",
111
+ stdio: ["ignore", "pipe", "pipe"],
112
+ });
113
+ if (status.status !== 0) {
114
+ summary.warnings.push("git status unavailable");
115
+ return summary;
116
+ }
117
+
118
+ const lines = status.stdout.split(/\r?\n/).filter(Boolean);
119
+ summary.branchState = lines[0] ?? null;
120
+ summary.hasUncommittedChanges = lines.length > 1;
121
+ if (summary.hasUncommittedChanges) {
122
+ summary.warnings.push("working tree has local changes; filenames omitted");
123
+ }
124
+ if (/\[(?:ahead|behind|gone|diverged)[^\]]*\]/i.test(summary.branchState ?? "")) {
125
+ summary.warnings.push("branch state indicates remote divergence; revalidate after update");
126
+ }
127
+ return summary;
128
+ }
129
+
130
+ function loadRepoMapAdapters(loaded) {
131
+ const adapters = [];
132
+ const errors = [];
133
+ const declarations = loaded.declaration.adapters ?? [];
134
+ const container = path.resolve(loaded.projectRoot, loaded.declaration.adapterRoot);
135
+ const manifestCandidates = [];
136
+
137
+ if (!inside(loaded.projectRoot, container) || !fs.existsSync(container)) {
138
+ return { adapters, errors: ["adapter-root-not-found"] };
139
+ }
140
+
141
+ for (const entry of fs.readdirSync(container, { withFileTypes: true })) {
142
+ if (entry.isSymbolicLink() || !entry.isDirectory()) continue;
143
+ const manifestPath = path.join(container, entry.name, ADAPTER_MANIFEST_FILENAME);
144
+ if (!inside(loaded.projectRoot, manifestPath) || !fs.existsSync(manifestPath)) continue;
145
+ const record = readSafeJsonFile(manifestPath);
146
+ if (!record.value) {
147
+ errors.push(...record.codes);
148
+ continue;
149
+ }
150
+ manifestCandidates.push({
151
+ manifestPath,
152
+ manifest: record.value,
153
+ });
154
+ }
155
+
156
+ for (const declaration of declarations) {
157
+ if (!(declaration.skillIds ?? []).includes("repo-map")) continue;
158
+ const match = manifestCandidates.find(
159
+ (candidate) => candidate.manifest.adapterId === declaration.id,
160
+ );
161
+ if (!match) {
162
+ errors.push("declared-repo-map-adapter-not-found");
163
+ continue;
164
+ }
165
+ adapters.push({
166
+ declaration,
167
+ manifestPath: path.relative(loaded.projectRoot, match.manifestPath),
168
+ manifest: match.manifest,
169
+ });
170
+ }
171
+
172
+ return { adapters, errors };
173
+ }
174
+
175
+ export function buildAdapterRepoMapReport(projectRootInput, options = {}) {
176
+ const coreRoot = path.resolve(options.coreRoot ?? DEFAULT_CORE_ROOT);
177
+ const validation = validateProjectAdapters(projectRootInput, { coreRoot });
178
+ if (!validation.ok) {
179
+ return {
180
+ ok: false,
181
+ status: "failed",
182
+ codes: validation.codes,
183
+ validation,
184
+ };
185
+ }
186
+ if (!validation.acceptedSkills.includes("repo-map")) {
187
+ return {
188
+ ok: false,
189
+ status: "failed",
190
+ codes: ["repo-map-not-enabled"],
191
+ validation,
192
+ };
193
+ }
194
+
195
+ const loaded = readProjectAdapterDeclaration(projectRootInput);
196
+ if (!loaded.ok) {
197
+ return {
198
+ ok: false,
199
+ status: "failed",
200
+ codes: loaded.codes,
201
+ validation,
202
+ };
203
+ }
204
+
205
+ const { adapters, errors } = loadRepoMapAdapters(loaded);
206
+ if (errors.length > 0 || adapters.length === 0) {
207
+ return {
208
+ ok: false,
209
+ status: "failed",
210
+ codes: errors.length > 0 ? unique(errors) : ["repo-map-adapter-not-found"],
211
+ validation,
212
+ };
213
+ }
214
+
215
+ const rootMarkers = adapters.flatMap(
216
+ (adapter) => adapter.manifest.project?.detection?.rootMarkers ?? [],
217
+ );
218
+ const maximumDepth = Math.max(
219
+ ...adapters.map((adapter) => adapter.manifest.project?.detection?.maximumDepth ?? 0),
220
+ );
221
+ const documentationPrecedence = unique(
222
+ adapters.flatMap((adapter) => adapter.manifest.extensions.documentationPrecedence),
223
+ ).map((relativePath) => describeApprovedPath(loaded.projectRoot, relativePath));
224
+ const safeReadPaths = unique(
225
+ adapters.flatMap((adapter) => adapter.manifest.extensions.safeReadPaths),
226
+ ).map((relativePath) => describeApprovedPath(loaded.projectRoot, relativePath));
227
+ const ignoredPaths = unique(
228
+ adapters.flatMap((adapter) => adapter.manifest.extensions.ignoredPaths),
229
+ );
230
+ const requiredEvidence = unique(
231
+ adapters.flatMap((adapter) => adapter.manifest.extensions.requiredEvidence),
232
+ );
233
+ const packageManagers = unique(
234
+ adapters.flatMap((adapter) => adapter.manifest.extensions.expectedPackageManagers),
235
+ );
236
+ const git = gitSummary(loaded.projectRoot);
237
+
238
+ return {
239
+ ok: true,
240
+ status: "complete",
241
+ coreVersion: PILOT_VERSION,
242
+ projectRoot: loaded.projectRoot,
243
+ declarationPath: loaded.declarationPath,
244
+ adapterRoot: loaded.declaration.adapterRoot,
245
+ projectId: loaded.declaration.projectId,
246
+ adapterIds: adapters.map((adapter) => adapter.manifest.adapterId).sort(),
247
+ manifestPaths: adapters.map((adapter) => adapter.manifestPath).sort(),
248
+ enabledSkills: ["repo-map"],
249
+ rootMarkers,
250
+ maximumDepth,
251
+ scope: "declared-project-root",
252
+ requireApprovalOutsideScope: true,
253
+ documentationPrecedence,
254
+ safeReadPaths,
255
+ ignoredPaths,
256
+ requiredEvidence,
257
+ packageManagers,
258
+ git,
259
+ warnings: unique([
260
+ ...git.warnings,
261
+ "adapter-aware repo-map is metadata-only and read-only",
262
+ ]),
263
+ refusedBehavior: REFUSED_BEHAVIOR,
264
+ validation,
265
+ };
266
+ }
267
+
268
+ function formatPathRecord(record, index, numbered = false) {
269
+ const prefix = numbered ? `${index + 1}.` : "-";
270
+ return `${prefix} ${record.path} (${record.type} ${record.status})`;
271
+ }
272
+
273
+ function formatList(title, values) {
274
+ if (!values.length) return [`## ${title}`, "- none declared"];
275
+ return [`## ${title}`, ...values.map((value) => `- ${value}`)];
276
+ }
277
+
278
+ export function renderAdapterRepoMapReport(report) {
279
+ if (!report.ok) {
280
+ return [
281
+ "# Adapter-Aware Repo Map",
282
+ "",
283
+ `Status: ${report.status}`,
284
+ `Rejection codes: ${(report.codes ?? []).join(", ")}`,
285
+ ].join("\n");
286
+ }
287
+
288
+ const lines = [
289
+ "# Adapter-Aware Repo Map",
290
+ "",
291
+ `Status: ${report.status}`,
292
+ `Core version: ${report.coreVersion}`,
293
+ `Project ID: ${report.projectId}`,
294
+ `Project root: ${redactSensitiveText(report.projectRoot)}`,
295
+ `Declaration: ${report.declarationPath}`,
296
+ `Adapter root: ${report.adapterRoot}`,
297
+ `Adapter IDs: ${report.adapterIds.join(", ")}`,
298
+ `Adapter manifests: ${report.manifestPaths.join(", ")}`,
299
+ `Enabled skills: ${report.enabledSkills.join(", ")}`,
300
+ "",
301
+ "## Git State",
302
+ `- Git root: ${redactSensitiveText(report.git.root ?? "not detected")}`,
303
+ `- Branch state: ${redactSensitiveText(report.git.branchState ?? "not detected")}`,
304
+ `- Local changes: ${report.git.hasUncommittedChanges ? "present; filenames omitted" : "not detected"}`,
305
+ "",
306
+ "## Adapter Bounds",
307
+ `- Scope: ${report.scope}`,
308
+ `- Maximum detection depth: ${report.maximumDepth}`,
309
+ `- Approval outside scope: ${report.requireApprovalOutsideScope ? "required" : "not declared"}`,
310
+ ...report.rootMarkers.map(
311
+ (marker) => `- Root marker: ${marker.kind} ${marker.path}`,
312
+ ),
313
+ "",
314
+ "## Documentation Precedence",
315
+ ...(report.documentationPrecedence.length
316
+ ? report.documentationPrecedence.map((record, index) =>
317
+ formatPathRecord(record, index, true),
318
+ )
319
+ : ["- none declared"]),
320
+ "",
321
+ "## Safe Read Paths",
322
+ ...(report.safeReadPaths.length
323
+ ? report.safeReadPaths.map((record, index) => formatPathRecord(record, index))
324
+ : ["- none declared"]),
325
+ "",
326
+ ...formatList("Ignored Paths", report.ignoredPaths),
327
+ "",
328
+ ...formatList("Required Evidence", report.requiredEvidence),
329
+ "",
330
+ ...formatList("Package Manager Hints", report.packageManagers),
331
+ "",
332
+ ...formatList("Warnings", report.warnings),
333
+ "",
334
+ ...formatList("Refused Behavior", report.refusedBehavior),
335
+ "",
336
+ "No target project build, test, runtime, deployment, migration, package installation, or secret-file read was performed.",
337
+ ];
338
+
339
+ return lines.join("\n");
340
+ }
341
+
342
+ export function adapterRepoMapCliResult(projectRoot, options = {}) {
343
+ if (!projectRoot) {
344
+ return {
345
+ exitCode: 2,
346
+ stream: "stderr",
347
+ lines: ["usage: node scripts/render-adapter-repo-map.mjs <project-root>"],
348
+ };
349
+ }
350
+
351
+ const report = buildAdapterRepoMapReport(projectRoot, options);
352
+ return {
353
+ exitCode: report.ok ? 0 : 1,
354
+ stream: report.ok ? "stdout" : "stderr",
355
+ lines: renderAdapterRepoMapReport(report).split("\n"),
356
+ report,
357
+ };
358
+ }
@@ -0,0 +1,261 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ import { checkAdapterUpgrade } from "./adapter-upgrade.mjs";
6
+ import { PILOT_VERSION, PREVIOUS_PILOT_VERSION } from "./pack-rules.mjs";
7
+ import { readProjectAdapterDeclaration } from "./project-adapter-installation.mjs";
8
+ import { writeSafeEvidenceJson } from "./safe-evidence-output.mjs";
9
+ import { compareSemver, parseSemver } from "./semver.mjs";
10
+ import { buildAdapterChainEvidence } from "./upgrade-evidence.mjs";
11
+
12
+ const DEFAULT_CORE_ROOT = path.resolve(
13
+ path.dirname(fileURLToPath(import.meta.url)),
14
+ "..",
15
+ "..",
16
+ );
17
+ const REVISION_NAME = /^([0-9]{2})-[a-z0-9]+(?:-[a-z0-9]+)*$/;
18
+
19
+ function baseFailure(code) {
20
+ return {
21
+ ok: false,
22
+ status: "failed",
23
+ revisionCount: 0,
24
+ transitionCount: 0,
25
+ passedTransitions: 0,
26
+ failedTransitions: 0,
27
+ transitions: [],
28
+ codes: [code],
29
+ };
30
+ }
31
+
32
+ function inside(root, candidate) {
33
+ const relative = path.relative(root, candidate);
34
+ return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
35
+ }
36
+
37
+ function discoverRevisions(chainRootInput) {
38
+ const input = String(chainRootInput ?? "");
39
+ if (!input.trim()) return { ok: false, codes: ["missing-chain-root"] };
40
+ if (input.split(/[\\/]+/).includes("..")) {
41
+ return { ok: false, codes: ["root-path-traversal"] };
42
+ }
43
+
44
+ const chainRoot = path.resolve(input);
45
+ if (!fs.existsSync(chainRoot)) return { ok: false, codes: ["chain-root-not-found"] };
46
+ const stat = fs.lstatSync(chainRoot);
47
+ if (stat.isSymbolicLink()) return { ok: false, codes: ["symlink-escape"] };
48
+ if (!stat.isDirectory()) return { ok: false, codes: ["chain-root-not-directory"] };
49
+
50
+ const realRoot = fs.realpathSync(chainRoot);
51
+ const revisions = [];
52
+ const codes = new Set();
53
+
54
+ for (const entry of fs.readdirSync(realRoot, { withFileTypes: true })) {
55
+ if (/^\.env(?:\.|$)/.test(entry.name)) continue;
56
+ const match = REVISION_NAME.exec(entry.name);
57
+ if (!match) {
58
+ codes.add("unexpected-chain-entry");
59
+ continue;
60
+ }
61
+ const candidate = path.join(realRoot, entry.name);
62
+ if (entry.isSymbolicLink()) {
63
+ codes.add("symlink-escape");
64
+ continue;
65
+ }
66
+ if (!entry.isDirectory()) {
67
+ codes.add("revision-not-directory");
68
+ continue;
69
+ }
70
+ const realCandidate = fs.realpathSync(candidate);
71
+ if (!inside(realRoot, realCandidate)) {
72
+ codes.add("symlink-escape");
73
+ continue;
74
+ }
75
+ revisions.push({
76
+ order: Number(match[1]),
77
+ root: realCandidate,
78
+ });
79
+ }
80
+
81
+ revisions.sort((left, right) => left.order - right.order);
82
+ if (revisions.length < 2) codes.add("insufficient-chain-revisions");
83
+ revisions.forEach((revision, index) => {
84
+ if (revision.order !== index + 1) codes.add("non-contiguous-chain-order");
85
+ });
86
+
87
+ return {
88
+ ok: codes.size === 0,
89
+ chainRoot: realRoot,
90
+ revisions,
91
+ codes: [...codes].sort(),
92
+ };
93
+ }
94
+
95
+ function expectedVersion(projectRoot) {
96
+ const loaded = readProjectAdapterDeclaration(projectRoot);
97
+ const version = loaded.declaration?.core?.expectedVersion;
98
+ return parseSemver(version) ? version : null;
99
+ }
100
+
101
+ function pinKind(pin) {
102
+ return typeof pin === "string" && /^\d+\.\d+\.\d+$/.test(pin)
103
+ ? "stale-exact-pin"
104
+ : "stale-compatible-range";
105
+ }
106
+
107
+ function progressionCodes(beforeRoot, afterRoot) {
108
+ const before = readProjectAdapterDeclaration(beforeRoot);
109
+ const after = readProjectAdapterDeclaration(afterRoot);
110
+ if (!before.ok || !after.ok) return [];
111
+
112
+ const beforeVersion = before.declaration.core?.expectedVersion;
113
+ const afterVersion = after.declaration.core?.expectedVersion;
114
+ const comparison = compareSemver(afterVersion, beforeVersion);
115
+ if (comparison === null) return ["incompatible-core-chain"];
116
+ if (comparison === 0) return [pinKind(after.declaration.core?.versionPin)];
117
+
118
+ const parsedBefore = parseSemver(beforeVersion);
119
+ const parsedAfter = parseSemver(afterVersion);
120
+ const adjacentPatch =
121
+ parsedBefore &&
122
+ parsedAfter &&
123
+ parsedBefore[0] === parsedAfter[0] &&
124
+ parsedBefore[1] === parsedAfter[1] &&
125
+ parsedAfter[2] === parsedBefore[2] + 1;
126
+ const adjacentMinorBoundary =
127
+ parsedBefore &&
128
+ parsedAfter &&
129
+ parsedBefore[0] === parsedAfter[0] &&
130
+ parsedAfter[1] === parsedBefore[1] + 1 &&
131
+ parsedAfter[2] === 0;
132
+ const currentReleaseBoundary =
133
+ beforeVersion === PREVIOUS_PILOT_VERSION && afterVersion === PILOT_VERSION;
134
+ return adjacentPatch || adjacentMinorBoundary || currentReleaseBoundary
135
+ ? []
136
+ : ["incompatible-core-chain"];
137
+ }
138
+
139
+ export function checkAdapterUpgradeChain(chainRootInput, options = {}) {
140
+ const discovery = discoverRevisions(chainRootInput);
141
+ if (!discovery.ok) {
142
+ return {
143
+ ...baseFailure(discovery.codes[0]),
144
+ revisionCount: discovery.revisions?.length ?? 0,
145
+ codes: discovery.codes,
146
+ };
147
+ }
148
+
149
+ const coreRoot = path.resolve(options.coreRoot ?? DEFAULT_CORE_ROOT);
150
+ const transitions = [];
151
+ const chainCodes = new Set();
152
+
153
+ for (let index = 0; index < discovery.revisions.length - 1; index += 1) {
154
+ const beforeRoot = discovery.revisions[index].root;
155
+ const afterRoot = discovery.revisions[index + 1].root;
156
+ const targetCoreVersion = expectedVersion(afterRoot) ?? PILOT_VERSION;
157
+ const result = checkAdapterUpgrade(beforeRoot, afterRoot, {
158
+ coreRoot,
159
+ targetCoreVersion,
160
+ });
161
+ const codes = new Set([
162
+ ...result.codes,
163
+ ...progressionCodes(beforeRoot, afterRoot),
164
+ ]);
165
+ for (const code of codes) chainCodes.add(code);
166
+ transitions.push({
167
+ stepIndex: index + 1,
168
+ ok: codes.size === 0,
169
+ codes: [...codes].sort(),
170
+ result,
171
+ });
172
+ }
173
+
174
+ const lastVersion = expectedVersion(discovery.revisions.at(-1).root);
175
+ if (lastVersion !== PILOT_VERSION) chainCodes.add("chain-target-stale");
176
+
177
+ const firstContext = transitions[0]?.result.context?.before;
178
+ const lastContext = transitions.at(-1)?.result.context?.after;
179
+ const passedTransitions = transitions.filter((transition) => transition.ok).length;
180
+ const failedTransitions = transitions.length - passedTransitions;
181
+ const ok = chainCodes.size === 0 && failedTransitions === 0;
182
+
183
+ return {
184
+ ok,
185
+ status: ok ? "complete" : "failed",
186
+ revisionCount: discovery.revisions.length,
187
+ transitionCount: transitions.length,
188
+ passedTransitions,
189
+ failedTransitions,
190
+ transitions,
191
+ codes: [...chainCodes].sort(),
192
+ targetCoreVersion: PILOT_VERSION,
193
+ context: {
194
+ before: firstContext,
195
+ after: lastContext,
196
+ },
197
+ };
198
+ }
199
+
200
+ export function formatAdapterChainSummary(result) {
201
+ if (result.ok) {
202
+ return [
203
+ `adapter upgrade chain complete: ${result.revisionCount} revisions, ` +
204
+ `${result.transitionCount} transitions accepted`,
205
+ ];
206
+ }
207
+ return [
208
+ `adapter upgrade chain failed: ${result.failedTransitions} of ` +
209
+ `${result.transitionCount} transitions rejected`,
210
+ `rejection codes: ${result.codes.join(",")}`,
211
+ ];
212
+ }
213
+
214
+ export function adapterChainCliResult(chainRoot, options = {}) {
215
+ if (!chainRoot) {
216
+ return {
217
+ exitCode: 2,
218
+ stream: "stderr",
219
+ lines: [
220
+ "usage: node scripts/check-adapter-upgrade-chain.mjs " +
221
+ "<chain-root> [--json | --output <file>]",
222
+ ],
223
+ };
224
+ }
225
+
226
+ const result = checkAdapterUpgradeChain(chainRoot, options);
227
+ const evidence = buildAdapterChainEvidence(result, options);
228
+ if (options.output) {
229
+ const written = writeSafeEvidenceJson(options.output, evidence, {
230
+ baseDirectory: options.outputBase,
231
+ });
232
+ if (!written.ok) {
233
+ return {
234
+ exitCode: 2,
235
+ stream: "stderr",
236
+ lines: [`adapter chain evidence output failed: ${written.code}`],
237
+ result,
238
+ evidence,
239
+ };
240
+ }
241
+ }
242
+ if (options.json) {
243
+ return {
244
+ exitCode: result.ok ? 0 : 1,
245
+ stream: "stdout",
246
+ lines: [JSON.stringify(evidence, null, 2)],
247
+ result,
248
+ evidence,
249
+ };
250
+ }
251
+ return {
252
+ exitCode: result.ok ? 0 : 1,
253
+ stream: result.ok ? "stdout" : "stderr",
254
+ lines: [
255
+ ...formatAdapterChainSummary(result),
256
+ ...(options.output ? ["sanitized evidence output written"] : []),
257
+ ],
258
+ result,
259
+ evidence,
260
+ };
261
+ }