project-tiny-context-harness 0.2.85 → 0.6.0

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 (361) hide show
  1. package/README.md +163 -428
  2. package/assets/README.md +283 -455
  3. package/assets/README.zh-CN.md +199 -123
  4. package/assets/agents/AGENTS_CORE.md +54 -67
  5. package/assets/context_templates/context.toml +3 -0
  6. package/assets/context_templates/global.md +6 -6
  7. package/assets/github/harness.yml +2 -2
  8. package/assets/skills/context_development_engineer/SKILL.md +91 -107
  9. package/assets/skills/context_product_plan/SKILL.md +18 -28
  10. package/assets/skills/context_surface_contract/SKILL.md +35 -38
  11. package/assets/skills/context_uiux_design/SKILL.md +31 -30
  12. package/assets/skills/long-task-workflow/SKILL.md +76 -0
  13. package/assets/skills/long-task-workflow/agents/openai.yaml +4 -0
  14. package/assets/skills/long-task-workflow/references/authority-lifecycle.md +41 -0
  15. package/assets/skills/long-task-workflow/references/contract-authoring.md +62 -0
  16. package/assets/skills/long-task-workflow/references/evidence-design.md +45 -0
  17. package/assets/skills/normal-long-task/SKILL.md +12 -489
  18. package/assets/skills/source-plan-authoring/SKILL.md +379 -0
  19. package/assets/tools/validate_context.py +293 -127
  20. package/dist/cli.js +3 -1
  21. package/dist/commands/check-modularity.js +33 -10
  22. package/dist/commands/composite-campaign.d.ts +1 -0
  23. package/dist/commands/composite-campaign.js +8 -0
  24. package/dist/commands/composite-long-task.d.ts +1 -6
  25. package/dist/commands/composite-long-task.js +7 -163
  26. package/dist/commands/delivery-set.d.ts +1 -0
  27. package/dist/commands/delivery-set.js +8 -0
  28. package/dist/commands/disable.d.ts +1 -0
  29. package/dist/commands/disable.js +15 -0
  30. package/dist/commands/enable.d.ts +1 -0
  31. package/dist/commands/enable.js +14 -0
  32. package/dist/commands/export-context-args.js +13 -4
  33. package/dist/commands/export-context.js +18 -7
  34. package/dist/commands/index.js +42 -30
  35. package/dist/commands/init.js +12 -6
  36. package/dist/commands/long-task-authoring.d.ts +3 -0
  37. package/dist/commands/long-task-authoring.js +92 -0
  38. package/dist/commands/long-task-explain.d.ts +1 -0
  39. package/dist/commands/long-task-explain.js +52 -0
  40. package/dist/commands/long-task.d.ts +1 -0
  41. package/dist/commands/long-task.js +226 -0
  42. package/dist/commands/package-source.js +2 -2
  43. package/dist/commands/upgrade.js +10 -10
  44. package/dist/index.d.ts +11 -1
  45. package/dist/index.js +8 -0
  46. package/dist/lib/config.js +34 -8
  47. package/dist/lib/context-default-footprint.d.ts +16 -0
  48. package/dist/lib/context-default-footprint.js +107 -0
  49. package/dist/lib/context-export.js +105 -41
  50. package/dist/lib/context-graph-snapshot.d.ts +18 -0
  51. package/dist/lib/context-graph-snapshot.js +171 -0
  52. package/dist/lib/context-manifest-schema.d.ts +28 -0
  53. package/dist/lib/context-manifest-schema.js +150 -0
  54. package/dist/lib/context-manifest.js +28 -20
  55. package/dist/lib/context-templates.js +5 -5
  56. package/dist/lib/design-md.js +1 -1
  57. package/dist/lib/doctor.js +54 -1
  58. package/dist/lib/harness-root.js +25 -8
  59. package/dist/lib/init.js +6 -3
  60. package/dist/lib/legacy-managed-scan.js +23 -7
  61. package/dist/lib/legacy-sdlc-migration.js +21 -11
  62. package/dist/lib/long-task-acceptance-reference.d.ts +22 -0
  63. package/dist/lib/long-task-acceptance-reference.js +46 -0
  64. package/dist/lib/long-task-acceptance-shape.d.ts +5 -0
  65. package/dist/lib/long-task-acceptance-shape.js +131 -0
  66. package/dist/lib/long-task-activation-validation.d.ts +21 -0
  67. package/dist/lib/long-task-activation-validation.js +136 -0
  68. package/dist/lib/long-task-artifacts.d.ts +5 -0
  69. package/dist/lib/long-task-artifacts.js +34 -0
  70. package/dist/lib/long-task-assertions-v2.d.ts +22 -0
  71. package/dist/lib/long-task-assertions-v2.js +212 -0
  72. package/dist/lib/long-task-authoring-authority-preview.d.ts +5 -0
  73. package/dist/lib/long-task-authoring-authority-preview.js +85 -0
  74. package/dist/lib/long-task-authoring-preflight-diagnostics.d.ts +8 -0
  75. package/dist/lib/long-task-authoring-preflight-diagnostics.js +179 -0
  76. package/dist/lib/long-task-authoring-preflight-repair-order.d.ts +8 -0
  77. package/dist/lib/long-task-authoring-preflight-repair-order.js +95 -0
  78. package/dist/lib/long-task-authoring-preflight-types.d.ts +46 -0
  79. package/dist/lib/long-task-authoring-preflight-types.js +38 -0
  80. package/dist/lib/long-task-authoring-preflight.d.ts +3 -0
  81. package/dist/lib/long-task-authoring-preflight.js +44 -0
  82. package/dist/lib/long-task-authority-material-diff.d.ts +17 -0
  83. package/dist/lib/long-task-authority-material-diff.js +152 -0
  84. package/dist/lib/long-task-authority-materials.d.ts +7 -0
  85. package/dist/lib/long-task-authority-materials.js +83 -0
  86. package/dist/lib/long-task-authority-policy.d.ts +168 -0
  87. package/dist/lib/long-task-authority-policy.js +181 -0
  88. package/dist/lib/long-task-authority-revision-details.d.ts +19 -0
  89. package/dist/lib/long-task-authority-revision-details.js +192 -0
  90. package/dist/lib/long-task-authority-revision-enforcement.d.ts +3 -0
  91. package/dist/lib/long-task-authority-revision-enforcement.js +41 -0
  92. package/dist/lib/long-task-authority-revision-types.d.ts +50 -0
  93. package/dist/lib/long-task-authority-revision-types.js +1 -0
  94. package/dist/lib/long-task-authority-revision.d.ts +4 -0
  95. package/dist/lib/long-task-authority-revision.js +188 -0
  96. package/dist/lib/long-task-authority-transition-policy.d.ts +62 -0
  97. package/dist/lib/long-task-authority-transition-policy.js +62 -0
  98. package/dist/lib/long-task-authority-types.d.ts +96 -0
  99. package/dist/lib/long-task-authority-types.js +1 -0
  100. package/dist/lib/long-task-authority.d.ts +7 -0
  101. package/dist/lib/long-task-authority.js +142 -0
  102. package/dist/lib/long-task-boundary-check.d.ts +15 -0
  103. package/dist/lib/long-task-boundary-check.js +9 -0
  104. package/dist/lib/long-task-check-evidence-decoder.d.ts +3 -0
  105. package/dist/lib/long-task-check-evidence-decoder.js +74 -0
  106. package/dist/lib/long-task-check-execution-policy.d.ts +18 -0
  107. package/dist/lib/long-task-check-execution-policy.js +36 -0
  108. package/dist/lib/long-task-check-runner.d.ts +2 -0
  109. package/dist/lib/long-task-check-runner.js +181 -0
  110. package/dist/lib/long-task-check-shape.d.ts +2 -0
  111. package/dist/lib/long-task-check-shape.js +136 -0
  112. package/dist/lib/long-task-claim-definitions.d.ts +7 -0
  113. package/dist/lib/long-task-claim-definitions.js +78 -0
  114. package/dist/lib/long-task-claim-proof-policy.d.ts +4 -0
  115. package/dist/lib/long-task-claim-proof-policy.js +57 -0
  116. package/dist/lib/long-task-claims.d.ts +10 -0
  117. package/dist/lib/long-task-claims.js +187 -0
  118. package/dist/lib/long-task-context-authority-topology.d.ts +7 -0
  119. package/dist/lib/long-task-context-authority-topology.js +37 -0
  120. package/dist/lib/long-task-context-authority.d.ts +14 -0
  121. package/dist/lib/long-task-context-authority.js +66 -0
  122. package/dist/lib/long-task-contract-types.d.ts +203 -0
  123. package/dist/lib/long-task-contract-types.js +1 -0
  124. package/dist/lib/long-task-counterfactual-claim-policy.d.ts +10 -0
  125. package/dist/lib/long-task-counterfactual-claim-policy.js +57 -0
  126. package/dist/lib/long-task-counterfactual-sandbox.d.ts +6 -0
  127. package/dist/lib/long-task-counterfactual-sandbox.js +87 -0
  128. package/dist/lib/long-task-counterfactual-types.d.ts +24 -0
  129. package/dist/lib/long-task-counterfactual-types.js +1 -0
  130. package/dist/lib/long-task-delivery-compiler.d.ts +10 -0
  131. package/dist/lib/long-task-delivery-compiler.js +129 -0
  132. package/dist/lib/long-task-delivery-parser.d.ts +13 -0
  133. package/dist/lib/long-task-delivery-parser.js +90 -0
  134. package/dist/lib/long-task-delivery-preflight.d.ts +5 -0
  135. package/dist/lib/long-task-delivery-preflight.js +151 -0
  136. package/dist/lib/long-task-delivery-shape.d.ts +5 -0
  137. package/dist/lib/long-task-delivery-shape.js +5 -0
  138. package/dist/lib/long-task-delivery-types.d.ts +8 -0
  139. package/dist/lib/long-task-delivery-types.js +8 -0
  140. package/dist/lib/long-task-delivery-validation.d.ts +3 -0
  141. package/dist/lib/long-task-delivery-validation.js +175 -0
  142. package/dist/lib/long-task-evidence-adapter-policy.d.ts +4 -0
  143. package/dist/lib/long-task-evidence-adapter-policy.js +15 -0
  144. package/dist/lib/long-task-evidence-adapter-types.d.ts +1 -0
  145. package/dist/lib/long-task-evidence-adapter-types.js +1 -0
  146. package/dist/lib/long-task-evidence-findings.d.ts +5 -0
  147. package/dist/lib/long-task-evidence-findings.js +113 -0
  148. package/dist/lib/long-task-evidence-sensitivity-policy.d.ts +4 -0
  149. package/dist/lib/long-task-evidence-sensitivity-policy.js +98 -0
  150. package/dist/lib/long-task-evidence-v2.d.ts +5 -0
  151. package/dist/lib/long-task-evidence-v2.js +226 -0
  152. package/dist/lib/long-task-explain-acceptance-link.d.ts +46 -0
  153. package/dist/lib/long-task-explain-acceptance-link.js +96 -0
  154. package/dist/lib/long-task-explain-claim-links.d.ts +45 -0
  155. package/dist/lib/long-task-explain-claim-links.js +88 -0
  156. package/dist/lib/long-task-explain-source-links.d.ts +93 -0
  157. package/dist/lib/long-task-explain-source-links.js +51 -0
  158. package/dist/lib/long-task-final-v2.d.ts +2 -0
  159. package/dist/lib/long-task-final-v2.js +124 -0
  160. package/dist/lib/long-task-finding-context.d.ts +3 -0
  161. package/dist/lib/long-task-finding-context.js +63 -0
  162. package/dist/lib/long-task-freshness.d.ts +3 -0
  163. package/dist/lib/long-task-freshness.js +80 -0
  164. package/dist/lib/long-task-hook-install.d.ts +9 -0
  165. package/dist/lib/long-task-hook-install.js +184 -0
  166. package/dist/lib/long-task-hook-preflight.d.ts +7 -0
  167. package/dist/lib/long-task-hook-preflight.js +58 -0
  168. package/dist/lib/long-task-observation-ownership.d.ts +2 -0
  169. package/dist/lib/long-task-observation-ownership.js +22 -0
  170. package/dist/lib/long-task-outcome-parser.d.ts +4 -0
  171. package/dist/lib/long-task-outcome-parser.js +100 -0
  172. package/dist/lib/long-task-paths.d.ts +49 -0
  173. package/dist/lib/long-task-paths.js +418 -0
  174. package/dist/lib/long-task-playwright-counterfactual-policy.d.ts +7 -0
  175. package/dist/lib/long-task-playwright-counterfactual-policy.js +125 -0
  176. package/dist/lib/long-task-playwright-evidence.d.ts +6 -0
  177. package/dist/lib/long-task-playwright-evidence.js +244 -0
  178. package/dist/lib/long-task-product-shape.d.ts +6 -0
  179. package/dist/lib/long-task-product-shape.js +73 -0
  180. package/dist/lib/long-task-progress.d.ts +4 -0
  181. package/dist/lib/long-task-progress.js +114 -0
  182. package/dist/lib/long-task-protected-files.d.ts +1 -0
  183. package/dist/lib/long-task-protected-files.js +30 -0
  184. package/dist/lib/long-task-required-proof-surfaces.d.ts +2 -0
  185. package/dist/lib/long-task-required-proof-surfaces.js +13 -0
  186. package/dist/lib/long-task-requirement-shape.d.ts +2 -0
  187. package/dist/lib/long-task-requirement-shape.js +18 -0
  188. package/dist/lib/long-task-risk-surfaces.d.ts +2 -0
  189. package/dist/lib/long-task-risk-surfaces.js +60 -0
  190. package/dist/lib/long-task-risk-types.d.ts +5 -0
  191. package/dist/lib/long-task-risk-types.js +12 -0
  192. package/dist/lib/long-task-risk.d.ts +9 -0
  193. package/dist/lib/long-task-risk.js +132 -0
  194. package/dist/lib/long-task-root-shape.d.ts +4 -0
  195. package/dist/lib/long-task-root-shape.js +86 -0
  196. package/dist/lib/long-task-runner-environment.d.ts +7 -0
  197. package/dist/lib/long-task-runner-environment.js +57 -0
  198. package/dist/lib/long-task-runner-files.d.ts +3 -0
  199. package/dist/lib/long-task-runner-files.js +39 -0
  200. package/dist/lib/long-task-runner-freeze.d.ts +2 -0
  201. package/dist/lib/long-task-runner-freeze.js +168 -0
  202. package/dist/lib/long-task-runtime-types.d.ts +214 -0
  203. package/dist/lib/long-task-runtime-types.js +1 -0
  204. package/dist/lib/long-task-shape-primitives.d.ts +17 -0
  205. package/dist/lib/long-task-shape-primitives.js +81 -0
  206. package/dist/lib/long-task-source-authority-types.d.ts +13 -0
  207. package/dist/lib/long-task-source-authority-types.js +1 -0
  208. package/dist/lib/long-task-source-claim-validation.d.ts +5 -0
  209. package/dist/lib/long-task-source-claim-validation.js +96 -0
  210. package/dist/lib/long-task-source-continuity.d.ts +4 -0
  211. package/dist/lib/long-task-source-continuity.js +57 -0
  212. package/dist/lib/long-task-source-inventory.d.ts +2 -0
  213. package/dist/lib/long-task-source-inventory.js +21 -0
  214. package/dist/lib/long-task-source-item-parser.d.ts +3 -0
  215. package/dist/lib/long-task-source-item-parser.js +112 -0
  216. package/dist/lib/long-task-source-shape.d.ts +2 -0
  217. package/dist/lib/long-task-source-shape.js +56 -0
  218. package/dist/lib/long-task-source-target-continuity.d.ts +4 -0
  219. package/dist/lib/long-task-source-target-continuity.js +80 -0
  220. package/dist/lib/long-task-source-target-index.d.ts +12 -0
  221. package/dist/lib/long-task-source-target-index.js +76 -0
  222. package/dist/lib/long-task-source-validation.d.ts +3 -0
  223. package/dist/lib/long-task-source-validation.js +46 -0
  224. package/dist/lib/long-task-state.d.ts +91 -0
  225. package/dist/lib/long-task-state.js +611 -0
  226. package/dist/lib/long-task-status-projection.d.ts +21 -0
  227. package/dist/lib/long-task-status-projection.js +116 -0
  228. package/dist/lib/long-task-status-v2.d.ts +37 -0
  229. package/dist/lib/long-task-status-v2.js +306 -0
  230. package/dist/lib/long-task-technical-shape.d.ts +3 -0
  231. package/dist/lib/long-task-technical-shape.js +44 -0
  232. package/dist/lib/long-task-verifier-authority.d.ts +12 -0
  233. package/dist/lib/long-task-verifier-authority.js +47 -0
  234. package/dist/lib/long-task-verifier-identity.d.ts +2 -0
  235. package/dist/lib/long-task-verifier-identity.js +55 -0
  236. package/dist/lib/long-task-verifier-v2.d.ts +13 -0
  237. package/dist/lib/long-task-verifier-v2.js +266 -0
  238. package/dist/lib/long-task-workspace-runtime-types.d.ts +23 -0
  239. package/dist/lib/long-task-workspace-runtime-types.js +1 -0
  240. package/dist/lib/long-task-workspace.d.ts +25 -0
  241. package/dist/lib/long-task-workspace.js +366 -0
  242. package/dist/lib/managed-file.js +20 -5
  243. package/dist/lib/migrations.js +156 -32
  244. package/dist/lib/modularity.d.ts +27 -1
  245. package/dist/lib/modularity.js +499 -23
  246. package/dist/lib/package-json-config.js +14 -5
  247. package/dist/lib/package-source.js +4 -2
  248. package/dist/lib/profiles.d.ts +13 -0
  249. package/dist/lib/profiles.js +66 -0
  250. package/dist/lib/schema-guard.js +4 -2
  251. package/dist/lib/source-files.js +14 -7
  252. package/dist/lib/source-pack-classify.js +91 -19
  253. package/dist/lib/source-pack-config.js +25 -8
  254. package/dist/lib/source-pack-export.js +84 -25
  255. package/dist/lib/source-pack-manifest.js +18 -6
  256. package/dist/lib/source-pack-records.js +35 -11
  257. package/dist/lib/source-pack-render.js +47 -18
  258. package/dist/lib/stable-json.d.ts +2 -0
  259. package/dist/lib/stable-json.js +21 -0
  260. package/dist/lib/strict-codec.d.ts +4 -0
  261. package/dist/lib/strict-codec.js +65 -0
  262. package/dist/lib/sync-engine.js +76 -24
  263. package/dist/lib/types.d.ts +8 -1
  264. package/dist/lib/upgrade.js +4 -3
  265. package/dist/lib/validators.js +218 -191
  266. package/dist/long-task-hook.d.ts +2 -0
  267. package/dist/long-task-hook.js +55 -0
  268. package/dist/schemas/long-task-delivery-v2/long-task-delivery-v2.schema.json +340 -0
  269. package/dist/schemas/long-task-delivery-v2/long-task-outcomes-v2.schema.json +18 -0
  270. package/migrations/README.md +8 -3
  271. package/package.json +17 -6
  272. package/source-mappings.yaml +0 -3
  273. package/assets/protected-harness-baseline.json +0 -20
  274. package/assets/skills/composite-long-task-workflow/SKILL.md +0 -245
  275. package/assets/skills/composite-long-task-workflow/assets/execution-binding.template.md +0 -62
  276. package/assets/skills/composite-long-task-workflow/assets/goal-objective.template.md +0 -17
  277. package/assets/skills/composite-long-task-workflow/references/composite-long-task-workflow-protocol.md +0 -682
  278. package/dist/commands/superpowers.d.ts +0 -1
  279. package/dist/commands/superpowers.js +0 -8
  280. package/dist/lib/composite-long-task-renderer.d.ts +0 -12
  281. package/dist/lib/composite-long-task-renderer.js +0 -109
  282. package/dist/lib/plan-acceptance-artifacts.d.ts +0 -1
  283. package/dist/lib/plan-acceptance-artifacts.js +0 -220
  284. package/dist/lib/plan-acceptance-evidence.d.ts +0 -2
  285. package/dist/lib/plan-acceptance-evidence.js +0 -108
  286. package/dist/lib/plan-acceptance-json.d.ts +0 -15
  287. package/dist/lib/plan-acceptance-json.js +0 -133
  288. package/dist/lib/plan-acceptance-validator.d.ts +0 -2
  289. package/dist/lib/plan-acceptance-validator.js +0 -209
  290. package/dist/lib/plan-contract-validator.d.ts +0 -2
  291. package/dist/lib/plan-contract-validator.js +0 -127
  292. package/dist/lib/plan-validator-common.d.ts +0 -24
  293. package/dist/lib/plan-validator-common.js +0 -196
  294. package/dist/lib/superpowers-task-ac010.d.ts +0 -6
  295. package/dist/lib/superpowers-task-ac010.js +0 -26
  296. package/dist/lib/superpowers-task-assertion-normalizers.d.ts +0 -3
  297. package/dist/lib/superpowers-task-assertion-normalizers.js +0 -74
  298. package/dist/lib/superpowers-task-assertions.d.ts +0 -20
  299. package/dist/lib/superpowers-task-assertions.js +0 -257
  300. package/dist/lib/superpowers-task-attempt.d.ts +0 -4
  301. package/dist/lib/superpowers-task-attempt.js +0 -102
  302. package/dist/lib/superpowers-task-command-run-correlation.d.ts +0 -8
  303. package/dist/lib/superpowers-task-command-run-correlation.js +0 -103
  304. package/dist/lib/superpowers-task-command-specs.d.ts +0 -3
  305. package/dist/lib/superpowers-task-command-specs.js +0 -52
  306. package/dist/lib/superpowers-task-compile-diagnostics.d.ts +0 -5
  307. package/dist/lib/superpowers-task-compile-diagnostics.js +0 -20
  308. package/dist/lib/superpowers-task-compile-guards.d.ts +0 -2
  309. package/dist/lib/superpowers-task-compile-guards.js +0 -66
  310. package/dist/lib/superpowers-task-compile.d.ts +0 -6
  311. package/dist/lib/superpowers-task-compile.js +0 -133
  312. package/dist/lib/superpowers-task-completion-output.d.ts +0 -91
  313. package/dist/lib/superpowers-task-completion-output.js +0 -374
  314. package/dist/lib/superpowers-task-conformance.d.ts +0 -2
  315. package/dist/lib/superpowers-task-conformance.js +0 -24
  316. package/dist/lib/superpowers-task-contradictions.d.ts +0 -6
  317. package/dist/lib/superpowers-task-contradictions.js +0 -126
  318. package/dist/lib/superpowers-task-current-evidence.d.ts +0 -3
  319. package/dist/lib/superpowers-task-current-evidence.js +0 -176
  320. package/dist/lib/superpowers-task-delivery.d.ts +0 -4
  321. package/dist/lib/superpowers-task-delivery.js +0 -96
  322. package/dist/lib/superpowers-task-derive.d.ts +0 -14
  323. package/dist/lib/superpowers-task-derive.js +0 -393
  324. package/dist/lib/superpowers-task-events.d.ts +0 -1
  325. package/dist/lib/superpowers-task-events.js +0 -13
  326. package/dist/lib/superpowers-task-evidence-kernel.d.ts +0 -19
  327. package/dist/lib/superpowers-task-evidence-kernel.js +0 -347
  328. package/dist/lib/superpowers-task-evidence-records.d.ts +0 -2
  329. package/dist/lib/superpowers-task-evidence-records.js +0 -55
  330. package/dist/lib/superpowers-task-evidence.d.ts +0 -10
  331. package/dist/lib/superpowers-task-evidence.js +0 -147
  332. package/dist/lib/superpowers-task-fields.d.ts +0 -22
  333. package/dist/lib/superpowers-task-fields.js +0 -276
  334. package/dist/lib/superpowers-task-final-card.d.ts +0 -3
  335. package/dist/lib/superpowers-task-final-card.js +0 -35
  336. package/dist/lib/superpowers-task-gates.d.ts +0 -12
  337. package/dist/lib/superpowers-task-gates.js +0 -267
  338. package/dist/lib/superpowers-task-harness-drift.d.ts +0 -11
  339. package/dist/lib/superpowers-task-harness-drift.js +0 -90
  340. package/dist/lib/superpowers-task-next-slices.d.ts +0 -1
  341. package/dist/lib/superpowers-task-next-slices.js +0 -12
  342. package/dist/lib/superpowers-task-protected-baseline.d.ts +0 -10
  343. package/dist/lib/superpowers-task-protected-baseline.js +0 -66
  344. package/dist/lib/superpowers-task-source-compile.d.ts +0 -5
  345. package/dist/lib/superpowers-task-source-compile.js +0 -226
  346. package/dist/lib/superpowers-task-source-parser.d.ts +0 -23
  347. package/dist/lib/superpowers-task-source-parser.js +0 -218
  348. package/dist/lib/superpowers-task-state-schema.d.ts +0 -460
  349. package/dist/lib/superpowers-task-state-schema.js +0 -66
  350. package/dist/lib/superpowers-task-state-shape.d.ts +0 -3
  351. package/dist/lib/superpowers-task-state-shape.js +0 -50
  352. package/dist/lib/superpowers-task-state.d.ts +0 -16
  353. package/dist/lib/superpowers-task-state.js +0 -246
  354. package/dist/lib/superpowers-task-status.d.ts +0 -2
  355. package/dist/lib/superpowers-task-status.js +0 -24
  356. package/dist/lib/superpowers-task-under-specified.d.ts +0 -7
  357. package/dist/lib/superpowers-task-under-specified.js +0 -61
  358. package/dist/lib/superpowers-task-unregistered-evidence.d.ts +0 -11
  359. package/dist/lib/superpowers-task-unregistered-evidence.js +0 -72
  360. package/dist/lib/superpowers-task-validator.d.ts +0 -5
  361. package/dist/lib/superpowers-task-validator.js +0 -293
@@ -1,5 +1,5 @@
1
1
  import { runDoctor } from "./doctor.js";
2
- import { createUpgradePlan, formatUpgradePlan, runMigrations } from "./migrations.js";
2
+ import { createUpgradePlan, formatUpgradePlan, runMigrations, } from "./migrations.js";
3
3
  import { assertSupportedSchema } from "./schema-guard.js";
4
4
  import { runSync } from "./sync-engine.js";
5
5
  export class UpgradeBlockedError extends Error {
@@ -29,11 +29,12 @@ export async function runUpgradeReport(projectRoot) {
29
29
  }
30
30
  const migrationReport = await runMigrations(projectRoot, plan);
31
31
  lines.push(`migrations changed=${migrationReport.changed.length} skipped=${migrationReport.skipped.length} manual_required=${migrationReport.manualRequired.length} blocked=${migrationReport.blocked.length}`);
32
- if (migrationReport.manualRequired.length > 0 || migrationReport.blocked.length > 0) {
32
+ if (migrationReport.manualRequired.length > 0 ||
33
+ migrationReport.blocked.length > 0) {
33
34
  lines.push(...formatUpgradePlan({
34
35
  safe_pending: [],
35
36
  manual_required: migrationReport.manualRequired,
36
- blocked: migrationReport.blocked
37
+ blocked: migrationReport.blocked,
37
38
  }).slice(1));
38
39
  }
39
40
  const syncReport = await runSync(projectRoot);
@@ -1,19 +1,16 @@
1
1
  import path from "node:path";
2
+ import { existsSync } from "node:fs";
3
+ import { realpath } from "node:fs/promises";
2
4
  import { readConfig } from "./config.js";
5
+ import { parseContextManifest, } from "./context-manifest-schema.js";
3
6
  import { harnessPath, harnessRoot } from "./harness-root.js";
4
7
  import { listFiles, pathExists, readText } from "./fs.js";
5
8
  import { runModularityCheck } from "./modularity.js";
6
- import { validatePlanAcceptance } from "./plan-acceptance-validator.js";
7
- import { validatePlanContract } from "./plan-contract-validator.js";
8
- import { validateSuperpowersState } from "./superpowers-task-validator.js";
9
9
  import { unsupportedSchemaMessage } from "./schema-guard.js";
10
10
  const VALIDATORS = {
11
11
  "validate-context": validateContext,
12
12
  "validate-code-modularity": validateCodeModularity,
13
13
  "validate-harness": validateHarness,
14
- "validate-plan-contract": validatePlanContract,
15
- "validate-plan-acceptance": validatePlanAcceptance,
16
- "validate-superpowers-state": validateSuperpowersState
17
14
  };
18
15
  const GLOBAL_REQUIRED_SECTIONS = [
19
16
  ...sectionSpecs([
@@ -24,9 +21,9 @@ const GLOBAL_REQUIRED_SECTIONS = [
24
21
  "Architecture Context",
25
22
  "Verification Entry Points",
26
23
  "Current State",
27
- "Next Safe Action"
24
+ "Next Safe Action",
28
25
  ]),
29
- sectionSpec("Context Index", ["Context Index", "Module Index"])
26
+ sectionSpec("Context Index", ["Context Index", "Module Index"]),
30
27
  ];
31
28
  const ARCHITECTURE_REQUIRED_SECTIONS = sectionSpecs([
32
29
  "System Boundary",
@@ -35,7 +32,7 @@ const ARCHITECTURE_REQUIRED_SECTIONS = sectionSpecs([
35
32
  "Design Rationale",
36
33
  "Constraints And Tradeoffs",
37
34
  "Verification Implications",
38
- "Open Risks"
35
+ "Open Risks",
39
36
  ]);
40
37
  const ROLE_ALIASES = {
41
38
  global: "global",
@@ -51,9 +48,15 @@ const ROLE_ALIASES = {
51
48
  "implementation-index": "implementation-index",
52
49
  implementation_index: "implementation-index",
53
50
  "decision-rationale": "decision-rationale",
54
- decision_rationale: "decision-rationale"
51
+ decision_rationale: "decision-rationale",
55
52
  };
56
- const VALID_READ_POLICIES = new Set(["default", "always", "optional", "on-demand", "never-default"]);
53
+ const VALID_READ_POLICIES = new Set([
54
+ "default",
55
+ "always",
56
+ "optional",
57
+ "on-demand",
58
+ "never-default",
59
+ ]);
57
60
  const EXPORT_ARTIFACT_NAME_PATTERNS = [
58
61
  /full-project-context/i,
59
62
  /当前项目context/i,
@@ -62,16 +65,16 @@ const EXPORT_ARTIFACT_NAME_PATTERNS = [
62
65
  /project-overview/i,
63
66
  /context-bundle/i,
64
67
  /context-summary/i,
65
- /context-export/i
68
+ /context-export/i,
66
69
  ];
67
70
  const FAKE_VERIFICATION_PATTERNS = [
68
71
  /\btests?\s+(?:pass(?:ed|es)?|green)\b/i,
69
72
  /\bverified\b/i,
70
73
  /\bdeployed\s+successfully\b/i,
71
74
  /\bvalidation\s+passed\b/i,
72
- /\b测试(?:已)?通过\b/,
73
- /\b验证(?:已)?通过\b/,
74
- /\b部署(?:已)?成功\b/
75
+ /测试(?:已)?通过/,
76
+ /验证(?:已)?通过/,
77
+ /部署(?:已)?成功/,
75
78
  ];
76
79
  export async function runValidator(projectRoot, gate, args = []) {
77
80
  const validator = VALIDATORS[gate];
@@ -79,8 +82,8 @@ export async function runValidator(projectRoot, gate, args = []) {
79
82
  return {
80
83
  info: [],
81
84
  errors: [
82
- `unknown validator: ${gate}. Minimal Context Harness supports validate-context, validate-code-modularity, validate-harness, validate-plan-contract, validate-plan-acceptance and validate-superpowers-state only.`
83
- ]
85
+ `unknown validator: ${gate}. Minimal Context Harness supports validate-context, validate-code-modularity and validate-harness only.`,
86
+ ],
84
87
  };
85
88
  }
86
89
  return validator(projectRoot, args);
@@ -90,21 +93,33 @@ async function validateHarness(projectRoot) {
90
93
  const modularityReport = await validateCodeModularity(projectRoot);
91
94
  return {
92
95
  info: [...contextReport.info, ...modularityReport.info],
93
- warnings: [...(contextReport.warnings ?? []), ...(modularityReport.warnings ?? [])],
94
- hygiene: [...(contextReport.hygiene ?? []), ...(modularityReport.hygiene ?? [])],
95
- errors: [...contextReport.errors, ...modularityReport.errors]
96
+ warnings: [
97
+ ...(contextReport.warnings ?? []),
98
+ ...(modularityReport.warnings ?? []),
99
+ ],
100
+ hygiene: [
101
+ ...(contextReport.hygiene ?? []),
102
+ ...(modularityReport.hygiene ?? []),
103
+ ],
104
+ errors: [...contextReport.errors, ...modularityReport.errors],
96
105
  };
97
106
  }
98
107
  async function validateCodeModularity(projectRoot) {
99
108
  const report = await runModularityCheck(projectRoot, { touched: true });
100
109
  const info = [
101
- `code modularity audited=${report.files.length} warning=${report.warnings.length} waived=${report.waivedWarnings.length} limit=${report.limit}`
110
+ `code modularity audited=${report.files.length} warning=${report.warnings.length} waived=${report.waivedWarnings.length} limit=${report.limit}`,
102
111
  ];
103
112
  if (report.files.length === 0) {
104
113
  info.push("No handwritten source files matched the selected scope.");
105
114
  }
106
115
  for (const file of report.files) {
107
- const prefix = file.overLimit && file.waived ? "waived" : file.overLimit ? "over-limit" : "ok";
116
+ const prefix = file.regressed && file.waived
117
+ ? "waived"
118
+ : file.regressed
119
+ ? "over-limit"
120
+ : file.overLimit
121
+ ? "observed-risk"
122
+ : "ok";
108
123
  info.push(`${prefix}: ${file.relativePath} ${file.lines} lines`);
109
124
  }
110
125
  for (const waiver of report.waivedWarnings) {
@@ -115,11 +130,12 @@ async function validateCodeModularity(projectRoot) {
115
130
  }
116
131
  return {
117
132
  info,
118
- errors: [...report.errors, ...report.warnings]
133
+ errors: [...report.errors, ...report.warnings],
119
134
  };
120
135
  }
121
136
  async function validateContext(projectRoot) {
122
137
  const info = [];
138
+ const warnings = [];
123
139
  const errors = [];
124
140
  const root = await harnessRoot(projectRoot);
125
141
  const globalPath = path.join(projectRoot, "project_context", "global.md");
@@ -128,6 +144,7 @@ async function validateContext(projectRoot) {
128
144
  const configPath = path.join(projectRoot, harnessPath(root, "config.yaml"));
129
145
  const manifestPath = path.join(projectRoot, "project_context", "context.toml");
130
146
  const manifestRoles = new Map();
147
+ const manifestReadPolicies = new Map();
131
148
  let schemaVersion = "4";
132
149
  if (!(await pathExists(configPath))) {
133
150
  errors.push(`${harnessPath(root, "config.yaml")} is missing`);
@@ -137,7 +154,7 @@ async function validateContext(projectRoot) {
137
154
  const unsupportedSchema = unsupportedSchemaMessage(schemaVersion, "validate-context");
138
155
  if (unsupportedSchema) {
139
156
  errors.push(unsupportedSchema);
140
- return { info, errors };
157
+ return { info, warnings, errors };
141
158
  }
142
159
  }
143
160
  if (!(await pathExists(globalPath))) {
@@ -149,6 +166,7 @@ async function validateContext(projectRoot) {
149
166
  assertSectionHasContent("project_context/global.md", global, sectionSpec("Verification Entry Points"), errors);
150
167
  assertSectionHasContent("project_context/global.md", global, sectionSpec("Next Safe Action"), errors);
151
168
  assertNoFakeVerification("project_context/global.md", global, errors);
169
+ validateContextFile(projectRoot, "project_context/global.md", global, "global", errors);
152
170
  }
153
171
  if (!(await pathExists(architecturePath))) {
154
172
  errors.push("project_context/architecture.md is missing");
@@ -159,11 +177,14 @@ async function validateContext(projectRoot) {
159
177
  assertSectionHasContent("project_context/architecture.md", architecture, sectionSpec("System Boundary"), errors);
160
178
  assertSectionHasContent("project_context/architecture.md", architecture, sectionSpec("Component Map"), errors);
161
179
  assertNoFakeVerification("project_context/architecture.md", architecture, errors);
180
+ validateContextFile(projectRoot, "project_context/architecture.md", architecture, "architecture", errors);
162
181
  }
163
182
  if (await pathExists(manifestPath)) {
164
- const manifest = parseContextManifest(await readText(manifestPath), "project_context/context.toml", errors);
165
- if (manifest) {
166
- await validateContextManifest(projectRoot, manifest, manifestRoles, errors);
183
+ const parsed = parseContextManifest(await readText(manifestPath));
184
+ errors.push(...parsed.errors);
185
+ if (parsed.manifest) {
186
+ await validateContextManifest(projectRoot, parsed.manifest, manifestRoles, manifestReadPolicies, errors);
187
+ const manifest = parsed.manifest;
167
188
  info.push(`loaded project_context/context.toml with ${manifest.areas.length} area(s) and ${manifest.contexts.length} context node(s)`);
168
189
  }
169
190
  }
@@ -180,21 +201,35 @@ async function validateContext(projectRoot) {
180
201
  const content = await readText(file);
181
202
  const frontMatter = parseFrontMatter(content);
182
203
  const frontMatterRole = frontMatterContextRole(frontMatter, relative, errors);
183
- if (frontMatter.read_policy && !VALID_READ_POLICIES.has(frontMatter.read_policy)) {
204
+ if (frontMatter.read_policy &&
205
+ !VALID_READ_POLICIES.has(frontMatter.read_policy)) {
184
206
  errors.push(`${relative} has unsupported read_policy: ${frontMatter.read_policy}`);
185
207
  }
186
- const role = manifestRoles.get(relative) ?? frontMatterRole;
208
+ const manifestRole = manifestRoles.get(relative);
209
+ const manifestReadPolicy = manifestReadPolicies.get(relative);
210
+ if (manifestRole && frontMatterRole && manifestRole !== frontMatterRole) {
211
+ errors.push(`${relative} front matter context_role ${frontMatterRole} does not match manifest role ${manifestRole}`);
212
+ }
213
+ if (manifestReadPolicy &&
214
+ frontMatter.read_policy &&
215
+ manifestReadPolicy !== frontMatter.read_policy) {
216
+ errors.push(`${relative} front matter read_policy ${frontMatter.read_policy} does not match manifest read_policy ${manifestReadPolicy}`);
217
+ }
218
+ if (!manifestRole) {
219
+ warnings.push(`${relative} is an unregistered Context Markdown file; add it to project_context/context.toml or move it out of project_context/**`);
220
+ }
221
+ const role = manifestRole ?? frontMatterRole;
187
222
  if (!role) {
188
223
  continue;
189
224
  }
190
- validateContextFile(relative, content, role, errors);
225
+ validateContextFile(projectRoot, relative, content, role, errors);
191
226
  validatedContextFiles.set(relative, role);
192
227
  }
193
228
  for (const [relative, role] of manifestRoles.entries()) {
194
229
  if (!validatedContextFiles.has(relative)) {
195
230
  const absolute = path.join(projectRoot, ...relative.split("/"));
196
231
  if (await pathExists(absolute)) {
197
- validateContextFile(relative, await readText(absolute), role, errors);
232
+ validateContextFile(projectRoot, relative, await readText(absolute), role, errors);
198
233
  validatedContextFiles.set(relative, role);
199
234
  }
200
235
  }
@@ -203,52 +238,62 @@ async function validateContext(projectRoot) {
203
238
  if (errors.length === 0) {
204
239
  info.push("Minimal Context validation passed");
205
240
  }
206
- return { info, errors };
241
+ return { info, warnings, errors };
207
242
  }
208
- function validateContextFile(file, content, role, errors) {
209
- void role;
243
+ function validateContextFile(projectRoot, file, content, role, errors) {
210
244
  assertNoFakeVerification(file, content, errors);
245
+ assertMinimumRecoverability(file, content, errors);
246
+ assertRoleRecoverability(projectRoot, file, content, role, errors);
211
247
  }
212
- async function validateContextManifest(projectRoot, manifest, manifestRoles, errors) {
248
+ async function validateContextManifest(projectRoot, manifest, manifestRoles, manifestReadPolicies, errors) {
213
249
  if (manifest.areas.length === 0) {
214
250
  errors.push("project_context/context.toml must declare at least one [[areas]] entry");
215
251
  }
216
- let hasDefaultArea = false;
252
+ const areaIds = new Set();
253
+ const registeredPaths = new Set();
254
+ const defaultAreas = manifest.areas.filter((area) => area.default);
255
+ if (manifest.areas.length > 0 && defaultAreas.length !== 1) {
256
+ errors.push(`project_context/context.toml must mark exactly one [[areas]] entry with default = true; found ${defaultAreas.length}`);
257
+ }
217
258
  for (const area of manifest.areas) {
218
- const id = stringManifestValue(area, "id", "project_context/context.toml", errors);
219
- stringManifestValue(area, "root", "project_context/context.toml", errors);
220
- const context = stringManifestValue(area, "context", "project_context/context.toml", errors);
221
- optionalStringManifestValue(area, "kind", "project_context/context.toml", errors);
222
- const defaultArea = optionalBooleanManifestValue(area, "default", "project_context/context.toml", errors);
223
- hasDefaultArea = hasDefaultArea || defaultArea === true;
224
- optionalStringArrayManifestValue(area, "forbidden_runtime_dependencies", "project_context/context.toml", errors);
225
- if (id && context) {
226
- await addManifestRole(projectRoot, manifestRoles, context, "area", `area ${id}`, errors);
259
+ if (areaIds.has(area.id)) {
260
+ errors.push(`project_context/context.toml has duplicate area id: ${area.id}`);
227
261
  }
228
- }
229
- if (manifest.areas.length > 0 && !hasDefaultArea) {
230
- errors.push("project_context/context.toml must mark one [[areas]] entry with default = true");
262
+ areaIds.add(area.id);
263
+ await validateManifestPath(projectRoot, area.root, projectRoot, `area ${area.id} root`, false, errors);
264
+ const relative = normalizeContextPath(area.context);
265
+ if (registeredPaths.has(relative)) {
266
+ errors.push(`project_context/context.toml has duplicate Context path: ${relative}`);
267
+ }
268
+ registeredPaths.add(relative);
269
+ await addManifestRole(projectRoot, manifestRoles, manifestReadPolicies, area.context, "area", undefined, `area ${area.id}`, errors);
231
270
  }
232
271
  for (const context of manifest.contexts) {
233
- const pathValue = stringManifestValue(context, "path", "project_context/context.toml", errors);
234
- const roleValue = stringManifestValue(context, "role", "project_context/context.toml", errors);
235
- optionalStringManifestValue(context, "read_when", "project_context/context.toml", errors);
236
- const readPolicy = optionalStringManifestValue(context, "read_policy", "project_context/context.toml", errors);
237
- optionalStringArrayManifestValue(context, "triggers", "project_context/context.toml", errors);
238
- optionalStringArrayManifestValue(context, "default_children", "project_context/context.toml", errors);
239
- if (readPolicy && !VALID_READ_POLICIES.has(readPolicy)) {
240
- errors.push(`project_context/context.toml line ${context.line} has unsupported read_policy: ${readPolicy}`);
272
+ const relative = normalizeContextPath(context.path);
273
+ if (registeredPaths.has(relative)) {
274
+ errors.push(`project_context/context.toml has duplicate Context path: ${relative}`);
275
+ }
276
+ registeredPaths.add(relative);
277
+ if (context.read_policy && !VALID_READ_POLICIES.has(context.read_policy)) {
278
+ errors.push(`project_context/context.toml line ${context.line} has unsupported read_policy: ${context.read_policy}`);
241
279
  }
242
- const role = roleValue ? normalizeRole(roleValue) : undefined;
243
- if (roleValue && !role) {
244
- errors.push(`project_context/context.toml line ${context.line} has unsupported context role: ${roleValue}`);
280
+ const role = normalizeRole(context.role);
281
+ if (!role) {
282
+ errors.push(`project_context/context.toml line ${context.line} has unsupported context role: ${context.role}`);
283
+ continue;
245
284
  }
246
- if (role && pathValue) {
247
- await addManifestRole(projectRoot, manifestRoles, pathValue, role, `context ${pathValue}`, errors);
285
+ await addManifestRole(projectRoot, manifestRoles, manifestReadPolicies, context.path, role, context.read_policy, `context ${context.path}`, errors);
286
+ }
287
+ for (const context of manifest.contexts) {
288
+ for (const child of context.default_children) {
289
+ const normalizedChild = normalizeContextPath(child);
290
+ if (!registeredPaths.has(normalizedChild)) {
291
+ errors.push(`project_context/context.toml line ${context.line} default_children references unregistered Context path: ${child}`);
292
+ }
248
293
  }
249
294
  }
250
295
  }
251
- async function addManifestRole(projectRoot, roles, rawPath, role, source, errors) {
296
+ async function addManifestRole(projectRoot, roles, readPolicies, rawPath, role, readPolicy, source, errors) {
252
297
  const relative = normalizeContextPath(rawPath);
253
298
  if (looksLikeExportArtifact(relative)) {
254
299
  errors.push(`project_context/context.toml ${source} must not reference temporary export artifact ${rawPath}; export artifacts belong in tmp/ty-context/context-exports/** and must not be registered as Context graph nodes or implementation-index`);
@@ -258,16 +303,44 @@ async function addManifestRole(projectRoot, roles, rawPath, role, source, errors
258
303
  errors.push(`project_context/context.toml ${source} must reference a markdown file under project_context/: ${rawPath}`);
259
304
  return;
260
305
  }
261
- const existing = roles.get(relative);
262
- if (existing && existing !== role) {
263
- errors.push(`project_context/context.toml assigns conflicting roles to ${relative}: ${existing} and ${role}`);
306
+ if (!(await validateManifestPath(projectRoot, rawPath, path.join(projectRoot, "project_context"), source, true, errors))) {
264
307
  return;
265
308
  }
266
309
  roles.set(relative, role);
267
- if (!(await pathExists(path.join(projectRoot, ...relative.split("/"))))) {
268
- errors.push(`project_context/context.toml references missing context file: ${relative}`);
310
+ if (readPolicy) {
311
+ readPolicies.set(relative, readPolicy);
269
312
  }
270
313
  }
314
+ async function validateManifestPath(projectRoot, rawPath, allowedRoot, source, allowFile, errors) {
315
+ if (path.isAbsolute(rawPath) ||
316
+ rawPath.replace(/\\/g, "/").split("/").includes("..")) {
317
+ errors.push(`project_context/context.toml ${source} path must be relative and must not contain '..': ${rawPath}`);
318
+ return false;
319
+ }
320
+ const target = path.resolve(projectRoot, rawPath);
321
+ if (!isWithin(allowedRoot, target)) {
322
+ errors.push(`project_context/context.toml ${source} escapes its allowed root: ${rawPath}`);
323
+ return false;
324
+ }
325
+ if (!(await pathExists(target))) {
326
+ errors.push(`project_context/context.toml references missing ${allowFile ? "context file" : "area root"}: ${normalizeContextPath(rawPath)}`);
327
+ return false;
328
+ }
329
+ const realAllowedRoot = await realpath(allowedRoot);
330
+ const realTarget = await realpath(target);
331
+ if (!isWithin(realAllowedRoot, realTarget)) {
332
+ errors.push(`project_context/context.toml ${source} resolves through a symbolic link outside its allowed root: ${rawPath}`);
333
+ return false;
334
+ }
335
+ return true;
336
+ }
337
+ function isWithin(root, target) {
338
+ const relative = path.relative(root, target);
339
+ return (relative === "" ||
340
+ (!relative.startsWith(`..${path.sep}`) &&
341
+ relative !== ".." &&
342
+ !path.isAbsolute(relative)));
343
+ }
271
344
  function assertSections(file, content, sections, errors) {
272
345
  for (const section of sections) {
273
346
  if (!hasAnyHeading(content, section)) {
@@ -282,22 +355,87 @@ function assertSectionHasContent(file, content, section, errors) {
282
355
  }
283
356
  }
284
357
  function assertNoFakeVerification(file, content, errors) {
285
- const verification = sectionBody(content, "Verification Entry Points") ??
286
- sectionBody(content, "Verification Paths") ??
287
- sectionBody(content, "Deployment Paths") ??
288
- sectionBody(content, "Test Entry Points") ??
289
- sectionBody(content, "Verification Implications") ??
290
- sectionBody(content, "Tests");
291
- if (!verification) {
358
+ const verificationSections = sectionBodiesByHeading(content, /(?:verification|tests?|deployment|验证|测试|部署)/i);
359
+ if (verificationSections.length === 0) {
292
360
  return;
293
361
  }
294
- for (const pattern of FAKE_VERIFICATION_PATTERNS) {
295
- if (pattern.test(verification)) {
296
- errors.push(`${file} must list verification entry points, not claim tests were already executed`);
297
- return;
362
+ for (const verification of verificationSections) {
363
+ for (const pattern of FAKE_VERIFICATION_PATTERNS) {
364
+ if (pattern.test(verification)) {
365
+ errors.push(`${file} must list verification entry points, not claim tests were already executed`);
366
+ return;
367
+ }
298
368
  }
299
369
  }
300
370
  }
371
+ function assertMinimumRecoverability(file, content, errors) {
372
+ if (!/^#\s+\S.+$/m.test(content)) {
373
+ errors.push(`${file} must contain a non-empty level-one title`);
374
+ }
375
+ const withoutFrontMatter = content.replace(/^---\s*\r?\n[\s\S]*?\r?\n---\s*\r?\n?/, "");
376
+ const facts = withoutFrontMatter
377
+ .split(/\r?\n/)
378
+ .map((line) => line.trim())
379
+ .filter((line) => line &&
380
+ !line.startsWith("#") &&
381
+ !line.startsWith("```") &&
382
+ !line.startsWith("<!--"))
383
+ .map((line) => line.replace(/^[-*+>]\s*/, "").trim())
384
+ .filter((line) => line.length >= 8)
385
+ .filter((line) => !/^(?:todo|tbd|placeholder|coming soon|待补充|占位|暂无)[.!。…\s-]*$/i.test(line));
386
+ if (facts.length === 0) {
387
+ errors.push(`${file} must contain at least one concrete fact paragraph and cannot be only TODO or placeholder text`);
388
+ }
389
+ }
390
+ function assertRoleRecoverability(projectRoot, file, content, role, errors) {
391
+ if (role === "verification") {
392
+ const hasRepeatableEntry = /`[^`\r\n]+`|\b(?:npm|pnpm|yarn|make|node|python|pytest|cargo|go)\s+[^\r\n]+|(?:^|\s)(?:\.\/|[\w.-]+\/)[\w./-]+/im.test(content);
393
+ if (!hasRepeatableEntry) {
394
+ errors.push(`${file} verification Context must contain a command, repository path or repeatable entry point`);
395
+ }
396
+ }
397
+ if (role === "implementation-index") {
398
+ const candidates = [...content.matchAll(/`([^`]+)`/g)]
399
+ .map((match) => match[1])
400
+ .filter((value) => /[\\/]/.test(value) && !value.includes(" "));
401
+ const hasRepositoryPath = candidates.some((candidate) => {
402
+ const clean = candidate.replace(/[.:,;]+$/, "").replace(/\\/g, "/");
403
+ if (path.isAbsolute(clean) || clean.split("/").includes("..")) {
404
+ return false;
405
+ }
406
+ const target = path.resolve(projectRoot, clean);
407
+ return isWithin(projectRoot, target) && existsSync(target);
408
+ });
409
+ if (!hasRepositoryPath) {
410
+ errors.push(`${file} implementation-index Context must contain at least one existing repository path`);
411
+ }
412
+ }
413
+ if (role === "contract" &&
414
+ !/(?:producer|consumer|input|output|schema|compatibility|constraint|must|shall|禁止|必须|输入|输出|兼容)/i.test(content)) {
415
+ errors.push(`${file} contract Context must state at least one constraint or input/output semantic`);
416
+ }
417
+ if (role === "decision-rationale") {
418
+ const hasDecision = /^##\s+(?:(?:Decision|Current Design Choice|Design Choice)(?:\b|\s|$)|决定(?:\s|$)|当前设计选择(?:\s|$))/im.test(content);
419
+ const hasReason = /^##\s+(?:(?:Reason|Rationale|Why)(?:\b|\s|$)|原因(?:\s|$)|理由(?:\s|$)|为什么(?:\s|$))/im.test(content);
420
+ if (!hasDecision || !hasReason) {
421
+ errors.push(`${file} decision-rationale Context must contain both a Decision and a Reason`);
422
+ }
423
+ }
424
+ }
425
+ function sectionBodiesByHeading(content, headingPattern) {
426
+ const matches = [...content.matchAll(/^(#{2,6})\s+(.+?)\s*$/gm)];
427
+ const bodies = [];
428
+ for (const [index, match] of matches.entries()) {
429
+ if (!headingPattern.test(match[2])) {
430
+ continue;
431
+ }
432
+ const start = (match.index ?? 0) + match[0].length;
433
+ const next = matches[index + 1];
434
+ const end = next?.index ?? content.length;
435
+ bodies.push(content.slice(start, end).trim());
436
+ }
437
+ return bodies;
438
+ }
301
439
  function hasAnyHeading(content, section) {
302
440
  return section.headings.some((heading) => hasHeading(content, heading));
303
441
  }
@@ -364,118 +502,6 @@ function parseFrontMatter(content) {
364
502
  }
365
503
  return {};
366
504
  }
367
- function parseContextManifest(content, file, errors) {
368
- const manifest = { areas: [], contexts: [] };
369
- let current;
370
- const lines = content.split(/\r?\n/);
371
- for (let index = 0; index < lines.length; index += 1) {
372
- const lineNumber = index + 1;
373
- const line = stripTomlComment(lines[index]).trim();
374
- if (!line) {
375
- continue;
376
- }
377
- const tableMatch = /^\[\[(areas|context)\]\]$/.exec(line);
378
- if (tableMatch) {
379
- current = { table: tableMatch[1], line: lineNumber, values: {} };
380
- if (current.table === "areas") {
381
- manifest.areas.push(current);
382
- }
383
- else {
384
- manifest.contexts.push(current);
385
- }
386
- continue;
387
- }
388
- if (!current) {
389
- errors.push(`${file} line ${lineNumber} must appear inside [[areas]] or [[context]]`);
390
- continue;
391
- }
392
- const assignment = /^([A-Za-z0-9_-]+)\s*=\s*(.+)$/.exec(line);
393
- if (!assignment) {
394
- errors.push(`${file} line ${lineNumber} is not a supported manifest assignment`);
395
- continue;
396
- }
397
- const parsed = parseTomlValue(assignment[2]);
398
- if (parsed === undefined) {
399
- errors.push(`${file} line ${lineNumber} has an unsupported value; use strings, booleans or string arrays`);
400
- continue;
401
- }
402
- current.values[assignment[1]] = parsed;
403
- }
404
- return manifest;
405
- }
406
- function parseTomlValue(raw) {
407
- const value = raw.trim();
408
- if (value === "true") {
409
- return true;
410
- }
411
- if (value === "false") {
412
- return false;
413
- }
414
- if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
415
- return stripQuotes(value);
416
- }
417
- if (value.startsWith("[") && value.endsWith("]")) {
418
- const inner = value.slice(1, -1).trim();
419
- if (!inner) {
420
- return [];
421
- }
422
- const values = [];
423
- for (const part of inner.split(",")) {
424
- const item = part.trim();
425
- if (!((item.startsWith('"') && item.endsWith('"')) || (item.startsWith("'") && item.endsWith("'")))) {
426
- return undefined;
427
- }
428
- values.push(stripQuotes(item));
429
- }
430
- return values;
431
- }
432
- return undefined;
433
- }
434
- function stripTomlComment(line) {
435
- let quote;
436
- for (let index = 0; index < line.length; index += 1) {
437
- const char = line[index];
438
- if ((char === '"' || char === "'") && line[index - 1] !== "\\") {
439
- quote = quote === char ? undefined : quote ?? char;
440
- }
441
- if (char === "#" && !quote) {
442
- return line.slice(0, index);
443
- }
444
- }
445
- return line;
446
- }
447
- function stringManifestValue(entry, key, file, errors) {
448
- const value = entry.values[key];
449
- if (typeof value === "string") {
450
- return value;
451
- }
452
- errors.push(`${file} line ${entry.line} must include string field ${key}`);
453
- return undefined;
454
- }
455
- function optionalStringManifestValue(entry, key, file, errors) {
456
- const value = entry.values[key];
457
- if (value === undefined || typeof value === "string") {
458
- return value;
459
- }
460
- errors.push(`${file} line ${entry.line} field ${key} must be a string`);
461
- return undefined;
462
- }
463
- function optionalBooleanManifestValue(entry, key, file, errors) {
464
- const value = entry.values[key];
465
- if (value === undefined || typeof value === "boolean") {
466
- return value;
467
- }
468
- errors.push(`${file} line ${entry.line} field ${key} must be a boolean`);
469
- return undefined;
470
- }
471
- function optionalStringArrayManifestValue(entry, key, file, errors) {
472
- const value = entry.values[key];
473
- if (value === undefined || (Array.isArray(value) && value.every((item) => typeof item === "string"))) {
474
- return value;
475
- }
476
- errors.push(`${file} line ${entry.line} field ${key} must be an array of strings`);
477
- return undefined;
478
- }
479
505
  function normalizeRole(value) {
480
506
  return ROLE_ALIASES[value.trim().toLowerCase()];
481
507
  }
@@ -487,7 +513,8 @@ function looksLikeExportArtifact(value) {
487
513
  return EXPORT_ARTIFACT_NAME_PATTERNS.some((pattern) => pattern.test(normalized));
488
514
  }
489
515
  function stripQuotes(value) {
490
- if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
516
+ if ((value.startsWith('"') && value.endsWith('"')) ||
517
+ (value.startsWith("'") && value.endsWith("'"))) {
491
518
  return value.slice(1, -1);
492
519
  }
493
520
  return value;
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};