@dommaker/harness 0.13.0 → 0.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (420) hide show
  1. package/CHANGELOG.md +169 -0
  2. package/bin/harness-knowledge-capture.js +99 -0
  3. package/bin/harness-knowledge-check.js +149 -0
  4. package/bin/harness-knowledge-track.js +92 -0
  5. package/bin/harness-knowledge-track.sh +47 -0
  6. package/bin/harness-sensitive-check.sh +67 -0
  7. package/dist/cli/commands/init.js +34 -2
  8. package/dist/cli/commands/init.js.map +1 -1
  9. package/package.json +6 -3
  10. package/src/CONTEXT.md +34 -0
  11. package/src/__tests__/acceptance-gate.test.ts +364 -0
  12. package/src/__tests__/annotation-checker.test.ts +183 -0
  13. package/src/__tests__/architecture-engine.test.ts +619 -0
  14. package/src/__tests__/checker-extra.test.ts +1627 -0
  15. package/src/__tests__/checker.test.ts +1268 -0
  16. package/src/__tests__/checkpoint.test.ts +697 -0
  17. package/src/__tests__/clean-state-extra.test.ts +301 -0
  18. package/src/__tests__/clean-state.test.ts +169 -0
  19. package/src/__tests__/constraint-doctor.test.ts +410 -0
  20. package/src/__tests__/constraint-evolver.test.ts +404 -0
  21. package/src/__tests__/constraint-handler.test.ts +136 -0
  22. package/src/__tests__/context/progressive-loader.test.ts +131 -0
  23. package/src/__tests__/contract-gate.test.ts +321 -0
  24. package/src/__tests__/cross-project-checker.test.ts +318 -0
  25. package/src/__tests__/cso-validator.test.ts +205 -0
  26. package/src/__tests__/detect-source-roots.test.ts +98 -0
  27. package/src/__tests__/doctor-evolver.test.ts +381 -0
  28. package/src/__tests__/error-classifier.test.ts +304 -0
  29. package/src/__tests__/exec.test.ts +83 -0
  30. package/src/__tests__/extend-exceptions.test.ts +149 -0
  31. package/src/__tests__/failure-recorder.test.ts +335 -0
  32. package/src/__tests__/hooks-pipeline.test.ts +214 -0
  33. package/src/__tests__/interceptor.test.ts +89 -0
  34. package/src/__tests__/iron-laws.test.ts +246 -0
  35. package/src/__tests__/long-running.test.ts +17 -0
  36. package/src/__tests__/passes-gate-check.test.ts +138 -0
  37. package/src/__tests__/passes-gate-extension.test.ts +151 -0
  38. package/src/__tests__/passes-gate-extra.test.ts +238 -0
  39. package/src/__tests__/passes-gate.test.ts +231 -0
  40. package/src/__tests__/performance-analyzer.test.ts +501 -0
  41. package/src/__tests__/performance-collector.test.ts +276 -0
  42. package/src/__tests__/performance-gate.test.ts +74 -0
  43. package/src/__tests__/presets.test.ts +104 -0
  44. package/src/__tests__/project-config-loader-extra.test.ts +269 -0
  45. package/src/__tests__/project-config-loader.test.ts +127 -0
  46. package/src/__tests__/review-gate.test.ts +92 -0
  47. package/src/__tests__/security-gate.test.ts +100 -0
  48. package/src/__tests__/session-startup.test.ts +334 -0
  49. package/src/__tests__/spec-validator.test.ts +57 -0
  50. package/src/__tests__/token-budget.test.ts +252 -0
  51. package/src/__tests__/trace-analyzer-extra.test.ts +307 -0
  52. package/src/__tests__/trace-analyzer.test.ts +131 -0
  53. package/src/__tests__/trace-collector.test.ts +258 -0
  54. package/src/__tests__/traces.test.ts +347 -0
  55. package/src/agents/CONTEXT.md +21 -0
  56. package/src/agents/__tests__/lifecycle.test.ts +248 -0
  57. package/src/agents/index.ts +2 -0
  58. package/src/agents/lifecycle.ts +201 -0
  59. package/src/agents/types.ts +46 -0
  60. package/src/architecture/CONTEXT.md +22 -0
  61. package/src/architecture/constraint-engine.ts +356 -0
  62. package/src/architecture/cross-project-checker.ts +563 -0
  63. package/src/cli/commands/CONTEXT.md +24 -0
  64. package/src/cli/commands/__tests__/acceptance.test.ts +180 -0
  65. package/src/cli/commands/__tests__/check.test.ts +598 -0
  66. package/src/cli/commands/__tests__/command.test.ts +149 -0
  67. package/src/cli/commands/__tests__/contract.test.ts +151 -0
  68. package/src/cli/commands/__tests__/failure.test.ts +199 -0
  69. package/src/cli/commands/__tests__/flow.test.ts +343 -0
  70. package/src/cli/commands/__tests__/init.test.ts +306 -0
  71. package/src/cli/commands/__tests__/passes-gate.test.ts +256 -0
  72. package/src/cli/commands/__tests__/performance.test.ts +116 -0
  73. package/src/cli/commands/__tests__/posteval-plan.test.ts +201 -0
  74. package/src/cli/commands/__tests__/report-extra.test.ts +98 -0
  75. package/src/cli/commands/__tests__/report.test.ts +109 -0
  76. package/src/cli/commands/__tests__/review.test.ts +153 -0
  77. package/src/cli/commands/__tests__/security.test.ts +147 -0
  78. package/src/cli/commands/__tests__/spec.test.ts +193 -0
  79. package/src/cli/commands/__tests__/status-extra.test.ts +223 -0
  80. package/src/cli/commands/__tests__/status.test.ts +306 -0
  81. package/src/cli/commands/__tests__/sync-docs.test.ts +335 -0
  82. package/src/cli/commands/__tests__/validate.test.ts +139 -0
  83. package/src/cli/commands/acceptance.ts +111 -0
  84. package/src/cli/commands/analyze-sessions.ts +488 -0
  85. package/src/cli/commands/check.ts +441 -0
  86. package/src/cli/commands/command.ts +90 -0
  87. package/src/cli/commands/constraints.ts +86 -0
  88. package/src/cli/commands/contract.ts +168 -0
  89. package/src/cli/commands/failure.ts +117 -0
  90. package/src/cli/commands/flow.ts +275 -0
  91. package/src/cli/commands/index.ts +26 -0
  92. package/src/cli/commands/init.ts +832 -0
  93. package/src/cli/commands/knowledge.ts +391 -0
  94. package/src/cli/commands/passes-gate.ts +158 -0
  95. package/src/cli/commands/performance.ts +108 -0
  96. package/src/cli/commands/posteval-plan.ts +85 -0
  97. package/src/cli/commands/release.ts +159 -0
  98. package/src/cli/commands/report.ts +198 -0
  99. package/src/cli/commands/review.ts +118 -0
  100. package/src/cli/commands/security.ts +122 -0
  101. package/src/cli/commands/spec.ts +158 -0
  102. package/src/cli/commands/status.ts +169 -0
  103. package/src/cli/commands/sync-docs.ts +743 -0
  104. package/src/cli/commands/update-user-model.ts +527 -0
  105. package/src/cli/commands/validate.ts +222 -0
  106. package/src/constraints/__tests__/lifecycle-runner.test.ts +246 -0
  107. package/src/constraints/__tests__/registry.test.ts +196 -0
  108. package/src/constraints/index.ts +3 -0
  109. package/src/constraints/lifecycle-runner.ts +184 -0
  110. package/src/constraints/registry.ts +134 -0
  111. package/src/constraints/types.ts +59 -0
  112. package/src/context/CONTEXT.md +28 -0
  113. package/src/context/__tests__/compaction.test.ts +169 -0
  114. package/src/context/__tests__/file-budget.test.ts +142 -0
  115. package/src/context/__tests__/knowledge-injector.test.ts +148 -0
  116. package/src/context/__tests__/progressive-loader.test.ts +264 -0
  117. package/src/context/__tests__/session-manager.test.ts +300 -0
  118. package/src/context/__tests__/token-budget.test.ts +338 -0
  119. package/src/context/__tests__/token-pipeline.test.ts +178 -0
  120. package/src/context/__tests__/tool-output-budget.test.ts +95 -0
  121. package/src/context/compaction.ts +202 -0
  122. package/src/context/file-budget.ts +142 -0
  123. package/src/context/index.ts +15 -0
  124. package/src/context/knowledge-injector.ts +168 -0
  125. package/src/context/progressive-loader.ts +260 -0
  126. package/src/context/session-manager.ts +343 -0
  127. package/src/context/token-budget.ts +295 -0
  128. package/src/context/token-pipeline.ts +265 -0
  129. package/src/context/tool-output-budget.ts +178 -0
  130. package/src/context/types.ts +160 -0
  131. package/src/core/CONTEXT.md +26 -0
  132. package/src/core/constraints/__tests__/default-executors.test.ts +57 -0
  133. package/src/core/constraints/__tests__/interceptor.test.ts +251 -0
  134. package/src/core/constraints/__tests__/prompt-injection.test.ts +89 -0
  135. package/src/core/constraints/check-cache.ts +96 -0
  136. package/src/core/constraints/checker.ts +1169 -0
  137. package/src/core/constraints/default-executors.ts +92 -0
  138. package/src/core/constraints/definitions.ts +1119 -0
  139. package/src/core/constraints/doc-freshness/__tests__/runner.test.ts +551 -0
  140. package/src/core/constraints/doc-freshness/auto-fix.ts +69 -0
  141. package/src/core/constraints/doc-freshness/runner.ts +486 -0
  142. package/src/core/constraints/index.ts +78 -0
  143. package/src/core/constraints/interceptor.ts +220 -0
  144. package/src/core/constraints/prompt-injection.ts +73 -0
  145. package/src/core/index.ts +23 -0
  146. package/src/core/project-config-loader.ts +252 -0
  147. package/src/core/session/__tests__/startup.test.ts +281 -0
  148. package/src/core/session/clean-state.ts +178 -0
  149. package/src/core/session/index.ts +15 -0
  150. package/src/core/session/startup.ts +253 -0
  151. package/src/core/spec/__tests__/validator.test.ts +379 -0
  152. package/src/core/spec/index.ts +7 -0
  153. package/src/core/spec/validator.ts +383 -0
  154. package/src/core/validators/__tests__/passes-gate.test.ts +131 -0
  155. package/src/core/validators/checkpoint.ts +547 -0
  156. package/src/core/validators/cso.ts +124 -0
  157. package/src/core/validators/index.ts +25 -0
  158. package/src/core/validators/passes-gate.ts +613 -0
  159. package/src/dashboard/CONTEXT.md +21 -0
  160. package/src/dashboard/__tests__/data.test.ts +115 -0
  161. package/src/dashboard/__tests__/stats.test.ts +156 -0
  162. package/src/dashboard/data.ts +113 -0
  163. package/src/dashboard/index.ts +3 -0
  164. package/src/dashboard/stats.ts +127 -0
  165. package/src/dashboard/types.ts +113 -0
  166. package/src/evolution/CONTEXT.md +22 -0
  167. package/src/evolution/__tests__/auto-evolve.test.ts +320 -0
  168. package/src/evolution/auto-evolve.ts +98 -0
  169. package/src/evolution/index.ts +1 -0
  170. package/src/failure/CONTEXT.md +24 -0
  171. package/src/failure/classifier.ts +156 -0
  172. package/src/failure/constraint-handler.ts +173 -0
  173. package/src/failure/index.ts +35 -0
  174. package/src/failure/recorder.ts +201 -0
  175. package/src/failure/types.ts +165 -0
  176. package/src/gates/CONTEXT.md +27 -0
  177. package/src/gates/__tests__/acceptance.test.ts +608 -0
  178. package/src/gates/__tests__/command.test.ts +206 -0
  179. package/src/gates/__tests__/performance.test.ts +381 -0
  180. package/src/gates/__tests__/review.test.ts +302 -0
  181. package/src/gates/__tests__/security.test.ts +332 -0
  182. package/src/gates/acceptance.ts +493 -0
  183. package/src/gates/command.ts +444 -0
  184. package/src/gates/contract.ts +260 -0
  185. package/src/gates/index.ts +67 -0
  186. package/src/gates/performance.ts +359 -0
  187. package/src/gates/review.ts +169 -0
  188. package/src/gates/security.ts +244 -0
  189. package/src/gates/types.ts +159 -0
  190. package/src/governance/CONTEXT.md +22 -0
  191. package/src/governance/__tests__/executor.test.ts +249 -0
  192. package/src/governance/executor.ts +229 -0
  193. package/src/governance/index.ts +13 -0
  194. package/src/governance/types.ts +53 -0
  195. package/src/hooks/CONTEXT.md +23 -0
  196. package/src/hooks/__tests__/bootstrap.test.ts +184 -0
  197. package/src/hooks/bootstrap.ts +144 -0
  198. package/src/hooks/index.ts +15 -0
  199. package/src/hooks/pipeline.ts +157 -0
  200. package/src/hooks/registry.ts +88 -0
  201. package/src/hooks/types.ts +80 -0
  202. package/src/index.ts +198 -0
  203. package/src/knowledge/CONTEXT.md +29 -0
  204. package/src/knowledge/__tests__/doctor.test.ts +272 -0
  205. package/src/knowledge/__tests__/import.test.ts +376 -0
  206. package/src/knowledge/__tests__/ingest.test.ts +125 -0
  207. package/src/knowledge/__tests__/lifecycle-hooks.test.ts +137 -0
  208. package/src/knowledge/__tests__/lifecycle.test.ts +248 -0
  209. package/src/knowledge/__tests__/lint.test.ts +401 -0
  210. package/src/knowledge/__tests__/query.test.ts +185 -0
  211. package/src/knowledge/__tests__/reference-tracker.test.ts +129 -0
  212. package/src/knowledge/__tests__/store.test.ts +238 -0
  213. package/src/knowledge/doctor.ts +104 -0
  214. package/src/knowledge/import.ts +505 -0
  215. package/src/knowledge/index.ts +16 -0
  216. package/src/knowledge/ingest.ts +126 -0
  217. package/src/knowledge/lifecycle-hooks.ts +199 -0
  218. package/src/knowledge/lifecycle.ts +175 -0
  219. package/src/knowledge/lint.ts +360 -0
  220. package/src/knowledge/query.ts +150 -0
  221. package/src/knowledge/reference-tracker.ts +99 -0
  222. package/src/knowledge/store.ts +264 -0
  223. package/src/knowledge/types.ts +139 -0
  224. package/src/llm/CONTEXT.md +21 -0
  225. package/src/llm/__tests__/adapter.test.ts +172 -0
  226. package/src/llm/adapter.ts +149 -0
  227. package/src/llm/index.ts +2 -0
  228. package/src/llm/types.ts +81 -0
  229. package/src/monitoring/CONTEXT.md +29 -0
  230. package/src/monitoring/__tests__/context-tracker.test.ts +172 -0
  231. package/src/monitoring/__tests__/knowledge-doctor.test.ts +276 -0
  232. package/src/monitoring/__tests__/knowledge-evolver.test.ts +365 -0
  233. package/src/monitoring/__tests__/performance-analyzer.test.ts +137 -0
  234. package/src/monitoring/__tests__/performance-collector.test.ts +332 -0
  235. package/src/monitoring/__tests__/traces.test.ts +190 -0
  236. package/src/monitoring/constraint-doctor.ts +499 -0
  237. package/src/monitoring/constraint-evolver.ts +573 -0
  238. package/src/monitoring/context-tracker.ts +148 -0
  239. package/src/monitoring/index.ts +23 -0
  240. package/src/monitoring/knowledge-doctor.ts +323 -0
  241. package/src/monitoring/knowledge-evolver.ts +289 -0
  242. package/src/monitoring/performance-analyzer.ts +450 -0
  243. package/src/monitoring/performance-collector.ts +348 -0
  244. package/src/monitoring/trace-analyzer.ts +470 -0
  245. package/src/monitoring/traces.ts +339 -0
  246. package/src/presets/__tests__/standard.test.ts +104 -0
  247. package/src/presets/index.ts +16 -0
  248. package/src/presets/standard.ts +163 -0
  249. package/src/safety/CONTEXT.md +23 -0
  250. package/src/safety/__tests__/input-guardrail.test.ts +105 -0
  251. package/src/safety/__tests__/output-guardrail.test.ts +108 -0
  252. package/src/safety/__tests__/sandbox.test.ts +158 -0
  253. package/src/safety/__tests__/tool-guardrail.test.ts +127 -0
  254. package/src/safety/index.ts +5 -0
  255. package/src/safety/input-guardrail.ts +133 -0
  256. package/src/safety/output-guardrail.ts +174 -0
  257. package/src/safety/sandbox.ts +148 -0
  258. package/src/safety/tool-guardrail.ts +176 -0
  259. package/src/safety/types.ts +124 -0
  260. package/src/spec/CONTEXT.md +19 -0
  261. package/src/spec/__tests__/annotation-checker.test.ts +289 -0
  262. package/src/spec/annotation-checker.ts +342 -0
  263. package/src/tools/CONTEXT.md +25 -0
  264. package/src/tools/__tests__/loader.test.ts +252 -0
  265. package/src/tools/__tests__/registry.test.ts +157 -0
  266. package/src/tools/core/__tests__/core.test.ts +122 -0
  267. package/src/tools/core/index.ts +201 -0
  268. package/src/tools/core/package.json +7 -0
  269. package/src/tools/core/pnpm-lock.yaml +232 -0
  270. package/src/tools/definitions/core/code/fingerprint.sh +273 -0
  271. package/src/tools/definitions/core/code/fingerprint.yml +72 -0
  272. package/src/tools/definitions/core/code/parse.yml +68 -0
  273. package/src/tools/definitions/core/code/register-language.sh +475 -0
  274. package/src/tools/definitions/core/code/register-language.yml +74 -0
  275. package/src/tools/definitions/core/docker/build.yml +73 -0
  276. package/src/tools/definitions/core/docker/run.yml +81 -0
  277. package/src/tools/definitions/core/file/copy.yml +88 -0
  278. package/src/tools/definitions/core/file/read.yml +69 -0
  279. package/src/tools/definitions/core/file/write.yml +75 -0
  280. package/src/tools/definitions/core/git/branch.yml +61 -0
  281. package/src/tools/definitions/core/git/cleanup-worktree.yml +50 -0
  282. package/src/tools/definitions/core/git/clone.yml +69 -0
  283. package/src/tools/definitions/core/git/commit.yml +65 -0
  284. package/src/tools/definitions/core/git/push.yml +79 -0
  285. package/src/tools/definitions/core/git/worktree.yml +96 -0
  286. package/src/tools/definitions/core/notification/notify.sh +152 -0
  287. package/src/tools/definitions/core/notification/notify.yml +60 -0
  288. package/src/tools/definitions/core/npm/build.yml +75 -0
  289. package/src/tools/definitions/core/npm/install.yml +58 -0
  290. package/src/tools/definitions/core/npm/test.yml +75 -0
  291. package/src/tools/definitions/core/validation/check-reuse.yml +170 -0
  292. package/src/tools/definitions/core/validation/validate-handlers.yml +118 -0
  293. package/src/tools/definitions/core/validation/validate-readme-stats.yml +155 -0
  294. package/src/tools/definitions/core/validation/validate-yaml-syntax.yml +134 -0
  295. package/src/tools/definitions/ext/browser/browser-automate.sh +255 -0
  296. package/src/tools/definitions/ext/browser/browser-automate.yml +166 -0
  297. package/src/tools/definitions/ext/browser/browser-close.sh +104 -0
  298. package/src/tools/definitions/ext/browser/browser-close.yml +55 -0
  299. package/src/tools/definitions/ext/browser/browser-mcp-debug.sh +682 -0
  300. package/src/tools/definitions/ext/browser/browser-mcp-debug.yml +167 -0
  301. package/src/tools/definitions/ext/browser/browser-start.sh +101 -0
  302. package/src/tools/definitions/ext/browser/browser-start.yml +62 -0
  303. package/src/tools/definitions/registry.json +795 -0
  304. package/src/tools/definitions/std/README.md +350 -0
  305. package/src/tools/definitions/std/analysis/analyze-codebase.yml +72 -0
  306. package/src/tools/definitions/std/analysis/analyze-diff.yml +182 -0
  307. package/src/tools/definitions/std/analysis/analyze-git-diff.yml +70 -0
  308. package/src/tools/definitions/std/analysis/analyze-impact.yml +78 -0
  309. package/src/tools/definitions/std/analysis/analyze-requirements.yml +105 -0
  310. package/src/tools/definitions/std/analysis/brainstorm-options.yml +106 -0
  311. package/src/tools/definitions/std/analysis/build-graph.yml +154 -0
  312. package/src/tools/definitions/std/analysis/clarify-requirements.yml +90 -0
  313. package/src/tools/definitions/std/analysis/detect-context.yml +109 -0
  314. package/src/tools/definitions/std/analysis/detect-layers.yml +125 -0
  315. package/src/tools/definitions/std/analysis/generate-tour.yml +102 -0
  316. package/src/tools/definitions/std/analysis/search-enhance.yml +105 -0
  317. package/src/tools/definitions/std/backlog/add.yml +51 -0
  318. package/src/tools/definitions/std/backlog/decide.yml +39 -0
  319. package/src/tools/definitions/std/backlog/github-sync.yml +161 -0
  320. package/src/tools/definitions/std/backlog/list.yml +53 -0
  321. package/src/tools/definitions/std/backlog/load.yml +46 -0
  322. package/src/tools/definitions/std/backlog/resolve.yml +37 -0
  323. package/src/tools/definitions/std/backlog/update.yml +42 -0
  324. package/src/tools/definitions/std/bugfix/diagnose.yml +68 -0
  325. package/src/tools/definitions/std/bugfix/fix.yml +66 -0
  326. package/src/tools/definitions/std/bugfix/verify.yml +69 -0
  327. package/src/tools/definitions/std/constraint/check-decomposition.yml +103 -0
  328. package/src/tools/definitions/std/constraint/check-feature-list.yml +77 -0
  329. package/src/tools/definitions/std/constraint/check-progress.yml +97 -0
  330. package/src/tools/definitions/std/constraint/generate-report.yml +147 -0
  331. package/src/tools/definitions/std/deploy/commit-push.yml +33 -0
  332. package/src/tools/definitions/std/deploy/deploy-backend.yml +37 -0
  333. package/src/tools/definitions/std/deploy/deploy-frontend.yml +37 -0
  334. package/src/tools/definitions/std/deploy/rollback.yml +148 -0
  335. package/src/tools/definitions/std/design/analyze-architecture-impact.yml +113 -0
  336. package/src/tools/definitions/std/design/design-api.yml +55 -0
  337. package/src/tools/definitions/std/design/design-architecture.yml +97 -0
  338. package/src/tools/definitions/std/design/design-db.yml +81 -0
  339. package/src/tools/definitions/std/design/generate-spec.yml +182 -0
  340. package/src/tools/definitions/std/development/develop-api.yml +85 -0
  341. package/src/tools/definitions/std/development/develop-backend.yml +88 -0
  342. package/src/tools/definitions/std/development/develop-frontend.yml +87 -0
  343. package/src/tools/definitions/std/development/develop-shared-types.yml +74 -0
  344. package/src/tools/definitions/std/development/develop-task.yml +122 -0
  345. package/src/tools/definitions/std/development/develop-tests.yml +76 -0
  346. package/src/tools/definitions/std/development/execute-batch.yml +152 -0
  347. package/src/tools/definitions/std/development/fix-issues.yml +100 -0
  348. package/src/tools/definitions/std/development/implement-task.yml +124 -0
  349. package/src/tools/definitions/std/development/review-fix-cycle.yml +232 -0
  350. package/src/tools/definitions/std/evolution/implement.yml +125 -0
  351. package/src/tools/definitions/std/evolution/prioritize.yml +112 -0
  352. package/src/tools/definitions/std/evolution/report-gap.yml +166 -0
  353. package/src/tools/definitions/std/file/read.yml +21 -0
  354. package/src/tools/definitions/std/governance/aggregate-opinions.sh +201 -0
  355. package/src/tools/definitions/std/governance/aggregate-opinions.yml +79 -0
  356. package/src/tools/definitions/std/governance/audit-task.yml +178 -0
  357. package/src/tools/definitions/std/governance/cast-vote.yml +129 -0
  358. package/src/tools/definitions/std/governance/collect-issues.yml +16 -0
  359. package/src/tools/definitions/std/governance/create-signed-document.yml +23 -0
  360. package/src/tools/definitions/std/governance/create-voting-session.yml +101 -0
  361. package/src/tools/definitions/std/governance/define-stance.sh +243 -0
  362. package/src/tools/definitions/std/governance/define-stance.yml +82 -0
  363. package/src/tools/definitions/std/governance/generate-review-report.yml +23 -0
  364. package/src/tools/definitions/std/governance/impeach.yml +179 -0
  365. package/src/tools/definitions/std/governance/multi-stance-review.yml +154 -0
  366. package/src/tools/definitions/std/governance/prepare-artifact.yml +20 -0
  367. package/src/tools/definitions/std/governance/review-spec-approval.yml +262 -0
  368. package/src/tools/definitions/std/governance/rollback.yml +186 -0
  369. package/src/tools/definitions/std/governance/stance-review.yml +149 -0
  370. package/src/tools/definitions/std/governance/track-effect.yml +199 -0
  371. package/src/tools/definitions/std/governance/vote-tally.yml +144 -0
  372. package/src/tools/definitions/std/patch/execute.yml +51 -0
  373. package/src/tools/definitions/std/planning/generate-tasks.yml +36 -0
  374. package/src/tools/definitions/std/planning/load-tasks.yml +44 -0
  375. package/src/tools/definitions/std/planning/split-batch.yml +481 -0
  376. package/src/tools/definitions/std/planning/split-tasks.yml +359 -0
  377. package/src/tools/definitions/std/planning/update-tasks.yml +51 -0
  378. package/src/tools/definitions/std/planning/validate-tasks.yml +46 -0
  379. package/src/tools/definitions/std/project/decide-next-workflow.yml +38 -0
  380. package/src/tools/definitions/std/project/load-state.yml +31 -0
  381. package/src/tools/definitions/std/project/save-state.yml +32 -0
  382. package/src/tools/definitions/std/quality/check-quality.yml +241 -0
  383. package/src/tools/definitions/std/quality/debug-systematic.yml +163 -0
  384. package/src/tools/definitions/std/quality/handle-feedback.yml +108 -0
  385. package/src/tools/definitions/std/quality/review-code.yml +128 -0
  386. package/src/tools/definitions/std/quality/review-spec.yml +140 -0
  387. package/src/tools/definitions/std/quality/review-task.yml +190 -0
  388. package/src/tools/definitions/std/quality/run-tests.yml +80 -0
  389. package/src/tools/definitions/std/quick/analyze.yml +56 -0
  390. package/src/tools/definitions/std/quick/implement.yml +67 -0
  391. package/src/tools/definitions/std/quick/verify.yml +71 -0
  392. package/src/tools/definitions/std/verification/verify_completion.yml +113 -0
  393. package/src/tools/definitions/std/verification/wait-condition.yml +107 -0
  394. package/src/tools/index.ts +5 -0
  395. package/src/tools/loader.ts +216 -0
  396. package/src/tools/paths.ts +15 -0
  397. package/src/tools/registry.ts +128 -0
  398. package/src/tools/types.ts +46 -0
  399. package/src/types/__tests__/types.test.ts +86 -0
  400. package/src/types/checkpoint.ts +174 -0
  401. package/src/types/constraint.ts +335 -0
  402. package/src/types/cso.ts +37 -0
  403. package/src/types/enforcement.ts +48 -0
  404. package/src/types/index.ts +59 -0
  405. package/src/types/iron-law.ts +50 -0
  406. package/src/types/passes-gate.ts +185 -0
  407. package/src/types/performance.ts +295 -0
  408. package/src/types/project-config.ts +251 -0
  409. package/src/types/session.ts +132 -0
  410. package/src/types/spec.ts +91 -0
  411. package/src/types/trace.ts +228 -0
  412. package/src/utils/detect-source-roots.ts +114 -0
  413. package/src/utils/exec.ts +61 -0
  414. package/src/verification/CONTEXT.md +23 -0
  415. package/src/verification/__tests__/loop.test.ts +303 -0
  416. package/src/verification/__tests__/rules-based.test.ts +240 -0
  417. package/src/verification/index.ts +3 -0
  418. package/src/verification/loop.ts +137 -0
  419. package/src/verification/rules-based.ts +153 -0
  420. package/src/verification/types.ts +81 -0
@@ -0,0 +1,253 @@
1
+ /**
2
+ * SessionStartup - Session 启动检查点验证
3
+ *
4
+ * 确保 Agent 启动时必须先读上下文,防止"失忆"乱搞。
5
+ */
6
+
7
+ import { execAsync } from '../../utils/exec';
8
+ import * as fs from 'fs/promises';
9
+ import * as path from 'path';
10
+ import * as yaml from 'js-yaml';
11
+ import type {
12
+ StartupCheckpoints,
13
+ StartupCheckpointResult,
14
+ StartupCheckpointType,
15
+ TaskListJson,
16
+ } from '../../types/session';
17
+
18
+
19
+ const DEFAULT_TIMEOUT = 30000; // 30 seconds
20
+
21
+ export class SessionStartup {
22
+ private checkpoints: StartupCheckpoints;
23
+ private workDir: string;
24
+
25
+ constructor(workDir: string, checkpoints: StartupCheckpoints) {
26
+ this.workDir = workDir;
27
+ this.checkpoints = checkpoints;
28
+ }
29
+
30
+ async run(): Promise<{ success: boolean; results: StartupCheckpointResult[]; errors: string[] }> {
31
+ const results: StartupCheckpointResult[] = [];
32
+ const errors: string[] = [];
33
+
34
+ // 1. Run required checkpoints
35
+ for (const type of this.checkpoints.required) {
36
+ const result = await this.runCheckpoint(type);
37
+ results.push(result);
38
+ if (!result.success) {
39
+ errors.push(`Required checkpoint failed: ${type} - ${result.error}`);
40
+ }
41
+ }
42
+
43
+ // 2. Run optional checkpoints (don't fail on error)
44
+ for (const type of this.checkpoints.optional || []) {
45
+ const result = await this.runCheckpoint(type);
46
+ results.push(result);
47
+ }
48
+
49
+ return {
50
+ success: errors.length === 0,
51
+ results,
52
+ errors,
53
+ };
54
+ }
55
+
56
+ private async runCheckpoint(type: StartupCheckpointType): Promise<StartupCheckpointResult> {
57
+ const start = Date.now();
58
+
59
+ try {
60
+ let data: any;
61
+
62
+ switch (type) {
63
+ case 'pwd':
64
+ data = await this.checkPwd();
65
+ break;
66
+ case 'git_log':
67
+ data = await this.checkGitLog();
68
+ break;
69
+ case 'git_status':
70
+ data = await this.checkGitStatus();
71
+ break;
72
+ case 'read_progress':
73
+ data = await this.checkProgress();
74
+ break;
75
+ case 'read_task_list':
76
+ data = await this.checkTaskList();
77
+ break;
78
+ case 'init_sh':
79
+ data = await this.checkInitSh();
80
+ break;
81
+ case 'basic_verification':
82
+ data = await this.checkBasicVerification();
83
+ break;
84
+ case 'load_context':
85
+ data = await this.checkLoadContext();
86
+ break;
87
+ default:
88
+ throw new Error(`Unknown checkpoint type: ${type}`);
89
+ }
90
+
91
+ return { type, success: true, data, duration: Date.now() - start };
92
+ } catch (error: any) {
93
+ return { type, success: false, error: error.message, duration: Date.now() - start };
94
+ }
95
+ }
96
+
97
+ private async checkPwd(): Promise<string> {
98
+ return this.workDir;
99
+ }
100
+
101
+ private async checkGitLog(): Promise<string[]> {
102
+ try {
103
+ const { stdout } = await execAsync('git log --oneline -10', { cwd: this.workDir });
104
+ return stdout.split('\n').filter(Boolean);
105
+ } catch {
106
+ return [];
107
+ }
108
+ }
109
+
110
+ private async checkGitStatus(): Promise<{ staged: string[]; unstaged: string[]; untracked: string[] }> {
111
+ try {
112
+ const { stdout } = await execAsync('git status --porcelain', { cwd: this.workDir });
113
+ const staged: string[] = [], unstaged: string[] = [], untracked: string[] = [];
114
+
115
+ for (const line of stdout.split('\n').filter(Boolean)) {
116
+ const status = line.substring(0, 2);
117
+ const file = line.substring(3);
118
+ if (status.includes('??')) untracked.push(file);
119
+ else if (status.match(/[MADRC]/)) staged.push(file);
120
+ else unstaged.push(file);
121
+ }
122
+
123
+ return { staged, unstaged, untracked };
124
+ } catch {
125
+ return { staged: [], unstaged: [], untracked: [] };
126
+ }
127
+ }
128
+
129
+ private async checkProgress(): Promise<any> {
130
+ const progressPath = path.join(this.workDir, '.harness', 'progress.yml');
131
+ try {
132
+ const content = await fs.readFile(progressPath, 'utf-8');
133
+ return yaml.load(content) as any;
134
+ } catch {
135
+ return null;
136
+ }
137
+ }
138
+
139
+ private async checkTaskList(): Promise<TaskListJson | null> {
140
+ // Try tasks.yml first (existing format)
141
+ const tasksPath = path.join(this.workDir, 'tasks.yml');
142
+ try {
143
+ const content = await fs.readFile(tasksPath, 'utf-8');
144
+ return yaml.load(content) as TaskListJson;
145
+ } catch {
146
+ // Try tasks.json
147
+ const jsonPath = path.join(this.workDir, 'tasks.json');
148
+ try {
149
+ const content = await fs.readFile(jsonPath, 'utf-8');
150
+ return JSON.parse(content);
151
+ } catch {
152
+ return null;
153
+ }
154
+ }
155
+ }
156
+
157
+ private async checkInitSh(): Promise<boolean> {
158
+ const initPath = path.join(this.workDir, 'init.sh');
159
+ try {
160
+ await fs.access(initPath);
161
+ return true;
162
+ } catch {
163
+ return false;
164
+ }
165
+ }
166
+
167
+ private async checkBasicVerification(): Promise<{ hasPackageJson: boolean; hasTests: boolean; hasReadme: boolean }> {
168
+ const [hasPackageJson, hasTests, hasReadme] = await Promise.all([
169
+ fs.access(path.join(this.workDir, 'package.json')).then(() => true).catch(() => false),
170
+ this.hasTestFiles(),
171
+ fs.access(path.join(this.workDir, 'README.md')).then(() => true).catch(() => false),
172
+ ]);
173
+ return { hasPackageJson, hasTests, hasReadme };
174
+ }
175
+
176
+ private async hasTestFiles(): Promise<boolean> {
177
+ const testPatterns = ['test', 'spec', '__tests__'];
178
+ try {
179
+ const files = await fs.readdir(this.workDir);
180
+ return files.some(f => testPatterns.some(p => f.toLowerCase().includes(p)));
181
+ } catch {
182
+ return false;
183
+ }
184
+ }
185
+
186
+ private async checkLoadContext(): Promise<any> {
187
+ const context: Record<string, string> = {};
188
+ const files = this.checkpoints.contextFiles || [];
189
+
190
+ for (const file of files) {
191
+ try {
192
+ context[file] = await fs.readFile(path.join(this.workDir, file), 'utf-8');
193
+ } catch {}
194
+ }
195
+
196
+ return context;
197
+ }
198
+
199
+ /**
200
+ * Get current task from task list
201
+ */
202
+ async getCurrentTask(): Promise<{ task: any; index: number } | null> {
203
+ const taskList = await this.checkTaskList();
204
+ if (!taskList?.tasks) return null;
205
+
206
+ for (let i = 0; i < taskList.tasks.length; i++) {
207
+ const task = taskList.tasks[i];
208
+ if (task && !task.passes) {
209
+ return { task, index: i };
210
+ }
211
+ }
212
+
213
+ return null;
214
+ }
215
+
216
+ /**
217
+ * Generate startup report
218
+ */
219
+ generateReport(results: StartupCheckpointResult[]): string {
220
+ const lines: string[] = ['## Session Startup Report\n'];
221
+
222
+ for (const result of results) {
223
+ const icon = result.success ? '✅' : '❌';
224
+ lines.push(`${icon} ${result.type} (${result.duration}ms)`);
225
+ if (result.error) {
226
+ lines.push(` Error: ${result.error}`);
227
+ }
228
+ }
229
+
230
+ return lines.join('\n');
231
+ }
232
+ }
233
+
234
+ export const createSessionStartup = (workDir: string, checkpoints: StartupCheckpoints) =>
235
+ new SessionStartup(workDir, checkpoints);
236
+
237
+ /**
238
+ * Default startup checkpoints for code workflows
239
+ */
240
+ export const DEFAULT_CODE_CHECKPOINTS: StartupCheckpoints = {
241
+ required: ['pwd', 'git_log', 'read_task_list'],
242
+ optional: ['read_progress', 'init_sh', 'basic_verification'],
243
+ timeout: DEFAULT_TIMEOUT,
244
+ };
245
+
246
+ /**
247
+ * Minimal startup checkpoints
248
+ */
249
+ export const MINIMAL_CHECKPOINTS: StartupCheckpoints = {
250
+ required: ['pwd', 'read_task_list'],
251
+ optional: [],
252
+ timeout: DEFAULT_TIMEOUT,
253
+ };
@@ -0,0 +1,379 @@
1
+ /**
2
+ * SpecValidator 测试
3
+ */
4
+
5
+ import { SpecValidator, validateSpec, validateAllSpecs } from '../validator';
6
+ import * as fs from 'fs/promises';
7
+
8
+ // Mock fs
9
+ jest.mock('fs/promises', () => ({
10
+ readFile: jest.fn(),
11
+ writeFile: jest.fn(),
12
+ access: jest.fn(),
13
+ stat: jest.fn(),
14
+ }));
15
+
16
+ const mockFs = fs as jest.Mocked<typeof fs>;
17
+
18
+ describe('SpecValidator', () => {
19
+ let validator: SpecValidator;
20
+
21
+ beforeEach(() => {
22
+ jest.clearAllMocks();
23
+ // Reset singleton
24
+ (SpecValidator as any).instance = undefined;
25
+ validator = SpecValidator.getInstance();
26
+ });
27
+
28
+ describe('getInstance()', () => {
29
+ it('should return singleton instance', () => {
30
+ const v1 = SpecValidator.getInstance();
31
+ const v2 = SpecValidator.getInstance();
32
+ expect(v1).toBe(v2);
33
+ });
34
+
35
+ it('should accept custom config', () => {
36
+ (SpecValidator as any).instance = undefined;
37
+ const v = SpecValidator.getInstance({ enabled: false });
38
+ expect(v).toBeDefined();
39
+ });
40
+ });
41
+
42
+ describe('setConfig()', () => {
43
+ it('should update config', () => {
44
+ validator.setConfig({ enabled: false });
45
+ expect(validator).toBeDefined();
46
+ });
47
+ });
48
+
49
+ describe('detectSpecType()', () => {
50
+ it('should detect architecture type', () => {
51
+ const type = validator.detectSpecType('ARCHITECTURE.md');
52
+ expect(type).toBe('architecture');
53
+ });
54
+
55
+ it('should detect module type', () => {
56
+ const type = validator.detectSpecType('specs/modules/user.yml');
57
+ expect(type).toBe('module');
58
+ });
59
+
60
+ it('should detect api type', () => {
61
+ const type = validator.detectSpecType('specs/api/auth.yaml');
62
+ expect(type).toBe('api');
63
+ });
64
+
65
+ it('should return custom for unknown files', () => {
66
+ const type = validator.detectSpecType('specs/custom.json');
67
+ expect(type).toBe('custom');
68
+ });
69
+
70
+ it('should handle lowercase architecture', () => {
71
+ const type = validator.detectSpecType('architecture.md');
72
+ expect(type).toBe('architecture');
73
+ });
74
+ });
75
+
76
+ describe('validateFile()', () => {
77
+ it('should return invalid for non-existent file', async () => {
78
+ mockFs.access.mockRejectedValueOnce(new Error('Not found'));
79
+
80
+ const result = await validator.validateFile('/non/existent.yml');
81
+
82
+ expect(result.valid).toBe(false);
83
+ expect(result.errors.length).toBeGreaterThan(0);
84
+ });
85
+ });
86
+
87
+ describe('loadSchema()', () => {
88
+ it('should return null for invalid path', async () => {
89
+ mockFs.access.mockRejectedValue(new Error('Not found'));
90
+
91
+ const schema = await validator.loadSchema('/non/existent');
92
+
93
+ expect(schema).toBeNull();
94
+ });
95
+ });
96
+
97
+ describe('validateAll()', () => {
98
+ it('should validate multiple files', async () => {
99
+ mockFs.access.mockRejectedValue(new Error('Not found'));
100
+
101
+ const result = await validator.validateAll('/test/project');
102
+
103
+ expect(result).toBeDefined();
104
+ });
105
+
106
+ it('should validate staged files', async () => {
107
+ // Mock exec for git diff
108
+ const mockExec = jest.fn().mockResolvedValue({ stdout: 'specs/test.yml\nARCHITECTURE.md\n' });
109
+ jest.doMock('child_process', () => ({ exec: mockExec }));
110
+ jest.doMock('util', () => ({ promisify: () => mockExec }));
111
+
112
+ mockFs.access.mockRejectedValue(new Error('Not found'));
113
+
114
+ const result = await validator.validateAll('/test/project', true);
115
+
116
+ expect(result).toBeDefined();
117
+ });
118
+ });
119
+
120
+ describe('validateFile() with YAML', () => {
121
+ it('should validate valid YAML file', async () => {
122
+ mockFs.access.mockResolvedValue(undefined);
123
+ mockFs.readFile.mockResolvedValue('name: test\nversion: 1');
124
+
125
+ const result = await validator.validateFile('specs/test.yml');
126
+
127
+ expect(result.valid).toBe(true);
128
+ });
129
+
130
+ it('should detect invalid YAML', async () => {
131
+ mockFs.access.mockResolvedValue(undefined);
132
+ mockFs.readFile.mockResolvedValue('invalid: yaml: content:');
133
+
134
+ const result = await validator.validateFile('specs/bad.yml');
135
+
136
+ expect(result.errors.length).toBeGreaterThan(0);
137
+ });
138
+ });
139
+
140
+ describe('validateFile() with ARCHITECTURE.md', () => {
141
+ it('should validate valid ARCHITECTURE.md', async () => {
142
+ mockFs.access.mockResolvedValue(undefined);
143
+ mockFs.readFile.mockResolvedValue('# Architecture\n\n## Module A\n\nContent...');
144
+
145
+ const result = await validator.validateFile('ARCHITECTURE.md');
146
+
147
+ expect(result.type).toBe('architecture');
148
+ });
149
+
150
+ it('should warn on missing headers', async () => {
151
+ mockFs.access.mockResolvedValue(undefined);
152
+ mockFs.readFile.mockResolvedValue('Just plain text without headers');
153
+
154
+ const result = await validator.validateFile('ARCHITECTURE.md');
155
+
156
+ // 警告可能被添加到 errors 或 warnings
157
+ const hasWarning = result.warnings.length > 0 || result.errors.some(e => e.severity === 'warning');
158
+ expect(hasWarning || result.valid).toBe(true);
159
+ });
160
+ });
161
+
162
+ describe('isSpecFile()', () => {
163
+ it('should identify ARCHITECTURE.md as spec file', () => {
164
+ // 通过 validateAll 间接测试 - ARCHITECTURE.md 会被过滤为 spec 文件
165
+ // 直接测试 isSpecFile (private, 通过 validateAll 间接验证)
166
+ expect(validator.detectSpecType('ARCHITECTURE.md')).toBe('architecture');
167
+ });
168
+
169
+ it('should identify specs directory files', async () => {
170
+ // specs/ 下的文件应该被识别
171
+ mockFs.access.mockResolvedValue(undefined);
172
+ mockFs.readFile.mockResolvedValue('# Test\n\nContent');
173
+ const result = await validator.validateFile('specs/modules/test.md');
174
+ expect(result.file).toBe('specs/modules/test.md');
175
+ });
176
+ });
177
+
178
+ describe('basicValidation()', () => {
179
+ it('should return valid for empty content', async () => {
180
+ mockFs.access.mockResolvedValue(undefined);
181
+ mockFs.readFile.mockResolvedValue('');
182
+
183
+ const result = await validator.validateFile('specs/empty.yml');
184
+
185
+ // 空 YAML 是合法的
186
+ expect(result.valid).toBe(true);
187
+ });
188
+ });
189
+
190
+ describe('fileExists()', () => {
191
+ it('should return true for existing file', async () => {
192
+ mockFs.access.mockResolvedValue(undefined);
193
+ mockFs.readFile.mockResolvedValue('test');
194
+
195
+ const result = await validator.validateFile('specs/existing.yml');
196
+
197
+ expect(result).toBeDefined();
198
+ });
199
+
200
+ it('should return false for non-existing file', async () => {
201
+ mockFs.access.mockRejectedValue(new Error('Not found'));
202
+
203
+ const result = await validator.validateFile('specs/nonexistent.yml');
204
+
205
+ expect(result.valid).toBe(false);
206
+ expect(result.errors[0]?.message).toContain('不存在');
207
+ });
208
+ });
209
+
210
+ describe('dynamicImport()', () => {
211
+ it('should handle import errors', async () => {
212
+ mockFs.access.mockRejectedValue(new Error('Not found'));
213
+
214
+ const schema = await validator.loadSchema('/invalid/module.ts');
215
+
216
+ expect(schema).toBeNull();
217
+ });
218
+ });
219
+
220
+ describe('loadSchema() with cache', () => {
221
+ it('should return cached schema on second call', async () => {
222
+ mockFs.access.mockRejectedValue(new Error('Not found'));
223
+
224
+ // First call - no cache
225
+ const schema1 = await validator.loadSchema('/cached/path');
226
+ // Second call - should hit cache (which is empty since first call failed)
227
+ const schema2 = await validator.loadSchema('/cached/path');
228
+
229
+ expect(schema1).toBeNull();
230
+ expect(schema2).toBeNull();
231
+ });
232
+
233
+ it('should clear cache on setConfig', () => {
234
+ validator.setConfig({ schemaPath: './new/path' });
235
+ // Cache should be cleared
236
+ expect(validator).toBeDefined();
237
+ });
238
+ });
239
+
240
+ describe('detectSpecType() edge cases', () => {
241
+ it('should detect modules (plural) path', () => {
242
+ const type = validator.detectSpecType('src/modules/auth.ts');
243
+ expect(type).toBe('module');
244
+ });
245
+
246
+ it('should detect apis (plural) path', () => {
247
+ const type = validator.detectSpecType('src/apis/users.ts');
248
+ expect(type).toBe('api');
249
+ });
250
+
251
+ it('should return custom for regular files', () => {
252
+ const type = validator.detectSpecType('src/utils/helper.ts');
253
+ expect(type).toBe('custom');
254
+ });
255
+ });
256
+
257
+ describe('getStagedFiles()', () => {
258
+ it('should handle git errors', async () => {
259
+ // git 命令失败时返回空数组
260
+ const result = await validator.validateAll('/test', true);
261
+
262
+ // 可能无法找到 spec 文件
263
+ expect(result).toBeDefined();
264
+ expect(result.total).toBeGreaterThanOrEqual(0);
265
+ });
266
+ });
267
+
268
+ describe('validate with custom schema', () => {
269
+ it('should use provided schema', async () => {
270
+ mockFs.access.mockResolvedValue(undefined);
271
+ mockFs.readFile.mockResolvedValue('custom content');
272
+
273
+ const customSchema = {
274
+ name: 'custom',
275
+ validate: async () => ({
276
+ valid: true,
277
+ file: 'test.yml',
278
+ type: 'custom' as const,
279
+ errors: [],
280
+ warnings: [],
281
+ }),
282
+ };
283
+
284
+ const result = await validator.validateFile('test.yml', customSchema);
285
+
286
+ expect(result.valid).toBe(true);
287
+ });
288
+
289
+ it('should handle schema validation errors', async () => {
290
+ mockFs.access.mockResolvedValue(undefined);
291
+ mockFs.readFile.mockResolvedValue('bad content');
292
+
293
+ const failingSchema = {
294
+ name: 'failing',
295
+ validate: async () => ({
296
+ valid: false,
297
+ file: 'test.yml',
298
+ type: 'custom' as const,
299
+ errors: [{ path: '', message: 'Schema error', severity: 'error' as const }],
300
+ warnings: [],
301
+ }),
302
+ };
303
+
304
+ const result = await validator.validateFile('test.yml', failingSchema);
305
+
306
+ expect(result.valid).toBe(false);
307
+ expect(result.errors[0]?.message).toBe('Schema error');
308
+ });
309
+
310
+ it('should handle schema throwing exception', async () => {
311
+ mockFs.access.mockResolvedValue(undefined);
312
+ mockFs.readFile.mockResolvedValue('content');
313
+
314
+ const throwingSchema = {
315
+ name: 'throwing',
316
+ validate: async () => {
317
+ throw new Error('Validation exception');
318
+ },
319
+ };
320
+
321
+ const result = await validator.validateFile('test.yml', throwingSchema);
322
+
323
+ expect(result.valid).toBe(false);
324
+ expect(result.errors[0]?.message).toContain('验证失败');
325
+ });
326
+ });
327
+
328
+ describe('validateFile() without schema', () => {
329
+ it('should use basicValidation when no schema provided', async () => {
330
+ mockFs.access.mockResolvedValue(undefined);
331
+ mockFs.readFile.mockResolvedValue('# Title\n\n## Section\n\nContent');
332
+
333
+ const result = await validator.validateFile('ARCHITECTURE.md');
334
+
335
+ expect(result.type).toBe('architecture');
336
+ expect(result.valid).toBe(true);
337
+ });
338
+
339
+ it('should detect missing headers in architecture file', async () => {
340
+ mockFs.access.mockResolvedValue(undefined);
341
+ mockFs.readFile.mockResolvedValue('Plain text without any headers');
342
+
343
+ const result = await validator.validateFile('ARCHITECTURE.md');
344
+
345
+ expect(result.type).toBe('architecture');
346
+ // Should have a warning about missing headers
347
+ const hasWarning = result.errors.some(e => e.severity === 'warning');
348
+ expect(hasWarning).toBe(true);
349
+ });
350
+ });
351
+
352
+ describe('convenience functions', () => {
353
+ it('validateSpec should work without schemaPath', async () => {
354
+ mockFs.access.mockResolvedValue(undefined);
355
+ mockFs.readFile.mockResolvedValue('content');
356
+
357
+ const result = await validateSpec('specs/test.yml');
358
+ expect(result).toBeDefined();
359
+ expect(result.file).toBe('specs/test.yml');
360
+ });
361
+
362
+ it('validateSpec should work with schemaPath', async () => {
363
+ mockFs.access.mockRejectedValue(new Error('Not found'));
364
+
365
+ const result = await validateSpec('specs/test.yml', '/non/existent/schema');
366
+ expect(result).toBeDefined();
367
+ });
368
+
369
+ it('validateAllSpecs should return batch result', async () => {
370
+ mockFs.access.mockRejectedValue(new Error('Not found'));
371
+
372
+ const result = await validateAllSpecs('/test/project');
373
+ expect(result).toBeDefined();
374
+ expect(typeof result.total).toBe('number');
375
+ expect(typeof result.passed).toBe('number');
376
+ expect(typeof result.failed).toBe('number');
377
+ });
378
+ });
379
+ });
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Spec 验证模块
3
+ *
4
+ * 框架提供验证机制,项目定义自己的 Spec Schema
5
+ */
6
+
7
+ export * from './validator';