@sun-asterisk/sungen 3.2.34 → 3.3.0-alpha.2

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 (889) hide show
  1. package/dist/basis/anchor-grammar.d.ts +32 -0
  2. package/dist/basis/anchor-grammar.d.ts.map +1 -0
  3. package/dist/basis/anchor-grammar.js +82 -0
  4. package/dist/basis/anchor-grammar.js.map +1 -0
  5. package/dist/basis/anchor-hash.d.ts +6 -0
  6. package/dist/basis/anchor-hash.d.ts.map +1 -0
  7. package/dist/basis/anchor-hash.js +28 -0
  8. package/dist/basis/anchor-hash.js.map +1 -0
  9. package/dist/basis/bm51-tables.d.ts +20 -0
  10. package/dist/basis/bm51-tables.d.ts.map +1 -0
  11. package/dist/basis/bm51-tables.js +71 -0
  12. package/dist/basis/bm51-tables.js.map +1 -0
  13. package/dist/basis/extract-spec-anchors.d.ts +39 -0
  14. package/dist/basis/extract-spec-anchors.d.ts.map +1 -0
  15. package/dist/basis/extract-spec-anchors.js +81 -0
  16. package/dist/basis/extract-spec-anchors.js.map +1 -0
  17. package/dist/basis/migration-sentinel.d.ts +47 -0
  18. package/dist/basis/migration-sentinel.d.ts.map +1 -0
  19. package/dist/basis/migration-sentinel.js +219 -0
  20. package/dist/basis/migration-sentinel.js.map +1 -0
  21. package/dist/basis/spec-frontmatter.d.ts +18 -0
  22. package/dist/basis/spec-frontmatter.d.ts.map +1 -0
  23. package/dist/basis/spec-frontmatter.js +55 -0
  24. package/dist/basis/spec-frontmatter.js.map +1 -0
  25. package/dist/basis/spec-sections.d.ts +18 -0
  26. package/dist/basis/spec-sections.d.ts.map +1 -0
  27. package/dist/basis/spec-sections.js +27 -0
  28. package/dist/basis/spec-sections.js.map +1 -0
  29. package/dist/basis/test-basis-schema.d.ts +28 -0
  30. package/dist/basis/test-basis-schema.d.ts.map +1 -0
  31. package/dist/basis/test-basis-schema.js +141 -0
  32. package/dist/basis/test-basis-schema.js.map +1 -0
  33. package/dist/capabilities/discover.d.ts +4 -0
  34. package/dist/capabilities/discover.d.ts.map +1 -1
  35. package/dist/capabilities/discover.js +16 -2
  36. package/dist/capabilities/discover.js.map +1 -1
  37. package/dist/capabilities/registry.d.ts +15 -0
  38. package/dist/capabilities/registry.d.ts.map +1 -1
  39. package/dist/capabilities/registry.js.map +1 -1
  40. package/dist/cli/commands/audit.d.ts.map +1 -1
  41. package/dist/cli/commands/audit.js +10 -5
  42. package/dist/cli/commands/audit.js.map +1 -1
  43. package/dist/cli/commands/capability.d.ts.map +1 -1
  44. package/dist/cli/commands/capability.js +6 -2
  45. package/dist/cli/commands/capability.js.map +1 -1
  46. package/dist/cli/commands/contract-derive-command.d.ts +11 -0
  47. package/dist/cli/commands/contract-derive-command.d.ts.map +1 -0
  48. package/dist/cli/commands/contract-derive-command.js +99 -0
  49. package/dist/cli/commands/contract-derive-command.js.map +1 -0
  50. package/dist/cli/commands/contract.d.ts +17 -0
  51. package/dist/cli/commands/contract.d.ts.map +1 -0
  52. package/dist/cli/commands/contract.js +162 -0
  53. package/dist/cli/commands/contract.js.map +1 -0
  54. package/dist/cli/commands/defect.d.ts +7 -0
  55. package/dist/cli/commands/defect.d.ts.map +1 -0
  56. package/dist/cli/commands/defect.js +68 -0
  57. package/dist/cli/commands/defect.js.map +1 -0
  58. package/dist/cli/commands/delivery.d.ts.map +1 -1
  59. package/dist/cli/commands/delivery.js +96 -12
  60. package/dist/cli/commands/delivery.js.map +1 -1
  61. package/dist/cli/commands/generate.d.ts.map +1 -1
  62. package/dist/cli/commands/generate.js +3 -1
  63. package/dist/cli/commands/generate.js.map +1 -1
  64. package/dist/cli/commands/journey.d.ts.map +1 -1
  65. package/dist/cli/commands/journey.js +43 -15
  66. package/dist/cli/commands/journey.js.map +1 -1
  67. package/dist/cli/commands/next.d.ts +8 -0
  68. package/dist/cli/commands/next.d.ts.map +1 -1
  69. package/dist/cli/commands/next.js +68 -8
  70. package/dist/cli/commands/next.js.map +1 -1
  71. package/dist/cli/commands/triage.d.ts +7 -0
  72. package/dist/cli/commands/triage.d.ts.map +1 -0
  73. package/dist/cli/commands/triage.js +98 -0
  74. package/dist/cli/commands/triage.js.map +1 -0
  75. package/dist/cli/commands/update.d.ts +11 -0
  76. package/dist/cli/commands/update.d.ts.map +1 -1
  77. package/dist/cli/commands/update.js +31 -6
  78. package/dist/cli/commands/update.js.map +1 -1
  79. package/dist/cli/index.js +24 -33
  80. package/dist/cli/index.js.map +1 -1
  81. package/dist/cli/project-sungen-invocation.d.ts +7 -0
  82. package/dist/cli/project-sungen-invocation.d.ts.map +1 -0
  83. package/dist/cli/project-sungen-invocation.js +76 -0
  84. package/dist/cli/project-sungen-invocation.js.map +1 -0
  85. package/dist/contract/approve-contract.d.ts +31 -0
  86. package/dist/contract/approve-contract.d.ts.map +1 -0
  87. package/dist/contract/approve-contract.js +87 -0
  88. package/dist/contract/approve-contract.js.map +1 -0
  89. package/dist/contract/assertion-matcher-vocabulary.d.ts +24 -0
  90. package/dist/contract/assertion-matcher-vocabulary.d.ts.map +1 -0
  91. package/dist/contract/assertion-matcher-vocabulary.js +100 -0
  92. package/dist/contract/assertion-matcher-vocabulary.js.map +1 -0
  93. package/dist/contract/build-contract-verdict.d.ts +32 -0
  94. package/dist/contract/build-contract-verdict.d.ts.map +1 -0
  95. package/dist/contract/build-contract-verdict.js +123 -0
  96. package/dist/contract/build-contract-verdict.js.map +1 -0
  97. package/dist/contract/build-trace-conformance.d.ts +18 -0
  98. package/dist/contract/build-trace-conformance.d.ts.map +1 -0
  99. package/dist/contract/build-trace-conformance.js +153 -0
  100. package/dist/contract/build-trace-conformance.js.map +1 -0
  101. package/dist/contract/classify-contract-change.d.ts +23 -0
  102. package/dist/contract/classify-contract-change.d.ts.map +1 -0
  103. package/dist/contract/classify-contract-change.js +98 -0
  104. package/dist/contract/classify-contract-change.js.map +1 -0
  105. package/dist/contract/classify-contract-unit.d.ts +18 -0
  106. package/dist/contract/classify-contract-unit.d.ts.map +1 -0
  107. package/dist/contract/classify-contract-unit.js +49 -0
  108. package/dist/contract/classify-contract-unit.js.map +1 -0
  109. package/dist/contract/classify-trace-conformance.d.ts +32 -0
  110. package/dist/contract/classify-trace-conformance.d.ts.map +1 -0
  111. package/dist/contract/classify-trace-conformance.js +117 -0
  112. package/dist/contract/classify-trace-conformance.js.map +1 -0
  113. package/dist/contract/contract-git.d.ts +24 -0
  114. package/dist/contract/contract-git.d.ts.map +1 -0
  115. package/dist/contract/contract-git.js +144 -0
  116. package/dist/contract/contract-git.js.map +1 -0
  117. package/dist/contract/contract-hash.d.ts +7 -0
  118. package/dist/contract/contract-hash.d.ts.map +1 -0
  119. package/dist/contract/contract-hash.js +38 -0
  120. package/dist/contract/contract-hash.js.map +1 -0
  121. package/dist/contract/contract-report-file.d.ts +4 -0
  122. package/dist/contract/contract-report-file.d.ts.map +1 -0
  123. package/dist/contract/contract-report-file.js +60 -0
  124. package/dist/contract/contract-report-file.js.map +1 -0
  125. package/dist/contract/contract-schema.d.ts +71 -0
  126. package/dist/contract/contract-schema.d.ts.map +1 -0
  127. package/dist/contract/contract-schema.js +102 -0
  128. package/dist/contract/contract-schema.js.map +1 -0
  129. package/dist/contract/contract-units.d.ts +12 -0
  130. package/dist/contract/contract-units.d.ts.map +1 -0
  131. package/dist/contract/contract-units.js +96 -0
  132. package/dist/contract/contract-units.js.map +1 -0
  133. package/dist/contract/contracts-lock-file.d.ts +24 -0
  134. package/dist/contract/contracts-lock-file.d.ts.map +1 -0
  135. package/dist/contract/contracts-lock-file.js +140 -0
  136. package/dist/contract/contracts-lock-file.js.map +1 -0
  137. package/dist/contract/data-normalize.d.ts +10 -0
  138. package/dist/contract/data-normalize.d.ts.map +1 -0
  139. package/dist/contract/data-normalize.js +110 -0
  140. package/dist/contract/data-normalize.js.map +1 -0
  141. package/dist/contract/derive-free-feature.d.ts +38 -0
  142. package/dist/contract/derive-free-feature.d.ts.map +1 -0
  143. package/dist/contract/derive-free-feature.js +154 -0
  144. package/dist/contract/derive-free-feature.js.map +1 -0
  145. package/dist/contract/field-semantic-redaction.d.ts +21 -0
  146. package/dist/contract/field-semantic-redaction.d.ts.map +1 -0
  147. package/dist/contract/field-semantic-redaction.js +118 -0
  148. package/dist/contract/field-semantic-redaction.js.map +1 -0
  149. package/dist/contract/free-feature-blocks.d.ts +10 -0
  150. package/dist/contract/free-feature-blocks.d.ts.map +1 -0
  151. package/dist/contract/free-feature-blocks.js +94 -0
  152. package/dist/contract/free-feature-blocks.js.map +1 -0
  153. package/dist/contract/lock-secret-guard.d.ts +22 -0
  154. package/dist/contract/lock-secret-guard.d.ts.map +1 -0
  155. package/dist/contract/lock-secret-guard.js +134 -0
  156. package/dist/contract/lock-secret-guard.js.map +1 -0
  157. package/dist/contract/lock-vs-git-head.d.ts +26 -0
  158. package/dist/contract/lock-vs-git-head.d.ts.map +1 -0
  159. package/dist/contract/lock-vs-git-head.js +28 -0
  160. package/dist/contract/lock-vs-git-head.js.map +1 -0
  161. package/dist/contract/normalize-contract-step.d.ts +21 -0
  162. package/dist/contract/normalize-contract-step.d.ts.map +1 -0
  163. package/dist/contract/normalize-contract-step.js +70 -0
  164. package/dist/contract/normalize-contract-step.js.map +1 -0
  165. package/dist/contract/normalize-feature-steps.d.ts +7 -0
  166. package/dist/contract/normalize-feature-steps.d.ts.map +1 -0
  167. package/dist/contract/normalize-feature-steps.js +127 -0
  168. package/dist/contract/normalize-feature-steps.js.map +1 -0
  169. package/dist/contract/oracle-strength.d.ts +12 -0
  170. package/dist/contract/oracle-strength.d.ts.map +1 -0
  171. package/dist/contract/oracle-strength.js +88 -0
  172. package/dist/contract/oracle-strength.js.map +1 -0
  173. package/dist/contract/project-contract-blockers.d.ts +10 -0
  174. package/dist/contract/project-contract-blockers.d.ts.map +1 -0
  175. package/dist/contract/project-contract-blockers.js +73 -0
  176. package/dist/contract/project-contract-blockers.js.map +1 -0
  177. package/dist/contract/record-contract-approval.d.ts +21 -0
  178. package/dist/contract/record-contract-approval.d.ts.map +1 -0
  179. package/dist/contract/record-contract-approval.js +98 -0
  180. package/dist/contract/record-contract-approval.js.map +1 -0
  181. package/dist/contract/render-free-gherkin.d.ts +40 -0
  182. package/dist/contract/render-free-gherkin.d.ts.map +1 -0
  183. package/dist/contract/render-free-gherkin.js +141 -0
  184. package/dist/contract/render-free-gherkin.js.map +1 -0
  185. package/dist/contract/render-trace-sentence.d.ts +20 -0
  186. package/dist/contract/render-trace-sentence.d.ts.map +1 -0
  187. package/dist/contract/render-trace-sentence.js +109 -0
  188. package/dist/contract/render-trace-sentence.js.map +1 -0
  189. package/dist/contract/render-trace-target.d.ts +14 -0
  190. package/dist/contract/render-trace-target.d.ts.map +1 -0
  191. package/dist/contract/render-trace-target.js +70 -0
  192. package/dist/contract/render-trace-target.js.map +1 -0
  193. package/dist/contract/resolve-unit-trace-identities.d.ts +8 -0
  194. package/dist/contract/resolve-unit-trace-identities.d.ts.map +1 -0
  195. package/dist/contract/resolve-unit-trace-identities.js +78 -0
  196. package/dist/contract/resolve-unit-trace-identities.js.map +1 -0
  197. package/dist/contract/trace/collect-trace-evidence.d.ts +33 -0
  198. package/dist/contract/trace/collect-trace-evidence.d.ts.map +1 -0
  199. package/dist/contract/trace/collect-trace-evidence.js +161 -0
  200. package/dist/contract/trace/collect-trace-evidence.js.map +1 -0
  201. package/dist/contract/trace/identity-cache.d.ts +19 -0
  202. package/dist/contract/trace/identity-cache.d.ts.map +1 -0
  203. package/dist/contract/trace/identity-cache.js +104 -0
  204. package/dist/contract/trace/identity-cache.js.map +1 -0
  205. package/dist/contract/trace/select-final-attempt.d.ts +27 -0
  206. package/dist/contract/trace/select-final-attempt.d.ts.map +1 -0
  207. package/dist/contract/trace/select-final-attempt.js +116 -0
  208. package/dist/contract/trace/select-final-attempt.js.map +1 -0
  209. package/dist/contract/trace/snapshot-html-renderer.d.ts +31 -0
  210. package/dist/contract/trace/snapshot-html-renderer.d.ts.map +1 -0
  211. package/dist/contract/trace/snapshot-html-renderer.js +172 -0
  212. package/dist/contract/trace/snapshot-html-renderer.js.map +1 -0
  213. package/dist/contract/trace/snapshot-resolver.d.ts +21 -0
  214. package/dist/contract/trace/snapshot-resolver.d.ts.map +1 -0
  215. package/dist/contract/trace/snapshot-resolver.js +65 -0
  216. package/dist/contract/trace/snapshot-resolver.js.map +1 -0
  217. package/dist/contract/trace/snapshot-store.d.ts +66 -0
  218. package/dist/contract/trace/snapshot-store.d.ts.map +1 -0
  219. package/dist/contract/trace/snapshot-store.js +173 -0
  220. package/dist/contract/trace/snapshot-store.js.map +1 -0
  221. package/dist/contract/trace/target-identity.d.ts +74 -0
  222. package/dist/contract/trace/target-identity.d.ts.map +1 -0
  223. package/dist/contract/trace/target-identity.js +68 -0
  224. package/dist/contract/trace/target-identity.js.map +1 -0
  225. package/dist/contract/trace/test-step-join.d.ts +65 -0
  226. package/dist/contract/trace/test-step-join.d.ts.map +1 -0
  227. package/dist/contract/trace/test-step-join.js +80 -0
  228. package/dist/contract/trace/test-step-join.js.map +1 -0
  229. package/dist/contract/trace/trace-binding.d.ts +21 -0
  230. package/dist/contract/trace/trace-binding.d.ts.map +1 -0
  231. package/dist/contract/trace/trace-binding.js +88 -0
  232. package/dist/contract/trace/trace-binding.js.map +1 -0
  233. package/dist/contract/trace/trace-file-reader.d.ts +41 -0
  234. package/dist/contract/trace/trace-file-reader.d.ts.map +1 -0
  235. package/dist/contract/trace/trace-file-reader.js +161 -0
  236. package/dist/contract/trace/trace-file-reader.js.map +1 -0
  237. package/dist/contract/trace/trace-fingerprint.d.ts +22 -0
  238. package/dist/contract/trace/trace-fingerprint.d.ts.map +1 -0
  239. package/dist/contract/trace/trace-fingerprint.js +96 -0
  240. package/dist/contract/trace/trace-fingerprint.js.map +1 -0
  241. package/dist/contract/trace/trace-identity-resolution.d.ts +26 -0
  242. package/dist/contract/trace/trace-identity-resolution.d.ts.map +1 -0
  243. package/dist/contract/trace/trace-identity-resolution.js +84 -0
  244. package/dist/contract/trace/trace-identity-resolution.js.map +1 -0
  245. package/dist/contract/trace/trace-run-record.d.ts +30 -0
  246. package/dist/contract/trace/trace-run-record.d.ts.map +1 -0
  247. package/dist/contract/trace/trace-run-record.js +121 -0
  248. package/dist/contract/trace/trace-run-record.js.map +1 -0
  249. package/dist/contract/trace/trace-steps.d.ts +19 -0
  250. package/dist/contract/trace/trace-steps.d.ts.map +1 -0
  251. package/dist/contract/trace/trace-steps.js +79 -0
  252. package/dist/contract/trace/trace-steps.js.map +1 -0
  253. package/dist/contract/trace/trace-zip-limits.d.ts +45 -0
  254. package/dist/contract/trace/trace-zip-limits.d.ts.map +1 -0
  255. package/dist/contract/trace/trace-zip-limits.js +52 -0
  256. package/dist/contract/trace/trace-zip-limits.js.map +1 -0
  257. package/dist/contract/trace/trace-zip-reader.d.ts +10 -0
  258. package/dist/contract/trace/trace-zip-reader.d.ts.map +1 -0
  259. package/dist/contract/trace/trace-zip-reader.js +186 -0
  260. package/dist/contract/trace/trace-zip-reader.js.map +1 -0
  261. package/dist/contract/verify-approval-decisions.d.ts +5 -0
  262. package/dist/contract/verify-approval-decisions.d.ts.map +1 -0
  263. package/dist/contract/verify-approval-decisions.js +104 -0
  264. package/dist/contract/verify-approval-decisions.js.map +1 -0
  265. package/dist/decisions/append-decision.d.ts +12 -0
  266. package/dist/decisions/append-decision.d.ts.map +1 -0
  267. package/dist/decisions/append-decision.js +73 -0
  268. package/dist/decisions/append-decision.js.map +1 -0
  269. package/dist/decisions/confirmed-decision-commands.d.ts +41 -0
  270. package/dist/decisions/confirmed-decision-commands.d.ts.map +1 -0
  271. package/dist/decisions/confirmed-decision-commands.js +190 -0
  272. package/dist/decisions/confirmed-decision-commands.js.map +1 -0
  273. package/dist/decisions/decision-file.d.ts +31 -0
  274. package/dist/decisions/decision-file.d.ts.map +1 -0
  275. package/dist/decisions/decision-file.js +139 -0
  276. package/dist/decisions/decision-file.js.map +1 -0
  277. package/dist/decisions/decision-identity.d.ts +12 -0
  278. package/dist/decisions/decision-identity.d.ts.map +1 -0
  279. package/dist/decisions/decision-identity.js +78 -0
  280. package/dist/decisions/decision-identity.js.map +1 -0
  281. package/dist/decisions/decision-integrity-check.d.ts +12 -0
  282. package/dist/decisions/decision-integrity-check.d.ts.map +1 -0
  283. package/dist/decisions/decision-integrity-check.js +102 -0
  284. package/dist/decisions/decision-integrity-check.js.map +1 -0
  285. package/dist/decisions/decision-schema.d.ts +42 -0
  286. package/dist/decisions/decision-schema.d.ts.map +1 -0
  287. package/dist/decisions/decision-schema.js +75 -0
  288. package/dist/decisions/decision-schema.js.map +1 -0
  289. package/dist/decisions/decision-source.d.ts +2 -0
  290. package/dist/decisions/decision-source.d.ts.map +1 -0
  291. package/dist/decisions/decision-source.js +18 -0
  292. package/dist/decisions/decision-source.js.map +1 -0
  293. package/dist/decisions/exclusive-file-create.d.ts +3 -0
  294. package/dist/decisions/exclusive-file-create.d.ts.map +1 -0
  295. package/dist/decisions/exclusive-file-create.js +84 -0
  296. package/dist/decisions/exclusive-file-create.js.map +1 -0
  297. package/dist/decisions/git-head-trust.d.ts +7 -0
  298. package/dist/decisions/git-head-trust.d.ts.map +1 -0
  299. package/dist/decisions/git-head-trust.js +76 -0
  300. package/dist/decisions/git-head-trust.js.map +1 -0
  301. package/dist/decisions/human-confirmation.d.ts +35 -0
  302. package/dist/decisions/human-confirmation.d.ts.map +1 -0
  303. package/dist/decisions/human-confirmation.js +161 -0
  304. package/dist/decisions/human-confirmation.js.map +1 -0
  305. package/dist/decisions/legacy-waiver-migration.d.ts +31 -0
  306. package/dist/decisions/legacy-waiver-migration.d.ts.map +1 -0
  307. package/dist/decisions/legacy-waiver-migration.js +170 -0
  308. package/dist/decisions/legacy-waiver-migration.js.map +1 -0
  309. package/dist/decisions/read-decisions.d.ts +19 -0
  310. package/dist/decisions/read-decisions.d.ts.map +1 -0
  311. package/dist/decisions/read-decisions.js +90 -0
  312. package/dist/decisions/read-decisions.js.map +1 -0
  313. package/dist/decisions/viewpoint-baseline-adapter.d.ts +7 -0
  314. package/dist/decisions/viewpoint-baseline-adapter.d.ts.map +1 -0
  315. package/dist/decisions/viewpoint-baseline-adapter.js +109 -0
  316. package/dist/decisions/viewpoint-baseline-adapter.js.map +1 -0
  317. package/dist/decisions/waiver-decisions.d.ts +24 -0
  318. package/dist/decisions/waiver-decisions.d.ts.map +1 -0
  319. package/dist/decisions/waiver-decisions.js +46 -0
  320. package/dist/decisions/waiver-decisions.js.map +1 -0
  321. package/dist/exporters/csv-exporter.d.ts +4 -0
  322. package/dist/exporters/csv-exporter.d.ts.map +1 -1
  323. package/dist/exporters/csv-exporter.js +1 -1
  324. package/dist/exporters/csv-exporter.js.map +1 -1
  325. package/dist/exporters/feature-parser.d.ts +8 -0
  326. package/dist/exporters/feature-parser.d.ts.map +1 -1
  327. package/dist/exporters/feature-parser.js +12 -0
  328. package/dist/exporters/feature-parser.js.map +1 -1
  329. package/dist/exporters/matrix/build.d.ts +3 -0
  330. package/dist/exporters/matrix/build.d.ts.map +1 -1
  331. package/dist/exporters/matrix/build.js +59 -19
  332. package/dist/exporters/matrix/build.js.map +1 -1
  333. package/dist/exporters/matrix/carry-manual-results.d.ts +19 -0
  334. package/dist/exporters/matrix/carry-manual-results.d.ts.map +1 -1
  335. package/dist/exporters/matrix/carry-manual-results.js +76 -6
  336. package/dist/exporters/matrix/carry-manual-results.js.map +1 -1
  337. package/dist/exporters/matrix/export.d.ts +8 -2
  338. package/dist/exporters/matrix/export.d.ts.map +1 -1
  339. package/dist/exporters/matrix/export.js +16 -3
  340. package/dist/exporters/matrix/export.js.map +1 -1
  341. package/dist/exporters/matrix/gates.d.ts +6 -1
  342. package/dist/exporters/matrix/gates.d.ts.map +1 -1
  343. package/dist/exporters/matrix/gates.js +57 -128
  344. package/dist/exporters/matrix/gates.js.map +1 -1
  345. package/dist/exporters/matrix/render-csv.d.ts.map +1 -1
  346. package/dist/exporters/matrix/render-csv.js +4 -1
  347. package/dist/exporters/matrix/render-csv.js.map +1 -1
  348. package/dist/exporters/matrix/render-gate-overrides-sheet.d.ts +13 -0
  349. package/dist/exporters/matrix/render-gate-overrides-sheet.d.ts.map +1 -0
  350. package/dist/exporters/matrix/render-gate-overrides-sheet.js +44 -0
  351. package/dist/exporters/matrix/render-gate-overrides-sheet.js.map +1 -0
  352. package/dist/exporters/matrix/render-xlsx.d.ts +1 -0
  353. package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
  354. package/dist/exporters/matrix/render-xlsx.js +6 -0
  355. package/dist/exporters/matrix/render-xlsx.js.map +1 -1
  356. package/dist/exporters/matrix/types.d.ts +9 -1
  357. package/dist/exporters/matrix/types.d.ts.map +1 -1
  358. package/dist/exporters/matrix/types.js.map +1 -1
  359. package/dist/exporters/matrix/xlsx-cells.js +1 -1
  360. package/dist/exporters/matrix/xlsx-cells.js.map +1 -1
  361. package/dist/exporters/playwright-report-parser.d.ts.map +1 -1
  362. package/dist/exporters/playwright-report-parser.js +1 -0
  363. package/dist/exporters/playwright-report-parser.js.map +1 -1
  364. package/dist/exporters/scenario-merger.d.ts.map +1 -1
  365. package/dist/exporters/scenario-merger.js +2 -0
  366. package/dist/exporters/scenario-merger.js.map +1 -1
  367. package/dist/exporters/types.d.ts +5 -0
  368. package/dist/exporters/types.d.ts.map +1 -1
  369. package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
  370. package/dist/generators/test-generator/code-generator.js +13 -0
  371. package/dist/generators/test-generator/code-generator.js.map +1 -1
  372. package/dist/graph/evaluate-graph.d.ts +23 -0
  373. package/dist/graph/evaluate-graph.d.ts.map +1 -0
  374. package/dist/graph/evaluate-graph.js +52 -0
  375. package/dist/graph/evaluate-graph.js.map +1 -0
  376. package/dist/graph/locate-finding.d.ts +20 -0
  377. package/dist/graph/locate-finding.d.ts.map +1 -0
  378. package/dist/graph/locate-finding.js +137 -0
  379. package/dist/graph/locate-finding.js.map +1 -0
  380. package/dist/graph/node-decl.d.ts +66 -0
  381. package/dist/graph/node-decl.d.ts.map +1 -0
  382. package/dist/graph/node-decl.js +8 -0
  383. package/dist/graph/node-decl.js.map +1 -0
  384. package/dist/graph/nodes/core-node-catalog.d.ts +7 -0
  385. package/dist/graph/nodes/core-node-catalog.d.ts.map +1 -0
  386. package/dist/graph/nodes/core-node-catalog.js +13 -0
  387. package/dist/graph/nodes/core-node-catalog.js.map +1 -0
  388. package/dist/graph/nodes/test-case-contract-nodes.d.ts +21 -0
  389. package/dist/graph/nodes/test-case-contract-nodes.d.ts.map +1 -0
  390. package/dist/graph/nodes/test-case-contract-nodes.js +59 -0
  391. package/dist/graph/nodes/test-case-contract-nodes.js.map +1 -0
  392. package/dist/graph/nodes/test-case-nodes.d.ts +26 -0
  393. package/dist/graph/nodes/test-case-nodes.d.ts.map +1 -0
  394. package/dist/graph/nodes/test-case-nodes.js +66 -0
  395. package/dist/graph/nodes/test-case-nodes.js.map +1 -0
  396. package/dist/graph/nodes/unit-audit-nodes.d.ts +18 -0
  397. package/dist/graph/nodes/unit-audit-nodes.d.ts.map +1 -0
  398. package/dist/graph/nodes/unit-audit-nodes.js +95 -0
  399. package/dist/graph/nodes/unit-audit-nodes.js.map +1 -0
  400. package/dist/graph/nodes/unit-contract-node.d.ts +21 -0
  401. package/dist/graph/nodes/unit-contract-node.d.ts.map +1 -0
  402. package/dist/graph/nodes/unit-contract-node.js +88 -0
  403. package/dist/graph/nodes/unit-contract-node.js.map +1 -0
  404. package/dist/graph/nodes/unit-design-nodes.d.ts +14 -0
  405. package/dist/graph/nodes/unit-design-nodes.d.ts.map +1 -0
  406. package/dist/graph/nodes/unit-design-nodes.js +91 -0
  407. package/dist/graph/nodes/unit-design-nodes.js.map +1 -0
  408. package/dist/graph/nodes/unit-execution-nodes.d.ts +16 -0
  409. package/dist/graph/nodes/unit-execution-nodes.d.ts.map +1 -0
  410. package/dist/graph/nodes/unit-execution-nodes.js +79 -0
  411. package/dist/graph/nodes/unit-execution-nodes.js.map +1 -0
  412. package/dist/graph/test-case-identity.d.ts +13 -0
  413. package/dist/graph/test-case-identity.d.ts.map +1 -0
  414. package/dist/graph/test-case-identity.js +106 -0
  415. package/dist/graph/test-case-identity.js.map +1 -0
  416. package/dist/graph/test-case-results.d.ts +11 -0
  417. package/dist/graph/test-case-results.d.ts.map +1 -0
  418. package/dist/graph/test-case-results.js +137 -0
  419. package/dist/graph/test-case-results.js.map +1 -0
  420. package/dist/graph/test-case-satisfied.d.ts +25 -0
  421. package/dist/graph/test-case-satisfied.d.ts.map +1 -0
  422. package/dist/graph/test-case-satisfied.js +51 -0
  423. package/dist/graph/test-case-satisfied.js.map +1 -0
  424. package/dist/graph/test-case-state-shape.d.ts +67 -0
  425. package/dist/graph/test-case-state-shape.d.ts.map +1 -0
  426. package/dist/graph/test-case-state-shape.js +3 -0
  427. package/dist/graph/test-case-state-shape.js.map +1 -0
  428. package/dist/graph/test-case-states.d.ts +9 -0
  429. package/dist/graph/test-case-states.d.ts.map +1 -0
  430. package/dist/graph/test-case-states.js +116 -0
  431. package/dist/graph/test-case-states.js.map +1 -0
  432. package/dist/graph/unit-artifact-probes.d.ts +19 -0
  433. package/dist/graph/unit-artifact-probes.d.ts.map +1 -0
  434. package/dist/graph/unit-artifact-probes.js +133 -0
  435. package/dist/graph/unit-artifact-probes.js.map +1 -0
  436. package/dist/graph/unit-state-facts.d.ts +43 -0
  437. package/dist/graph/unit-state-facts.d.ts.map +1 -0
  438. package/dist/graph/unit-state-facts.js +87 -0
  439. package/dist/graph/unit-state-facts.js.map +1 -0
  440. package/dist/harness/audit.d.ts +11 -0
  441. package/dist/harness/audit.d.ts.map +1 -1
  442. package/dist/harness/audit.js +34 -9
  443. package/dist/harness/audit.js.map +1 -1
  444. package/dist/harness/catalog/gate-rules.yaml +647 -0
  445. package/dist/harness/counted-assertions.d.ts +2 -0
  446. package/dist/harness/counted-assertions.d.ts.map +1 -0
  447. package/dist/harness/counted-assertions.js +38 -0
  448. package/dist/harness/counted-assertions.js.map +1 -0
  449. package/dist/harness/defect-draft.d.ts +14 -0
  450. package/dist/harness/defect-draft.d.ts.map +1 -0
  451. package/dist/harness/defect-draft.js +143 -0
  452. package/dist/harness/defect-draft.js.map +1 -0
  453. package/dist/harness/defects.d.ts +24 -0
  454. package/dist/harness/defects.d.ts.map +1 -0
  455. package/dist/harness/defects.js +118 -0
  456. package/dist/harness/defects.js.map +1 -0
  457. package/dist/harness/gates/audit-gate-terms.d.ts +41 -0
  458. package/dist/harness/gates/audit-gate-terms.d.ts.map +1 -0
  459. package/dist/harness/gates/audit-gate-terms.js +72 -0
  460. package/dist/harness/gates/audit-gate-terms.js.map +1 -0
  461. package/dist/harness/gates/audit-gate-verdict.d.ts +31 -0
  462. package/dist/harness/gates/audit-gate-verdict.d.ts.map +1 -0
  463. package/dist/harness/gates/audit-gate-verdict.js +101 -0
  464. package/dist/harness/gates/audit-gate-verdict.js.map +1 -0
  465. package/dist/harness/gates/audit-input-hash.d.ts +4 -0
  466. package/dist/harness/gates/audit-input-hash.d.ts.map +1 -0
  467. package/dist/harness/gates/audit-input-hash.js +96 -0
  468. package/dist/harness/gates/audit-input-hash.js.map +1 -0
  469. package/dist/harness/gates/audit-report-verification.d.ts +41 -0
  470. package/dist/harness/gates/audit-report-verification.d.ts.map +1 -0
  471. package/dist/harness/gates/audit-report-verification.js +236 -0
  472. package/dist/harness/gates/audit-report-verification.js.map +1 -0
  473. package/dist/harness/gates/decisions-hash.d.ts +13 -0
  474. package/dist/harness/gates/decisions-hash.d.ts.map +1 -0
  475. package/dist/harness/gates/decisions-hash.js +72 -0
  476. package/dist/harness/gates/decisions-hash.js.map +1 -0
  477. package/dist/harness/gates/delivery-checklist.d.ts +21 -0
  478. package/dist/harness/gates/delivery-checklist.d.ts.map +1 -0
  479. package/dist/harness/gates/delivery-checklist.js +128 -0
  480. package/dist/harness/gates/delivery-checklist.js.map +1 -0
  481. package/dist/harness/gates/delivery-decision-gate.d.ts +33 -0
  482. package/dist/harness/gates/delivery-decision-gate.d.ts.map +1 -0
  483. package/dist/harness/gates/delivery-decision-gate.js +116 -0
  484. package/dist/harness/gates/delivery-decision-gate.js.map +1 -0
  485. package/dist/harness/gates/delivery-decision-step.d.ts +19 -0
  486. package/dist/harness/gates/delivery-decision-step.d.ts.map +1 -0
  487. package/dist/harness/gates/delivery-decision-step.js +86 -0
  488. package/dist/harness/gates/delivery-decision-step.js.map +1 -0
  489. package/dist/harness/gates/gate-override-report.d.ts +59 -0
  490. package/dist/harness/gates/gate-override-report.d.ts.map +1 -0
  491. package/dist/harness/gates/gate-override-report.js +86 -0
  492. package/dist/harness/gates/gate-override-report.js.map +1 -0
  493. package/dist/harness/gates/gate-override-scope.d.ts +18 -0
  494. package/dist/harness/gates/gate-override-scope.d.ts.map +1 -0
  495. package/dist/harness/gates/gate-override-scope.js +98 -0
  496. package/dist/harness/gates/gate-override-scope.js.map +1 -0
  497. package/dist/harness/gates/gate-override-validation.d.ts +25 -0
  498. package/dist/harness/gates/gate-override-validation.d.ts.map +1 -0
  499. package/dist/harness/gates/gate-override-validation.js +81 -0
  500. package/dist/harness/gates/gate-override-validation.js.map +1 -0
  501. package/dist/harness/gates/gate-rule-catalog.d.ts +24 -0
  502. package/dist/harness/gates/gate-rule-catalog.d.ts.map +1 -0
  503. package/dist/harness/gates/gate-rule-catalog.js +112 -0
  504. package/dist/harness/gates/gate-rule-catalog.js.map +1 -0
  505. package/dist/harness/gates/gate-terms.d.ts +33 -0
  506. package/dist/harness/gates/gate-terms.d.ts.map +1 -0
  507. package/dist/harness/gates/gate-terms.js +41 -0
  508. package/dist/harness/gates/gate-terms.js.map +1 -0
  509. package/dist/harness/gates/in-run-decision-check.d.ts +21 -0
  510. package/dist/harness/gates/in-run-decision-check.d.ts.map +1 -0
  511. package/dist/harness/gates/in-run-decision-check.js +138 -0
  512. package/dist/harness/gates/in-run-decision-check.js.map +1 -0
  513. package/dist/harness/gates/journey-gate-inputs.d.ts +37 -0
  514. package/dist/harness/gates/journey-gate-inputs.d.ts.map +1 -0
  515. package/dist/harness/gates/journey-gate-inputs.js +81 -0
  516. package/dist/harness/gates/journey-gate-inputs.js.map +1 -0
  517. package/dist/harness/gates/migrated-waiver-review.d.ts +6 -0
  518. package/dist/harness/gates/migrated-waiver-review.d.ts.map +1 -0
  519. package/dist/harness/gates/migrated-waiver-review.js +116 -0
  520. package/dist/harness/gates/migrated-waiver-review.js.map +1 -0
  521. package/dist/harness/gates/resolve-rule.d.ts +59 -0
  522. package/dist/harness/gates/resolve-rule.d.ts.map +1 -0
  523. package/dist/harness/gates/resolve-rule.js +41 -0
  524. package/dist/harness/gates/resolve-rule.js.map +1 -0
  525. package/dist/harness/gates/unit-gate-overrides.d.ts +25 -0
  526. package/dist/harness/gates/unit-gate-overrides.d.ts.map +1 -0
  527. package/dist/harness/gates/unit-gate-overrides.js +122 -0
  528. package/dist/harness/gates/unit-gate-overrides.js.map +1 -0
  529. package/dist/harness/journey.d.ts +43 -1
  530. package/dist/harness/journey.d.ts.map +1 -1
  531. package/dist/harness/journey.js +207 -33
  532. package/dist/harness/journey.js.map +1 -1
  533. package/dist/harness/manifest.d.ts +12 -0
  534. package/dist/harness/manifest.d.ts.map +1 -1
  535. package/dist/harness/manifest.js +73 -45
  536. package/dist/harness/manifest.js.map +1 -1
  537. package/dist/harness/next-step.d.ts +37 -6
  538. package/dist/harness/next-step.d.ts.map +1 -1
  539. package/dist/harness/next-step.js +34 -174
  540. package/dist/harness/next-step.js.map +1 -1
  541. package/dist/harness/parse.d.ts +25 -0
  542. package/dist/harness/parse.d.ts.map +1 -1
  543. package/dist/harness/parse.js +38 -13
  544. package/dist/harness/parse.js.map +1 -1
  545. package/dist/harness/provenance.d.ts +29 -0
  546. package/dist/harness/provenance.d.ts.map +1 -1
  547. package/dist/harness/provenance.js +109 -9
  548. package/dist/harness/provenance.js.map +1 -1
  549. package/dist/harness/script-check.d.ts.map +1 -1
  550. package/dist/harness/script-check.js +29 -6
  551. package/dist/harness/script-check.js.map +1 -1
  552. package/dist/harness/sensors.d.ts +14 -3
  553. package/dist/harness/sensors.d.ts.map +1 -1
  554. package/dist/harness/sensors.js +64 -44
  555. package/dist/harness/sensors.js.map +1 -1
  556. package/dist/harness/triage-signals.d.ts +20 -0
  557. package/dist/harness/triage-signals.d.ts.map +1 -0
  558. package/dist/harness/triage-signals.js +30 -0
  559. package/dist/harness/triage-signals.js.map +1 -0
  560. package/dist/harness/triage-unit.d.ts +23 -0
  561. package/dist/harness/triage-unit.d.ts.map +1 -0
  562. package/dist/harness/triage-unit.js +142 -0
  563. package/dist/harness/triage-unit.js.map +1 -0
  564. package/dist/harness/triage.d.ts +28 -0
  565. package/dist/harness/triage.d.ts.map +1 -0
  566. package/dist/harness/triage.js +99 -0
  567. package/dist/harness/triage.js.map +1 -0
  568. package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
  569. package/dist/harness/viewpoint-ledger.js +2 -1
  570. package/dist/harness/viewpoint-ledger.js.map +1 -1
  571. package/dist/hooks/bash-write-targets.d.ts +15 -0
  572. package/dist/hooks/bash-write-targets.d.ts.map +1 -0
  573. package/dist/hooks/bash-write-targets.js +173 -0
  574. package/dist/hooks/bash-write-targets.js.map +1 -0
  575. package/dist/hooks/claude-hook-entry.d.ts +11 -0
  576. package/dist/hooks/claude-hook-entry.d.ts.map +1 -0
  577. package/dist/hooks/claude-hook-entry.js +137 -0
  578. package/dist/hooks/claude-hook-entry.js.map +1 -0
  579. package/dist/hooks/claude-transcript-turn.d.ts +11 -0
  580. package/dist/hooks/claude-transcript-turn.d.ts.map +1 -0
  581. package/dist/hooks/claude-transcript-turn.js +143 -0
  582. package/dist/hooks/claude-transcript-turn.js.map +1 -0
  583. package/dist/hooks/guard-delivery-contract-rule.d.ts +10 -0
  584. package/dist/hooks/guard-delivery-contract-rule.d.ts.map +1 -0
  585. package/dist/hooks/guard-delivery-contract-rule.js +152 -0
  586. package/dist/hooks/guard-delivery-contract-rule.js.map +1 -0
  587. package/dist/hooks/guard-protected-paths.d.ts +9 -0
  588. package/dist/hooks/guard-protected-paths.d.ts.map +1 -0
  589. package/dist/hooks/guard-protected-paths.js +107 -0
  590. package/dist/hooks/guard-protected-paths.js.map +1 -0
  591. package/dist/hooks/guard-rules.d.ts +37 -0
  592. package/dist/hooks/guard-rules.d.ts.map +1 -0
  593. package/dist/hooks/guard-rules.js +61 -0
  594. package/dist/hooks/guard-rules.js.map +1 -0
  595. package/dist/hooks/guard-tty-spoof-rule.d.ts +15 -0
  596. package/dist/hooks/guard-tty-spoof-rule.d.ts.map +1 -0
  597. package/dist/hooks/guard-tty-spoof-rule.js +21 -0
  598. package/dist/hooks/guard-tty-spoof-rule.js.map +1 -0
  599. package/dist/hooks/hand-back-core.d.ts +39 -0
  600. package/dist/hooks/hand-back-core.d.ts.map +1 -0
  601. package/dist/hooks/hand-back-core.js +122 -0
  602. package/dist/hooks/hand-back-core.js.map +1 -0
  603. package/dist/hooks/hook-cli-command.d.ts +9 -0
  604. package/dist/hooks/hook-cli-command.d.ts.map +1 -0
  605. package/dist/hooks/hook-cli-command.js +46 -0
  606. package/dist/hooks/hook-cli-command.js.map +1 -0
  607. package/dist/hooks/hook-registry.d.ts +10 -0
  608. package/dist/hooks/hook-registry.d.ts.map +1 -0
  609. package/dist/hooks/hook-registry.js +24 -0
  610. package/dist/hooks/hook-registry.js.map +1 -0
  611. package/dist/hooks/hook-result-contract.d.ts +50 -0
  612. package/dist/hooks/hook-result-contract.d.ts.map +1 -0
  613. package/dist/hooks/hook-result-contract.js +80 -0
  614. package/dist/hooks/hook-result-contract.js.map +1 -0
  615. package/dist/hooks/hook-toggles.d.ts +10 -0
  616. package/dist/hooks/hook-toggles.d.ts.map +1 -0
  617. package/dist/hooks/hook-toggles.js +107 -0
  618. package/dist/hooks/hook-toggles.js.map +1 -0
  619. package/dist/hooks/pre-tool-guard-hook.d.ts +10 -0
  620. package/dist/hooks/pre-tool-guard-hook.d.ts.map +1 -0
  621. package/dist/hooks/pre-tool-guard-hook.js +105 -0
  622. package/dist/hooks/pre-tool-guard-hook.js.map +1 -0
  623. package/dist/hooks/session-start-unit-state-hook.d.ts +13 -0
  624. package/dist/hooks/session-start-unit-state-hook.d.ts.map +1 -0
  625. package/dist/hooks/session-start-unit-state-hook.js +57 -0
  626. package/dist/hooks/session-start-unit-state-hook.js.map +1 -0
  627. package/dist/hooks/stop-next-step-hook.d.ts +16 -0
  628. package/dist/hooks/stop-next-step-hook.d.ts.map +1 -0
  629. package/dist/hooks/stop-next-step-hook.js +42 -0
  630. package/dist/hooks/stop-next-step-hook.js.map +1 -0
  631. package/dist/hooks/sungen-project-root.d.ts +19 -0
  632. package/dist/hooks/sungen-project-root.d.ts.map +1 -0
  633. package/dist/hooks/sungen-project-root.js +130 -0
  634. package/dist/hooks/sungen-project-root.js.map +1 -0
  635. package/dist/orchestrator/ai-skills/command-partial-includes.d.ts +15 -0
  636. package/dist/orchestrator/ai-skills/command-partial-includes.d.ts.map +1 -0
  637. package/dist/orchestrator/ai-skills/command-partial-includes.js +106 -0
  638. package/dist/orchestrator/ai-skills/command-partial-includes.js.map +1 -0
  639. package/dist/orchestrator/ai-skills/commands.d.ts +5 -1
  640. package/dist/orchestrator/ai-skills/commands.d.ts.map +1 -1
  641. package/dist/orchestrator/ai-skills/commands.js +16 -6
  642. package/dist/orchestrator/ai-skills/commands.js.map +1 -1
  643. package/dist/orchestrator/ai-skills/golden-skills.test.js +29 -0
  644. package/dist/orchestrator/ai-skills/golden-skills.test.js.map +1 -1
  645. package/dist/orchestrator/assets-drift.d.ts +5 -0
  646. package/dist/orchestrator/assets-drift.d.ts.map +1 -1
  647. package/dist/orchestrator/assets-drift.js +12 -3
  648. package/dist/orchestrator/assets-drift.js.map +1 -1
  649. package/dist/orchestrator/claude-hooks-install.d.ts +27 -0
  650. package/dist/orchestrator/claude-hooks-install.d.ts.map +1 -0
  651. package/dist/orchestrator/claude-hooks-install.js +203 -0
  652. package/dist/orchestrator/claude-hooks-install.js.map +1 -0
  653. package/dist/orchestrator/lockstep-version.d.ts +15 -5
  654. package/dist/orchestrator/lockstep-version.d.ts.map +1 -1
  655. package/dist/orchestrator/lockstep-version.js +30 -17
  656. package/dist/orchestrator/lockstep-version.js.map +1 -1
  657. package/dist/orchestrator/project-initializer.d.ts +6 -0
  658. package/dist/orchestrator/project-initializer.d.ts.map +1 -1
  659. package/dist/orchestrator/project-initializer.js +24 -0
  660. package/dist/orchestrator/project-initializer.js.map +1 -1
  661. package/dist/orchestrator/screen-manager.d.ts.map +1 -1
  662. package/dist/orchestrator/screen-manager.js +4 -2
  663. package/dist/orchestrator/screen-manager.js.map +1 -1
  664. package/dist/orchestrator/templates/ai-src/commands/add-api.md +2 -0
  665. package/dist/orchestrator/templates/ai-src/commands/add-flow.md +2 -0
  666. package/dist/orchestrator/templates/ai-src/commands/add-screen.md +2 -0
  667. package/dist/orchestrator/templates/ai-src/commands/create-data-test.md +1 -0
  668. package/dist/orchestrator/templates/ai-src/commands/create-test.md +14 -16
  669. package/dist/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
  670. package/dist/orchestrator/templates/ai-src/commands/delivery.md +2 -0
  671. package/dist/orchestrator/templates/ai-src/commands/design.md +2 -0
  672. package/dist/orchestrator/templates/ai-src/commands/feedback.md +2 -0
  673. package/dist/orchestrator/templates/ai-src/commands/locale.md +2 -0
  674. package/dist/orchestrator/templates/ai-src/commands/review.md +2 -0
  675. package/dist/orchestrator/templates/ai-src/commands/run-test.md +14 -10
  676. package/dist/orchestrator/templates/ai-src/config/claude.md +20 -7
  677. package/dist/orchestrator/templates/ai-src/config/copilot.md +20 -7
  678. package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.claude.md +20 -0
  679. package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.codex.md +20 -0
  680. package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.copilot.md +20 -0
  681. package/dist/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +1 -1
  682. package/dist/orchestrator/templates/ai-src/skills/sungen-capture-mobile/SKILL.md +3 -3
  683. package/dist/orchestrator/templates/ai-src/skills/sungen-data-factory/SKILL.md +9 -0
  684. package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +2 -0
  685. package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +1 -1
  686. package/dist/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +2 -0
  687. package/dist/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
  688. package/dist/utils/safe-yaml-parse.d.ts +8 -0
  689. package/dist/utils/safe-yaml-parse.d.ts.map +1 -0
  690. package/dist/utils/safe-yaml-parse.js +51 -0
  691. package/dist/utils/safe-yaml-parse.js.map +1 -0
  692. package/package.json +3 -3
  693. package/src/basis/anchor-grammar.ts +83 -0
  694. package/src/basis/anchor-hash.ts +27 -0
  695. package/src/basis/bm51-tables.ts +65 -0
  696. package/src/basis/extract-spec-anchors.ts +95 -0
  697. package/src/basis/migration-sentinel.ts +175 -0
  698. package/src/basis/spec-frontmatter.ts +68 -0
  699. package/src/basis/spec-sections.ts +35 -0
  700. package/src/basis/test-basis-schema.ts +81 -0
  701. package/src/capabilities/discover.ts +15 -2
  702. package/src/capabilities/registry.ts +16 -0
  703. package/src/cli/commands/audit.ts +10 -5
  704. package/src/cli/commands/capability.ts +4 -2
  705. package/src/cli/commands/contract-derive-command.ts +61 -0
  706. package/src/cli/commands/contract.ts +130 -0
  707. package/src/cli/commands/defect.ts +49 -0
  708. package/src/cli/commands/delivery.ts +92 -15
  709. package/src/cli/commands/generate.ts +3 -1
  710. package/src/cli/commands/journey.ts +41 -16
  711. package/src/cli/commands/next.ts +64 -10
  712. package/src/cli/commands/triage.ts +57 -0
  713. package/src/cli/commands/update.ts +35 -8
  714. package/src/cli/index.ts +24 -30
  715. package/src/cli/project-sungen-invocation.ts +39 -0
  716. package/src/contract/approve-contract.ts +94 -0
  717. package/src/contract/assertion-matcher-vocabulary.ts +93 -0
  718. package/src/contract/build-contract-verdict.ts +108 -0
  719. package/src/contract/build-trace-conformance.ts +100 -0
  720. package/src/contract/classify-contract-change.ts +92 -0
  721. package/src/contract/classify-contract-unit.ts +47 -0
  722. package/src/contract/classify-trace-conformance.ts +116 -0
  723. package/src/contract/contract-git.ts +106 -0
  724. package/src/contract/contract-hash.ts +34 -0
  725. package/src/contract/contract-report-file.ts +25 -0
  726. package/src/contract/contract-schema.ts +137 -0
  727. package/src/contract/contract-units.ts +52 -0
  728. package/src/contract/contracts-lock-file.ts +97 -0
  729. package/src/contract/data-normalize.ts +66 -0
  730. package/src/contract/derive-free-feature.ts +120 -0
  731. package/src/contract/field-semantic-redaction.ts +80 -0
  732. package/src/contract/free-feature-blocks.ts +56 -0
  733. package/src/contract/lock-secret-guard.ts +95 -0
  734. package/src/contract/lock-vs-git-head.ts +38 -0
  735. package/src/contract/normalize-contract-step.ts +74 -0
  736. package/src/contract/normalize-feature-steps.ts +93 -0
  737. package/src/contract/oracle-strength.ts +80 -0
  738. package/src/contract/project-contract-blockers.ts +36 -0
  739. package/src/contract/record-contract-approval.ts +70 -0
  740. package/src/contract/render-free-gherkin.ts +113 -0
  741. package/src/contract/render-trace-sentence.ts +98 -0
  742. package/src/contract/render-trace-target.ts +68 -0
  743. package/src/contract/resolve-unit-trace-identities.ts +35 -0
  744. package/src/contract/trace/collect-trace-evidence.ts +109 -0
  745. package/src/contract/trace/identity-cache.ts +61 -0
  746. package/src/contract/trace/select-final-attempt.ts +70 -0
  747. package/src/contract/trace/snapshot-html-renderer.ts +136 -0
  748. package/src/contract/trace/snapshot-resolver.ts +66 -0
  749. package/src/contract/trace/snapshot-store.ts +151 -0
  750. package/src/contract/trace/target-identity.ts +104 -0
  751. package/src/contract/trace/test-step-join.ts +104 -0
  752. package/src/contract/trace/trace-binding.ts +56 -0
  753. package/src/contract/trace/trace-file-reader.ts +133 -0
  754. package/src/contract/trace/trace-fingerprint.ts +68 -0
  755. package/src/contract/trace/trace-identity-resolution.ts +74 -0
  756. package/src/contract/trace/trace-run-record.ts +80 -0
  757. package/src/contract/trace/trace-steps.ts +88 -0
  758. package/src/contract/trace/trace-zip-limits.ts +77 -0
  759. package/src/contract/trace/trace-zip-reader.ts +127 -0
  760. package/src/contract/verify-approval-decisions.ts +60 -0
  761. package/src/decisions/append-decision.ts +35 -0
  762. package/src/decisions/confirmed-decision-commands.ts +149 -0
  763. package/src/decisions/decision-file.ts +93 -0
  764. package/src/decisions/decision-identity.ts +73 -0
  765. package/src/decisions/decision-integrity-check.ts +61 -0
  766. package/src/decisions/decision-schema.ts +76 -0
  767. package/src/decisions/decision-source.ts +14 -0
  768. package/src/decisions/exclusive-file-create.ts +42 -0
  769. package/src/decisions/git-head-trust.ts +32 -0
  770. package/src/decisions/human-confirmation.ts +119 -0
  771. package/src/decisions/legacy-waiver-migration.ts +135 -0
  772. package/src/decisions/read-decisions.ts +61 -0
  773. package/src/decisions/viewpoint-baseline-adapter.ts +74 -0
  774. package/src/decisions/waiver-decisions.ts +56 -0
  775. package/src/exporters/csv-exporter.ts +5 -1
  776. package/src/exporters/feature-parser.ts +12 -0
  777. package/src/exporters/matrix/build.ts +62 -18
  778. package/src/exporters/matrix/carry-manual-results.ts +70 -7
  779. package/src/exporters/matrix/export.ts +17 -2
  780. package/src/exporters/matrix/gates.ts +62 -129
  781. package/src/exporters/matrix/render-csv.ts +4 -1
  782. package/src/exporters/matrix/render-gate-overrides-sheet.ts +50 -0
  783. package/src/exporters/matrix/render-xlsx.ts +6 -0
  784. package/src/exporters/matrix/types.ts +9 -1
  785. package/src/exporters/matrix/xlsx-cells.ts +1 -1
  786. package/src/exporters/playwright-report-parser.ts +1 -0
  787. package/src/exporters/scenario-merger.ts +2 -1
  788. package/src/exporters/types.ts +5 -0
  789. package/src/generators/test-generator/code-generator.ts +13 -0
  790. package/src/graph/evaluate-graph.ts +66 -0
  791. package/src/graph/locate-finding.ts +93 -0
  792. package/src/graph/node-decl.ts +72 -0
  793. package/src/graph/nodes/core-node-catalog.ts +15 -0
  794. package/src/graph/nodes/test-case-contract-nodes.ts +74 -0
  795. package/src/graph/nodes/test-case-nodes.ts +68 -0
  796. package/src/graph/nodes/unit-audit-nodes.ts +95 -0
  797. package/src/graph/nodes/unit-contract-node.ts +89 -0
  798. package/src/graph/nodes/unit-design-nodes.ts +89 -0
  799. package/src/graph/nodes/unit-execution-nodes.ts +77 -0
  800. package/src/graph/test-case-identity.ts +75 -0
  801. package/src/graph/test-case-results.ts +90 -0
  802. package/src/graph/test-case-satisfied.ts +55 -0
  803. package/src/graph/test-case-state-shape.ts +62 -0
  804. package/src/graph/test-case-states.ts +84 -0
  805. package/src/graph/unit-artifact-probes.ts +77 -0
  806. package/src/graph/unit-state-facts.ts +112 -0
  807. package/src/harness/audit.ts +46 -11
  808. package/src/harness/catalog/gate-rules.yaml +647 -0
  809. package/src/harness/counted-assertions.ts +33 -0
  810. package/src/harness/defect-draft.ts +115 -0
  811. package/src/harness/defects.ts +94 -0
  812. package/src/harness/gates/audit-gate-terms.ts +80 -0
  813. package/src/harness/gates/audit-gate-verdict.ts +78 -0
  814. package/src/harness/gates/audit-input-hash.ts +55 -0
  815. package/src/harness/gates/audit-report-verification.ts +201 -0
  816. package/src/harness/gates/decisions-hash.ts +42 -0
  817. package/src/harness/gates/delivery-checklist.ts +120 -0
  818. package/src/harness/gates/delivery-decision-gate.ts +139 -0
  819. package/src/harness/gates/delivery-decision-step.ts +89 -0
  820. package/src/harness/gates/gate-override-report.ts +114 -0
  821. package/src/harness/gates/gate-override-scope.ts +66 -0
  822. package/src/harness/gates/gate-override-validation.ts +75 -0
  823. package/src/harness/gates/gate-rule-catalog.ts +82 -0
  824. package/src/harness/gates/gate-terms.ts +59 -0
  825. package/src/harness/gates/in-run-decision-check.ts +99 -0
  826. package/src/harness/gates/journey-gate-inputs.ts +89 -0
  827. package/src/harness/gates/migrated-waiver-review.ts +68 -0
  828. package/src/harness/gates/resolve-rule.ts +94 -0
  829. package/src/harness/gates/unit-gate-overrides.ts +99 -0
  830. package/src/harness/journey.ts +215 -38
  831. package/src/harness/manifest.ts +69 -45
  832. package/src/harness/next-step.ts +60 -170
  833. package/src/harness/parse.ts +40 -13
  834. package/src/harness/provenance.ts +99 -11
  835. package/src/harness/script-check.ts +27 -6
  836. package/src/harness/sensors.ts +73 -47
  837. package/src/harness/triage-signals.ts +46 -0
  838. package/src/harness/triage-unit.ts +113 -0
  839. package/src/harness/triage.ts +127 -0
  840. package/src/harness/viewpoint-ledger.ts +2 -2
  841. package/src/hooks/bash-write-targets.ts +109 -0
  842. package/src/hooks/claude-hook-entry.ts +85 -0
  843. package/src/hooks/claude-transcript-turn.ts +96 -0
  844. package/src/hooks/guard-delivery-contract-rule.ts +110 -0
  845. package/src/hooks/guard-protected-paths.ts +71 -0
  846. package/src/hooks/guard-rules.ts +98 -0
  847. package/src/hooks/guard-tty-spoof-rule.ts +31 -0
  848. package/src/hooks/hand-back-core.ts +112 -0
  849. package/src/hooks/hook-cli-command.ts +17 -0
  850. package/src/hooks/hook-registry.ts +24 -0
  851. package/src/hooks/hook-result-contract.ts +114 -0
  852. package/src/hooks/hook-toggles.ts +66 -0
  853. package/src/hooks/pre-tool-guard-hook.ts +67 -0
  854. package/src/hooks/session-start-unit-state-hook.ts +56 -0
  855. package/src/hooks/stop-next-step-hook.ts +37 -0
  856. package/src/hooks/sungen-project-root.ts +80 -0
  857. package/src/orchestrator/ai-skills/command-partial-includes.ts +72 -0
  858. package/src/orchestrator/ai-skills/commands.ts +22 -8
  859. package/src/orchestrator/ai-skills/golden-skills.test.ts +23 -0
  860. package/src/orchestrator/assets-drift.ts +12 -5
  861. package/src/orchestrator/claude-hooks-install.ts +168 -0
  862. package/src/orchestrator/lockstep-version.ts +28 -15
  863. package/src/orchestrator/project-initializer.ts +22 -0
  864. package/src/orchestrator/screen-manager.ts +3 -1
  865. package/src/orchestrator/templates/ai-src/commands/add-api.md +2 -0
  866. package/src/orchestrator/templates/ai-src/commands/add-flow.md +2 -0
  867. package/src/orchestrator/templates/ai-src/commands/add-screen.md +2 -0
  868. package/src/orchestrator/templates/ai-src/commands/create-data-test.md +1 -0
  869. package/src/orchestrator/templates/ai-src/commands/create-test.md +14 -16
  870. package/src/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
  871. package/src/orchestrator/templates/ai-src/commands/delivery.md +2 -0
  872. package/src/orchestrator/templates/ai-src/commands/design.md +2 -0
  873. package/src/orchestrator/templates/ai-src/commands/feedback.md +2 -0
  874. package/src/orchestrator/templates/ai-src/commands/locale.md +2 -0
  875. package/src/orchestrator/templates/ai-src/commands/review.md +2 -0
  876. package/src/orchestrator/templates/ai-src/commands/run-test.md +14 -10
  877. package/src/orchestrator/templates/ai-src/config/claude.md +20 -7
  878. package/src/orchestrator/templates/ai-src/config/copilot.md +20 -7
  879. package/src/orchestrator/templates/ai-src/partials/hand-back-rule.claude.md +20 -0
  880. package/src/orchestrator/templates/ai-src/partials/hand-back-rule.codex.md +20 -0
  881. package/src/orchestrator/templates/ai-src/partials/hand-back-rule.copilot.md +20 -0
  882. package/src/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +1 -1
  883. package/src/orchestrator/templates/ai-src/skills/sungen-capture-mobile/SKILL.md +3 -3
  884. package/src/orchestrator/templates/ai-src/skills/sungen-data-factory/SKILL.md +9 -0
  885. package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +2 -0
  886. package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +1 -1
  887. package/src/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +2 -0
  888. package/src/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
  889. package/src/utils/safe-yaml-parse.ts +44 -0
@@ -12,6 +12,7 @@ import * as fs from 'fs';
12
12
  import { NON_DECLARATION_SECTION, PRIORITY_WORDS, ScenarioInfo } from './parse';
13
13
  import { readViewpointText } from './read-text';
14
14
  import { keywordHit } from './keyword-match';
15
+ import { countedAssertions } from './counted-assertions';
15
16
 
16
17
  export interface LedgerItem { id?: string; text: string; covered: boolean }
17
18
 
@@ -238,8 +239,7 @@ export function viewpointLedger(viewpointPath: string, scenarios: ScenarioInfo[]
238
239
  const n = claimedCount(item.text);
239
240
  const auto = carriers.filter((s) => !s.manual);
240
241
  if (n !== null && auto.length > 0 && !auto.some((s) => /\bsee all\b/.test(s.stepsText))) {
241
- const asserted = Math.max(...auto.map((s) =>
242
- (s.stepsText.match(/\bsee \[[^\]]+\][^|]*?\b(?:with|contains) \{\{/g) ?? []).length));
242
+ const asserted = Math.max(...auto.map((s) => countedAssertions(s.stepsText)));
243
243
  if (asserted > 0 && asserted < n) partial.push({ id: item.id, text: item.text, claimed: n, asserted });
244
244
  }
245
245
  }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * The files a Bash command line WRITES through the three forms the pre-tool guard covers (P0.1):
3
+ * output redirection (`>`, `>>`, `>|`, `&>`, `2>`…), `tee`, and in-place `sed -i`.
4
+ *
5
+ * A floor, not a shell interpreter: quotes, escapes, `;`/`&&`/`||`/`|` and a leading `cd` are
6
+ * understood; anything else that can write a file (`cp`, a script, `python -c`) is out of scope by
7
+ * design. The command string is untrusted — it is only tokenized here, never executed.
8
+ */
9
+ import * as path from 'path';
10
+
11
+ type Tok = { kind: 'word'; value: string } | { kind: 'sep' } | { kind: 'redir'; writes: boolean };
12
+
13
+ /** Commands that run another command: the real one is the next word. */
14
+ const WRAPPERS = new Set(['sudo', 'env', 'command', 'nohup', 'time', 'exec', 'nice']);
15
+ const ASSIGNMENT = /^[A-Za-z_]\w*=/;
16
+
17
+ function tokenize(cmd: string): Tok[] {
18
+ const toks: Tok[] = [];
19
+ let word = '';
20
+ let inWord = false;
21
+ const flush = (): void => { if (inWord) toks.push({ kind: 'word', value: word }); word = ''; inWord = false; };
22
+ for (let i = 0; i < cmd.length;) {
23
+ const ch = cmd[i];
24
+ if (ch === "'") {
25
+ const end = cmd.indexOf("'", i + 1);
26
+ word += cmd.slice(i + 1, end < 0 ? cmd.length : end); inWord = true; i = end < 0 ? cmd.length : end + 1;
27
+ } else if (ch === '"') {
28
+ let j = i + 1;
29
+ for (; j < cmd.length && cmd[j] !== '"'; j++) { if (cmd[j] === '\\' && j + 1 < cmd.length) j++; word += cmd[j]; }
30
+ inWord = true; i = j + 1;
31
+ } else if (ch === '\\' && i + 1 < cmd.length) {
32
+ word += cmd[i + 1]; inWord = true; i += 2;
33
+ } else if (ch === ' ' || ch === '\t') {
34
+ flush(); i++;
35
+ } else if ('\n;|()'.includes(ch) || (ch === '&' && cmd[i + 1] !== '>')) {
36
+ flush(); toks.push({ kind: 'sep' }); i += (ch === '|' || ch === '&') && cmd[i + 1] === ch ? 2 : 1;
37
+ } else if (ch === '>' || (ch === '&' && cmd[i + 1] === '>')) {
38
+ if (ch === '>' && inWord && /^\d+$/.test(word)) { word = ''; inWord = false; } else flush(); // `2>`: an fd, not a word
39
+ i += ch === '&' ? 2 : 1;
40
+ if (cmd[i] === '>' || cmd[i] === '|') i++;
41
+ if (cmd[i] === '&') { i++; toks.push({ kind: 'redir', writes: false }); } // `>&2`: an fd dup
42
+ else toks.push({ kind: 'redir', writes: true });
43
+ } else if (ch === '<') {
44
+ flush(); i++;
45
+ while (cmd[i] === '<') i++;
46
+ toks.push({ kind: 'redir', writes: false });
47
+ } else {
48
+ word += ch; inWord = true; i++;
49
+ }
50
+ }
51
+ flush();
52
+ return toks;
53
+ }
54
+
55
+ const isInPlaceFlag = (a: string): boolean => a === '--in-place' || a.startsWith('--in-place=') || /^-[a-zA-Z]*i/.test(a);
56
+
57
+ /** One simple command of a Bash line (`a | b && c` is three). */
58
+ export interface BashSegment {
59
+ /** The command name (basename, after env assignments and wrappers like `sudo`), or ''. */
60
+ cmd: string;
61
+ /** Its arguments, and every redirection target, as written. */
62
+ words: string[];
63
+ /** The directory it runs in — a preceding `cd` in the same line is followed. */
64
+ dir: string;
65
+ /** Absolute paths it writes via redirection, `tee` or `sed -i`. */
66
+ writes: string[];
67
+ }
68
+
69
+ export function bashSegments(command: string, cwd: string): BashSegment[] {
70
+ const out: BashSegment[] = [];
71
+ const toks = tokenize(command);
72
+ let dir = cwd;
73
+ let seg: string[] = [];
74
+ let redirected: string[] = [];
75
+ let writes: string[] = [];
76
+ const endSegment = (): void => {
77
+ let k = 0;
78
+ while (k < seg.length && (ASSIGNMENT.test(seg[k]) || WRAPPERS.has(seg[k]))) k++;
79
+ const cmd = path.basename(seg[k] ?? '');
80
+ const args = seg.slice(k + 1).filter((a) => a !== '');
81
+ if (cmd === 'tee') writes.push(...args.filter((a) => !a.startsWith('-')).map((a) => path.resolve(dir, a)));
82
+ else if ((cmd === 'sed' || cmd === 'gsed') && args.some(isInPlaceFlag)) {
83
+ writes.push(...args.filter((a) => !a.startsWith('-')).map((a) => path.resolve(dir, a)));
84
+ }
85
+ if (cmd || redirected.length) out.push({ cmd, words: [...args, ...redirected], dir, writes });
86
+ if (cmd === 'cd' && args.length === 1 && !/^[-~]/.test(args[0])) dir = path.resolve(dir, args[0]);
87
+ seg = []; redirected = []; writes = [];
88
+ };
89
+ for (let t = 0; t < toks.length; t++) {
90
+ const tok = toks[t];
91
+ if (tok.kind === 'sep') { endSegment(); continue; }
92
+ if (tok.kind === 'redir') {
93
+ const target = toks[t + 1];
94
+ if (target?.kind !== 'word') continue;
95
+ t++;
96
+ redirected.push(target.value);
97
+ if (tok.writes && target.value && target.value !== '/dev/null' && target.value !== '-') writes.push(path.resolve(dir, target.value));
98
+ continue;
99
+ }
100
+ seg.push(tok.value);
101
+ }
102
+ endSegment();
103
+ return out;
104
+ }
105
+
106
+ /** Absolute paths the command writes via redirection, `tee` or `sed -i`, resolved against `cwd`. */
107
+ export function bashWriteTargets(command: string, cwd: string): string[] {
108
+ return bashSegments(command, cwd).flatMap((s) => s.writes);
109
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Claude Code → sungen hook bridge (P0.1). Three ways in, one behaviour:
3
+ *
4
+ * node dist/hooks/claude-hook-entry.js <hook> executed directly (`require.main` branch)
5
+ * .claude/hooks/sungen-hook.cjs <hook> the project launcher `require`s this, calls main
6
+ * sungen hook <hook> the hidden CLI command (debugging, dev checkouts)
7
+ *
8
+ * Reads the event JSON on stdin, runs the hook through `runHook` (toggles + fail-open), and prints
9
+ * the Claude Code JSON on stdout. Exit code is ALWAYS 0 and anything unexpected prints `{}`: a hook
10
+ * error must never block or derail a session. The payload is untrusted — it is parsed as JSON and
11
+ * read field by field, never executed.
12
+ */
13
+ import * as path from 'path';
14
+ import { ClaudeHookEvent, HookContext, HookInput, runHook, runHookOnUnreadableInput, toClaudeStdout } from './hook-result-contract';
15
+ import { loadHook } from './hook-registry';
16
+ import { hooksKilled } from './hook-toggles';
17
+
18
+ /**
19
+ * Payloads above this are not parsed. Not a free pass either: a hook declares what an unreadable
20
+ * payload means (`onUnreadableInput`) — the guard asks, the advisory hooks stay quiet.
21
+ */
22
+ const MAX_PAYLOAD_BYTES = 5 * 1024 * 1024;
23
+ /** A hook whose stdin never closes still answers (as a no-op) well inside its timeout. */
24
+ const STDIN_TIMEOUT_MS = 2000;
25
+
26
+ export function parsePayload(raw: string): HookInput {
27
+ try {
28
+ const v: unknown = JSON.parse(raw);
29
+ return v && typeof v === 'object' && !Array.isArray(v) ? (v as HookInput) : {};
30
+ } catch { return {}; }
31
+ }
32
+
33
+ export function contextFor(input: HookInput, env: Record<string, string | undefined>): HookContext {
34
+ const cwd = typeof input.cwd === 'string' && path.isAbsolute(input.cwd) ? input.cwd : env.CLAUDE_PROJECT_DIR || process.cwd();
35
+ return { env, cwd };
36
+ }
37
+
38
+ /**
39
+ * What to print for this hook and raw payload — pure apart from the hook's own reads. `oversize`
40
+ * means the payload was too large to read at all.
41
+ */
42
+ export function dispatch(hookName: string, raw: string, env: Record<string, string | undefined>, oversize = false): string {
43
+ if (hooksKilled(env)) return '{}';
44
+ const hook = loadHook(hookName);
45
+ if (!hook) return '{}';
46
+ if (oversize) return toClaudeStdout(hook.meta.events[0], runHookOnUnreadableInput(hook, contextFor({}, env)));
47
+ const input = parsePayload(raw);
48
+ const event = typeof input.hook_event_name === 'string' ? input.hook_event_name : hook.meta.events[0];
49
+ if (!hook.meta.events.includes(event as ClaudeHookEvent)) return '{}';
50
+ return toClaudeStdout(event, runHook(hook, input, contextFor(input, env)));
51
+ }
52
+
53
+ function readStdin(): Promise<{ raw: string; oversize: boolean }> {
54
+ return new Promise((resolve) => {
55
+ if (process.stdin.isTTY) { resolve({ raw: '', oversize: false }); return; }
56
+ let size = 0;
57
+ const chunks: Buffer[] = [];
58
+ const done = (raw: string, oversize = false): void => {
59
+ clearTimeout(timer); process.stdin.removeAllListeners(); process.stdin.destroy(); resolve({ raw, oversize });
60
+ };
61
+ const timer = setTimeout(() => done(''), STDIN_TIMEOUT_MS);
62
+ process.stdin.on('data', (c: Buffer) => {
63
+ size += c.length;
64
+ if (size > MAX_PAYLOAD_BYTES) done('', true); else chunks.push(c);
65
+ });
66
+ process.stdin.on('end', () => done(Buffer.concat(chunks).toString('utf8')));
67
+ process.stdin.on('error', () => done(''));
68
+ });
69
+ }
70
+
71
+ /** Run one hook end to end. Resolves once stdout has flushed; never rejects. */
72
+ export async function main(hookName: string = process.argv[2] ?? ''): Promise<void> {
73
+ let out = '{}';
74
+ try {
75
+ const { raw, oversize } = await readStdin();
76
+ out = dispatch(hookName, raw, process.env, oversize);
77
+ } catch { out = '{}'; }
78
+ await new Promise<void>((resolve) => process.stdout.write(`${out}\n`, () => resolve()));
79
+ process.exitCode = 0;
80
+ }
81
+
82
+ if (require.main === module) {
83
+ // Exit explicitly once flushed: a stray handle must not keep a hook alive into its timeout.
84
+ void main().then(() => process.exit(0), () => process.exit(0));
85
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * What happened in the turn that just ended, read from the tail of Claude Code's transcript.
3
+ *
4
+ * The Stop hook must not nag every turn of every conversation in a sungen project — only a turn
5
+ * that ran sungen work and then ended without handing back. The transcript (JSONL) answers both:
6
+ * walk back from its end to the human prompt that opened the turn, noting sungen activity and any
7
+ * AskUserQuestion that came after it.
8
+ *
9
+ * The transcript is untrusted data: each line is JSON-parsed and inspected as strings. Nothing in
10
+ * it is ever executed.
11
+ */
12
+ import * as fs from 'fs';
13
+ import * as path from 'path';
14
+
15
+ export interface TurnSummary {
16
+ /** The turn ran sungen: a `/sungen:` prompt, a Bash call running `sungen`, a sungen skill. */
17
+ sungenActivity: boolean;
18
+ /** An AskUserQuestion came AFTER the last sungen activity — the turn already handed back. */
19
+ askedAfter: boolean;
20
+ /** The last unit a sungen call named (`--screen x`, `/sungen:create-test x`). */
21
+ lastUnit?: string;
22
+ }
23
+
24
+ /** Enough for any realistic turn; a transcript can be many MB and the hook has a time budget. */
25
+ const TAIL_BYTES = 512 * 1024;
26
+ const SUNGEN_BASH = /(?:^|[\s;&|(])(?:\S*\/)?sungen(?:\.js)?\s+[a-z]/;
27
+ const UNIT_FLAG = /--(?:screen|flow|area|api)[= ]([\w.-]+(?:\/[\w.-]+)?)/g;
28
+ /** `/sungen:<cmd>` typed, or as Claude Code records it; the unit argument is optional. */
29
+ const SLASH = /\/sungen:[a-z-]+(?:(?:<\/command-name>[\s\S]*?<command-args>|[ \t]+)([\w.-]+))?/;
30
+
31
+ type Block = { type?: unknown; name?: unknown; input?: unknown; text?: unknown };
32
+ type Entry = { type?: unknown; isMeta?: unknown; message?: { role?: unknown; content?: unknown } };
33
+
34
+ function readTail(file: string): string[] {
35
+ const fd = fs.openSync(file, 'r');
36
+ try {
37
+ const size = fs.fstatSync(fd).size;
38
+ const start = Math.max(0, size - TAIL_BYTES);
39
+ const buf = Buffer.alloc(size - start);
40
+ // Only the bytes actually read: a transcript truncated between fstat and read must not leave
41
+ // zero-filled garbage at the end of the buffer.
42
+ const read = fs.readSync(fd, buf, 0, buf.length, start);
43
+ const lines = buf.subarray(0, read).toString('utf8').split('\n');
44
+ return start > 0 ? lines.slice(1) : lines; // the first line of a cut tail is partial
45
+ } finally { fs.closeSync(fd); }
46
+ }
47
+
48
+ const lastUnitIn = (s: string): string | undefined => [...s.matchAll(UNIT_FLAG)].pop()?.[1];
49
+
50
+ /** The human prompt's text, or null when this user entry is a tool result or injected meta. */
51
+ function promptText(e: Entry): string | null {
52
+ if (e.type !== 'user' || e.isMeta === true || e.message?.role !== 'user') return null;
53
+ const c = e.message.content;
54
+ if (typeof c === 'string') return c;
55
+ if (!Array.isArray(c)) return null;
56
+ const text = (c as Block[]).filter((b) => b?.type === 'text' && typeof b.text === 'string').map((b) => b.text as string);
57
+ return text.length ? text.join('\n') : null;
58
+ }
59
+
60
+ /** Summarize the last turn, or null when the transcript cannot be read (callers fail open). */
61
+ export function summarizeTurn(transcriptPath: unknown): TurnSummary | null {
62
+ if (typeof transcriptPath !== 'string' || !path.isAbsolute(transcriptPath)) return null;
63
+ let lines: string[];
64
+ try { lines = readTail(transcriptPath); } catch { return null; }
65
+
66
+ const turn: TurnSummary = { sungenActivity: false, askedAfter: false };
67
+ // Walking backwards, the first unit seen is the most recently named one.
68
+ const sawSungen = (unit?: string): void => {
69
+ turn.lastUnit ??= unit;
70
+ turn.sungenActivity = true;
71
+ };
72
+ for (let i = lines.length - 1; i >= 0; i--) {
73
+ let e: Entry;
74
+ try { e = JSON.parse(lines[i]) as Entry; } catch { continue; }
75
+ if (!e || typeof e !== 'object') continue;
76
+ const prompt = promptText(e);
77
+ if (prompt !== null) {
78
+ const m = prompt.match(SLASH);
79
+ if (m) sawSungen(m[1]);
80
+ break; // the turn starts here
81
+ }
82
+ if (e.type !== 'assistant' || !Array.isArray(e.message?.content)) continue;
83
+ const blocks = e.message!.content as Block[];
84
+ for (let j = blocks.length - 1; j >= 0; j--) {
85
+ const b = blocks[j];
86
+ if (b?.type !== 'tool_use' || !b.input || typeof b.input !== 'object') continue;
87
+ const input = b.input as Record<string, unknown>;
88
+ if (b.name === 'AskUserQuestion') { if (!turn.sungenActivity) turn.askedAfter = true; continue; }
89
+ const cmd = typeof input.command === 'string' ? input.command : '';
90
+ if (b.name === 'Bash' && SUNGEN_BASH.test(cmd)) sawSungen(lastUnitIn(cmd));
91
+ else if (b.name === 'SlashCommand' && cmd.includes('/sungen:')) sawSungen(cmd.match(SLASH)?.[1]);
92
+ else if (b.name === 'Skill' && typeof input.skill === 'string' && input.skill.startsWith('sungen')) sawSungen();
93
+ }
94
+ }
95
+ return turn;
96
+ }
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Guard rule `delivery-contract-verdict` (phase 06, OES-12.3, DOS-14.4, takumi T4): Claude Code may
3
+ * not run `sungen delivery` while a delivered unit's Test Contract verdict is not `pass`.
4
+ *
5
+ * - the verdict is REBUILT from .feature + lock + git HEAD (buildContractVerdict); the report file
6
+ * is never read, so a hand-edited "pass" there is ignored
7
+ * - which units: those `delivery` itself would deliver (contract-units.ts) — every candidate of an
8
+ * ambiguous name, api flows included; bare `delivery`, a runner (`npx`, `pnpm dlx`, `tsx`, `node`…)
9
+ * whose sungen cannot be named, or a `bash -c` / `eval` wrapper → every unit
10
+ * - recognized: `sungen`, `sungen.js`, `@scope/sungen@1.2.3`, `sungen@latest`; `delivery --check`
11
+ * (writes nothing) is allowed; a unit with no lock in the tree or in HEAD is skipped
12
+ * - git runs with a ≈3 s timeout (the hook's own budget is 5 s); git failing while a lock exists,
13
+ * or any other read error, → `ask` (onError), never a silent pass
14
+ * - the command is only tokenized, never executed; unit names are matched against directories
15
+ *
16
+ * The contract module loads only when a command mentions both `sungen` (or a runner) and `delivery`,
17
+ * so every other Edit/Write/Bash call pays nothing for this rule.
18
+ */
19
+ import * as path from 'path';
20
+ import type { HookResult } from './hook-result-contract';
21
+ import { bashSegments } from './bash-write-targets';
22
+ import type { GuardRule } from './guard-rules';
23
+ import { findSungenRoot } from './sungen-project-root';
24
+
25
+ const SUNGEN = /^sungen(?:\.js)?(?:@[^/]*)?$/;
26
+ const RUNNERS = new Set(['npx', 'pnpm', 'yarn', 'bunx', 'bun', 'npm', 'tsx', 'ts-node', 'node', 'deno']);
27
+ /** delivery options that take a value (commander would consume the next word). */
28
+ const VALUE_OPTS = new Set(['--env', '--format', '--approve']);
29
+ const READ_ONLY_OPTS = new Set(['--check', '--help', '-h']);
30
+ const WRAPPED = /\b(?:bash|sh|zsh|dash|eval|xargs)\b/;
31
+ const MENTION = /\bsungen\b[^\n]*\bdelivery\b/;
32
+ const GUARD_GIT_TIMEOUT_MS = 3_000;
33
+
34
+ interface Invocation { dir: string; names: string[] }
35
+
36
+ function namesAfter(args: string[]): string[] {
37
+ const names: string[] = [];
38
+ for (let i = 0; i < args.length; i++) {
39
+ if (VALUE_OPTS.has(args[i])) { i++; continue; }
40
+ if (!args[i].startsWith('-')) names.push(args[i]);
41
+ }
42
+ return names;
43
+ }
44
+
45
+ /**
46
+ * Where `delivery` sits as sungen's subcommand, or -1. Only options, and a word that may be an
47
+ * option's value (`--env staging`), may precede it — so `sungen --env x delivery` is caught while
48
+ * `sungen add --screen delivery` (a unit named delivery) is not a delivery call.
49
+ */
50
+ function deliverySubcommandAt(rest: string[]): number {
51
+ for (let i = 0; i < rest.length; i++) {
52
+ if (rest[i] === 'delivery') return i;
53
+ if (rest[i].startsWith('-')) continue;
54
+ const prev = rest[i - 1];
55
+ if (prev && prev.startsWith('--') && !prev.includes('=')) continue;
56
+ return -1;
57
+ }
58
+ return -1;
59
+ }
60
+
61
+ /** Every `sungen delivery …` the command line would run, with the unit names it passes ([] = every unit). */
62
+ export function deliveryInvocations(command: string, cwd: string): Invocation[] {
63
+ const out: Invocation[] = [];
64
+ for (const seg of bashSegments(command, cwd)) {
65
+ const words = [seg.cmd, ...seg.words];
66
+ const at = words.findIndex((w) => SUNGEN.test(path.basename(w)));
67
+ if (at >= 0) {
68
+ const rest = words.slice(at + 1);
69
+ const sub = deliverySubcommandAt(rest);
70
+ if (sub < 0) continue;
71
+ const args = rest.slice(sub + 1);
72
+ if (!args.some((a) => READ_ONLY_OPTS.has(a))) out.push({ dir: seg.dir, names: namesAfter(args) });
73
+ } else if (RUNNERS.has(seg.cmd) && seg.words.includes('delivery') && !seg.words.some((a) => READ_ONLY_OPTS.has(a))) {
74
+ out.push({ dir: seg.dir, names: [] }); // `tsx src/cli/index.ts delivery`, `node dist/cli/index.js delivery`
75
+ }
76
+ }
77
+ if (!out.length && MENTION.test(command) && WRAPPED.test(command)) out.push({ dir: cwd, names: [] });
78
+ return out;
79
+ }
80
+
81
+ function denyFor(blockers: Array<{ unit: string; verdict: string; headline: string }>): HookResult {
82
+ const lines = blockers.slice(0, 5).map((b) => `\`${b.unit}\` is ${b.verdict}: ${b.headline} — see \`sungen contract check --screen ${b.unit}\``);
83
+ return {
84
+ status: 'deny',
85
+ denyReason: `sungen: delivery is blocked — the Test Contract does not pass.\n${lines.join('\n')}${blockers.length > 5 ? `\n(+${blockers.length - 5} more)` : ''}\n`
86
+ + 'Restore the approved checks in the .feature, or ask QA to approve the change themselves on a terminal (`sungen contract approve --screen <unit>`). '
87
+ + 'Do not edit the lock or the report.',
88
+ };
89
+ }
90
+
91
+ export const deliveryContractVerdict: GuardRule = {
92
+ id: 'delivery-contract-verdict',
93
+ onError: 'ask',
94
+ check(call) {
95
+ const cmd = call.tool === 'Bash' ? call.bashCommand : undefined;
96
+ if (!cmd || !cmd.includes('delivery')) return null;
97
+ const invocations = deliveryInvocations(cmd, call.cwd);
98
+ if (!invocations.length) return null;
99
+ const units = require('../contract/contract-units') as typeof import('../contract/contract-units');
100
+ const { contractBlockers } = require('../contract/project-contract-blockers') as typeof import('../contract/project-contract-blockers');
101
+ const blockers: Array<{ unit: string; verdict: string; headline: string }> = [];
102
+ for (const inv of invocations) {
103
+ const root = findSungenRoot(inv.dir);
104
+ if (!root) continue;
105
+ const targets = inv.names.length ? inv.names.flatMap((n) => units.deliveryUnitsNamed(root, n)) : units.allContractUnits(root);
106
+ blockers.push(...contractBlockers(root, targets, { gitTimeoutMs: GUARD_GIT_TIMEOUT_MS }));
107
+ }
108
+ return blockers.length ? denyFor(blockers) : null;
109
+ },
110
+ };
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Which paths the pre-tool guard protects, and how (P0.1 + review fixes H2, L5).
3
+ *
4
+ * approval records — DENY an agent write:
5
+ * qa/**\/contracts.lock.yaml
6
+ * qa/decisions/<id>.yaml (project decisions, phase 03)
7
+ * qa/<screens|flows|api[/flows]>/<unit>/decisions/<id>.yaml (unit decisions)
8
+ * .sungen/journey/<slug>.state.json (legacy waivers and their dual-written copy, DOS-13.5)
9
+ * .sungen/viewpoint-baseline.json (the accepted viewpoint declaration)
10
+ * — the CLI still writes the last two itself; the guard only judges an agent's tool calls
11
+ * trace evidence — DENY an agent write (phase 08; the verdict trusts it only as far as this guard and git review):
12
+ * .sungen/trace-identity/** (the driver's identity answers — written by the CLI)
13
+ * test-results[-free]/sungen-run-record*.json (run id + test-file hashes — written by the Playwright reporter;
14
+ * test-results-free/ is the free run's own outputDir, #941)
15
+ * hook control — ASK before an agent write (the agent must not switch its own guard off):
16
+ * qa/sungen.config.yaml · .claude/settings.json · .claude/settings.local.json ·
17
+ * .claude/hooks/sungen-hook.cjs
18
+ *
19
+ * The human path for the hook-control files is editing them by hand, then `sungen update`.
20
+ * A `decisions/` folder anywhere else (e.g. `requirements/decisions/notes.md`) is not a record.
21
+ */
22
+ import * as path from 'path';
23
+ import { findSungenRoot } from './sungen-project-root';
24
+
25
+ const LOCK = /^qa\/(?:.+\/)?contracts\.lock\.yaml$/i;
26
+ const DECISION = /^qa\/(?:(?:screens|flows|api(?:\/flows)?)\/[^/]+\/)?decisions\/[^/]+/i;
27
+ const APPROVAL_STATE = /^\.sungen\/(?:journey\/[^/]+\.state\.json|viewpoint-baseline\.json)$/i;
28
+ /** Trace evidence (phase 08, DOS-14.6): the driver's identity answers and the run records. */
29
+ const TRACE_EVIDENCE = /^(?:\.sungen\/trace-identity\/.+|test-results(?:-free)?\/sungen-run-record(?:\.[A-Za-z0-9._-]+)?\.json)$/i;
30
+ const HOOK_CONTROL = ['qa/sungen.config.yaml', '.claude/settings.json', '.claude/settings.local.json', '.claude/hooks/sungen-hook.cjs'];
31
+
32
+ /** The same paths as they appear INSIDE a command string (e.g. in `bash -c "…"` or `python -c "…"`). */
33
+ const MENTIONS = [
34
+ /contracts\.lock\.yaml/i,
35
+ /(?:^|[^\w.-])qa\/(?:(?:screens|flows|api(?:\/flows)?)\/[^/\s'"]+\/)?decisions\//i,
36
+ /\.sungen\/(?:journey\/[^/\s'"]+\.state\.json|viewpoint-baseline\.json)/i,
37
+ /(?:^|[/\s'"=])(?:qa\/sungen\.config\.yaml|\.claude\/settings(?:\.local)?\.json|\.claude\/hooks\/sungen-hook\.cjs)/i,
38
+ /\.sungen\/trace-identity\//i,
39
+ /(?:^|[/\s'"=])sungen-run-record(?:\.[A-Za-z0-9._-]+)?\.json/i,
40
+ ];
41
+
42
+ const posix = (p: string): string => p.split(path.sep).join('/');
43
+
44
+ /** `abs` relative to its sungen project, when it is an approval record (lock, decision, approval state); else null. */
45
+ export function approvalRecordPath(abs: string): string | null {
46
+ const root = findSungenRoot(path.dirname(abs));
47
+ if (!root) return null;
48
+ const rel = posix(path.relative(root, abs));
49
+ return LOCK.test(rel) || DECISION.test(rel) || APPROVAL_STATE.test(rel) ? rel : null;
50
+ }
51
+
52
+ /** `abs` relative to its sungen project, when it is a trace evidence store; else null. */
53
+ export function traceEvidencePath(abs: string): string | null {
54
+ const root = findSungenRoot(path.dirname(abs));
55
+ if (!root) return null;
56
+ const rel = posix(path.relative(root, abs));
57
+ return TRACE_EVIDENCE.test(rel) ? rel : null;
58
+ }
59
+
60
+ /** The hook-control file `abs` is (as its project-relative name), or null. */
61
+ export function hookControlPath(abs: string): string | null {
62
+ const p = posix(path.resolve(abs)).toLowerCase();
63
+ return HOOK_CONTROL.find((rel) => p.endsWith(`/${rel}`)) ?? null;
64
+ }
65
+
66
+ /** Does this command word name a protected path — as text, or once resolved against `dir`? */
67
+ export function mentionsProtectedPath(word: string, dir: string): boolean {
68
+ if (MENTIONS.some((re) => re.test(word))) return true;
69
+ const abs = path.resolve(dir, word);
70
+ return approvalRecordPath(abs) !== null || traceEvidencePath(abs) !== null || hookControlPath(abs) !== null;
71
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * The pre-tool guard's rules. Each looks at one normalized tool call and returns a decision or
3
+ * null; pre-tool-guard-hook.ts runs them in order (first deny wins, else first ask).
4
+ *
5
+ * protected-approval-paths DENY a precise write (Edit/Write/MultiEdit, or Bash `>`, `tee`,
6
+ * `sed -i`) to a contract lock, a decision record, approval state or
7
+ * trace evidence (.sungen/trace-identity, test-results[-free]/sungen-run-record*)
8
+ * protected-hook-control ASK the same writes to the files that control the hooks, so the
9
+ * agent cannot switch its own guard off unasked
10
+ * bash-protected-mention ASK any other Bash segment that names a protected path and does not
11
+ * start with a read-only command (cp, mv, ln, install, rm,
12
+ * bash -c, python -c, perl -i…)
13
+ *
14
+ * A floor, not a sandbox: a path built at runtime, a symlink, or a script file that writes without
15
+ * naming the path on the command line is out of reach by design. Each rule only matches strings,
16
+ * so each fails open (`onError: 'no-op'`); a rule that READS project state must declare `'ask'`.
17
+ */
18
+ import type { HookContext, HookResult } from './hook-result-contract';
19
+ import { bashSegments } from './bash-write-targets';
20
+ import { approvalRecordPath, hookControlPath, mentionsProtectedPath, traceEvidencePath } from './guard-protected-paths';
21
+
22
+ /** One tool call, normalized from the untrusted payload. */
23
+ export interface GuardedCall {
24
+ tool: string;
25
+ /** Absolute target paths of a file tool (Edit/Write/MultiEdit). */
26
+ filePaths: string[];
27
+ bashCommand?: string;
28
+ cwd: string;
29
+ }
30
+
31
+ export interface GuardRule {
32
+ id: string;
33
+ /** What a throw inside `check` becomes: `ask` for a rule that reads state, `no-op` otherwise. */
34
+ onError: 'ask' | 'no-op';
35
+ /** A decision for this call, or null when the rule has nothing to say about it. */
36
+ check(call: GuardedCall, ctx: HookContext): HookResult | null;
37
+ }
38
+
39
+ /** The files a call writes precisely: a file tool's target, or Bash's `>` / `tee` / `sed -i` targets. */
40
+ const preciseWrites = (call: GuardedCall): string[] =>
41
+ call.tool === 'Bash' ? bashSegments(call.bashCommand ?? '', call.cwd).flatMap((s) => s.writes) : call.filePaths;
42
+
43
+ export const protectedApprovalPaths: GuardRule = {
44
+ id: 'protected-approval-paths',
45
+ onError: 'no-op',
46
+ check(call) {
47
+ const writes = preciseWrites(call);
48
+ const rel = writes.map(approvalRecordPath).find((r): r is string => r !== null);
49
+ if (rel) {
50
+ return {
51
+ status: 'deny',
52
+ denyReason: `sungen: \`${rel}\` is an approval record — contract locks, decisions, waivers and the accepted `
53
+ + 'viewpoint baseline change only through a human at a terminal, never by an agent edit. If this change is '
54
+ + 'intended, stop and ask the user to make it themselves.',
55
+ };
56
+ }
57
+ const evidence = writes.map(traceEvidencePath).find((r): r is string => r !== null);
58
+ return evidence ? {
59
+ status: 'deny',
60
+ denyReason: `sungen: \`${evidence}\` is trace evidence — only \`sungen contract check --trace\` / \`contract derive\` `
61
+ + 'and the Playwright run-record reporter write it. Re-run the free tests or the CLI instead of editing it.',
62
+ } : null;
63
+ },
64
+ };
65
+
66
+ export const protectedHookControl: GuardRule = {
67
+ id: 'protected-hook-control',
68
+ onError: 'no-op',
69
+ check(call) {
70
+ const rel = preciseWrites(call).map(hookControlPath).find((r): r is string => r !== null);
71
+ return rel ? {
72
+ status: 'ask',
73
+ askReason: `sungen: \`${rel}\` controls sungen's hooks and guard, so an agent does not change it on its own. `
74
+ + 'Allow only if you asked for exactly this change — the usual path is to edit it by hand, then run `sungen update`.',
75
+ } : null;
76
+ },
77
+ };
78
+
79
+ /** Segments that only read: they may name a protected path freely. */
80
+ const READ_ONLY = new Set(['cat', 'ls', 'head', 'tail', 'grep', 'rg', 'wc', 'diff', 'sungen', 'sungen.js']);
81
+ const GIT_READ_ONLY = new Set(['diff', 'log', 'show', 'status']);
82
+ const isReadOnly = (cmd: string, words: string[]): boolean =>
83
+ READ_ONLY.has(cmd) || (cmd === 'git' && GIT_READ_ONLY.has(words.find((w) => !w.startsWith('-')) ?? ''));
84
+
85
+ export const bashProtectedMention: GuardRule = {
86
+ id: 'bash-protected-mention',
87
+ onError: 'no-op',
88
+ check(call) {
89
+ if (call.tool !== 'Bash' || !call.bashCommand) return null;
90
+ const seg = bashSegments(call.bashCommand, call.cwd)
91
+ .find((s) => s.cmd && !isReadOnly(s.cmd, s.words) && s.words.some((w) => mentionsProtectedPath(w, s.dir)));
92
+ return seg ? {
93
+ status: 'ask',
94
+ askReason: `sungen: this \`${seg.cmd}\` command names a contract lock, a decision record, approval state or a hook-control file, `
95
+ + 'and the guard cannot tell whether it writes it. Allow only if you asked for exactly this.',
96
+ } : null;
97
+ },
98
+ };
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Guard rule `tty-spoof` (phase 06, M5): ASK before an agent runs a human-confirmed sungen command
3
+ * through a terminal emulator.
4
+ *
5
+ * `contract approve`, `journey --waive`, `journey --decide` and `journey --signoff` refuse without a TTY (DOS-13.4), and
6
+ * an agent's Bash has none — unless it borrows one: `script`, `expect`, `unbuffer`, or a pty from
7
+ * Python/Perl/zsh. Then the prompt sees a "terminal" and a piped phrase reads as a human typing it.
8
+ * This rule spots the pair in the raw command (quotes included, so `bash -c "…"` and `expect -c '…'`
9
+ * are covered) and hands the call to the user. A floor, not a sandbox: a script file that does the
10
+ * same without naming either on the command line is out of reach by design. String match only, so
11
+ * it fails open.
12
+ */
13
+ import type { GuardRule } from './guard-rules';
14
+
15
+ const TTY_EMULATOR = /\b(?:script|unbuffer|expect|pty|zpty|openpty|forkpty|ptyprocess)\b/i;
16
+ const HUMAN_GATED = /\bsungen\b[\s\S]*?\b(?:contract['",\s]+approve\b|journey\b[\s\S]*?--(?:waive|decide|signoff)\b)/i;
17
+
18
+ export const ttySpoof: GuardRule = {
19
+ id: 'tty-spoof',
20
+ onError: 'no-op',
21
+ check(call) {
22
+ const cmd = call.tool === 'Bash' ? call.bashCommand : undefined;
23
+ if (!cmd || !TTY_EMULATOR.test(cmd) || !HUMAN_GATED.test(cmd)) return null;
24
+ return {
25
+ status: 'ask',
26
+ askReason: 'sungen: this runs a human-confirmed sungen action (`contract approve` / `journey --waive|--decide|--signoff`) through a terminal '
27
+ + 'emulator (script / expect / unbuffer / pty). Those confirmations exist so a PERSON at a terminal decides — allow only if you '
28
+ + 'are that person and asked for exactly this; otherwise run the command yourself in your own terminal.',
29
+ };
30
+ },
31
+ };