@dommaker/harness 1.6.0 → 1.8.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 (560) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/bin/harness.js +17 -1
  3. package/dist/agents/index.d.ts +6 -2
  4. package/dist/agents/index.d.ts.map +1 -1
  5. package/dist/agents/index.js +6 -16
  6. package/dist/agents/index.js.map +1 -1
  7. package/dist/cli/commands/__tests__/gate-decision.d.ts +18 -0
  8. package/dist/cli/commands/__tests__/gate-decision.d.ts.map +1 -0
  9. package/dist/cli/commands/__tests__/gate-decision.js +26 -0
  10. package/dist/cli/commands/__tests__/gate-decision.js.map +1 -0
  11. package/dist/cli/commands/acceptance.d.ts.map +1 -1
  12. package/dist/cli/commands/acceptance.js +17 -28
  13. package/dist/cli/commands/acceptance.js.map +1 -1
  14. package/dist/cli/commands/check.d.ts +11 -3
  15. package/dist/cli/commands/check.d.ts.map +1 -1
  16. package/dist/cli/commands/check.js +26 -11
  17. package/dist/cli/commands/check.js.map +1 -1
  18. package/dist/cli/commands/command.d.ts +0 -1
  19. package/dist/cli/commands/command.d.ts.map +1 -1
  20. package/dist/cli/commands/command.js +8 -6
  21. package/dist/cli/commands/command.js.map +1 -1
  22. package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
  23. package/dist/cli/commands/constraints-retire.js +36 -57
  24. package/dist/cli/commands/constraints-retire.js.map +1 -1
  25. package/dist/cli/commands/contract.d.ts.map +1 -1
  26. package/dist/cli/commands/contract.js +36 -42
  27. package/dist/cli/commands/contract.js.map +1 -1
  28. package/dist/cli/commands/definitions.d.ts +2 -0
  29. package/dist/cli/commands/definitions.d.ts.map +1 -1
  30. package/dist/cli/commands/definitions.js +11 -6
  31. package/dist/cli/commands/definitions.js.map +1 -1
  32. package/dist/cli/commands/failure.d.ts.map +1 -1
  33. package/dist/cli/commands/failure.js +16 -2
  34. package/dist/cli/commands/failure.js.map +1 -1
  35. package/dist/cli/commands/init.d.ts +14 -8
  36. package/dist/cli/commands/init.d.ts.map +1 -1
  37. package/dist/cli/commands/init.js +172 -364
  38. package/dist/cli/commands/init.js.map +1 -1
  39. package/dist/cli/commands/knowledge-view.d.ts +90 -0
  40. package/dist/cli/commands/knowledge-view.d.ts.map +1 -0
  41. package/dist/cli/commands/knowledge-view.js +198 -0
  42. package/dist/cli/commands/knowledge-view.js.map +1 -0
  43. package/dist/cli/commands/knowledge.d.ts +137 -52
  44. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  45. package/dist/cli/commands/knowledge.js +534 -400
  46. package/dist/cli/commands/knowledge.js.map +1 -1
  47. package/dist/cli/commands/passes-gate.d.ts +4 -1
  48. package/dist/cli/commands/passes-gate.d.ts.map +1 -1
  49. package/dist/cli/commands/passes-gate.js +11 -2
  50. package/dist/cli/commands/passes-gate.js.map +1 -1
  51. package/dist/cli/commands/performance.d.ts.map +1 -1
  52. package/dist/cli/commands/performance.js +19 -31
  53. package/dist/cli/commands/performance.js.map +1 -1
  54. package/dist/cli/commands/report.d.ts.map +1 -1
  55. package/dist/cli/commands/report.js +2 -1
  56. package/dist/cli/commands/report.js.map +1 -1
  57. package/dist/cli/commands/review.d.ts.map +1 -1
  58. package/dist/cli/commands/review.js +13 -25
  59. package/dist/cli/commands/review.js.map +1 -1
  60. package/dist/cli/commands/scaffold-templates.d.ts +73 -0
  61. package/dist/cli/commands/scaffold-templates.d.ts.map +1 -0
  62. package/dist/cli/commands/scaffold-templates.js +424 -0
  63. package/dist/cli/commands/scaffold-templates.js.map +1 -0
  64. package/dist/cli/commands/scaffold.d.ts +105 -0
  65. package/dist/cli/commands/scaffold.d.ts.map +1 -0
  66. package/dist/cli/commands/scaffold.js +263 -0
  67. package/dist/cli/commands/scaffold.js.map +1 -0
  68. package/dist/cli/commands/security.d.ts.map +1 -1
  69. package/dist/cli/commands/security.js +22 -24
  70. package/dist/cli/commands/security.js.map +1 -1
  71. package/dist/cli/commands/spec-baseline-check.d.ts +43 -0
  72. package/dist/cli/commands/spec-baseline-check.d.ts.map +1 -1
  73. package/dist/cli/commands/spec-baseline-check.js +109 -34
  74. package/dist/cli/commands/spec-baseline-check.js.map +1 -1
  75. package/dist/cli/commands/sync-docs/context-syncer.d.ts +21 -2
  76. package/dist/cli/commands/sync-docs/context-syncer.d.ts.map +1 -1
  77. package/dist/cli/commands/sync-docs/context-syncer.js +112 -28
  78. package/dist/cli/commands/sync-docs/context-syncer.js.map +1 -1
  79. package/dist/cli/commands/sync-docs/index.d.ts +1 -1
  80. package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
  81. package/dist/cli/commands/sync-docs/index.js +86 -27
  82. package/dist/cli/commands/sync-docs/index.js.map +1 -1
  83. package/dist/cli/commands/sync-docs/project-reader.d.ts +24 -1
  84. package/dist/cli/commands/sync-docs/project-reader.d.ts.map +1 -1
  85. package/dist/cli/commands/sync-docs/project-reader.js +33 -7
  86. package/dist/cli/commands/sync-docs/project-reader.js.map +1 -1
  87. package/dist/cli/commands/validate.d.ts +0 -16
  88. package/dist/cli/commands/validate.d.ts.map +1 -1
  89. package/dist/cli/commands/validate.js +2 -97
  90. package/dist/cli/commands/validate.js.map +1 -1
  91. package/dist/cli/gate-command.d.ts +37 -0
  92. package/dist/cli/gate-command.d.ts.map +1 -0
  93. package/dist/cli/gate-command.js +64 -0
  94. package/dist/cli/gate-command.js.map +1 -0
  95. package/dist/completion-checkers/index.d.ts +1 -1
  96. package/dist/completion-checkers/index.d.ts.map +1 -1
  97. package/dist/completion-checkers/index.js +0 -15
  98. package/dist/completion-checkers/index.js.map +1 -1
  99. package/dist/context/knowledge-injector.d.ts +4 -2
  100. package/dist/context/knowledge-injector.d.ts.map +1 -1
  101. package/dist/context/knowledge-injector.js +13 -6
  102. package/dist/context/knowledge-injector.js.map +1 -1
  103. package/dist/core/constraints/agent-prompt-renderer.js +2 -2
  104. package/dist/core/constraints/agent-prompt-renderer.js.map +1 -1
  105. package/dist/core/constraints/capabilities-reconcile.d.ts +20 -0
  106. package/dist/core/constraints/capabilities-reconcile.d.ts.map +1 -1
  107. package/dist/core/constraints/capabilities-reconcile.js +26 -4
  108. package/dist/core/constraints/capabilities-reconcile.js.map +1 -1
  109. package/dist/core/constraints/check-cache.d.ts +1 -1
  110. package/dist/core/constraints/check-cache.js +1 -1
  111. package/dist/core/constraints/checker.d.ts +8 -3
  112. package/dist/core/constraints/checker.d.ts.map +1 -1
  113. package/dist/core/constraints/checker.js +30 -19
  114. package/dist/core/constraints/checker.js.map +1 -1
  115. package/dist/core/constraints/checkers/capability-sync.d.ts +3 -1
  116. package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
  117. package/dist/core/constraints/checkers/capability-sync.js +17 -24
  118. package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
  119. package/dist/core/constraints/checkers/context-doc-sync.d.ts +1 -1
  120. package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
  121. package/dist/core/constraints/checkers/context-doc-sync.js +9 -6
  122. package/dist/core/constraints/checkers/context-doc-sync.js.map +1 -1
  123. package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
  124. package/dist/core/constraints/checkers/docs-freshness.js +24 -30
  125. package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
  126. package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
  127. package/dist/core/constraints/checkers/governance-presence.js +10 -4
  128. package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
  129. package/dist/core/constraints/checkers/types.d.ts +10 -6
  130. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  131. package/dist/core/constraints/checkers/types.js +7 -3
  132. package/dist/core/constraints/checkers/types.js.map +1 -1
  133. package/dist/core/constraints/context-builder.d.ts +11 -10
  134. package/dist/core/constraints/context-builder.d.ts.map +1 -1
  135. package/dist/core/constraints/context-builder.js +31 -27
  136. package/dist/core/constraints/context-builder.js.map +1 -1
  137. package/dist/core/constraints/context-reconcile.d.ts +75 -0
  138. package/dist/core/constraints/context-reconcile.d.ts.map +1 -0
  139. package/dist/core/constraints/context-reconcile.js +161 -0
  140. package/dist/core/constraints/context-reconcile.js.map +1 -0
  141. package/dist/core/constraints/doc-freshness/runner.d.ts +7 -0
  142. package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
  143. package/dist/core/constraints/doc-freshness/runner.js +8 -3
  144. package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
  145. package/dist/core/constraints/git-evidence.js +1 -1
  146. package/dist/core/constraints/git-evidence.js.map +1 -1
  147. package/dist/core/constraints/injection-drift.d.ts +7 -2
  148. package/dist/core/constraints/injection-drift.d.ts.map +1 -1
  149. package/dist/core/constraints/injection-drift.js +13 -7
  150. package/dist/core/constraints/injection-drift.js.map +1 -1
  151. package/dist/core/constraints/run-env.d.ts +92 -0
  152. package/dist/core/constraints/run-env.d.ts.map +1 -0
  153. package/dist/core/constraints/run-env.js +175 -0
  154. package/dist/core/constraints/run-env.js.map +1 -0
  155. package/dist/core/constraints/triggers.d.ts +22 -0
  156. package/dist/core/constraints/triggers.d.ts.map +1 -0
  157. package/dist/core/constraints/triggers.js +31 -0
  158. package/dist/core/constraints/triggers.js.map +1 -0
  159. package/dist/core/effective-constraints.d.ts +13 -4
  160. package/dist/core/effective-constraints.d.ts.map +1 -1
  161. package/dist/core/effective-constraints.js +16 -6
  162. package/dist/core/effective-constraints.js.map +1 -1
  163. package/dist/core/effective-set.d.ts +8 -15
  164. package/dist/core/effective-set.d.ts.map +1 -1
  165. package/dist/core/effective-set.js +7 -12
  166. package/dist/core/effective-set.js.map +1 -1
  167. package/dist/core/index.d.ts +2 -1
  168. package/dist/core/index.d.ts.map +1 -1
  169. package/dist/core/index.js.map +1 -1
  170. package/dist/core/project-config-loader.d.ts +39 -17
  171. package/dist/core/project-config-loader.d.ts.map +1 -1
  172. package/dist/core/project-config-loader.js +51 -122
  173. package/dist/core/project-config-loader.js.map +1 -1
  174. package/dist/core/validators/check-handlers/http.d.ts +2 -2
  175. package/dist/core/validators/check-handlers/http.d.ts.map +1 -1
  176. package/dist/core/validators/check-handlers/http.js +12 -7
  177. package/dist/core/validators/check-handlers/http.js.map +1 -1
  178. package/dist/core/validators/index.d.ts +1 -1
  179. package/dist/core/validators/index.d.ts.map +1 -1
  180. package/dist/core/validators/passes-gate.d.ts.map +1 -1
  181. package/dist/core/validators/passes-gate.js +2 -2
  182. package/dist/core/validators/passes-gate.js.map +1 -1
  183. package/dist/failure/classifier.d.ts +1 -1
  184. package/dist/failure/classifier.d.ts.map +1 -1
  185. package/dist/failure/classifier.js +8 -8
  186. package/dist/failure/classifier.js.map +1 -1
  187. package/dist/failure/index.d.ts +2 -1
  188. package/dist/failure/index.d.ts.map +1 -1
  189. package/dist/failure/index.js +9 -17
  190. package/dist/failure/index.js.map +1 -1
  191. package/dist/failure/recorder.d.ts +1 -1
  192. package/dist/failure/recorder.d.ts.map +1 -1
  193. package/dist/gates/checker-gate.d.ts +2 -1
  194. package/dist/gates/checker-gate.d.ts.map +1 -1
  195. package/dist/gates/checker-gate.js +3 -2
  196. package/dist/gates/checker-gate.js.map +1 -1
  197. package/dist/gates/command.d.ts +10 -4
  198. package/dist/gates/command.d.ts.map +1 -1
  199. package/dist/gates/command.js +36 -62
  200. package/dist/gates/command.js.map +1 -1
  201. package/dist/gates/contract.d.ts.map +1 -1
  202. package/dist/gates/contract.js +0 -4
  203. package/dist/gates/contract.js.map +1 -1
  204. package/dist/gates/definitions.d.ts +2 -1
  205. package/dist/gates/definitions.d.ts.map +1 -1
  206. package/dist/gates/definitions.js +6 -5
  207. package/dist/gates/definitions.js.map +1 -1
  208. package/dist/gates/index.d.ts +0 -4
  209. package/dist/gates/index.d.ts.map +1 -1
  210. package/dist/gates/index.js +1 -6
  211. package/dist/gates/index.js.map +1 -1
  212. package/dist/gates/performance.d.ts.map +1 -1
  213. package/dist/gates/performance.js +0 -4
  214. package/dist/gates/performance.js.map +1 -1
  215. package/dist/gates/runner.d.ts +1 -1
  216. package/dist/gates/runner.js +1 -1
  217. package/dist/gates/security.d.ts +1 -1
  218. package/dist/gates/security.d.ts.map +1 -1
  219. package/dist/gates/security.js +5 -6
  220. package/dist/gates/security.js.map +1 -1
  221. package/dist/gates/types.d.ts +14 -17
  222. package/dist/gates/types.d.ts.map +1 -1
  223. package/dist/gates/types.js.map +1 -1
  224. package/dist/hooks/bootstrap.d.ts +6 -4
  225. package/dist/hooks/bootstrap.d.ts.map +1 -1
  226. package/dist/hooks/bootstrap.js +25 -13
  227. package/dist/hooks/bootstrap.js.map +1 -1
  228. package/dist/hooks/config.d.ts +6 -2
  229. package/dist/hooks/config.d.ts.map +1 -1
  230. package/dist/hooks/config.js +5 -1
  231. package/dist/hooks/config.js.map +1 -1
  232. package/dist/hooks/index.d.ts +1 -1
  233. package/dist/hooks/index.d.ts.map +1 -1
  234. package/dist/hooks/index.js +0 -15
  235. package/dist/hooks/index.js.map +1 -1
  236. package/dist/hooks/pipeline.d.ts.map +1 -1
  237. package/dist/hooks/pipeline.js +2 -4
  238. package/dist/hooks/pipeline.js.map +1 -1
  239. package/dist/hooks/registry.d.ts +11 -8
  240. package/dist/hooks/registry.d.ts.map +1 -1
  241. package/dist/hooks/registry.js +22 -7
  242. package/dist/hooks/registry.js.map +1 -1
  243. package/dist/hooks/types.d.ts +23 -7
  244. package/dist/hooks/types.d.ts.map +1 -1
  245. package/dist/index.d.ts +4 -4
  246. package/dist/index.d.ts.map +1 -1
  247. package/dist/index.js +3 -4
  248. package/dist/index.js.map +1 -1
  249. package/dist/knowledge/audit-scoring.d.ts +87 -0
  250. package/dist/knowledge/audit-scoring.d.ts.map +1 -0
  251. package/dist/knowledge/audit-scoring.js +470 -0
  252. package/dist/knowledge/audit-scoring.js.map +1 -0
  253. package/dist/knowledge/audit.d.ts +11 -59
  254. package/dist/knowledge/audit.d.ts.map +1 -1
  255. package/dist/knowledge/audit.js +47 -522
  256. package/dist/knowledge/audit.js.map +1 -1
  257. package/dist/knowledge/import.d.ts.map +1 -1
  258. package/dist/knowledge/import.js +2 -0
  259. package/dist/knowledge/import.js.map +1 -1
  260. package/dist/knowledge/index-generator.d.ts.map +1 -1
  261. package/dist/knowledge/index-generator.js +4 -5
  262. package/dist/knowledge/index-generator.js.map +1 -1
  263. package/dist/knowledge/index.d.ts +3 -2
  264. package/dist/knowledge/index.d.ts.map +1 -1
  265. package/dist/knowledge/index.js +3 -16
  266. package/dist/knowledge/index.js.map +1 -1
  267. package/dist/knowledge/ingest.js +1 -1
  268. package/dist/knowledge/ingest.js.map +1 -1
  269. package/dist/knowledge/lifecycle.d.ts.map +1 -1
  270. package/dist/knowledge/lifecycle.js +4 -2
  271. package/dist/knowledge/lifecycle.js.map +1 -1
  272. package/dist/knowledge/migration.d.ts +3 -0
  273. package/dist/knowledge/migration.d.ts.map +1 -1
  274. package/dist/knowledge/migration.js +8 -2
  275. package/dist/knowledge/migration.js.map +1 -1
  276. package/dist/knowledge/query.d.ts +6 -0
  277. package/dist/knowledge/query.d.ts.map +1 -1
  278. package/dist/knowledge/query.js +8 -2
  279. package/dist/knowledge/query.js.map +1 -1
  280. package/dist/knowledge/reference-tracker.d.ts.map +1 -1
  281. package/dist/knowledge/reference-tracker.js +4 -6
  282. package/dist/knowledge/reference-tracker.js.map +1 -1
  283. package/dist/knowledge/store.d.ts +22 -16
  284. package/dist/knowledge/store.d.ts.map +1 -1
  285. package/dist/knowledge/store.js +53 -12
  286. package/dist/knowledge/store.js.map +1 -1
  287. package/dist/knowledge/tree-walker.d.ts +19 -0
  288. package/dist/knowledge/tree-walker.d.ts.map +1 -0
  289. package/dist/knowledge/tree-walker.js +30 -0
  290. package/dist/knowledge/tree-walker.js.map +1 -0
  291. package/dist/knowledge/types.d.ts +16 -0
  292. package/dist/knowledge/types.d.ts.map +1 -1
  293. package/dist/monitoring/traces.d.ts +5 -3
  294. package/dist/monitoring/traces.d.ts.map +1 -1
  295. package/dist/monitoring/traces.js +19 -5
  296. package/dist/monitoring/traces.js.map +1 -1
  297. package/dist/test-setup/jsonl-fake-fs.d.ts +30 -0
  298. package/dist/test-setup/jsonl-fake-fs.d.ts.map +1 -0
  299. package/dist/test-setup/jsonl-fake-fs.js +49 -0
  300. package/dist/test-setup/jsonl-fake-fs.js.map +1 -0
  301. package/dist/tools/index.d.ts +4 -1
  302. package/dist/tools/index.d.ts.map +1 -1
  303. package/dist/tools/index.js +7 -15
  304. package/dist/tools/index.js.map +1 -1
  305. package/dist/types/checkpoint.d.ts +5 -0
  306. package/dist/types/checkpoint.d.ts.map +1 -1
  307. package/dist/types/passes-gate.d.ts +0 -13
  308. package/dist/types/passes-gate.d.ts.map +1 -1
  309. package/dist/types/project-config.d.ts +18 -0
  310. package/dist/types/project-config.d.ts.map +1 -1
  311. package/dist/types/trace.d.ts +13 -4
  312. package/dist/types/trace.d.ts.map +1 -1
  313. package/dist/types/trace.js +4 -3
  314. package/dist/types/trace.js.map +1 -1
  315. package/dist/utils/exec.d.ts +4 -27
  316. package/dist/utils/exec.d.ts.map +1 -1
  317. package/dist/utils/exec.js +4 -94
  318. package/dist/utils/exec.js.map +1 -1
  319. package/dist/utils/jsonl.d.ts +17 -7
  320. package/dist/utils/jsonl.d.ts.map +1 -1
  321. package/dist/utils/jsonl.js +144 -17
  322. package/dist/utils/jsonl.js.map +1 -1
  323. package/dist/utils/numeric-flag.d.ts +44 -0
  324. package/dist/utils/numeric-flag.d.ts.map +1 -0
  325. package/dist/utils/numeric-flag.js +62 -0
  326. package/dist/utils/numeric-flag.js.map +1 -0
  327. package/package.json +1 -1
  328. package/src/CONTEXT.md +5 -2
  329. package/src/__tests__/acceptance-gate.test.ts +7 -4
  330. package/src/__tests__/checker-extra.test.ts +3 -2
  331. package/src/__tests__/checker.test.ts +4 -3
  332. package/src/__tests__/checkpoint.test.ts +26 -9
  333. package/src/__tests__/context-files-resolution.test.ts +29 -15
  334. package/src/__tests__/contract-gate.test.ts +19 -40
  335. package/src/__tests__/error-classifier.test.ts +1 -1
  336. package/src/__tests__/exec.test.ts +45 -107
  337. package/src/__tests__/failure-recorder.test.ts +7 -5
  338. package/src/__tests__/hooks-pipeline.test.ts +34 -47
  339. package/src/__tests__/layering.test.ts +217 -25
  340. package/src/__tests__/passes-gate.test.ts +9 -4
  341. package/src/__tests__/performance-gate.test.ts +3 -15
  342. package/src/__tests__/project-config-loader-extra.test.ts +31 -57
  343. package/src/__tests__/project-config-loader.test.ts +6 -3
  344. package/src/__tests__/public-exports.test.ts +27 -6
  345. package/src/__tests__/public-type-surface.test.ts +360 -0
  346. package/src/__tests__/public-value-surface.test.ts +182 -0
  347. package/src/__tests__/review-gate.test.ts +4 -6
  348. package/src/__tests__/security-gate.test.ts +5 -20
  349. package/src/__tests__/skip-semantics.test.ts +5 -3
  350. package/src/__tests__/spec-validator.test.ts +3 -2
  351. package/src/__tests__/sub-barrels-explicit.test.ts +87 -0
  352. package/src/__tests__/test-fixture-hygiene.test.ts +53 -0
  353. package/src/__tests__/trace-analyzer-extra.test.ts +5 -3
  354. package/src/__tests__/trace-analyzer.test.ts +5 -3
  355. package/src/__tests__/trace-collector.test.ts +5 -3
  356. package/src/agents/index.ts +13 -2
  357. package/src/cli/__tests__/gate-command.test.ts +162 -0
  358. package/src/cli/commands/CONTEXT.md +29 -5
  359. package/src/cli/commands/__tests__/acceptance.test.ts +24 -25
  360. package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +15 -0
  361. package/src/cli/commands/__tests__/check-drift.test.ts +42 -1
  362. package/src/cli/commands/__tests__/check-read-count.test.ts +167 -0
  363. package/src/cli/commands/__tests__/check-skip-output.test.ts +4 -1
  364. package/src/cli/commands/__tests__/check.test.ts +43 -36
  365. package/src/cli/commands/__tests__/command-gate-dead-options.test.ts +60 -0
  366. package/src/cli/commands/__tests__/command.test.ts +33 -17
  367. package/src/cli/commands/__tests__/constraints-retire.test.ts +52 -0
  368. package/src/cli/commands/__tests__/context-syncer.test.ts +141 -0
  369. package/src/cli/commands/__tests__/contract.test.ts +20 -20
  370. package/src/cli/commands/__tests__/failure.test.ts +5 -4
  371. package/src/cli/commands/__tests__/gate-decision.ts +30 -0
  372. package/src/cli/commands/__tests__/init-dead-options.test.ts +50 -0
  373. package/src/cli/commands/__tests__/init-governance-io.test.ts +139 -0
  374. package/src/cli/commands/__tests__/init-injection.test.ts +3 -3
  375. package/src/cli/commands/__tests__/init-ondisk.test.ts +867 -0
  376. package/src/cli/commands/__tests__/init.test.ts +82 -6
  377. package/src/cli/commands/__tests__/knowledge-audit-threshold.test.ts +146 -0
  378. package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +1 -1
  379. package/src/cli/commands/__tests__/knowledge-tone-mapping.test.ts +244 -0
  380. package/src/cli/commands/__tests__/knowledge-view.test.ts +839 -0
  381. package/src/cli/commands/__tests__/knowledge.test.ts +33 -15
  382. package/src/cli/commands/__tests__/numeric-flag-assembly.test.ts +368 -0
  383. package/src/cli/commands/__tests__/passes-gate-dead-options.test.ts +89 -1
  384. package/src/cli/commands/__tests__/performance.test.ts +19 -21
  385. package/src/cli/commands/__tests__/posteval-plan.test.ts +5 -3
  386. package/src/cli/commands/__tests__/pre-push-hook.test.ts +181 -0
  387. package/src/cli/commands/__tests__/project-path-anchoring.test.ts +95 -2
  388. package/src/cli/commands/__tests__/project-path-convention.test.ts +103 -25
  389. package/src/cli/commands/__tests__/registry.test.ts +2 -0
  390. package/src/cli/commands/__tests__/report.test.ts +23 -1
  391. package/src/cli/commands/__tests__/review.test.ts +10 -17
  392. package/src/cli/commands/__tests__/scaffold.test.ts +505 -0
  393. package/src/cli/commands/__tests__/security-default-scan.test.ts +75 -0
  394. package/src/cli/commands/__tests__/security.test.ts +21 -24
  395. package/src/cli/commands/__tests__/spec-baseline-check.test.ts +3 -2
  396. package/src/cli/commands/__tests__/spec-baseline-index-cap.test.ts +131 -0
  397. package/src/cli/commands/__tests__/spec-baseline-read-count.test.ts +325 -0
  398. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +19 -4
  399. package/src/cli/commands/__tests__/sync-docs-context-drift.test.ts +232 -0
  400. package/src/cli/commands/__tests__/sync-docs-module-order.test.ts +111 -0
  401. package/src/cli/commands/__tests__/sync-docs-read-count.test.ts +192 -0
  402. package/src/cli/commands/__tests__/sync-docs.test.ts +3 -2
  403. package/src/cli/commands/__tests__/validate.test.ts +1 -48
  404. package/src/cli/commands/acceptance.ts +24 -29
  405. package/src/cli/commands/check.ts +40 -17
  406. package/src/cli/commands/command.ts +9 -8
  407. package/src/cli/commands/constraints-retire.ts +57 -70
  408. package/src/cli/commands/contract.ts +44 -47
  409. package/src/cli/commands/definitions.ts +12 -6
  410. package/src/cli/commands/failure.ts +16 -3
  411. package/src/cli/commands/init.ts +242 -389
  412. package/src/cli/commands/knowledge-view.ts +224 -0
  413. package/src/cli/commands/knowledge.ts +643 -448
  414. package/src/cli/commands/passes-gate.ts +12 -3
  415. package/src/cli/commands/performance.ts +31 -38
  416. package/src/cli/commands/report.ts +3 -2
  417. package/src/cli/commands/review.ts +22 -28
  418. package/src/cli/commands/scaffold-templates.ts +406 -0
  419. package/src/cli/commands/scaffold.ts +302 -0
  420. package/src/cli/commands/security.ts +27 -23
  421. package/src/cli/commands/spec-baseline-check.ts +158 -33
  422. package/src/cli/commands/sync-docs/__tests__/context-export-surface.test.ts +102 -0
  423. package/src/cli/commands/sync-docs/__tests__/module-descriptions.test.ts +196 -0
  424. package/src/cli/commands/sync-docs/context-syncer.ts +137 -31
  425. package/src/cli/commands/sync-docs/index.ts +103 -28
  426. package/src/cli/commands/sync-docs/project-reader.ts +51 -7
  427. package/src/cli/commands/validate.ts +1 -104
  428. package/src/cli/gate-command.ts +87 -0
  429. package/src/completion-checkers/index.ts +10 -1
  430. package/src/context/CONTEXT.md +2 -1
  431. package/src/context/__tests__/knowledge-injector.test.ts +27 -0
  432. package/src/context/__tests__/session-manager.test.ts +19 -12
  433. package/src/context/knowledge-injector.ts +14 -7
  434. package/src/core/CONTEXT.md +10 -7
  435. package/src/core/__tests__/effective-set.test.ts +36 -60
  436. package/src/core/constraints/__tests__/context-reconcile.test.ts +246 -0
  437. package/src/core/constraints/__tests__/run-env.test.ts +377 -0
  438. package/src/core/constraints/__tests__/triggers.test.ts +70 -0
  439. package/src/core/constraints/agent-prompt-renderer.ts +1 -1
  440. package/src/core/constraints/capabilities-reconcile.ts +28 -4
  441. package/src/core/constraints/check-cache.ts +1 -1
  442. package/src/core/constraints/checker.ts +30 -14
  443. package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +8 -3
  444. package/src/core/constraints/checkers/__tests__/governance-presence.test.ts +16 -7
  445. package/src/core/constraints/checkers/__tests__/no-hardcoded-credentials.test.ts +2 -1
  446. package/src/core/constraints/checkers/capability-sync.ts +27 -28
  447. package/src/core/constraints/checkers/context-doc-sync.ts +9 -7
  448. package/src/core/constraints/checkers/docs-freshness.ts +28 -33
  449. package/src/core/constraints/checkers/governance-presence.ts +10 -6
  450. package/src/core/constraints/checkers/types.ts +14 -8
  451. package/src/core/constraints/context-builder.ts +35 -26
  452. package/src/core/constraints/context-reconcile.ts +200 -0
  453. package/src/core/constraints/doc-freshness/__tests__/runner.test.ts +25 -0
  454. package/src/core/constraints/doc-freshness/runner.ts +18 -4
  455. package/src/core/constraints/git-evidence.ts +1 -1
  456. package/src/core/constraints/injection-drift.ts +19 -8
  457. package/src/core/constraints/run-env.ts +207 -0
  458. package/src/core/constraints/triggers.ts +33 -0
  459. package/src/core/effective-constraints.ts +17 -6
  460. package/src/core/effective-set.ts +8 -24
  461. package/src/core/index.ts +2 -1
  462. package/src/core/project-config-loader.ts +54 -102
  463. package/src/core/validators/__tests__/http-retry-sleep.test.ts +231 -0
  464. package/src/core/validators/check-handlers/http.ts +18 -7
  465. package/src/core/validators/index.ts +0 -1
  466. package/src/core/validators/passes-gate.ts +2 -3
  467. package/src/failure/CONTEXT.md +2 -1
  468. package/src/failure/classifier.ts +2 -2
  469. package/src/failure/index.ts +14 -2
  470. package/src/failure/recorder.ts +1 -1
  471. package/src/gates/CONTEXT.md +13 -7
  472. package/src/gates/__tests__/checker-gate.test.ts +1 -1
  473. package/src/gates/__tests__/command-single-predicate.test.ts +135 -0
  474. package/src/gates/__tests__/command.test.ts +8 -15
  475. package/src/gates/__tests__/contract.test.ts +5 -5
  476. package/src/gates/__tests__/gate-interface.test.ts +0 -17
  477. package/src/gates/__tests__/performance.test.ts +0 -13
  478. package/src/gates/__tests__/review.test.ts +0 -1
  479. package/src/gates/__tests__/runner.test.ts +1 -1
  480. package/src/gates/__tests__/security-default-scan.test.ts +97 -0
  481. package/src/gates/__tests__/security.test.ts +0 -13
  482. package/src/gates/checker-gate.ts +3 -2
  483. package/src/gates/command.ts +51 -74
  484. package/src/gates/contract.ts +0 -5
  485. package/src/gates/definitions.ts +6 -5
  486. package/src/gates/index.ts +0 -5
  487. package/src/gates/performance.ts +1 -6
  488. package/src/gates/runner.ts +1 -1
  489. package/src/gates/security.ts +9 -11
  490. package/src/gates/types.ts +20 -23
  491. package/src/hooks/CONTEXT.md +10 -9
  492. package/src/hooks/__tests__/bootstrap.test.ts +29 -6
  493. package/src/hooks/__tests__/pipeline.test.ts +28 -17
  494. package/src/hooks/__tests__/registry.test.ts +51 -3
  495. package/src/hooks/bootstrap.ts +35 -15
  496. package/src/hooks/config.ts +6 -2
  497. package/src/hooks/index.ts +10 -1
  498. package/src/hooks/pipeline.ts +4 -6
  499. package/src/hooks/registry.ts +31 -12
  500. package/src/hooks/types.ts +24 -7
  501. package/src/index.ts +1 -3
  502. package/src/knowledge/CONTEXT.md +14 -7
  503. package/src/knowledge/__tests__/audit-labels.test.ts +8 -5
  504. package/src/knowledge/__tests__/audit-scoring.test.ts +230 -0
  505. package/src/knowledge/__tests__/audit-write-count.test.ts +131 -0
  506. package/src/knowledge/__tests__/audit.test.ts +291 -208
  507. package/src/knowledge/__tests__/doctor.test.ts +3 -2
  508. package/src/knowledge/__tests__/ingest.test.ts +3 -2
  509. package/src/knowledge/__tests__/lifecycle.test.ts +57 -2
  510. package/src/knowledge/__tests__/migration.test.ts +35 -6
  511. package/src/knowledge/__tests__/query.test.ts +3 -2
  512. package/src/knowledge/__tests__/reference-tracker.test.ts +23 -2
  513. package/src/knowledge/__tests__/store.test.ts +149 -4
  514. package/src/knowledge/__tests__/tree-walker.test.ts +132 -0
  515. package/src/knowledge/audit-scoring.ts +589 -0
  516. package/src/knowledge/audit.ts +55 -599
  517. package/src/knowledge/import.ts +2 -0
  518. package/src/knowledge/index-generator.ts +4 -6
  519. package/src/knowledge/index.ts +27 -2
  520. package/src/knowledge/ingest.ts +1 -1
  521. package/src/knowledge/lifecycle.ts +5 -2
  522. package/src/knowledge/migration.ts +8 -2
  523. package/src/knowledge/query.ts +8 -1
  524. package/src/knowledge/reference-tracker.ts +5 -7
  525. package/src/knowledge/store.ts +75 -16
  526. package/src/knowledge/tree-walker.ts +29 -0
  527. package/src/knowledge/types.ts +19 -0
  528. package/src/monitoring/CONTEXT.md +5 -2
  529. package/src/monitoring/__tests__/context-tracker.test.ts +16 -8
  530. package/src/monitoring/__tests__/trace-file-anchoring.test.ts +80 -0
  531. package/src/monitoring/traces.ts +19 -5
  532. package/src/release/CONTEXT.md +1 -1
  533. package/src/release/__tests__/integrity.test.ts +21 -12
  534. package/src/test-setup/__tests__/jsonl-fake-fs.test.ts +98 -0
  535. package/src/test-setup/jsonl-fake-fs.ts +59 -0
  536. package/src/tools/index.ts +5 -1
  537. package/src/types/checkpoint.ts +6 -0
  538. package/src/types/passes-gate.ts +0 -17
  539. package/src/types/project-config.ts +21 -0
  540. package/src/types/trace.ts +14 -4
  541. package/src/utils/__tests__/file-walk.test.ts +3 -2
  542. package/src/utils/__tests__/jsonl-bounded-read.test.ts +106 -0
  543. package/src/utils/__tests__/jsonl-skip-disposition.test.ts +10 -6
  544. package/src/utils/__tests__/jsonl.test.ts +61 -14
  545. package/src/utils/__tests__/numeric-flag.test.ts +80 -0
  546. package/src/utils/__tests__/package-version.test.ts +2 -2
  547. package/src/utils/exec.ts +4 -64
  548. package/src/utils/jsonl.ts +159 -20
  549. package/src/utils/numeric-flag.ts +64 -0
  550. package/dist/failure/types.d.ts +0 -9
  551. package/dist/failure/types.d.ts.map +0 -1
  552. package/dist/failure/types.js +0 -25
  553. package/dist/failure/types.js.map +0 -1
  554. package/dist/gates/effective-gates.d.ts +0 -30
  555. package/dist/gates/effective-gates.d.ts.map +0 -1
  556. package/dist/gates/effective-gates.js +0 -81
  557. package/dist/gates/effective-gates.js.map +0 -1
  558. package/src/failure/types.ts +0 -9
  559. package/src/gates/__tests__/effective-gates.test.ts +0 -77
  560. package/src/gates/effective-gates.ts +0 -99
@@ -0,0 +1,302 @@
1
+ /**
2
+ * 脚手架落盘模块(harness#132,架构评审候选3)
3
+ *
4
+ * 一个决策只写一次:受管文件(managed file — harness 模板拥有正本、用户也可能
5
+ * 持有的落盘文件)在不在场、在场时算跳过还是算请用户手工合并、要不要建父目录、
6
+ * 打什么颜色的哪句话,全部收在本模块。此前这段判定复印在 init 6 处 + validate 2 处。
7
+ *
8
+ * 三态:
9
+ * - `created` 不在场 → 落盘模板正文
10
+ * - `exists` 在场 → 灰字告知跳过(**不细分内容是否等于模板**,内容比较是独立特性)
11
+ * - `manual` 在场 → 打印片段请用户手工合并
12
+ *
13
+ * 纪律:本模块不持有覆盖/跳过策略——「哪些文件要落」由命令层翻成 plan 列表传进来,
14
+ * 本模块只见 plan;模板正文住在 `scaffold-templates.ts`。
15
+ */
16
+
17
+ import * as path from 'path';
18
+ import chalk from 'chalk';
19
+ import * as nodeFs from 'fs/promises';
20
+ import type { CiPlatform } from '../../types/project-config';
21
+ import { log, type CommandIO } from '../command-contract';
22
+ import {
23
+ CUSTOM_CONSTRAINTS_TEMPLATE,
24
+ DEFAULT_CHECKPOINT_FILE,
25
+ HARNESS_CHECK_WORKFLOW,
26
+ PRE_COMMIT_SNIPPET,
27
+ PRE_PUSH_SNIPPET,
28
+ renderChangelog,
29
+ renderCheckpoints,
30
+ renderContextDoc,
31
+ renderGitLabCiFile,
32
+ renderGitLabCiJobs,
33
+ renderGovernanceWorkflow,
34
+ renderPreCommitHook,
35
+ renderPrePushHook,
36
+ renderResolutions,
37
+ } from './scaffold-templates';
38
+
39
+ /** 三态判定结果 */
40
+ export type ScaffoldOutcome = 'created' | 'exists' | 'manual';
41
+
42
+ /**
43
+ * 落盘注入面(缺省 node fs;测试注入内存替身即可断言「真写出了什么内容」)
44
+ */
45
+ export interface ScaffoldFileSystem {
46
+ exists(target: string): Promise<boolean>;
47
+ mkdir(dir: string): Promise<void>;
48
+ writeFile(target: string, content: string): Promise<void>;
49
+ chmod(target: string, mode: number): Promise<void>;
50
+ }
51
+
52
+ export const nodeScaffoldFs: ScaffoldFileSystem = {
53
+ async exists(target) {
54
+ try {
55
+ await nodeFs.access(target);
56
+ return true;
57
+ } catch {
58
+ return false;
59
+ }
60
+ },
61
+ async mkdir(dir) {
62
+ await nodeFs.mkdir(dir, { recursive: true });
63
+ },
64
+ async writeFile(target, content) {
65
+ await nodeFs.writeFile(target, content, 'utf-8');
66
+ },
67
+ async chmod(target, mode) {
68
+ await nodeFs.chmod(target, mode);
69
+ },
70
+ };
71
+
72
+ /**
73
+ * 在场处置:
74
+ * - `skip` harness 不再主张这份正文,灰字告知即可
75
+ * - `merge` 用户可能持有自己的内容,打印片段(与落盘正文同源)请其手工合并
76
+ */
77
+ export type OnPresent =
78
+ | { outcome: 'skip'; notice: string }
79
+ | {
80
+ outcome: 'merge';
81
+ notice: string;
82
+ /** 提示与指引之间的灰字补充行(如冲突来源清单) */
83
+ detail?: string[];
84
+ instruction: string;
85
+ snippet: string;
86
+ };
87
+
88
+ /** 一个受管文件 = 三态判定所需的全部数据 */
89
+ export interface ManagedFile {
90
+ /** 落盘目标(绝对路径) */
91
+ target: string;
92
+ /** harness 拥有的模板正文 */
93
+ content: string;
94
+ /** 落盘态绿字 */
95
+ created: string;
96
+ /** 在场态处置 */
97
+ onPresent: OnPresent;
98
+ /** 在场判定覆写,缺省 = target 自身在场(冲突面可以宽于 target,如 CI 配置目录) */
99
+ present?: () => Promise<boolean>;
100
+ /** 落盘权限位(Git hook 需要可执行位) */
101
+ mode?: number;
102
+ }
103
+
104
+ /**
105
+ * 落一个受管文件:判定 → 建目录 → 写盘 → 上色打印
106
+ */
107
+ export async function writeManagedFile(
108
+ file: ManagedFile,
109
+ io: CommandIO,
110
+ fs: ScaffoldFileSystem = nodeScaffoldFs,
111
+ ): Promise<ScaffoldOutcome> {
112
+ const present = file.present ? await file.present() : await fs.exists(file.target);
113
+
114
+ if (!present) {
115
+ await fs.mkdir(path.dirname(file.target));
116
+ await fs.writeFile(file.target, file.content);
117
+ if (file.mode !== undefined) await fs.chmod(file.target, file.mode);
118
+ log(io, chalk.green(file.created));
119
+ return 'created';
120
+ }
121
+
122
+ if (file.onPresent.outcome === 'skip') {
123
+ log(io, chalk.gray(file.onPresent.notice));
124
+ return 'exists';
125
+ }
126
+
127
+ log(io, chalk.yellow(file.onPresent.notice));
128
+ for (const line of file.onPresent.detail ?? []) {
129
+ log(io, chalk.gray(line));
130
+ }
131
+ log(io, chalk.gray(file.onPresent.instruction));
132
+ log(io);
133
+ log(io, chalk.cyan(file.onPresent.snippet));
134
+ return 'manual';
135
+ }
136
+
137
+ /** 按顺序落一组受管文件 */
138
+ export async function runPlan(
139
+ plan: readonly ManagedFile[],
140
+ io: CommandIO,
141
+ fs: ScaffoldFileSystem = nodeScaffoldFs,
142
+ ): Promise<ScaffoldOutcome[]> {
143
+ const outcomes: ScaffoldOutcome[] = [];
144
+ for (const file of plan) {
145
+ outcomes.push(await writeManagedFile(file, io, fs));
146
+ }
147
+ return outcomes;
148
+ }
149
+
150
+ // ── 站点:init 的 7 处 + 原住 validate 的 2 处 ──────────────────────────
151
+
152
+ /** .git/hooks/pre-commit(冲突片段 = 落盘正文去掉 shebang 头,逐字同源) */
153
+ export function preCommitHookFile(projectPath: string): ManagedFile {
154
+ return {
155
+ target: path.join(projectPath, '.git', 'hooks', 'pre-commit'),
156
+ content: renderPreCommitHook(),
157
+ created: '✅ 已创建 .git/hooks/pre-commit',
158
+ mode: 0o755,
159
+ onPresent: {
160
+ outcome: 'merge',
161
+ notice: '⚠️ .git/hooks/pre-commit 已存在',
162
+ instruction: '💡 请手动添加以下内容到文件末尾:',
163
+ snippet: PRE_COMMIT_SNIPPET,
164
+ },
165
+ };
166
+ }
167
+
168
+ /**
169
+ * .git/hooks/pre-push(harness#144 的第 9 站点,冲突片段与落盘正文逐字同源)
170
+ *
171
+ * 与 pre-commit 的分工:那道查暂存的(增量、快反馈),这道查整仓的(全量、兜底)。
172
+ * 本地 hook 是自检与提醒,门禁真正的落点仍是服务端 CI。
173
+ */
174
+ export function prePushHookFile(projectPath: string): ManagedFile {
175
+ return {
176
+ target: path.join(projectPath, '.git', 'hooks', 'pre-push'),
177
+ content: renderPrePushHook(),
178
+ created: '✅ 已创建 .git/hooks/pre-push',
179
+ mode: 0o755,
180
+ onPresent: {
181
+ outcome: 'merge',
182
+ notice: '⚠️ .git/hooks/pre-push 已存在',
183
+ instruction: '💡 请手动添加以下内容到文件末尾:',
184
+ snippet: PRE_PUSH_SNIPPET,
185
+ },
186
+ };
187
+ }
188
+
189
+ /**
190
+ * 服务端 CI 门禁站点(平台维度,harness#143)
191
+ *
192
+ * - `github` → `.github/workflows/harness-check.yml`;冲突判定宽于 target 自身:
193
+ * 工作流目录里已有任何 CI 配置就算冲突,片段是完整 workflow 正文(打印的即落盘的,#103 判据)
194
+ * - `gitlab` → `.gitlab-ci.yml`;冲突面就是该文件自身在场,片段是 harness 拥有的任务正文。
195
+ * GitLab 没有「第二个 CI 文件位」,所以 `-g` 档的治理任务并入同一份正文
196
+ * ——这也是 `governanceLevel` 只对 gitlab 形有意义的原因(GH 侧治理站是独立的
197
+ * `governanceWorkflowFile`)。
198
+ *
199
+ * `none`(不接线)不进来:那是命令层的 plan 里没有这个站点,scaffold 不持有跳过策略。
200
+ */
201
+ export function harnessCheckCiFile(
202
+ projectPath: string,
203
+ platform: CiPlatform,
204
+ existingCiWorkflows: string[],
205
+ governanceLevel?: string,
206
+ ): ManagedFile {
207
+ if (platform === 'gitlab') {
208
+ const content = renderGitLabCiFile(governanceLevel);
209
+ return {
210
+ target: path.join(projectPath, '.gitlab-ci.yml'),
211
+ content,
212
+ created: '✅ 已创建 .gitlab-ci.yml',
213
+ onPresent: {
214
+ outcome: 'merge',
215
+ notice: '⚠️ .gitlab-ci.yml 已存在',
216
+ instruction: '💡 请手动添加以下内容到文件中:',
217
+ snippet: renderGitLabCiJobs(governanceLevel),
218
+ },
219
+ };
220
+ }
221
+
222
+ const target = path.join(projectPath, '.github', 'workflows', 'harness-check.yml');
223
+ return {
224
+ target,
225
+ content: HARNESS_CHECK_WORKFLOW,
226
+ created: '✅ 已创建 .github/workflows/harness-check.yml',
227
+ present: async () => existingCiWorkflows.length > 0,
228
+ onPresent: {
229
+ outcome: 'merge',
230
+ notice: '⚠️ 检测到已存在的 CI 配置:',
231
+ detail: existingCiWorkflows.map(f => ` - .github/workflows/${f}`),
232
+ instruction: '💡 请手动添加以下内容到 jobs 中:',
233
+ snippet: HARNESS_CHECK_WORKFLOW,
234
+ },
235
+ };
236
+ }
237
+
238
+ /** .harness/custom-constraints.yml 示例 */
239
+ export function customConstraintsFile(projectPath: string): ManagedFile {
240
+ return {
241
+ target: path.join(projectPath, '.harness', 'custom-constraints.yml'),
242
+ content: CUSTOM_CONSTRAINTS_TEMPLATE,
243
+ created: '✅ 已创建自定义约束示例: custom-constraints.yml',
244
+ onPresent: { outcome: 'skip', notice: 'custom-constraints.yml 已存在' },
245
+ };
246
+ }
247
+
248
+ /** .harness/checkpoints.yml 示例(原住 validate.ts,路径约定与 validate 共用) */
249
+ export function checkpointsFile(projectPath: string): ManagedFile {
250
+ const target = path.join(projectPath, DEFAULT_CHECKPOINT_FILE);
251
+ return {
252
+ target,
253
+ content: renderCheckpoints(),
254
+ created: `✅ 已创建示例检查点文件: ${target}`,
255
+ onPresent: { outcome: 'skip', notice: 'checkpoints.yml 已存在,跳过' },
256
+ };
257
+ }
258
+
259
+ /** .harness/resolutions.json(RKB 狗粮 — 约束 → 已知解法映射,原住 validate.ts) */
260
+ export function resolutionsFile(projectPath: string): ManagedFile {
261
+ const target = path.join(projectPath, '.harness', 'resolutions.json');
262
+ return {
263
+ target,
264
+ content: renderResolutions(),
265
+ created: `✅ 已创建 Resolutions 文件: ${target}`,
266
+ onPresent: { outcome: 'skip', notice: 'resolutions.json 已存在,跳过' },
267
+ };
268
+ }
269
+
270
+ /** CHANGELOG.md 骨架 */
271
+ export function changelogFile(projectPath: string, format: string): ManagedFile {
272
+ return {
273
+ target: path.join(projectPath, 'CHANGELOG.md'),
274
+ content: renderChangelog(format),
275
+ created: '✅ 已创建 CHANGELOG.md',
276
+ onPresent: { outcome: 'skip', notice: 'CHANGELOG.md 已存在' },
277
+ };
278
+ }
279
+
280
+ /** `<dir>/CONTEXT.md` 骨架 */
281
+ export function contextDocFile(projectPath: string, dir: string): ManagedFile {
282
+ return {
283
+ target: path.join(projectPath, dir, 'CONTEXT.md'),
284
+ content: renderContextDoc(dir),
285
+ created: `✅ 已创建 ${dir}/CONTEXT.md`,
286
+ onPresent: { outcome: 'skip', notice: `${dir}/CONTEXT.md 已存在` },
287
+ };
288
+ }
289
+
290
+ /**
291
+ * .github/workflows/harness-governance.yml(治理 CI 面,仅 github 形)
292
+ *
293
+ * gitlab 形的治理任务并入 `.gitlab-ci.yml`(见 `harnessCheckCiFile`),无本站点。
294
+ */
295
+ export function governanceWorkflowFile(projectPath: string, level: string): ManagedFile {
296
+ return {
297
+ target: path.join(projectPath, '.github', 'workflows', 'harness-governance.yml'),
298
+ content: renderGovernanceWorkflow(level, 'github'),
299
+ created: '✅ 已创建 .github/workflows/harness-governance.yml',
300
+ onPresent: { outcome: 'skip', notice: 'harness-governance.yml 已存在' },
301
+ };
302
+ }
@@ -7,6 +7,7 @@
7
7
  import chalk from 'chalk';
8
8
  import { SecurityGate } from '../../gates/security';
9
9
  import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
10
+ import { reportGateDecision } from '../gate-command';
10
11
 
11
12
  export interface SecurityOptions {
12
13
  /** 项目路径 */
@@ -40,29 +41,32 @@ export async function security(
40
41
  ignoreDevDependencies: options.ignoreDevDeps,
41
42
  });
42
43
 
43
- const result = await gate.scan({ projectPath, projectId: 'default' });
44
+ const decision = await gate.evaluate({ projectPath });
44
45
 
45
- log(io);
46
- if (result.passed) {
47
- log(io, chalk.green('✅ 安全门控检查通过'));
48
- if (result.details) {
49
- log(io, chalk.gray(` critical: ${result.details.critical}, high: ${result.details.high}, moderate: ${result.details.moderate}, low: ${result.details.low}`));
50
- }
51
- } else {
52
- log(io, chalk.red('❌ 安全门控检查失败'));
53
- log(io, chalk.red(` ${result.message}`));
54
- if (result.details?.vulnerabilities) {
55
- log(io);
56
- (result.details.vulnerabilities as Array<{ name: string; severity: string; via: string }>).forEach((v, i) => {
57
- const severityColor = getSeverityColor(v.severity);
58
- log(io, severityColor(` ${i + 1}. [${v.severity.toUpperCase()}] ${v.name}`));
59
- log(io, chalk.gray(` via: ${v.via}`));
60
- });
61
- }
62
- log(io, chalk.gray('\n 运行 harness security audit 查看详情'));
63
- return { kind: 'fail', reason: `security gate denied (threshold ${options.severity || 'high'}): ${result.message}` };
64
- }
65
- return { kind: 'ok' };
46
+ return reportGateDecision(
47
+ io,
48
+ {
49
+ gateId: 'security',
50
+ label: '安全门控',
51
+ onPass: (r) =>
52
+ r.details
53
+ ? [chalk.gray(` critical: ${r.details.critical}, high: ${r.details.high}, moderate: ${r.details.moderate}, low: ${r.details.low}`)]
54
+ : [],
55
+ onFail: (r) => {
56
+ const lines = [chalk.gray(` 阈值: ${options.severity || 'high'}`)];
57
+ if (r.details?.vulnerabilities) {
58
+ lines.push('');
59
+ (r.details.vulnerabilities as Array<{ name: string; severity: string; via: string }>).forEach((v, i) => {
60
+ lines.push(getSeverityColor(v.severity)(` ${i + 1}. [${v.severity.toUpperCase()}] ${v.name}`));
61
+ lines.push(chalk.gray(` via: ${v.via}`));
62
+ });
63
+ }
64
+ lines.push(chalk.gray('\n 运行 harness security audit 查看详情'));
65
+ return lines;
66
+ },
67
+ },
68
+ decision
69
+ );
66
70
  } catch (error) {
67
71
  log(io);
68
72
  log(io, chalk.red(`❌ 安全检查异常: ${error instanceof Error ? error.message : String(error)}`));
@@ -105,7 +109,7 @@ export async function auditDetails(
105
109
  scanCommand: options.scanCommand,
106
110
  });
107
111
 
108
- const result = await gate.scan({ projectPath, projectId: 'default' });
112
+ const result = await gate.scan({ projectPath });
109
113
 
110
114
  if (result.passed && !result.details?.total) {
111
115
  log(io, chalk.green('✅ 未发现安全漏洞'));
@@ -81,6 +81,133 @@ export function extractBaselineSection(content: string): string[] {
81
81
  return prerequisites;
82
82
  }
83
83
 
84
+ // ============================================
85
+ // 命令级共享索引
86
+ // ============================================
87
+
88
+ /** package.json 依赖面的一次解析结果(失败态同样入库,不重试) */
89
+ type DependencySnapshot = { ok: true; deps: Record<string, string> } | { ok: false };
90
+
91
+ /**
92
+ * 共享索引的驻留上限(#162,统一复审遗留项 3):
93
+ * #146 把全仓源文件内容常驻一个 Map,排除面只有 node_modules/dist/隐藏目录与后缀,
94
+ * 无任何容量上限——峰值内存由 O(单文件) 变 O(全仓源码),大 monorepo 会承担这个峰值。
95
+ * 超出任一上限即放弃驻留、回落逐文件流式读(峰值回到 O(单文件)),
96
+ * 正常规模仓仍保留「一次遍历」收益。
97
+ */
98
+ export const SOURCE_INDEX_MAX_ENTRIES = 5000;
99
+ export const SOURCE_INDEX_MAX_BYTES = 64 * 1024 * 1024;
100
+
101
+ /** 驻留上限(测试可注入小值走回落路径;生产一律缺省常量) */
102
+ export interface SourceIndexLimits {
103
+ maxEntries: number;
104
+ maxBytes: number;
105
+ }
106
+
107
+ /**
108
+ * 一次 spec-baseline-check 运行内的取数面(工单 #146,母票 #140 A 票):
109
+ * 全仓内容扫描、`package.json` 解析、同一落点的存在性探测各至多一遍,
110
+ * 逐条前置只在索引上重放判定——此前是「前置条件数 × 关键词数 × 源文件数」的逐条重扫。
111
+ *
112
+ * 懒建:没有任何前置需要某类数据时,该类读取一次都不发生(口径与改前一致)。
113
+ * 运行结束即弃,不跨命令、不扩 `RunEnv` 公共面(#140 triage 裁决 5)。
114
+ */
115
+ interface BaselineIndex {
116
+ /**
117
+ * 内容含 keyword 的源文件数。上限内走驻留索引重放(一次运行全仓至多读一遍);
118
+ * 超 SOURCE_INDEX_MAX_ENTRIES / SOURCE_INDEX_MAX_BYTES 即放弃驻留,
119
+ * 每个关键词回落逐文件流式读(#162:驻留条目数有上界,峰值 O(单文件))。
120
+ */
121
+ countFilesContaining(keyword: string): number;
122
+ /** package.json 的 dependencies + devDependencies 合并面 */
123
+ dependencies(): DependencySnapshot;
124
+ /** 绝对路径是否在世(同一落点一次运行内只 stat 一次) */
125
+ exists(fullPath: string): boolean;
126
+ }
127
+
128
+ export function createBaselineIndex(
129
+ projectPath: string,
130
+ limits: SourceIndexLimits = { maxEntries: SOURCE_INDEX_MAX_ENTRIES, maxBytes: SOURCE_INDEX_MAX_BYTES }
131
+ ): BaselineIndex {
132
+ /** undefined = 未建(懒建);null = 超上限放弃驻留(回落流式读) */
133
+ let sources: Map<string, string> | null | undefined;
134
+ let dependencySnapshot: DependencySnapshot | undefined;
135
+ const stats = new Map<string, boolean>();
136
+
137
+ const walkSourceFiles = () =>
138
+ walkFiles(projectPath, {
139
+ skipDirs: ['node_modules', 'dist'],
140
+ skipHidden: true,
141
+ filter: (_name, filePath) => filePath.endsWith('.ts') || filePath.endsWith('.js'),
142
+ });
143
+
144
+ /** 遍历与内容读取各一次建驻留索引;超任一上限即弃表返回 null(#162 驻留上界) */
145
+ function buildIndex(): Map<string, string> | null {
146
+ const map = new Map<string, string>();
147
+ let totalBytes = 0;
148
+ for (const fullPath of walkSourceFiles()) {
149
+ try {
150
+ const content = fs.readFileSync(fullPath, 'utf-8');
151
+ map.set(fullPath, content);
152
+ totalBytes += Buffer.byteLength(content);
153
+ if (map.size > limits.maxEntries || totalBytes > limits.maxBytes) {
154
+ return null; // 已读内容随 map 一起弃,驻留峰值 ≤ 上限
155
+ }
156
+ } catch {
157
+ /* skip:读失败的文件不入表(与改前逐文件 try/catch 跳过同义) */
158
+ }
159
+ }
160
+ return map;
161
+ }
162
+
163
+ return {
164
+ countFilesContaining(keyword) {
165
+ if (sources === undefined) sources = buildIndex();
166
+ if (sources !== null) {
167
+ let count = 0;
168
+ for (const content of sources.values()) {
169
+ if (content.includes(keyword)) count++;
170
+ }
171
+ return count;
172
+ }
173
+ // 回落:逐文件流式读、读完即弃,驻留 O(单文件)(改前逐关键词重读同形)
174
+ let count = 0;
175
+ for (const fullPath of walkSourceFiles()) {
176
+ try {
177
+ if (fs.readFileSync(fullPath, 'utf-8').includes(keyword)) count++;
178
+ } catch {
179
+ /* skip */
180
+ }
181
+ }
182
+ return count;
183
+ },
184
+ dependencies() {
185
+ if (!dependencySnapshot) {
186
+ try {
187
+ const pkgJson = JSON.parse(
188
+ fs.readFileSync(path.join(projectPath, 'package.json'), 'utf-8')
189
+ );
190
+ dependencySnapshot = {
191
+ ok: true,
192
+ deps: { ...pkgJson.dependencies, ...pkgJson.devDependencies },
193
+ };
194
+ } catch {
195
+ dependencySnapshot = { ok: false };
196
+ }
197
+ }
198
+ return dependencySnapshot;
199
+ },
200
+ exists(fullPath) {
201
+ let hit = stats.get(fullPath);
202
+ if (hit === undefined) {
203
+ hit = fs.existsSync(fullPath);
204
+ stats.set(fullPath, hit);
205
+ }
206
+ return hit;
207
+ },
208
+ };
209
+ }
210
+
84
211
  // ============================================
85
212
  // 验证器
86
213
  // ============================================
@@ -88,7 +215,11 @@ export function extractBaselineSection(content: string): string[] {
88
215
  /**
89
216
  * 检查文件/目录是否存在
90
217
  */
91
- function checkFileExists(pattern: string, projectPath: string): { exists: boolean; evidence: string } {
218
+ function checkFileExists(
219
+ pattern: string,
220
+ projectPath: string,
221
+ index: BaselineIndex
222
+ ): { exists: boolean; evidence: string } {
92
223
  // 提取路径引用(反引号中的路径、引号中的路径、或直接的路径模式)
93
224
  const pathPatterns = [
94
225
  /`([^`]+\.[a-z]+)`/g, // `src/foo.ts`
@@ -115,7 +246,7 @@ function checkFileExists(pattern: string, projectPath: string): { exists: boolea
115
246
 
116
247
  for (const p of paths) {
117
248
  const fullPath = path.resolve(projectPath, p);
118
- if (fs.existsSync(fullPath)) {
249
+ if (index.exists(fullPath)) {
119
250
  found.push(p);
120
251
  } else {
121
252
  missing.push(p);
@@ -134,7 +265,7 @@ function checkFileExists(pattern: string, projectPath: string): { exists: boolea
134
265
  /**
135
266
  * 检查代码中是否存在特定模式
136
267
  */
137
- function checkCodePattern(pattern: string, projectPath: string): { exists: boolean; evidence: string } {
268
+ function checkCodePattern(pattern: string, index: BaselineIndex): { exists: boolean; evidence: string } {
138
269
  // 从描述中提取关键词
139
270
  const keywords: string[] = [];
140
271
 
@@ -162,21 +293,9 @@ function checkCodePattern(pattern: string, projectPath: string): { exists: boole
162
293
  const found: string[] = [];
163
294
  const notFound: string[] = [];
164
295
 
165
- // 遍历一次,供所有关键词复用(工单 19:walkFiles 收敛)
166
- const sourceFiles = walkFiles(projectPath, {
167
- skipDirs: ['node_modules', 'dist'],
168
- skipHidden: true,
169
- filter: (_name, fullPath) => fullPath.endsWith('.ts') || fullPath.endsWith('.js'),
170
- });
171
-
296
+ // 一次运行一份索引:全仓扫描与内容读取已在索引里发生一遍(超上限则回落流式),这里只做匹配
172
297
  for (const kw of keywords) {
173
- let count = 0;
174
- for (const fullPath of sourceFiles) {
175
- try {
176
- const content = fs.readFileSync(fullPath, 'utf-8');
177
- if (content.includes(kw)) count++;
178
- } catch { /* skip */ }
179
- }
298
+ const count = index.countFilesContaining(kw);
180
299
  if (count > 0) {
181
300
  found.push(`${kw} (${count} files)`);
182
301
  } else {
@@ -196,7 +315,11 @@ function checkCodePattern(pattern: string, projectPath: string): { exists: boole
196
315
  /**
197
316
  * 检查包依赖是否安装
198
317
  */
199
- function checkDependency(pattern: string, projectPath: string): { exists: boolean; evidence: string } {
318
+ function checkDependency(
319
+ pattern: string,
320
+ projectPath: string,
321
+ index: BaselineIndex
322
+ ): { exists: boolean; evidence: string } {
200
323
  // 提取包名
201
324
  const pkgPatterns = [
202
325
  /`(@?[\w-]+\/[\w-]+)`/g, // `@scope/pkg` or `pkg-name`
@@ -223,15 +346,12 @@ function checkDependency(pattern: string, projectPath: string): { exists: boolea
223
346
  const found: string[] = [];
224
347
  const missing: string[] = [];
225
348
 
226
- const pkgJsonPath = path.join(projectPath, 'package.json');
227
- let deps: Record<string, string> = {};
228
-
229
- try {
230
- const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
231
- deps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };
232
- } catch {
349
+ // 一次运行只读解析一遍 package.json(失败态同样入库)
350
+ const snapshot = index.dependencies();
351
+ if (!snapshot.ok) {
233
352
  return { exists: false, evidence: '无法读取 package.json' };
234
353
  }
354
+ const deps = snapshot.deps;
235
355
 
236
356
  for (const pkg of packages) {
237
357
  if (deps[pkg] || deps[`@types/${pkg}`]) {
@@ -239,7 +359,7 @@ function checkDependency(pattern: string, projectPath: string): { exists: boolea
239
359
  } else {
240
360
  // 检查 node_modules
241
361
  const nmPath = path.join(projectPath, 'node_modules', pkg);
242
- if (fs.existsSync(nmPath)) {
362
+ if (index.exists(nmPath)) {
243
363
  found.push(pkg);
244
364
  } else {
245
365
  missing.push(pkg);
@@ -257,15 +377,19 @@ function checkDependency(pattern: string, projectPath: string): { exists: boolea
257
377
  }
258
378
 
259
379
  /**
260
- * 综合验证一条前置条件
380
+ * 综合验证一条前置条件(取数一律经命令级共享索引 `index`)
261
381
  */
262
- function verifyPrerequisite(prereq: string, projectPath: string): PrerequisiteResult {
382
+ function verifyPrerequisite(
383
+ prereq: string,
384
+ projectPath: string,
385
+ index: BaselineIndex
386
+ ): PrerequisiteResult {
263
387
  const lower = prereq.toLowerCase();
264
388
 
265
389
  // 路径/文件存在性检查
266
390
  if (lower.includes('文件') || lower.includes('file') || lower.includes('目录') || lower.includes('directory')
267
391
  || /`[^`]+\.[a-z]+`/.test(prereq) || /\//.test(prereq)) {
268
- const { exists, evidence } = checkFileExists(prereq, projectPath);
392
+ const { exists, evidence } = checkFileExists(prereq, projectPath, index);
269
393
  if (exists || evidence.includes('文件不存在')) {
270
394
  return { prerequisite: prereq, satisfied: exists, evidence };
271
395
  }
@@ -273,7 +397,7 @@ function verifyPrerequisite(prereq: string, projectPath: string): PrerequisiteRe
273
397
 
274
398
  // 依赖检查
275
399
  if (lower.includes('依赖') || lower.includes('install') || lower.includes('package') || lower.includes('npm')) {
276
- const { exists, evidence } = checkDependency(prereq, projectPath);
400
+ const { exists, evidence } = checkDependency(prereq, projectPath, index);
277
401
  return { prerequisite: prereq, satisfied: exists, evidence };
278
402
  }
279
403
 
@@ -281,7 +405,7 @@ function verifyPrerequisite(prereq: string, projectPath: string): PrerequisiteRe
281
405
  if (lower.includes('实现') || lower.includes('implement') || lower.includes('exist')
282
406
  || lower.includes('已') || lower.includes('必须')
283
407
  || /`[^`]+`/.test(prereq)) {
284
- const { exists, evidence } = checkCodePattern(prereq, projectPath);
408
+ const { exists, evidence } = checkCodePattern(prereq, index);
285
409
  return { prerequisite: prereq, satisfied: exists, evidence };
286
410
  }
287
411
 
@@ -360,8 +484,9 @@ export async function specBaselineCheck(
360
484
  return { kind: 'skip', reason: '未找到 Baseline / 前置条件 section,无可判定项' };
361
485
  }
362
486
 
363
- // 验证每条前置条件
364
- const results = prerequisites.map(p => verifyPrerequisite(p, projectPath));
487
+ // 验证每条前置条件(全仓扫描与 package.json 解析在本次运行内各至多一遍)
488
+ const index = createBaselineIndex(projectPath);
489
+ const results = prerequisites.map(p => verifyPrerequisite(p, projectPath, index));
365
490
 
366
491
  // 输出
367
492
  if (options.json) {