@dommaker/harness 1.7.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 (549) hide show
  1. package/CHANGELOG.md +37 -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 +1 -0
  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/failure/classifier.d.ts +1 -1
  179. package/dist/failure/classifier.d.ts.map +1 -1
  180. package/dist/failure/classifier.js +8 -8
  181. package/dist/failure/classifier.js.map +1 -1
  182. package/dist/failure/index.d.ts +2 -1
  183. package/dist/failure/index.d.ts.map +1 -1
  184. package/dist/failure/index.js +9 -17
  185. package/dist/failure/index.js.map +1 -1
  186. package/dist/failure/recorder.d.ts +1 -1
  187. package/dist/failure/recorder.d.ts.map +1 -1
  188. package/dist/gates/checker-gate.d.ts +2 -1
  189. package/dist/gates/checker-gate.d.ts.map +1 -1
  190. package/dist/gates/checker-gate.js +3 -2
  191. package/dist/gates/checker-gate.js.map +1 -1
  192. package/dist/gates/command.d.ts +10 -4
  193. package/dist/gates/command.d.ts.map +1 -1
  194. package/dist/gates/command.js +36 -62
  195. package/dist/gates/command.js.map +1 -1
  196. package/dist/gates/contract.d.ts.map +1 -1
  197. package/dist/gates/contract.js +0 -4
  198. package/dist/gates/contract.js.map +1 -1
  199. package/dist/gates/definitions.d.ts +2 -1
  200. package/dist/gates/definitions.d.ts.map +1 -1
  201. package/dist/gates/definitions.js +6 -5
  202. package/dist/gates/definitions.js.map +1 -1
  203. package/dist/gates/index.d.ts +0 -4
  204. package/dist/gates/index.d.ts.map +1 -1
  205. package/dist/gates/index.js +1 -6
  206. package/dist/gates/index.js.map +1 -1
  207. package/dist/gates/performance.d.ts.map +1 -1
  208. package/dist/gates/performance.js +0 -4
  209. package/dist/gates/performance.js.map +1 -1
  210. package/dist/gates/runner.d.ts +1 -1
  211. package/dist/gates/runner.js +1 -1
  212. package/dist/gates/security.d.ts +1 -1
  213. package/dist/gates/security.d.ts.map +1 -1
  214. package/dist/gates/security.js +5 -6
  215. package/dist/gates/security.js.map +1 -1
  216. package/dist/gates/types.d.ts +14 -17
  217. package/dist/gates/types.d.ts.map +1 -1
  218. package/dist/gates/types.js.map +1 -1
  219. package/dist/hooks/bootstrap.d.ts +6 -4
  220. package/dist/hooks/bootstrap.d.ts.map +1 -1
  221. package/dist/hooks/bootstrap.js +25 -13
  222. package/dist/hooks/bootstrap.js.map +1 -1
  223. package/dist/hooks/config.d.ts +6 -2
  224. package/dist/hooks/config.d.ts.map +1 -1
  225. package/dist/hooks/config.js +5 -1
  226. package/dist/hooks/config.js.map +1 -1
  227. package/dist/hooks/index.d.ts +1 -1
  228. package/dist/hooks/index.d.ts.map +1 -1
  229. package/dist/hooks/index.js +0 -15
  230. package/dist/hooks/index.js.map +1 -1
  231. package/dist/hooks/pipeline.d.ts.map +1 -1
  232. package/dist/hooks/pipeline.js +2 -4
  233. package/dist/hooks/pipeline.js.map +1 -1
  234. package/dist/hooks/registry.d.ts +11 -8
  235. package/dist/hooks/registry.d.ts.map +1 -1
  236. package/dist/hooks/registry.js +22 -7
  237. package/dist/hooks/registry.js.map +1 -1
  238. package/dist/hooks/types.d.ts +23 -7
  239. package/dist/hooks/types.d.ts.map +1 -1
  240. package/dist/index.d.ts +3 -3
  241. package/dist/index.d.ts.map +1 -1
  242. package/dist/index.js +3 -4
  243. package/dist/index.js.map +1 -1
  244. package/dist/knowledge/audit-scoring.d.ts +87 -0
  245. package/dist/knowledge/audit-scoring.d.ts.map +1 -0
  246. package/dist/knowledge/audit-scoring.js +470 -0
  247. package/dist/knowledge/audit-scoring.js.map +1 -0
  248. package/dist/knowledge/audit.d.ts +11 -59
  249. package/dist/knowledge/audit.d.ts.map +1 -1
  250. package/dist/knowledge/audit.js +47 -522
  251. package/dist/knowledge/audit.js.map +1 -1
  252. package/dist/knowledge/import.d.ts.map +1 -1
  253. package/dist/knowledge/import.js +2 -0
  254. package/dist/knowledge/import.js.map +1 -1
  255. package/dist/knowledge/index-generator.d.ts.map +1 -1
  256. package/dist/knowledge/index-generator.js +4 -5
  257. package/dist/knowledge/index-generator.js.map +1 -1
  258. package/dist/knowledge/index.d.ts +3 -2
  259. package/dist/knowledge/index.d.ts.map +1 -1
  260. package/dist/knowledge/index.js +3 -16
  261. package/dist/knowledge/index.js.map +1 -1
  262. package/dist/knowledge/ingest.js +1 -1
  263. package/dist/knowledge/ingest.js.map +1 -1
  264. package/dist/knowledge/lifecycle.d.ts.map +1 -1
  265. package/dist/knowledge/lifecycle.js +4 -2
  266. package/dist/knowledge/lifecycle.js.map +1 -1
  267. package/dist/knowledge/migration.d.ts +3 -0
  268. package/dist/knowledge/migration.d.ts.map +1 -1
  269. package/dist/knowledge/migration.js +8 -2
  270. package/dist/knowledge/migration.js.map +1 -1
  271. package/dist/knowledge/query.d.ts +6 -0
  272. package/dist/knowledge/query.d.ts.map +1 -1
  273. package/dist/knowledge/query.js +8 -2
  274. package/dist/knowledge/query.js.map +1 -1
  275. package/dist/knowledge/reference-tracker.d.ts.map +1 -1
  276. package/dist/knowledge/reference-tracker.js +4 -6
  277. package/dist/knowledge/reference-tracker.js.map +1 -1
  278. package/dist/knowledge/store.d.ts +22 -16
  279. package/dist/knowledge/store.d.ts.map +1 -1
  280. package/dist/knowledge/store.js +53 -12
  281. package/dist/knowledge/store.js.map +1 -1
  282. package/dist/knowledge/tree-walker.d.ts +19 -0
  283. package/dist/knowledge/tree-walker.d.ts.map +1 -0
  284. package/dist/knowledge/tree-walker.js +30 -0
  285. package/dist/knowledge/tree-walker.js.map +1 -0
  286. package/dist/knowledge/types.d.ts +16 -0
  287. package/dist/knowledge/types.d.ts.map +1 -1
  288. package/dist/monitoring/traces.d.ts +5 -3
  289. package/dist/monitoring/traces.d.ts.map +1 -1
  290. package/dist/monitoring/traces.js +19 -5
  291. package/dist/monitoring/traces.js.map +1 -1
  292. package/dist/test-setup/jsonl-fake-fs.d.ts +30 -0
  293. package/dist/test-setup/jsonl-fake-fs.d.ts.map +1 -0
  294. package/dist/test-setup/jsonl-fake-fs.js +49 -0
  295. package/dist/test-setup/jsonl-fake-fs.js.map +1 -0
  296. package/dist/tools/index.d.ts +4 -1
  297. package/dist/tools/index.d.ts.map +1 -1
  298. package/dist/tools/index.js +7 -15
  299. package/dist/tools/index.js.map +1 -1
  300. package/dist/types/checkpoint.d.ts +5 -0
  301. package/dist/types/checkpoint.d.ts.map +1 -1
  302. package/dist/types/project-config.d.ts +18 -0
  303. package/dist/types/project-config.d.ts.map +1 -1
  304. package/dist/types/trace.d.ts +13 -4
  305. package/dist/types/trace.d.ts.map +1 -1
  306. package/dist/types/trace.js +4 -3
  307. package/dist/types/trace.js.map +1 -1
  308. package/dist/utils/exec.d.ts +4 -27
  309. package/dist/utils/exec.d.ts.map +1 -1
  310. package/dist/utils/exec.js +4 -94
  311. package/dist/utils/exec.js.map +1 -1
  312. package/dist/utils/jsonl.d.ts +17 -7
  313. package/dist/utils/jsonl.d.ts.map +1 -1
  314. package/dist/utils/jsonl.js +144 -17
  315. package/dist/utils/jsonl.js.map +1 -1
  316. package/dist/utils/numeric-flag.d.ts +44 -0
  317. package/dist/utils/numeric-flag.d.ts.map +1 -0
  318. package/dist/utils/numeric-flag.js +62 -0
  319. package/dist/utils/numeric-flag.js.map +1 -0
  320. package/package.json +1 -1
  321. package/src/CONTEXT.md +5 -2
  322. package/src/__tests__/acceptance-gate.test.ts +7 -4
  323. package/src/__tests__/checker-extra.test.ts +3 -2
  324. package/src/__tests__/checker.test.ts +4 -3
  325. package/src/__tests__/checkpoint.test.ts +26 -9
  326. package/src/__tests__/context-files-resolution.test.ts +29 -15
  327. package/src/__tests__/contract-gate.test.ts +19 -40
  328. package/src/__tests__/error-classifier.test.ts +1 -1
  329. package/src/__tests__/exec.test.ts +45 -107
  330. package/src/__tests__/failure-recorder.test.ts +7 -5
  331. package/src/__tests__/hooks-pipeline.test.ts +34 -47
  332. package/src/__tests__/layering.test.ts +217 -25
  333. package/src/__tests__/passes-gate.test.ts +9 -4
  334. package/src/__tests__/performance-gate.test.ts +3 -15
  335. package/src/__tests__/project-config-loader-extra.test.ts +31 -57
  336. package/src/__tests__/project-config-loader.test.ts +6 -3
  337. package/src/__tests__/public-exports.test.ts +0 -1
  338. package/src/__tests__/public-type-surface.test.ts +5 -4
  339. package/src/__tests__/public-value-surface.test.ts +182 -0
  340. package/src/__tests__/review-gate.test.ts +4 -6
  341. package/src/__tests__/security-gate.test.ts +5 -20
  342. package/src/__tests__/skip-semantics.test.ts +5 -3
  343. package/src/__tests__/spec-validator.test.ts +3 -2
  344. package/src/__tests__/sub-barrels-explicit.test.ts +87 -0
  345. package/src/__tests__/test-fixture-hygiene.test.ts +53 -0
  346. package/src/__tests__/trace-analyzer-extra.test.ts +5 -3
  347. package/src/__tests__/trace-analyzer.test.ts +5 -3
  348. package/src/__tests__/trace-collector.test.ts +5 -3
  349. package/src/agents/index.ts +13 -2
  350. package/src/cli/__tests__/gate-command.test.ts +162 -0
  351. package/src/cli/commands/CONTEXT.md +29 -5
  352. package/src/cli/commands/__tests__/acceptance.test.ts +24 -25
  353. package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +15 -0
  354. package/src/cli/commands/__tests__/check-drift.test.ts +42 -1
  355. package/src/cli/commands/__tests__/check-read-count.test.ts +167 -0
  356. package/src/cli/commands/__tests__/check-skip-output.test.ts +4 -1
  357. package/src/cli/commands/__tests__/check.test.ts +43 -36
  358. package/src/cli/commands/__tests__/command-gate-dead-options.test.ts +60 -0
  359. package/src/cli/commands/__tests__/command.test.ts +33 -17
  360. package/src/cli/commands/__tests__/constraints-retire.test.ts +52 -0
  361. package/src/cli/commands/__tests__/context-syncer.test.ts +141 -0
  362. package/src/cli/commands/__tests__/contract.test.ts +20 -20
  363. package/src/cli/commands/__tests__/failure.test.ts +5 -4
  364. package/src/cli/commands/__tests__/gate-decision.ts +30 -0
  365. package/src/cli/commands/__tests__/init-dead-options.test.ts +50 -0
  366. package/src/cli/commands/__tests__/init-governance-io.test.ts +139 -0
  367. package/src/cli/commands/__tests__/init-injection.test.ts +3 -3
  368. package/src/cli/commands/__tests__/init-ondisk.test.ts +867 -0
  369. package/src/cli/commands/__tests__/init.test.ts +82 -6
  370. package/src/cli/commands/__tests__/knowledge-audit-threshold.test.ts +146 -0
  371. package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +1 -1
  372. package/src/cli/commands/__tests__/knowledge-tone-mapping.test.ts +244 -0
  373. package/src/cli/commands/__tests__/knowledge-view.test.ts +839 -0
  374. package/src/cli/commands/__tests__/knowledge.test.ts +33 -15
  375. package/src/cli/commands/__tests__/numeric-flag-assembly.test.ts +368 -0
  376. package/src/cli/commands/__tests__/performance.test.ts +19 -21
  377. package/src/cli/commands/__tests__/posteval-plan.test.ts +5 -3
  378. package/src/cli/commands/__tests__/pre-push-hook.test.ts +181 -0
  379. package/src/cli/commands/__tests__/project-path-anchoring.test.ts +95 -2
  380. package/src/cli/commands/__tests__/project-path-convention.test.ts +103 -25
  381. package/src/cli/commands/__tests__/registry.test.ts +2 -0
  382. package/src/cli/commands/__tests__/report.test.ts +23 -1
  383. package/src/cli/commands/__tests__/review.test.ts +10 -17
  384. package/src/cli/commands/__tests__/scaffold.test.ts +505 -0
  385. package/src/cli/commands/__tests__/security-default-scan.test.ts +75 -0
  386. package/src/cli/commands/__tests__/security.test.ts +21 -24
  387. package/src/cli/commands/__tests__/spec-baseline-check.test.ts +3 -2
  388. package/src/cli/commands/__tests__/spec-baseline-index-cap.test.ts +131 -0
  389. package/src/cli/commands/__tests__/spec-baseline-read-count.test.ts +325 -0
  390. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +19 -4
  391. package/src/cli/commands/__tests__/sync-docs-context-drift.test.ts +232 -0
  392. package/src/cli/commands/__tests__/sync-docs-module-order.test.ts +111 -0
  393. package/src/cli/commands/__tests__/sync-docs-read-count.test.ts +192 -0
  394. package/src/cli/commands/__tests__/sync-docs.test.ts +3 -2
  395. package/src/cli/commands/__tests__/validate.test.ts +1 -48
  396. package/src/cli/commands/acceptance.ts +24 -29
  397. package/src/cli/commands/check.ts +40 -17
  398. package/src/cli/commands/command.ts +9 -8
  399. package/src/cli/commands/constraints-retire.ts +57 -70
  400. package/src/cli/commands/contract.ts +44 -47
  401. package/src/cli/commands/definitions.ts +12 -6
  402. package/src/cli/commands/failure.ts +16 -3
  403. package/src/cli/commands/init.ts +242 -389
  404. package/src/cli/commands/knowledge-view.ts +224 -0
  405. package/src/cli/commands/knowledge.ts +643 -448
  406. package/src/cli/commands/passes-gate.ts +12 -3
  407. package/src/cli/commands/performance.ts +31 -38
  408. package/src/cli/commands/report.ts +3 -2
  409. package/src/cli/commands/review.ts +22 -28
  410. package/src/cli/commands/scaffold-templates.ts +406 -0
  411. package/src/cli/commands/scaffold.ts +302 -0
  412. package/src/cli/commands/security.ts +27 -23
  413. package/src/cli/commands/spec-baseline-check.ts +158 -33
  414. package/src/cli/commands/sync-docs/__tests__/context-export-surface.test.ts +102 -0
  415. package/src/cli/commands/sync-docs/__tests__/module-descriptions.test.ts +196 -0
  416. package/src/cli/commands/sync-docs/context-syncer.ts +137 -31
  417. package/src/cli/commands/sync-docs/index.ts +103 -28
  418. package/src/cli/commands/sync-docs/project-reader.ts +51 -7
  419. package/src/cli/commands/validate.ts +1 -104
  420. package/src/cli/gate-command.ts +87 -0
  421. package/src/completion-checkers/index.ts +10 -1
  422. package/src/context/CONTEXT.md +2 -1
  423. package/src/context/__tests__/knowledge-injector.test.ts +27 -0
  424. package/src/context/__tests__/session-manager.test.ts +19 -12
  425. package/src/context/knowledge-injector.ts +14 -7
  426. package/src/core/CONTEXT.md +10 -7
  427. package/src/core/__tests__/effective-set.test.ts +36 -60
  428. package/src/core/constraints/__tests__/context-reconcile.test.ts +246 -0
  429. package/src/core/constraints/__tests__/run-env.test.ts +377 -0
  430. package/src/core/constraints/__tests__/triggers.test.ts +70 -0
  431. package/src/core/constraints/agent-prompt-renderer.ts +1 -1
  432. package/src/core/constraints/capabilities-reconcile.ts +28 -4
  433. package/src/core/constraints/check-cache.ts +1 -1
  434. package/src/core/constraints/checker.ts +30 -14
  435. package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +8 -3
  436. package/src/core/constraints/checkers/__tests__/governance-presence.test.ts +16 -7
  437. package/src/core/constraints/checkers/__tests__/no-hardcoded-credentials.test.ts +2 -1
  438. package/src/core/constraints/checkers/capability-sync.ts +27 -28
  439. package/src/core/constraints/checkers/context-doc-sync.ts +9 -7
  440. package/src/core/constraints/checkers/docs-freshness.ts +28 -33
  441. package/src/core/constraints/checkers/governance-presence.ts +10 -6
  442. package/src/core/constraints/checkers/types.ts +14 -8
  443. package/src/core/constraints/context-builder.ts +35 -26
  444. package/src/core/constraints/context-reconcile.ts +200 -0
  445. package/src/core/constraints/doc-freshness/__tests__/runner.test.ts +25 -0
  446. package/src/core/constraints/doc-freshness/runner.ts +18 -4
  447. package/src/core/constraints/git-evidence.ts +1 -1
  448. package/src/core/constraints/injection-drift.ts +19 -8
  449. package/src/core/constraints/run-env.ts +207 -0
  450. package/src/core/constraints/triggers.ts +33 -0
  451. package/src/core/effective-constraints.ts +17 -6
  452. package/src/core/effective-set.ts +8 -24
  453. package/src/core/index.ts +2 -0
  454. package/src/core/project-config-loader.ts +54 -102
  455. package/src/core/validators/__tests__/http-retry-sleep.test.ts +231 -0
  456. package/src/core/validators/check-handlers/http.ts +18 -7
  457. package/src/failure/CONTEXT.md +2 -1
  458. package/src/failure/classifier.ts +2 -2
  459. package/src/failure/index.ts +14 -2
  460. package/src/failure/recorder.ts +1 -1
  461. package/src/gates/CONTEXT.md +13 -7
  462. package/src/gates/__tests__/checker-gate.test.ts +1 -1
  463. package/src/gates/__tests__/command-single-predicate.test.ts +135 -0
  464. package/src/gates/__tests__/command.test.ts +8 -15
  465. package/src/gates/__tests__/contract.test.ts +5 -5
  466. package/src/gates/__tests__/gate-interface.test.ts +0 -17
  467. package/src/gates/__tests__/performance.test.ts +0 -13
  468. package/src/gates/__tests__/review.test.ts +0 -1
  469. package/src/gates/__tests__/runner.test.ts +1 -1
  470. package/src/gates/__tests__/security-default-scan.test.ts +97 -0
  471. package/src/gates/__tests__/security.test.ts +0 -13
  472. package/src/gates/checker-gate.ts +3 -2
  473. package/src/gates/command.ts +51 -74
  474. package/src/gates/contract.ts +0 -5
  475. package/src/gates/definitions.ts +6 -5
  476. package/src/gates/index.ts +0 -5
  477. package/src/gates/performance.ts +1 -6
  478. package/src/gates/runner.ts +1 -1
  479. package/src/gates/security.ts +9 -11
  480. package/src/gates/types.ts +20 -23
  481. package/src/hooks/CONTEXT.md +10 -9
  482. package/src/hooks/__tests__/bootstrap.test.ts +29 -6
  483. package/src/hooks/__tests__/pipeline.test.ts +28 -17
  484. package/src/hooks/__tests__/registry.test.ts +51 -3
  485. package/src/hooks/bootstrap.ts +35 -15
  486. package/src/hooks/config.ts +6 -2
  487. package/src/hooks/index.ts +10 -1
  488. package/src/hooks/pipeline.ts +4 -6
  489. package/src/hooks/registry.ts +31 -12
  490. package/src/hooks/types.ts +24 -7
  491. package/src/index.ts +1 -2
  492. package/src/knowledge/CONTEXT.md +14 -7
  493. package/src/knowledge/__tests__/audit-labels.test.ts +8 -5
  494. package/src/knowledge/__tests__/audit-scoring.test.ts +230 -0
  495. package/src/knowledge/__tests__/audit-write-count.test.ts +131 -0
  496. package/src/knowledge/__tests__/audit.test.ts +291 -208
  497. package/src/knowledge/__tests__/doctor.test.ts +3 -2
  498. package/src/knowledge/__tests__/ingest.test.ts +3 -2
  499. package/src/knowledge/__tests__/lifecycle.test.ts +57 -2
  500. package/src/knowledge/__tests__/migration.test.ts +35 -6
  501. package/src/knowledge/__tests__/query.test.ts +3 -2
  502. package/src/knowledge/__tests__/reference-tracker.test.ts +23 -2
  503. package/src/knowledge/__tests__/store.test.ts +149 -4
  504. package/src/knowledge/__tests__/tree-walker.test.ts +132 -0
  505. package/src/knowledge/audit-scoring.ts +589 -0
  506. package/src/knowledge/audit.ts +55 -599
  507. package/src/knowledge/import.ts +2 -0
  508. package/src/knowledge/index-generator.ts +4 -6
  509. package/src/knowledge/index.ts +27 -2
  510. package/src/knowledge/ingest.ts +1 -1
  511. package/src/knowledge/lifecycle.ts +5 -2
  512. package/src/knowledge/migration.ts +8 -2
  513. package/src/knowledge/query.ts +8 -1
  514. package/src/knowledge/reference-tracker.ts +5 -7
  515. package/src/knowledge/store.ts +75 -16
  516. package/src/knowledge/tree-walker.ts +29 -0
  517. package/src/knowledge/types.ts +19 -0
  518. package/src/monitoring/CONTEXT.md +5 -2
  519. package/src/monitoring/__tests__/context-tracker.test.ts +16 -8
  520. package/src/monitoring/__tests__/trace-file-anchoring.test.ts +80 -0
  521. package/src/monitoring/traces.ts +19 -5
  522. package/src/release/CONTEXT.md +1 -1
  523. package/src/release/__tests__/integrity.test.ts +21 -12
  524. package/src/test-setup/__tests__/jsonl-fake-fs.test.ts +98 -0
  525. package/src/test-setup/jsonl-fake-fs.ts +59 -0
  526. package/src/tools/index.ts +5 -1
  527. package/src/types/checkpoint.ts +6 -0
  528. package/src/types/project-config.ts +21 -0
  529. package/src/types/trace.ts +14 -4
  530. package/src/utils/__tests__/file-walk.test.ts +3 -2
  531. package/src/utils/__tests__/jsonl-bounded-read.test.ts +106 -0
  532. package/src/utils/__tests__/jsonl-skip-disposition.test.ts +10 -6
  533. package/src/utils/__tests__/jsonl.test.ts +61 -14
  534. package/src/utils/__tests__/numeric-flag.test.ts +80 -0
  535. package/src/utils/__tests__/package-version.test.ts +2 -2
  536. package/src/utils/exec.ts +4 -64
  537. package/src/utils/jsonl.ts +159 -20
  538. package/src/utils/numeric-flag.ts +64 -0
  539. package/dist/failure/types.d.ts +0 -9
  540. package/dist/failure/types.d.ts.map +0 -1
  541. package/dist/failure/types.js +0 -25
  542. package/dist/failure/types.js.map +0 -1
  543. package/dist/gates/effective-gates.d.ts +0 -30
  544. package/dist/gates/effective-gates.d.ts.map +0 -1
  545. package/dist/gates/effective-gates.js +0 -81
  546. package/dist/gates/effective-gates.js.map +0 -1
  547. package/src/failure/types.ts +0 -9
  548. package/src/gates/__tests__/effective-gates.test.ts +0 -77
  549. package/src/gates/effective-gates.ts +0 -99
@@ -8,11 +8,11 @@ import chalk from 'chalk';
8
8
  import * as fs from 'fs/promises';
9
9
  import * as path from 'path';
10
10
  import * as yaml from 'js-yaml';
11
- import { createExampleCheckpoint, createExampleResolutions } from './validate';
12
11
  import { detectSourceRoots } from '../../utils/detect-source-roots';
13
12
  import { getHarnessPackageVersion } from '../../utils/package-version';
14
13
  import { getEffectiveConstraints } from '../../core/effective-constraints';
15
- import type { GovernanceConfig } from '../../types/project-config';
14
+ import { loadRawProjectConfig } from '../../core/project-config-loader';
15
+ import type { CiConfig, CiPlatform, GovernanceConfig } from '../../types/project-config';
16
16
  import {
17
17
  CONSTRAINTS_START_MARKER,
18
18
  CONSTRAINTS_END_MARKER,
@@ -25,25 +25,111 @@ import {
25
25
  resolveGovernanceLanding,
26
26
  GOVERNANCE_HEADING,
27
27
  } from '../../core/constraints/injection-writer';
28
- import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
28
+ import { log, logError, processIO, type CommandIO, type CommandResult } from '../command-contract';
29
+ import {
30
+ runPlan,
31
+ nodeScaffoldFs,
32
+ preCommitHookFile,
33
+ prePushHookFile,
34
+ harnessCheckCiFile,
35
+ customConstraintsFile,
36
+ changelogFile,
37
+ contextDocFile,
38
+ governanceWorkflowFile,
39
+ checkpointsFile,
40
+ resolutionsFile,
41
+ type ManagedFile,
42
+ } from './scaffold';
43
+ import {
44
+ GITHUB_ACTIONS_SNIPPET,
45
+ renderGitLabCiJobs,
46
+ PRE_COMMIT_SNIPPET,
47
+ PRE_PUSH_SNIPPET,
48
+ } from './scaffold-templates';
29
49
 
30
50
  export interface InitOptions {
31
51
  /** 项目路径 */
32
52
  projectPath?: string;
33
53
  /** 预设名称 */
34
54
  preset: 'strict' | 'standard' | 'relaxed';
35
- /** 治理级别 */
55
+ /** 治理级别(值域 = `GOVERNANCE_PRESETS` 键集合,非法值在命令入口判 usage-error、零落盘,harness#156) */
36
56
  governance?: 'minimal' | 'standard' | 'strict';
37
- /** 项目类型 */
38
- type?: 'node-api' | 'nextjs-app' | 'python-api' | 'custom';
39
57
  /** 是否创建 Git hooks */
40
58
  gitHooks?: boolean;
41
- /** 是否创建 GitHub Actions */
59
+ /** 是否创建 GitHub Actions(`--no-github-actions`:已废弃,`--ci none` 的别名) */
42
60
  githubActions?: boolean;
61
+ /**
62
+ * 服务端 CI 接线平台(`--ci`,harness#143)
63
+ *
64
+ * 值域校验在命令层(bin 把用户敲的字符串原样递进来);缺省时回落 config.yml
65
+ * 的 `ci.platform`,再缺省即 `github`。
66
+ */
67
+ ci?: CiPlatform | 'none';
43
68
  /** 只输出代码片段,不创建文件 */
44
69
  printSnippets?: boolean;
45
70
  }
46
71
 
72
+ /** `--ci` 的可取值域(`none` = 不创建任何服务端 CI 文件,治理 CI 面亦不建,即旧 `--no-github-actions`) */
73
+ const CI_FLAG_VALUES: Array<CiPlatform | 'none'> = ['github', 'gitlab', 'none'];
74
+
75
+ /** CI 平台解析结果(`error` 属用法错误,命令层直接非零退出,不落任何文件) */
76
+ type CiResolution =
77
+ | { kind: 'ok'; platform: CiPlatform | 'none'; warning?: string }
78
+ | { kind: 'error'; reason: string };
79
+
80
+ /**
81
+ * 解析 CI 平台(harness#143 决议 ①④):flag > config.yml 的 `ci.platform` > `github`
82
+ *
83
+ * 不做 remote URL 自动检测:init 常跑在首次 push 之前无 remote 可测,而检测错的代价是
84
+ * 静默写错文件。`--no-github-actions` 保留为 `--ci none` 的废弃别名;它与显式
85
+ * `--ci <非 none>` 同时出现时不猜用户意图,判用法错误。
86
+ */
87
+ function resolveCiPlatform(
88
+ options: InitOptions,
89
+ configured: CiPlatform | 'none' | undefined,
90
+ ): CiResolution {
91
+ const flag = options.ci;
92
+ if (flag !== undefined && !CI_FLAG_VALUES.includes(flag)) {
93
+ return {
94
+ kind: 'error',
95
+ reason: `--ci 取值非法: ${String(flag)}(可取 ${CI_FLAG_VALUES.join(' | ')})`,
96
+ };
97
+ }
98
+ if (options.githubActions === false) {
99
+ if (flag !== undefined && flag !== 'none') {
100
+ return {
101
+ kind: 'error',
102
+ reason: `--ci ${flag} 与 --no-github-actions(即 --ci none 的废弃别名)冲突,二选一`,
103
+ };
104
+ }
105
+ return {
106
+ kind: 'ok',
107
+ platform: 'none',
108
+ warning: '⚠️ --no-github-actions 已废弃,请改用 --ci none',
109
+ };
110
+ }
111
+ return { kind: 'ok', platform: flag ?? configured ?? 'github' };
112
+ }
113
+
114
+ /**
115
+ * 读 config.yml 已持久化的 `ci.platform`(解析链第二级)
116
+ *
117
+ * 缺失 / 解析失败 / 形状不符一律按未配置处理(与 `getGovernanceConfig` 同一口径:
118
+ * 脏配置不替调用方做决定)。
119
+ */
120
+ function readConfiguredCiPlatform(projectPath: string): CiPlatform | 'none' | undefined {
121
+ let raw: Record<string, unknown> | undefined;
122
+ try {
123
+ raw = loadRawProjectConfig(projectPath);
124
+ } catch {
125
+ return undefined;
126
+ }
127
+ const ci = raw?.ci;
128
+ if (ci === null || typeof ci !== 'object') return undefined;
129
+ const platform = (ci as CiConfig).platform;
130
+ return platform !== undefined && CI_FLAG_VALUES.includes(platform) ? platform : undefined;
131
+ }
132
+
47
133
  /**
48
134
  * 默认配置
49
135
  *
@@ -145,15 +231,35 @@ const GOVERNANCE_PRESETS: Record<string, GovernanceConfig> = {
145
231
  * 初始化项目
146
232
  */
147
233
  export async function init(options: InitOptions, io: CommandIO = processIO): Promise<CommandResult> {
234
+ const projectPath = options.projectPath || process.cwd();
235
+
236
+ // CI 平台先解析:用法错误不落任何盘,且 `--print-snippets` 也要按解析出的平台出形
237
+ const ci = resolveCiPlatform(options, readConfiguredCiPlatform(projectPath));
238
+ if (ci.kind === 'error') {
239
+ logError(io, chalk.red(`❌ 用法错误: ${ci.reason}`));
240
+ return { kind: 'usage-error', reason: ci.reason };
241
+ }
242
+ if (ci.warning) log(io, chalk.yellow(ci.warning));
243
+
244
+ // `-g` 值域校验在命令入口(harness#156 裁决 F2,与 #152 脏输入 fail-loud 同判据):
245
+ // 非法值 usage-error、先于任何落盘;合法值域与装配共用同一份 GOVERNANCE_PRESETS 表,
246
+ // github / gitlab / none 三平台同判(bin 把用户敲的字符串原样递进来)。
247
+ // 用 Object.hasOwn 而非 `in`(harness#164):`in` 走原型链,`-g constructor`/`toString`
248
+ // 会穿透校验、把 Object 构造函数写进 configData 并在 yaml.dump 炸成 YAMLException。
249
+ if (options.governance !== undefined && !Object.hasOwn(GOVERNANCE_PRESETS, options.governance)) {
250
+ const reason = `-g/--governance 取值非法: ${String(options.governance)}(可取 ${Object.keys(GOVERNANCE_PRESETS).join(' | ')})`;
251
+ logError(io, chalk.red(`❌ 用法错误: ${reason}`));
252
+ return { kind: 'usage-error', reason };
253
+ }
254
+
148
255
  // 只输出代码片段
149
256
  if (options.printSnippets) {
150
- printSnippets(io);
257
+ printSnippets(io, ci.platform, options.governance);
151
258
  return { kind: 'ok' };
152
259
  }
153
260
 
154
261
  log(io, chalk.blue('🚀 初始化 harness 配置...'));
155
262
 
156
- const projectPath = options.projectPath || process.cwd();
157
263
  const configDir = path.join(projectPath, '.harness');
158
264
 
159
265
  // 创建配置目录
@@ -171,6 +277,13 @@ export async function init(options: InitOptions, io: CommandIO = processIO): Pro
171
277
  log(io, chalk.gray(`治理级别: ${options.governance}`));
172
278
  }
173
279
 
280
+ // 非默认平台才持久化:缺省即 github(旧配置零迁移),裸 init 重写 config.yml 时
281
+ // 也因此不会丢掉已选定的平台
282
+ if (ci.platform !== 'github') {
283
+ configData.ci = { platform: ci.platform };
284
+ log(io, chalk.gray(`CI 平台: ${ci.platform}`));
285
+ }
286
+
174
287
  // 写入 harness 版本
175
288
  const pkgVersion = getHarnessPackageVersion();
176
289
  configData.harness = { version: pkgVersion };
@@ -181,14 +294,11 @@ export async function init(options: InitOptions, io: CommandIO = processIO): Pro
181
294
  await fs.writeFile(configPath, configContent, 'utf-8');
182
295
  log(io, chalk.green(`✅ 已创建配置文件: ${configPath} (v${pkgVersion})`));
183
296
 
184
- // 创建检查点示例
185
- await createExampleCheckpoint(projectPath, io);
186
-
187
- // 创建 Resolutions(RKB 狗粮 — 约束 → 已知解法映射)
188
- await createExampleResolutions(projectPath, io);
189
-
190
- // 创建自定义约束示例
191
- await createCustomConstraintsExample(projectPath, io);
297
+ // 受管示例文件:检查点 / Resolutions(RKB 狗粮)/ 自定义约束
298
+ await runPlan(
299
+ [checkpointsFile(projectPath), resolutionsFile(projectPath), customConstraintsFile(projectPath)],
300
+ io,
301
+ );
192
302
 
193
303
  // CAPABILITIES.md / CHANGELOG.md 由 sync-docs(AI 治理)管理,init 不创建
194
304
 
@@ -197,14 +307,14 @@ export async function init(options: InitOptions, io: CommandIO = processIO): Pro
197
307
  await setupGitHooks(projectPath, io);
198
308
  }
199
309
 
200
- // 创建 GitHub Actions
201
- if (options.githubActions !== false) {
202
- await setupGitHubActions(projectPath, io);
310
+ // 服务端 CI 门禁接线(平台维度):`none` = CI 站点干脆不进 plan
311
+ if (ci.platform !== 'none') {
312
+ await setupCiWiring(projectPath, ci.platform, options.governance, io);
203
313
  }
204
314
 
205
315
  // 治理相关文件生成
206
316
  if (options.governance) {
207
- await setupGovernance(projectPath, options.governance, io);
317
+ await setupGovernance(projectPath, options.governance, io, ci.platform);
208
318
  }
209
319
 
210
320
  log(io);
@@ -213,7 +323,7 @@ export async function init(options: InitOptions, io: CommandIO = processIO): Pro
213
323
  log(io, chalk.gray('下一步:'));
214
324
  log(io, chalk.gray(' 1. 编辑 .harness/config.yml 自定义配置'));
215
325
  log(io, chalk.gray(' 2. 编辑 .harness/custom-constraints.yml 添加项目约束'));
216
- log(io, chalk.gray(' 3. 正常开发,每次 git commit 会自动检查约束'));
326
+ log(io, chalk.gray(' 3. 正常开发:每次 git commit 查暂存的(增量快反馈),每次 git push 查整仓的(全量兜底)——重复是设计使然'));
217
327
  log(io, chalk.gray(' 4. 运行 harness status 查看状态'));
218
328
  log(io);
219
329
  log(io, chalk.blue('💡 提示: 使用 harness init --print-snippets 查看配置代码片段'));
@@ -221,169 +331,81 @@ export async function init(options: InitOptions, io: CommandIO = processIO): Pro
221
331
  }
222
332
 
223
333
  /**
224
- * 输出代码片段
334
+ * 输出代码片段(CI 片段按解析出的平台出形,harness#143)
335
+ *
336
+ * gitlab 形打 `renderGitLabCiJobs(governanceLevel)`——与落盘 / 冲突分支同一个函数
337
+ * 的正本(harness#157:曾打无 level 的 GITLAB_CI_SNIPPET,`-g` 档照抄的用户少拿
338
+ * 治理与 docs 新鲜度两个任务)。
225
339
  */
226
- function printSnippets(io: CommandIO): void {
340
+ function printSnippets(
341
+ io: CommandIO,
342
+ platform: CiPlatform | 'none',
343
+ governanceLevel: string | undefined,
344
+ ): void {
227
345
  log(io, chalk.blue('📄 Harness 配置代码片段'));
228
346
  log(io);
229
-
347
+
230
348
  log(io, chalk.yellow('Git pre-commit hook:'));
231
349
  log(io, chalk.gray('添加到 .git/hooks/pre-commit'));
232
350
  log(io);
233
351
  log(io, chalk.cyan(PRE_COMMIT_SNIPPET));
234
-
235
- log(io, chalk.yellow('GitHub Actions:'));
236
- log(io, chalk.gray('添加到 .github/workflows/*.yml 的 jobs 中'));
237
- log(io);
238
- log(io, chalk.cyan(GITHUB_ACTIONS_SNIPPET));
239
-
240
- log(io, chalk.blue('💡 提示: 运行 npx @dommaker/harness init 自动创建配置文件'));
241
- }
242
352
 
243
- /**
244
- * Git pre-commit 代码片段(#103:打印片段与落盘 hook 的唯一正本;
245
- * 落盘 hook = `#!/bin/sh` 头 + 本常量,改钩子只改这里)
246
- */
247
- const PRE_COMMIT_SNIPPET = `
248
- echo "🔍 Running harness checks..."
249
-
250
- STAGED=$(git diff --cached --name-only --diff-filter=ACMR 2>/dev/null || true)
251
-
252
- # Harness 约束检查
253
- npx @dommaker/harness check --staged
254
- if [ $? -ne 0 ]; then
255
- echo "❌ Iron law check failed"
256
- exit 1
257
- fi
258
-
259
- # Plan coverage check (via PostEval)
260
- if command -v npx > /dev/null 2>&1; then
261
- PLAN_FILES=$(echo "$STAGED" | grep -E 'plans/.*\\.md$|\\.plan\\.md$' || true)
262
- if [ -n "$PLAN_FILES" ]; then
263
- echo "📋 Checking plan coverage..."
264
- for plan in $PLAN_FILES; do
265
- npx @dommaker/harness posteval-plan "$plan" || {
266
- echo "🛑 Plan coverage incomplete. See above for missed items."
267
- exit 1
268
- }
269
- done
270
- fi
271
- fi
353
+ log(io, chalk.yellow('Git pre-push hook:'));
354
+ log(io, chalk.gray('添加到 .git/hooks/pre-push(pre-commit 查暂存的、快反馈,这道查整仓的、全量兜底——重复是设计使然)'));
355
+ log(io);
356
+ log(io, chalk.cyan(PRE_PUSH_SNIPPET));
272
357
 
273
- echo "✅ All checks passed"
274
- `;
358
+ if (platform === 'gitlab') {
359
+ log(io, chalk.yellow('GitLab CI:'));
360
+ log(io, chalk.gray('添加到 .gitlab-ci.yml'));
361
+ log(io);
362
+ log(io, chalk.cyan(renderGitLabCiJobs(governanceLevel)));
363
+ } else {
364
+ log(io, chalk.yellow('GitHub Actions:'));
365
+ log(io, chalk.gray('添加到 .github/workflows/*.yml 的 jobs 下(以下正文取自 harness-check.yml 的 job 段)'));
366
+ log(io);
367
+ log(io, chalk.cyan(GITHUB_ACTIONS_SNIPPET));
368
+ }
275
369
 
276
- /**
277
- * GitHub Actions 代码片段
278
- */
279
- const GITHUB_ACTIONS_SNIPPET = `
280
- harness-check:
281
- runs-on: ubuntu-latest
282
- steps:
283
- - uses: actions/checkout@v4
284
- - uses: actions/setup-node@v4
285
- with:
286
- node-version: '20'
287
- - run: npm ci
288
- - run: npx @dommaker/harness check
289
- `;
370
+ log(io, chalk.blue('💡 提示: 运行 npx @dommaker/harness init 自动创建配置文件'));
371
+ }
290
372
 
291
373
  /**
292
- * 设置 Git hooks
374
+ * 设置 Git hooks(无 .git 即整站跳过;落盘语义在 scaffold plan)
375
+ *
376
+ * 两道:pre-commit 查暂存的(增量、快反馈),pre-push 查整仓的(全量、兜底,
377
+ * harness#144)。跳过旗帜 `--no-git-hooks` 在命令层翻成「本站点不进 plan」。
293
378
  */
294
379
  async function setupGitHooks(projectPath: string, io: CommandIO): Promise<void> {
295
- const gitDir = path.join(projectPath, '.git');
296
- const hooksDir = path.join(gitDir, 'hooks');
297
- const preCommitPath = path.join(hooksDir, 'pre-commit');
298
-
299
- try {
300
- await fs.access(gitDir);
301
- } catch {
380
+ if (!(await nodeScaffoldFs.exists(path.join(projectPath, '.git')))) {
302
381
  log(io, chalk.yellow('⚠️ 未检测到 Git 仓库,跳过 Git hooks'));
303
382
  log(io, chalk.gray('💡 初始化 Git 后可运行 npx @dommaker/harness init --print-snippets 查看配置'));
304
383
  return;
305
384
  }
306
-
307
- await fs.mkdir(hooksDir, { recursive: true });
308
-
309
- // 检查 pre-commit 是否已存在
310
- try {
311
- await fs.access(preCommitPath);
312
- // 已存在,输出代码片段
313
- log(io, chalk.yellow('⚠️ .git/hooks/pre-commit 已存在'));
314
- log(io, chalk.gray('💡 请手动添加以下内容到文件末尾:'));
315
- log(io);
316
- log(io, chalk.cyan(PRE_COMMIT_SNIPPET));
317
- } catch {
318
- // 不存在,创建文件:shebang 头 + 共享片段(#103 同源,无第二份文本)
319
- const preCommitContent = `#!/bin/sh
320
- # Harness pre-commit hook
321
- ${PRE_COMMIT_SNIPPET}`;
322
- await fs.writeFile(preCommitPath, preCommitContent, 'utf-8');
323
- await fs.chmod(preCommitPath, 0o755);
324
- log(io, chalk.green(`✅ 已创建 .git/hooks/pre-commit`));
325
- }
385
+ await runPlan([preCommitHookFile(projectPath), prePushHookFile(projectPath)], io);
326
386
  }
327
387
 
328
388
  /**
329
- * 设置 GitHub Actions
389
+ * 设置服务端 CI 接线(站点形状与冲突面由 scaffold 按平台给)
390
+ *
391
+ * gitlab 只有一个 `.gitlab-ci.yml`,治理任务已在正文里(`governanceLevel` 传给工厂);
392
+ * github 的冲突判定宽到整个 workflows 目录,需先扫一遍。
330
393
  */
331
- async function setupGitHubActions(projectPath: string, io: CommandIO): Promise<void> {
332
- const workflowsDir = path.join(projectPath, '.github', 'workflows');
333
- const workflowPath = path.join(workflowsDir, 'harness-check.yml');
334
-
335
- // 检查是否已有 CI 配置
336
- const existingFiles = await findCiWorkflows(workflowsDir);
337
-
338
- if (existingFiles.length > 0) {
339
- // 已有 CI 配置,输出代码片段
340
- log(io, chalk.yellow('⚠️ 检测到已存在的 CI 配置:'));
341
- existingFiles.forEach(f => {
342
- log(io, chalk.gray(` - .github/workflows/${f}`));
343
- });
344
- log(io, chalk.gray('💡 请手动添加以下内容到 jobs 中:'));
345
- log(io);
346
- log(io, chalk.cyan(GITHUB_ACTIONS_SNIPPET));
394
+ async function setupCiWiring(
395
+ projectPath: string,
396
+ platform: CiPlatform,
397
+ governanceLevel: string | undefined,
398
+ io: CommandIO,
399
+ ): Promise<void> {
400
+ if (platform === 'gitlab') {
401
+ await runPlan([harnessCheckCiFile(projectPath, 'gitlab', [], governanceLevel)], io);
347
402
  return;
348
403
  }
349
-
350
- // 没有现有 CI 配置,创建文件
351
- await fs.mkdir(workflowsDir, { recursive: true });
352
- const workflowContent = `name: Harness Check
353
-
354
- on:
355
- push:
356
- branches: [main, master]
357
- pull_request:
358
- branches: [main, master]
359
-
360
- jobs:
361
- harness-check:
362
- runs-on: ubuntu-latest
363
-
364
- steps:
365
- - uses: actions/checkout@v4
366
-
367
- - name: Setup Node.js
368
- uses: actions/setup-node@v4
369
- with:
370
- node-version: '20'
371
-
372
- - name: Install dependencies
373
- run: npm ci
374
-
375
- - name: Run harness check
376
- run: npx @dommaker/harness check
377
-
378
- - name: Run harness validate
379
- run: npx @dommaker/harness validate
380
-
381
- - name: Run harness passes-gate
382
- run: npx @dommaker/harness passes-gate
383
- `;
384
-
385
- await fs.writeFile(workflowPath, workflowContent, 'utf-8');
386
- log(io, chalk.green(`✅ 已创建 .github/workflows/harness-check.yml`));
404
+ const workflowsDir = path.join(projectPath, '.github', 'workflows');
405
+ await runPlan(
406
+ [harnessCheckCiFile(projectPath, 'github', await findCiWorkflows(workflowsDir))],
407
+ io,
408
+ );
387
409
  }
388
410
 
389
411
  /**
@@ -402,61 +424,6 @@ async function findCiWorkflows(workflowsDir: string): Promise<string[]> {
402
424
  }
403
425
  }
404
426
 
405
- /**
406
- * 创建自定义约束示例
407
- */
408
- async function createCustomConstraintsExample(projectPath: string, io: CommandIO): Promise<void> {
409
- const configDir = path.join(projectPath, '.harness');
410
- const customConstraintsPath = path.join(configDir, 'custom-constraints.yml');
411
-
412
- // 如果已存在,不覆盖
413
- try {
414
- await fs.access(customConstraintsPath);
415
- log(io, chalk.gray(`custom-constraints.yml 已存在`));
416
- return;
417
- } catch {
418
- // 文件不存在,创建
419
- }
420
-
421
- const content = `# 自定义约束配置
422
- #
423
- # 此文件定义项目特定的约束,扩展或覆盖 harness 内置约束
424
-
425
- # ========================================
426
- # 自定义约束示例
427
- # ========================================
428
-
429
- custom_constraints:
430
- # 示例 1:禁止 console.log
431
- # my_project_no_console_log:
432
- # id: my_project_no_console_log
433
- # level: guideline
434
- # rule: "NO CONSOLE.LOG IN PRODUCTION CODE"
435
- # message: "生产代码禁止使用 console.log,请使用 logger 模块"
436
- # trigger: ["code_implementation"]
437
- # description: "使用项目统一的 logger 模块代替 console.log"
438
-
439
- # 示例 2:禁止特定的导入
440
- # my_project_no_moment_js:
441
- # id: my_project_no_moment_js
442
- # level: guideline
443
- # rule: "NO MOMENT.JS IMPORTS"
444
- # message: "禁止使用 moment.js,请使用 date-fns 或 dayjs"
445
- # trigger: ["code_implementation"]
446
-
447
- # 示例 3:要求特定的文件命名
448
- # my_project_component_naming:
449
- # id: my_project_component_naming
450
- # level: tip
451
- # rule: "REACT COMPONENTS SHOULD BE PASCAL CASE"
452
- # message: "React 组件文件名应使用 PascalCase"
453
- # trigger: ["file_creation"]
454
- `;
455
-
456
- await fs.writeFile(customConstraintsPath, content, 'utf-8');
457
- log(io, chalk.green(`✅ 已创建自定义约束示例: custom-constraints.yml`));
458
- }
459
-
460
427
  /**
461
428
  * Output Style 段标记(ADR-0001:init 只写标记区间内,标记外只读)
462
429
  */
@@ -490,7 +457,7 @@ function renderOutputStyleSection(): string {
490
457
  * - 无标记且 `## Output Style` 段为用户自写(特征串不匹配):跳过并提示,不重复追加
491
458
  * - 完全没有该段:在文件顶部插入标记版
492
459
  */
493
- export async function setupClaudeMdOutputStyle(projectPath: string, io: CommandIO = processIO): Promise<void> {
460
+ export async function setupClaudeMdOutputStyle(projectPath: string, io: CommandIO): Promise<void> {
494
461
  const claudeMdPath = path.join(projectPath, 'CLAUDE.md');
495
462
  let content: string;
496
463
  try {
@@ -563,7 +530,7 @@ const GOVERNANCE_PRESERVE_END = '<!-- /PRESERVE:governance -->';
563
530
  * - 无该段:在文件末尾追加
564
531
  * - 段标记残缺(外层或段内 HARNESS_CONSTRAINTS 单边/乱序):不写入,告警交由人工修复(防二次损坏)
565
532
  */
566
- export async function setupAgentsMdConstraints(projectPath: string, io: CommandIO = processIO): Promise<void> {
533
+ export async function setupAgentsMdConstraints(projectPath: string, io: CommandIO): Promise<void> {
567
534
  const agentsMdPath = path.join(projectPath, 'AGENTS.md');
568
535
  const version = getHarnessPackageVersion();
569
536
 
@@ -640,7 +607,7 @@ export async function setupAgentsMdConstraints(projectPath: string, io: CommandI
640
607
  * - 如果存在 HARNESS_CONSTRAINTS_START/END 标记,替换标记间内容
641
608
  * - 如果不存在标记,在文件末尾追加约束段
642
609
  */
643
- export async function setupClaudeMdConstraints(projectPath: string, io: CommandIO = processIO): Promise<void> {
610
+ export async function setupClaudeMdConstraints(projectPath: string, io: CommandIO): Promise<void> {
644
611
  const claudeMdPath = path.join(projectPath, 'CLAUDE.md');
645
612
 
646
613
  const version = getHarnessPackageVersion();
@@ -691,17 +658,22 @@ export async function setupClaudeMdConstraints(projectPath: string, io: CommandI
691
658
  * 继续写 CLAUDE.md——init 幂等重跑不破坏既有仓,不制造双份约束正本
692
659
  * - 其余(新仓初始化):写 AGENTS.md PRESERVE:governance 段(入库公共面正本)
693
660
  */
694
- export async function setupGovernanceConstraints(projectPath: string): Promise<void> {
661
+ export async function setupGovernanceConstraints(projectPath: string, io: CommandIO): Promise<void> {
695
662
  const { target } = resolveGovernanceLanding(projectPath);
696
663
  return target === 'claude-md'
697
- ? setupClaudeMdConstraints(projectPath)
698
- : setupAgentsMdConstraints(projectPath);
664
+ ? setupClaudeMdConstraints(projectPath, io)
665
+ : setupAgentsMdConstraints(projectPath, io);
699
666
  }
700
667
 
701
668
  /**
702
669
  * 设置治理相关文件
703
670
  */
704
- async function setupGovernance(projectPath: string, level: string, io: CommandIO): Promise<void> {
671
+ async function setupGovernance(
672
+ projectPath: string,
673
+ level: string,
674
+ io: CommandIO,
675
+ platform: CiPlatform | 'none',
676
+ ): Promise<void> {
705
677
  const governance = GOVERNANCE_PRESETS[level];
706
678
  if (!governance) return;
707
679
 
@@ -709,129 +681,48 @@ async function setupGovernance(projectPath: string, level: string, io: CommandIO
709
681
  log(io, chalk.blue('📋 设置治理文件...'));
710
682
 
711
683
  // 1. 生成 CHANGELOG.md
712
- await createChangelog(projectPath, governance, io);
684
+ await runPlan([changelogFile(projectPath, governance.changelog?.format || 'keep-a-changelog')], io);
713
685
 
714
686
  // 2. 在 CLAUDE.md 中写入 Output Style 段(仅在不存在时创建)
715
- await setupClaudeMdOutputStyle(projectPath);
687
+ await setupClaudeMdOutputStyle(projectPath, io);
716
688
 
717
689
  // 3. 写入/更新 Governance Rules 约束段(新仓 → AGENTS.md PRESERVE:governance;
718
690
  // 旧模型仓 → CLAUDE.md,落点路由见 setupGovernanceConstraints)
719
- await setupGovernanceConstraints(projectPath);
691
+ await setupGovernanceConstraints(projectPath, io);
720
692
 
721
693
  // 4. 生成 CONTEXT.md 文件(预设形状即 GovernanceConfig,无需再 cast)
722
- const contextConfig = governance.context_files;
723
- if (contextConfig?.enabled) {
724
- let requiredDirs = contextConfig.required_dirs ?? [];
725
- if (requiredDirs.length === 0) {
726
- requiredDirs = detectSourceRoots(projectPath);
727
- }
728
- for (const dir of requiredDirs) {
729
- await createContextMd(projectPath, dir, io);
730
- }
731
- }
732
-
733
- // 4. 生成治理 CI workflow
734
- await setupGovernanceWorkflow(projectPath, level, io);
735
- }
736
-
737
- /**
738
- * 创建 CHANGELOG.md
739
- */
740
- async function createChangelog(projectPath: string, governance: GovernanceConfig, io: CommandIO): Promise<void> {
741
- const changelogPath = path.join(projectPath, 'CHANGELOG.md');
742
-
743
- try {
744
- await fs.access(changelogPath);
745
- log(io, chalk.gray(`CHANGELOG.md 已存在`));
746
- return;
747
- } catch {
748
- // 文件不存在,创建
749
- }
750
-
751
- const format = governance.changelog?.format || 'keep-a-changelog';
752
-
753
- let content: string;
754
- if (format === 'keep-a-changelog') {
755
- content = `# Changelog
756
-
757
- All notable changes to this project will be documented in this file.
758
-
759
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
760
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
761
-
762
- ## [Unreleased]
763
-
764
- ### Added
765
- - Initial project setup with harness governance
694
+ await runPlan(await contextDocPlan(projectPath, governance, io), io);
766
695
 
767
- ---
768
-
769
- > 此文件可由 \`harness sync-docs\` 辅助维护
770
- `;
771
- } else {
772
- content = `# Changelog
773
-
774
- ## [Unreleased]
775
-
776
- - Initial project setup with harness governance
777
-
778
- ---
779
-
780
- > 此文件可由 \`harness sync-docs\` 辅助维护
781
- `;
782
- }
783
-
784
- await fs.writeFile(changelogPath, content, 'utf-8');
785
- log(io, chalk.green(`✅ 已创建 CHANGELOG.md`));
696
+ // 5. 生成治理 CI 面(仅 github 形;gitlab 已并入 .gitlab-ci.yml 正文,none 不建,harness#156)
697
+ await setupGovernanceWorkflow(projectPath, level, io, platform);
786
698
  }
787
699
 
788
700
  /**
789
- * 在指定目录创建 CONTEXT.md
701
+ * 目录 CONTEXT.md 骨架的 plan:required_dirs 缺省时按源码根探测,
702
+ * 探测出来的目录不在场就不进 plan(告知由本函数负责)
790
703
  */
791
- async function createContextMd(projectPath: string, dir: string, io: CommandIO): Promise<void> {
792
- const contextPath = path.join(projectPath, dir, 'CONTEXT.md');
704
+ async function contextDocPlan(
705
+ projectPath: string,
706
+ governance: GovernanceConfig,
707
+ io: CommandIO,
708
+ ): Promise<ManagedFile[]> {
709
+ const contextConfig = governance.context_files;
710
+ if (!contextConfig?.enabled) return [];
793
711
 
794
- try {
795
- await fs.access(contextPath);
796
- log(io, chalk.gray(`${dir}/CONTEXT.md 已存在`));
797
- return;
798
- } catch {
799
- // 文件不存在,创建
712
+ let requiredDirs = contextConfig.required_dirs ?? [];
713
+ if (requiredDirs.length === 0) {
714
+ requiredDirs = detectSourceRoots(projectPath);
800
715
  }
801
716
 
802
- // 检查目录是否存在
803
- const dirPath = path.join(projectPath, dir);
804
- try {
805
- await fs.access(dirPath);
806
- } catch {
807
- log(io, chalk.yellow(`⚠️ 目录 ${dir} 不存在,跳过 CONTEXT.md`));
808
- return;
717
+ const plan: ManagedFile[] = [];
718
+ for (const dir of requiredDirs) {
719
+ if (!(await nodeScaffoldFs.exists(path.join(projectPath, dir)))) {
720
+ log(io, chalk.yellow(`⚠️ 目录 ${dir} 不存在,跳过 CONTEXT.md`));
721
+ continue;
722
+ }
723
+ plan.push(contextDocFile(projectPath, dir));
809
724
  }
810
-
811
- const dirName = path.basename(dir);
812
- const content = `# ${dirName}
813
-
814
- > 此文件描述 ${dir} 目录的职责和上下文
815
-
816
- ## 职责
817
-
818
- <!-- 本目录的核心职责是什么 -->
819
-
820
- ## 核心导出
821
-
822
- <!-- 本目录对外暴露的主要模块/函数 -->
823
-
824
- ## 依赖关系
825
-
826
- <!-- 本目录依赖哪些其他模块,谁依赖本目录 -->
827
-
828
- ## 注意事项
829
-
830
- <!-- 开发时需要注意的约束或约定 -->
831
- `;
832
-
833
- await fs.writeFile(contextPath, content, 'utf-8');
834
- log(io, chalk.green(`✅ 已创建 ${dir}/CONTEXT.md`));
725
+ return plan;
835
726
  }
836
727
 
837
728
  /**
@@ -855,68 +746,30 @@ async function findGovernanceCoverage(workflowsDir: string): Promise<string | un
855
746
  }
856
747
 
857
748
  /**
858
- * 设置治理 CI workflow
749
+ * 设置治理 CI workflow(目标已在场,或已有 workflow 覆盖治理命令时不新建 CI 面)
750
+ *
751
+ * 仅 github 形有本站点:gitlab 的治理任务已并入 `.gitlab-ci.yml` 正文(一个平台一份
752
+ * CI 文件,harness#143);`none` = 不创建任何 CI 文件,治理 CI 面随之不建
753
+ * (harness#156 裁决 F1;治理文档面不受影响,见 setupGovernance 1–4)。
859
754
  */
860
- async function setupGovernanceWorkflow(projectPath: string, level: string, io: CommandIO): Promise<void> {
861
- const workflowsDir = path.join(projectPath, '.github', 'workflows');
862
- const workflowPath = path.join(workflowsDir, 'harness-governance.yml');
755
+ async function setupGovernanceWorkflow(
756
+ projectPath: string,
757
+ level: string,
758
+ io: CommandIO,
759
+ platform: CiPlatform | 'none',
760
+ ): Promise<void> {
761
+ if (platform !== 'github') return;
863
762
 
864
- // 检查是否已存在
865
- try {
866
- await fs.access(workflowPath);
867
- log(io, chalk.gray(`harness-governance.yml 已存在`));
868
- return;
869
- } catch {
870
- // 不存在,继续创建
871
- }
763
+ const workflowsDir = path.join(projectPath, '.github', 'workflows');
764
+ const file = governanceWorkflowFile(projectPath, level);
872
765
 
873
- // 能力检测:已有 workflow 已跑 harness 治理命令时跳过,避免重复 CI 面
874
- const coveredBy = await findGovernanceCoverage(workflowsDir);
875
- if (coveredBy) {
876
- log(io, chalk.gray(`治理检查已由 ${coveredBy} 覆盖,跳过创建 harness-governance.yml`));
877
- return;
766
+ if (!(await nodeScaffoldFs.exists(file.target))) {
767
+ const coveredBy = await findGovernanceCoverage(workflowsDir);
768
+ if (coveredBy) {
769
+ log(io, chalk.gray(`治理检查已由 ${coveredBy} 覆盖,跳过创建 harness-governance.yml`));
770
+ return;
771
+ }
878
772
  }
879
773
 
880
- await fs.mkdir(workflowsDir, { recursive: true });
881
-
882
- const docsCheckStep = level !== 'minimal'
883
- ? `
884
- - name: Check docs freshness
885
- run: npx @dommaker/harness sync-docs --check
886
- continue-on-error: true`
887
- : '';
888
-
889
- const workflowContent = `name: Harness Governance
890
-
891
- on:
892
- push:
893
- branches: [main, master]
894
- pull_request:
895
- branches: [main, master]
896
-
897
- jobs:
898
- governance:
899
- runs-on: ubuntu-latest
900
-
901
- steps:
902
- - uses: actions/checkout@v4
903
-
904
- - name: Setup Node.js
905
- uses: actions/setup-node@v4
906
- with:
907
- node-version: '20'
908
-
909
- - name: Install dependencies
910
- run: npm ci
911
-
912
- - name: Constraint check
913
- run: npx @dommaker/harness check
914
-
915
- - name: Quality gate
916
- run: npx @dommaker/harness passes-gate
917
- ${docsCheckStep}
918
- `;
919
-
920
- await fs.writeFile(workflowPath, workflowContent, 'utf-8');
921
- log(io, chalk.green(`✅ 已创建 .github/workflows/harness-governance.yml`));
774
+ await runPlan([file], io);
922
775
  }