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,704 @@
1
+ export const PILOT_SKILLS = [
2
+ "repo-map",
3
+ "build-verify",
4
+ "git-preflight",
5
+ "runtime-truth",
6
+ "llm-drift-control",
7
+ ];
8
+
9
+ export const PILOT_VERSION = "0.2.3";
10
+ export const PREVIOUS_PILOT_VERSION = "0.2.2";
11
+
12
+ export const AUDIT_ONLY_SKILLS = [
13
+ "repo-map",
14
+ "git-preflight",
15
+ "runtime-truth",
16
+ "llm-drift-control",
17
+ ];
18
+
19
+ export const RESTRICTED_CATEGORIES = [
20
+ "file-write",
21
+ "package-install",
22
+ "deployment",
23
+ "git-mutation",
24
+ "unrestricted-scan",
25
+ "secret-read",
26
+ "process-mutation",
27
+ "service-mutation",
28
+ "migration-apply",
29
+ "privileged-api",
30
+ ];
31
+
32
+ const KNOWN_COMMANDS = new Set([
33
+ "./bin/coding-agent-skills",
34
+ "bin/coding-agent-skills",
35
+ "cat",
36
+ "coding-agent-skills",
37
+ "curl",
38
+ "docker",
39
+ "find",
40
+ "gh",
41
+ "git",
42
+ "head",
43
+ "jq",
44
+ "kill",
45
+ "ls",
46
+ "node",
47
+ "npm",
48
+ "npx",
49
+ "pgrep",
50
+ "pm2",
51
+ "pnpm",
52
+ "prisma",
53
+ "ps",
54
+ "pwd",
55
+ "rg",
56
+ "sed",
57
+ "ss",
58
+ "systemctl",
59
+ "touch",
60
+ "wrangler",
61
+ "yarn",
62
+ ]);
63
+
64
+ const SENSITIVE_PATTERNS = [
65
+ {
66
+ type: "private-key",
67
+ pattern:
68
+ /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/g,
69
+ },
70
+ {
71
+ type: "authorization-header",
72
+ pattern: /Authorization:\s*Bearer\s+[A-Za-z0-9._-]{8,}/gi,
73
+ },
74
+ {
75
+ type: "github-token",
76
+ pattern: /\bgh[pousr]_[A-Za-z0-9_]{16,}\b/g,
77
+ },
78
+ {
79
+ type: "github-token",
80
+ pattern: /\bgithub_pat_[A-Za-z0-9_]{16,}\b/gi,
81
+ },
82
+ {
83
+ type: "jwt",
84
+ pattern: /\beyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,
85
+ },
86
+ {
87
+ type: "url-credentials",
88
+ pattern: /\b[a-z][a-z0-9+.-]*:\/\/[^/\s:@]+:[^@\s/]+@[^\s]+/gi,
89
+ },
90
+ {
91
+ type: "env-secret",
92
+ pattern:
93
+ /(?:^|\n)[A-Z][A-Z0-9_]*(?:TOKEN|SECRET|PASSWORD|PRIVATE_KEY|DATABASE_URL|API_KEY)=[^\s]+/g,
94
+ },
95
+ {
96
+ type: "local-home-path",
97
+ pattern: /\/home\/[^/\s]+\/[^\s"'`]+/g,
98
+ },
99
+ {
100
+ type: "private-domain",
101
+ pattern: /\b(?:[a-z0-9-]+\.)+(?:internal|local|corp\.example\.invalid)\b/gi,
102
+ },
103
+ ];
104
+
105
+ function expectedMode(skill) {
106
+ return AUDIT_ONLY_SKILLS.includes(skill) ? "audit-only" : "action-capable";
107
+ }
108
+
109
+ function versionMatches(candidate, currentVersion) {
110
+ if (candidate === currentVersion) return true;
111
+ const [major, minor] = currentVersion.split(".");
112
+ return candidate === `${major}.${minor}.x`;
113
+ }
114
+
115
+ function hasMaterialRisk(risks = []) {
116
+ return risks.some((risk) => /\bmaterial\b/i.test(risk.summary ?? ""));
117
+ }
118
+
119
+ function hasSupportingEvidence(evidence) {
120
+ const successfulCommands = (evidence.commands ?? []).filter(
121
+ (command) => command.resultStatus === "success",
122
+ );
123
+ const findingReferences = (evidence.findings ?? []).flatMap(
124
+ (finding) => finding.evidence ?? [],
125
+ );
126
+ return successfulCommands.length > 0 || findingReferences.length > 0;
127
+ }
128
+
129
+ export function completionIssues(evidence) {
130
+ const issues = [];
131
+ const startedAt = Date.parse(evidence.invocation?.startedAt ?? "");
132
+ const endedAt = Date.parse(evidence.invocation?.endedAt ?? "");
133
+
134
+ if (!Number.isNaN(startedAt) && !Number.isNaN(endedAt) && endedAt < startedAt) {
135
+ issues.push("invocation ended before it started");
136
+ }
137
+
138
+ if (
139
+ AUDIT_ONLY_SKILLS.includes(evidence.skill?.name) &&
140
+ evidence.changedState?.changed === true
141
+ ) {
142
+ issues.push("audit-only skill reported a state change");
143
+ }
144
+
145
+ if (evidence.status === "complete") {
146
+ if (evidence.failures?.length) issues.push("complete evidence contains failures");
147
+ if (evidence.unresolvedQuestions?.length) {
148
+ issues.push("complete evidence contains unresolved questions");
149
+ }
150
+ if (evidence.skippedChecks?.some((check) => check.completionPermitted === false)) {
151
+ issues.push("complete evidence skipped a completion-blocking check");
152
+ }
153
+ if (
154
+ evidence.skippedChecks?.some(
155
+ (check) =>
156
+ !(check.reason ?? "").trim() || !(check.consequence ?? "").trim(),
157
+ )
158
+ ) {
159
+ issues.push("complete evidence contains a skipped check missing consequence or reason");
160
+ }
161
+ if (evidence.commands?.some((command) => command.resultStatus !== "success")) {
162
+ issues.push("complete evidence contains a non-success command");
163
+ }
164
+ if (hasMaterialRisk(evidence.risks)) {
165
+ issues.push("complete evidence contains an unresolved material risk");
166
+ }
167
+ if (
168
+ /\b(?:unknown|not determined|unverified|could not be determined)\b/i.test(
169
+ evidence.changedState?.summary ?? "",
170
+ )
171
+ ) {
172
+ issues.push("complete evidence state change is unknown");
173
+ }
174
+ if (!(evidence.confidence?.reason ?? "").trim()) {
175
+ issues.push("complete evidence lacks a confidence reason");
176
+ }
177
+ if (!evidence.repository?.root && !evidence.repository?.head) {
178
+ issues.push("complete evidence lacks repository identity");
179
+ }
180
+ if (!hasSupportingEvidence(evidence)) {
181
+ issues.push("complete evidence has no supporting evidence");
182
+ }
183
+ }
184
+
185
+ return issues;
186
+ }
187
+
188
+ export function adapterIssues(adapter, options = {}) {
189
+ const issues = [];
190
+ const skillVersion = options.skillVersion ?? PILOT_VERSION;
191
+
192
+ if (!adapter || typeof adapter !== "object") return ["adapter must be an object"];
193
+ if (!adapter.adapterId || typeof adapter.adapterId !== "string") {
194
+ issues.push("adapterId must be a non-empty string");
195
+ }
196
+ if (adapter.adapterVersion !== "1.0.0") issues.push("unsupported adapterVersion");
197
+
198
+ const supportedSkills = adapter.supportedSkills ?? [];
199
+ if (!Array.isArray(supportedSkills) || supportedSkills.length === 0) {
200
+ issues.push("adapter must declare supported skills");
201
+ }
202
+ for (const skill of supportedSkills) {
203
+ if (!PILOT_SKILLS.includes(skill.id)) {
204
+ issues.push(`unknown pilot skill: ${String(skill.id)}`);
205
+ continue;
206
+ }
207
+ if (skill.declaredMode !== expectedMode(skill.id)) {
208
+ issues.push(`adapter cannot override ${skill.id} mode`);
209
+ }
210
+ if (
211
+ !(skill.compatibleVersions ?? []).some((version) =>
212
+ versionMatches(version, skillVersion),
213
+ )
214
+ ) {
215
+ issues.push(`adapter is incompatible with ${skill.id} ${skillVersion}`);
216
+ }
217
+ }
218
+
219
+ const detection = adapter.project?.detection;
220
+ if (!detection || !Array.isArray(detection.rootMarkers) || !detection.rootMarkers.length) {
221
+ issues.push("project detection must include root markers");
222
+ }
223
+ if (detection?.scope !== "declared-project-root") {
224
+ issues.push("adapter scope must remain the declared project root");
225
+ }
226
+ if (detection?.requireApprovalOutsideScope !== true) {
227
+ issues.push("adapter must require approval outside declared scope");
228
+ }
229
+ if (!Number.isInteger(detection?.maximumDepth) || detection.maximumDepth < 0) {
230
+ issues.push("project detection maximumDepth must be a non-negative integer");
231
+ }
232
+
233
+ const relativePaths = [
234
+ ...(detection?.rootMarkers ?? []).map((marker) => marker.path),
235
+ ...(adapter.extensions?.safeReadPaths ?? []),
236
+ ...(adapter.extensions?.ignoredPaths ?? []),
237
+ ...(adapter.extensions?.documentationPrecedence ?? []),
238
+ ];
239
+ for (const candidate of relativePaths) {
240
+ if (
241
+ typeof candidate !== "string" ||
242
+ candidate === "." ||
243
+ candidate.startsWith("/") ||
244
+ candidate.split("/").includes("..") ||
245
+ /(^|\/)\.env(?:\.|$)/.test(candidate)
246
+ ) {
247
+ issues.push(`unsafe adapter path: ${String(candidate)}`);
248
+ }
249
+ }
250
+
251
+ const inheritance = adapter.inheritance ?? {};
252
+ const restrictions = new Set(inheritance.deniedOperationCategories ?? []);
253
+ for (const category of RESTRICTED_CATEGORIES) {
254
+ if (!restrictions.has(category)) {
255
+ issues.push(`adapter weakens required restriction: ${category}`);
256
+ }
257
+ }
258
+ if (inheritance.sharedRestrictions !== "required") {
259
+ issues.push("adapter must inherit shared restrictions");
260
+ }
261
+ const forbiddenInheritanceFlags = [
262
+ ["allowRestrictionRemoval", "remove shared restrictions"],
263
+ ["allowModeOverride", "override skill mode"],
264
+ ["allowFailureSuppression", "suppress failures"],
265
+ ["allowCompletionOverride", "redefine completion"],
266
+ ["allowSecretExposure", "expose secrets"],
267
+ ["allowRequiredEvidenceRemoval", "remove required evidence"],
268
+ ["allowScopeExpansionWithoutApproval", "expand scope without approval"],
269
+ ];
270
+ for (const [field, description] of forbiddenInheritanceFlags) {
271
+ if (inheritance[field] !== false) issues.push(`adapter cannot ${description}`);
272
+ }
273
+
274
+ const supportedIds = new Set(supportedSkills.map((skill) => skill.id));
275
+ for (const alias of adapter.extensions?.commandAliases ?? []) {
276
+ if (!supportedIds.has(alias.skillId)) {
277
+ issues.push(`command alias targets unsupported skill: ${String(alias.skillId)}`);
278
+ }
279
+ const policy = options.policies?.[alias.skillId];
280
+ const result = policy
281
+ ? commandPolicyDecision(alias.command, policy)
282
+ : analyzeCommand(alias.command);
283
+ if (!result.allowed) {
284
+ issues.push(`unsafe command alias ${alias.alias}: ${result.reasons.join(", ")}`);
285
+ }
286
+ if (policy && result.family !== alias.family) {
287
+ issues.push(
288
+ `command alias ${alias.alias} declares ${alias.family} but matches ${String(result.family)}`,
289
+ );
290
+ }
291
+ }
292
+ for (const status of adapter.extensions?.safeStatusCommands ?? []) {
293
+ const result = analyzeCommand(status.command);
294
+ if (!result.allowed) {
295
+ issues.push(`unsafe status command: ${result.reasons.join(", ")}`);
296
+ }
297
+ if (
298
+ !/^(?:systemctl\s+(?:--user\s+)?status|pm2\s+(?:list|status)|docker\s+(?:ps|inspect)|ps\b|pgrep\b|ss\b)/.test(
299
+ status.command,
300
+ )
301
+ ) {
302
+ issues.push("adapter status command is not status-only");
303
+ }
304
+ }
305
+ if (
306
+ (adapter.extensions?.safeStatusCommands ?? []).length > 0 &&
307
+ !supportedIds.has("runtime-truth")
308
+ ) {
309
+ issues.push("status commands require runtime-truth compatibility");
310
+ }
311
+ if (
312
+ !Array.isArray(adapter.extensions?.requiredEvidence) ||
313
+ adapter.extensions.requiredEvidence.length === 0
314
+ ) {
315
+ issues.push("adapter cannot remove required evidence");
316
+ } else if (
317
+ adapter.extensions.requiredEvidence.some(
318
+ (evidence) => typeof evidence !== "string" || !evidence.trim(),
319
+ )
320
+ ) {
321
+ issues.push("adapter required evidence must be explicit");
322
+ }
323
+
324
+ return issues;
325
+ }
326
+
327
+ export function classifyTrigger(prompt) {
328
+ const text = prompt.toLowerCase();
329
+
330
+ if (
331
+ /\b(?:deploy|install|update the lockfile|commit these|publish the branch|restart|enable it|rewrite the documentation)\b/.test(
332
+ text,
333
+ )
334
+ ) {
335
+ return null;
336
+ }
337
+ if (
338
+ /\b(?:disagree|contradict|reconcile|classify the claim|claim.*(?:stale|wrong)|docs?.*code)\b/.test(
339
+ text,
340
+ )
341
+ ) {
342
+ return "llm-drift-control";
343
+ }
344
+ if (
345
+ /\b(?:actually running|claimed to be live|live state|listener|health endpoint|expected port|process.*running)\b/.test(
346
+ text,
347
+ )
348
+ ) {
349
+ return "runtime-truth";
350
+ }
351
+ if (
352
+ /\b(?:git working tree|staged files?|untracked files?|whitespace state|ready for push|before i commit|branch.*head)\b/.test(
353
+ text,
354
+ )
355
+ ) {
356
+ return "git-preflight";
357
+ }
358
+ if (
359
+ /\b(?:typecheck|project-native|test and build|tests and build|validate the changed code|implementation is finished)\b/.test(
360
+ text,
361
+ )
362
+ ) {
363
+ return "build-verify";
364
+ }
365
+ if (
366
+ /\b(?:unfamiliar repository|canonical repository root|canonical repo|map the current packages|map this repository|identify its entry points|nested directory)\b/.test(
367
+ text,
368
+ )
369
+ ) {
370
+ return "repo-map";
371
+ }
372
+
373
+ return null;
374
+ }
375
+
376
+ function splitShellSegments(command) {
377
+ const segments = [];
378
+ let current = "";
379
+ let quote = null;
380
+
381
+ for (let index = 0; index < command.length; index += 1) {
382
+ const character = command[index];
383
+ const next = command[index + 1];
384
+
385
+ if (quote) {
386
+ current += character;
387
+ if (character === quote && command[index - 1] !== "\\") quote = null;
388
+ continue;
389
+ }
390
+ if (character === "'" || character === '"') {
391
+ quote = character;
392
+ current += character;
393
+ continue;
394
+ }
395
+ if (character === "\n" || character === ";" || character === "|") {
396
+ if (character === "|" && next === "|") index += 1;
397
+ if (current.trim()) segments.push(current.trim());
398
+ current = "";
399
+ continue;
400
+ }
401
+ if (character === "&" && next === "&") {
402
+ index += 1;
403
+ if (current.trim()) segments.push(current.trim());
404
+ current = "";
405
+ continue;
406
+ }
407
+ current += character;
408
+ }
409
+
410
+ if (current.trim()) segments.push(current.trim());
411
+ return { segments, balanced: quote === null };
412
+ }
413
+
414
+ function firstToken(segment) {
415
+ return segment.trim().split(/\s+/)[0]?.replace(/^['"]|['"]$/g, "");
416
+ }
417
+
418
+ function classifySegment(segment, options = {}) {
419
+ if (/(?:^|\s)(?:source|\.)\s+[^\s]*\.env\b/.test(segment) || /\bcat\s+[^\s]*\.env\b/.test(segment)) {
420
+ return "secret-file read";
421
+ }
422
+ if (/\bgit\s+(?:add|commit|push|pull|fetch|merge|rebase|reset|restore|clean|checkout|switch|stash|tag|update-index)\b/.test(segment)) {
423
+ return "Git mutation";
424
+ }
425
+ if (/\b(?:npm\s+(?:install|ci)|pnpm\s+(?:add|install)|yarn\s+(?:add|install))\b/.test(segment)) {
426
+ return "package installation";
427
+ }
428
+ if (/\bnpx\s+wrangler\b/.test(segment)) {
429
+ return "npx wrangler is deployment-capable";
430
+ }
431
+ if (/\bnpx\s+supabase\b/.test(segment)) {
432
+ return "npx supabase is database-capable";
433
+ }
434
+ if (/\b(?:wrangler|vercel|netlify)\s+(?:deploy|publish)\b/.test(segment)) {
435
+ return "deployment";
436
+ }
437
+ if (/\b(?:supabase\s+db\s+push|prisma\s+migrate|sequelize\s+db:migrate)\b/.test(segment)) {
438
+ return "migration application";
439
+ }
440
+ if (
441
+ /\bsystemctl(?:\s+--user)?\s+(?:start|stop|restart|reload|enable|disable)\b/.test(
442
+ segment,
443
+ ) ||
444
+ /\bpm2\s+(?:start|stop|restart|reload|save)\b/.test(segment)
445
+ ) {
446
+ return "service mutation";
447
+ }
448
+ if (/\b(?:kill|pkill|killall)\b/.test(segment)) return "process mutation";
449
+ if (/\bgh\s+api\b/.test(segment)) return "privileged API";
450
+ if (/\b(?:rm|mv|cp|touch|mkdir|chmod|chown|tee)\b/.test(segment)) {
451
+ return "filesystem mutation";
452
+ }
453
+ if (/\bnpx\b/.test(segment)) return "npx execution is not allowlisted";
454
+ if (
455
+ /\bcurl\b.*(?:Authorization:|--user|-u\s|--data(?:-raw|-binary)?|-d\s|--form|-F\s|--upload-file|-T\s)/i.test(
456
+ segment,
457
+ )
458
+ ) {
459
+ const isAuthenticated = /Authorization:|--user|-u\s/i.test(segment);
460
+ const url = segment.match(/https?:\/\/[^\s'"]+/i)?.[0];
461
+ if (
462
+ isAuthenticated &&
463
+ options.approvals?.includes("authenticated-local-health") &&
464
+ /^http:\/\/(?:127\.0\.0\.1|localhost)(?::\d+)?\/.*health/i.test(url ?? "")
465
+ ) {
466
+ return null;
467
+ }
468
+ return isAuthenticated ? "authenticated HTTP request" : "mutating HTTP request";
469
+ }
470
+ if (/\bcurl\b\s+\S*https?:\/\/[^/\s:@]+:[^@\s/]+@/i.test(segment)) {
471
+ return "URL credentials";
472
+ }
473
+ if (/\bfind\s+(?:\/|\/home\b|~)\b/.test(segment) || (/\bfind\b/.test(segment) && !/-maxdepth\s+\d+/.test(segment))) {
474
+ return "unbounded filesystem scan";
475
+ }
476
+ if (/\b(?:sed|head|jq|rg|ls)\b.*(?:\/home\/|~\/)/.test(segment)) {
477
+ return "read path is outside declared scope";
478
+ }
479
+ if (/\bnpm\s+run\s+\S*(?:fix|deploy|migrate|install|snapshot|update|watch|dev|start)\S*/i.test(segment)) {
480
+ return "unsafe npm script";
481
+ }
482
+
483
+ const executable = firstToken(segment);
484
+ if (!KNOWN_COMMANDS.has(executable)) return `executable not allowlisted: ${executable}`;
485
+
486
+ if (executable === "git") {
487
+ if (
488
+ !/^git\s+(?:rev-parse|remote\s+-v|status\b|branch\s+--show-current|log\b|diff\b|ls-files\b|show\b)/.test(
489
+ segment,
490
+ )
491
+ ) {
492
+ return "Git command is not read-only allowlisted";
493
+ }
494
+ }
495
+ if (executable === "npm" && !/^npm\s+(?:run\s+(?:lint|typecheck|test|build|check|validate)|test|pack\s+--dry-run\b)\b/.test(segment)) {
496
+ if (!/^npm\s+pkg\s+get\s+scripts\b/.test(segment)) return "unsafe npm script";
497
+ }
498
+ if (executable === "pnpm" && !/^pnpm\s+(?:run\s+)?(?:lint|typecheck|test|build|check|validate)\b/.test(segment)) {
499
+ return "unsafe pnpm script";
500
+ }
501
+ if (executable === "yarn" && !/^yarn\s+(?:run\s+)?(?:lint|typecheck|test|build|check|validate)\b/.test(segment)) {
502
+ return "unsafe yarn script";
503
+ }
504
+ if (
505
+ executable === "node" &&
506
+ !/^node\s+(?:--check\b|--test\b|scripts\/(?:validate-pack|validate-maintainer-loop|validate-adapters|validate-project-adapters|check-adapter-upgrade|check-adapter-upgrade-chain|verify-evidence-bundle|render-evidence-archive-report|render-adapter-repo-map|test-pack)\.mjs\b)/.test(
507
+ segment,
508
+ )
509
+ ) {
510
+ return "node execution is not allowlisted";
511
+ }
512
+ if (
513
+ ["coding-agent-skills", "bin/coding-agent-skills", "./bin/coding-agent-skills"].includes(
514
+ executable,
515
+ ) &&
516
+ !/^(?:\.\/)?(?:bin\/)?coding-agent-skills\s+(?:validate-pack|validate-project\s+\S+|repo-map\s+\S+|validate-adapters\s+\S+|help|--help|-h)\s*$/.test(
517
+ segment,
518
+ )
519
+ ) {
520
+ return "local CLI command is not allowlisted";
521
+ }
522
+ if (executable === "systemctl" && !/^systemctl\s+(?:--user\s+)?status\b/.test(segment)) {
523
+ return "systemctl operation is not status-only";
524
+ }
525
+ if (executable === "pm2" && !/^pm2\s+(?:list|status)\b/.test(segment)) {
526
+ return "pm2 operation is not status-only";
527
+ }
528
+ if (executable === "docker" && !/^docker\s+(?:ps|inspect)\b/.test(segment)) {
529
+ return "docker operation is not status-only";
530
+ }
531
+ if (executable === "curl") {
532
+ const url = segment.match(/https?:\/\/[^\s'"]+/i)?.[0];
533
+ if (!url || !/^http:\/\/(?:127\.0\.0\.1|localhost)(?::\d+)?\//i.test(url)) {
534
+ return "curl target is not an approved local health endpoint";
535
+ }
536
+ }
537
+ if (executable === "cat") return "cat is not allowlisted for reusable procedures";
538
+ if (executable === "prisma" || executable === "wrangler") {
539
+ return `${executable} operation is not allowlisted`;
540
+ }
541
+
542
+ return null;
543
+ }
544
+
545
+ export function analyzeCommand(command, options = {}) {
546
+ const text = String(command ?? "").trim();
547
+ const policyText = text
548
+ .replace(/<port>/gi, "3000")
549
+ .replace(/<[A-Za-z][A-Za-z0-9_-]*>/g, "placeholder");
550
+ const reasons = [];
551
+
552
+ if (!text) return { allowed: false, reasons: ["empty command"], segments: [] };
553
+ if (/<<-?\s*['"]?[A-Za-z_][A-Za-z0-9_]*['"]?/.test(policyText)) {
554
+ reasons.push("heredoc is not allowed");
555
+ }
556
+ if (/(?:^|\s)(?:bash|sh|zsh|fish)\s+-c\b|\beval\b/.test(policyText)) {
557
+ reasons.push("shell wrapper is not allowed");
558
+ }
559
+ if (/\$\(|`/.test(policyText)) reasons.push("command substitution is not allowed");
560
+ if (/(?:^|\s)(?:>{1,2}|<{1,2})(?=\s|[./~A-Za-z0-9_-])/.test(policyText)) {
561
+ reasons.push("redirection is not allowed");
562
+ }
563
+
564
+ const parsed = splitShellSegments(policyText);
565
+ if (!parsed.balanced) reasons.push("unbalanced shell quoting");
566
+ for (const segment of parsed.segments) {
567
+ const reason = classifySegment(segment, options);
568
+ if (reason) reasons.push(reason);
569
+
570
+ const npmScript = segment.match(/^npm\s+run\s+([^\s]+)/)?.[1];
571
+ if (npmScript && options.scripts) {
572
+ if (!Object.hasOwn(options.scripts, npmScript)) {
573
+ reasons.push(`npm script is not defined: ${npmScript}`);
574
+ } else {
575
+ const scriptResult = analyzeCommand(options.scripts[npmScript]);
576
+ if (!scriptResult.allowed) {
577
+ reasons.push(
578
+ `npm script definition is unsafe: ${scriptResult.reasons.join(", ")}`,
579
+ );
580
+ }
581
+ }
582
+ }
583
+ }
584
+
585
+ return {
586
+ allowed: reasons.length === 0,
587
+ reasons: [...new Set(reasons)],
588
+ segments: parsed.segments,
589
+ };
590
+ }
591
+
592
+ export function commandPolicyDecision(command, policy, options = {}) {
593
+ const analysis = analyzeCommand(command, options);
594
+ const executable = firstToken(analysis.segments[0] ?? "");
595
+ const family = policy.allowedFamilies?.find((candidate) =>
596
+ candidate.executables.includes(executable),
597
+ );
598
+ const reasons = [...analysis.reasons];
599
+
600
+ if (!family) reasons.push(`executable is not allowed by policy: ${executable}`);
601
+ if (
602
+ analysis.segments.length > 1 &&
603
+ policy.parserPolicy?.allowedComposition !== "read-only"
604
+ ) {
605
+ reasons.push("policy does not allow command composition");
606
+ }
607
+
608
+ return {
609
+ allowed: reasons.length === 0,
610
+ family: family?.name ?? null,
611
+ reasons: [...new Set(reasons)],
612
+ segments: analysis.segments,
613
+ };
614
+ }
615
+
616
+ export function restrictedShellReason(command) {
617
+ if (!String(command ?? "").trim() || String(command).trim().startsWith("#")) return null;
618
+ return analyzeCommand(command).reasons[0] ?? null;
619
+ }
620
+
621
+ function isDeniedContext(line, deniedSection) {
622
+ return (
623
+ deniedSection ||
624
+ /\b(?:do not|never|must not|cannot|reject|denied|unsafe|prohibit|restricted|outside this skill|without performing)\b/i.test(
625
+ line,
626
+ )
627
+ );
628
+ }
629
+
630
+ export function commandLooksExecutable(value) {
631
+ return KNOWN_COMMANDS.has(firstToken(value));
632
+ }
633
+
634
+ export function auditOnlyDocumentIssues(markdown) {
635
+ const issues = [];
636
+ let deniedSection = false;
637
+ let inShellFence = false;
638
+
639
+ for (const [index, line] of String(markdown).split(/\r?\n/).entries()) {
640
+ if (/^#{1,6}\s+/.test(line)) {
641
+ deniedSection = /\b(?:unsafe|denied|restricted|approval boundary|safety boundary)\b/i.test(
642
+ line,
643
+ );
644
+ }
645
+ if (/^```(?:bash|sh|shell)\s*$/.test(line)) {
646
+ inShellFence = true;
647
+ continue;
648
+ }
649
+ if (/^```\s*$/.test(line)) {
650
+ inShellFence = false;
651
+ continue;
652
+ }
653
+
654
+ const candidates = [];
655
+ if (inShellFence && line.trim()) candidates.push(line.trim());
656
+ for (const match of line.matchAll(/`([^`\n]+)`/g)) {
657
+ if (commandLooksExecutable(match[1])) candidates.push(match[1]);
658
+ }
659
+
660
+ for (const candidate of candidates) {
661
+ const result = analyzeCommand(candidate);
662
+ if (!result.allowed && !isDeniedContext(line, deniedSection)) {
663
+ issues.push({
664
+ line: index + 1,
665
+ command: candidate,
666
+ reasons: result.reasons,
667
+ });
668
+ }
669
+ }
670
+
671
+ if (
672
+ !isDeniedContext(line, deniedSection) &&
673
+ /^\s*(?:\d+\.\s+|[-*]\s+)?(?:run\s+)?(?:install|deploy|restart|kill|commit|push|stage|write|delete|migrate|source\s+\S*\.env|read\s+\S*\.env|scan\s+(?:\/home|the home directory))\b/i.test(
674
+ line,
675
+ )
676
+ ) {
677
+ issues.push({
678
+ line: index + 1,
679
+ command: line.trim(),
680
+ reasons: ["plain-language mutation instruction"],
681
+ });
682
+ }
683
+ }
684
+
685
+ return issues;
686
+ }
687
+
688
+ export function detectSensitiveValues(text) {
689
+ const findings = [];
690
+ for (const { type, pattern } of SENSITIVE_PATTERNS) {
691
+ pattern.lastIndex = 0;
692
+ if (pattern.test(String(text))) findings.push(type);
693
+ }
694
+ return [...new Set(findings)];
695
+ }
696
+
697
+ export function redactSensitiveText(text) {
698
+ let redacted = String(text);
699
+ for (const { type, pattern } of SENSITIVE_PATTERNS) {
700
+ pattern.lastIndex = 0;
701
+ redacted = redacted.replace(pattern, `[REDACTED:${type}]`);
702
+ }
703
+ return redacted;
704
+ }