@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,360 @@
1
+ /**
2
+ * 知识库 Lint(健康检查)
3
+ *
4
+ * 检查项:
5
+ * - 索引不一致(自动修复)
6
+ * - 孤儿条目(无引用、无验证)
7
+ * - 矛盾检测(同主题相反结论)
8
+ * - 过时检测(6 月未引用的 draft)
9
+ * - 重复/相似条目
10
+ * - 成熟度衰减
11
+ */
12
+
13
+ import { KnowledgeStore } from './store';
14
+ import { ReferenceTracker } from './reference-tracker';
15
+ import type { KnowledgeEntry, LintIssue, LintIssueType, MaturityLevel } from './types';
16
+
17
+ export interface LintReport {
18
+ timestamp: string;
19
+ totalEntries: number;
20
+ issues: LintIssue[];
21
+ fixed: number;
22
+ summary: Record<LintIssueType, number>;
23
+ }
24
+
25
+ export class KnowledgeLinter {
26
+ private store: KnowledgeStore;
27
+ private tracker: ReferenceTracker;
28
+
29
+ constructor(store: KnowledgeStore, tracker: ReferenceTracker) {
30
+ this.store = store;
31
+ this.tracker = tracker;
32
+ }
33
+
34
+ /**
35
+ * 执行完整 Lint 检查
36
+ */
37
+ run(autoFix: boolean = false): LintReport {
38
+ const entries = this.store.list({ excludeArchived: false });
39
+ const issues: LintIssue[] = [];
40
+
41
+ // 各项检查
42
+ issues.push(...this.checkIndexConsistency(entries));
43
+ issues.push(...this.checkOrphans(entries));
44
+ issues.push(...this.checkOutdated(entries));
45
+ issues.push(...this.checkDuplicates(entries));
46
+ issues.push(...this.checkContradictions(entries));
47
+
48
+ // 自动修复
49
+ let fixed = 0;
50
+ if (autoFix) {
51
+ fixed = this.autoFix(issues);
52
+ }
53
+
54
+ // 统计
55
+ const summary: Record<LintIssueType, number> = {
56
+ orphan: 0,
57
+ contradiction: 0,
58
+ outdated: 0,
59
+ duplicate: 0,
60
+ index_inconsistent: 0,
61
+ };
62
+ for (const issue of issues) {
63
+ summary[issue.type]++;
64
+ }
65
+
66
+ return {
67
+ timestamp: new Date().toISOString(),
68
+ totalEntries: entries.length,
69
+ issues,
70
+ fixed,
71
+ summary,
72
+ };
73
+ }
74
+
75
+ /**
76
+ * 检查索引一致性
77
+ */
78
+ checkIndexConsistency(entries: KnowledgeEntry[]): LintIssue[] {
79
+ const issues: LintIssue[] = [];
80
+ const index = this.store['readIndex']();
81
+
82
+ // 检查索引中的条目是否都有对应文件
83
+ for (const indexEntry of index) {
84
+ const fileEntry = this.store.get(indexEntry.id);
85
+ if (!fileEntry) {
86
+ issues.push({
87
+ type: 'index_inconsistent',
88
+ entryId: indexEntry.id,
89
+ severity: 'medium',
90
+ description: `索引条目 ${indexEntry.id} 无对应文件`,
91
+ suggestion: '从索引中移除或重建索引',
92
+ });
93
+ }
94
+ }
95
+
96
+ // 检查磁盘上的文件是否都在索引中
97
+ const indexIds = new Set(index.map(e => e.id));
98
+ const diskEntries = this.store['readEntriesFromDisk']();
99
+ for (const entry of diskEntries) {
100
+ if (!indexIds.has(entry.id)) {
101
+ issues.push({
102
+ type: 'index_inconsistent',
103
+ entryId: entry.id,
104
+ severity: 'medium',
105
+ description: `条目 ${entry.id} 不在索引中`,
106
+ suggestion: '重建索引',
107
+ });
108
+ }
109
+ }
110
+
111
+ return issues;
112
+ }
113
+
114
+ /**
115
+ * 检查孤儿条目(无引用、无验证)
116
+ */
117
+ checkOrphans(entries: KnowledgeEntry[]): LintIssue[] {
118
+ const issues: LintIssue[] = [];
119
+
120
+ for (const entry of entries) {
121
+ if (entry.maturity === 'archived') continue;
122
+
123
+ const refs = this.tracker.getReferencesForEntry(entry.id);
124
+ const hasReferences = refs.length > 0;
125
+ const hasContributors = entry.contributors.length > 0;
126
+ const hasProjects = entry.projects.length > 0;
127
+
128
+ if (!hasReferences && !hasContributors && !hasProjects && entry.maturity === 'draft') {
129
+ issues.push({
130
+ type: 'orphan',
131
+ entryId: entry.id,
132
+ severity: 'low',
133
+ description: `条目 ${entry.id} (${entry.title}) 无引用、无贡献者、无项目验证`,
134
+ suggestion: '考虑归档或标记为需要验证',
135
+ });
136
+ }
137
+ }
138
+
139
+ return issues;
140
+ }
141
+
142
+ /**
143
+ * 检查过时条目(6 月未引用的 draft)
144
+ */
145
+ checkOutdated(entries: KnowledgeEntry[]): LintIssue[] {
146
+ const issues: LintIssue[] = [];
147
+ const sixMonthsAgo = new Date();
148
+ sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6);
149
+
150
+ for (const entry of entries) {
151
+ if (entry.maturity === 'archived') continue;
152
+
153
+ const lastRef = entry.lastReferenced ? new Date(entry.lastReferenced) : null;
154
+ const created = new Date(entry.created);
155
+ const relevantDate = lastRef || created;
156
+
157
+ if (relevantDate < sixMonthsAgo && entry.maturity === 'draft') {
158
+ issues.push({
159
+ type: 'outdated',
160
+ entryId: entry.id,
161
+ severity: 'medium',
162
+ description: `条目 ${entry.id} (${entry.title}) 超过 6 个月未引用且为 draft`,
163
+ suggestion: '考虑归档或提升成熟度',
164
+ });
165
+ }
166
+ }
167
+
168
+ return issues;
169
+ }
170
+
171
+ /**
172
+ * 检查重复/相似条目
173
+ */
174
+ checkDuplicates(entries: KnowledgeEntry[]): LintIssue[] {
175
+ const issues: LintIssue[] = [];
176
+ const seen = new Map<string, KnowledgeEntry[]>();
177
+
178
+ for (const entry of entries) {
179
+ if (entry.maturity === 'archived') continue;
180
+
181
+ // 基于 title + type 去重(大小写不敏感)
182
+ const key = `${entry.type}:${entry.title.toLowerCase().trim()}`;
183
+ const existing = seen.get(key) || [];
184
+ existing.push(entry);
185
+ seen.set(key, existing);
186
+ }
187
+
188
+ for (const [key, group] of seen) {
189
+ if (group.length > 1) {
190
+ for (const entry of group) {
191
+ issues.push({
192
+ type: 'duplicate',
193
+ entryId: entry.id,
194
+ severity: 'low',
195
+ description: `条目 ${entry.id} (${entry.title}) 与同类型同标题的其他条目重复`,
196
+ suggestion: `考虑合并: ${group.map(e => e.id).join(', ')}`,
197
+ });
198
+ }
199
+ }
200
+ }
201
+
202
+ return issues;
203
+ }
204
+
205
+ /**
206
+ * 检查矛盾(同主题相反结论)
207
+ *
208
+ * 简单实现:同 tag 组合下成熟度冲突
209
+ */
210
+ checkContradictions(entries: KnowledgeEntry[]): LintIssue[] {
211
+ const issues: LintIssue[] = [];
212
+ const byTagGroup = new Map<string, KnowledgeEntry[]>();
213
+
214
+ // 按 tag 组合分组
215
+ for (const entry of entries) {
216
+ if (entry.maturity === 'archived') continue;
217
+ if (entry.tags.length === 0) continue;
218
+
219
+ const tagKey = entry.tags.sort().join(',');
220
+ const existing = byTagGroup.get(tagKey) || [];
221
+ existing.push(entry);
222
+ byTagGroup.set(tagKey, existing);
223
+ }
224
+
225
+ // 检查同 tag 组合内是否有成熟度差异大的条目
226
+ for (const [tagKey, group] of byTagGroup) {
227
+ if (group.length < 2) continue;
228
+
229
+ const maturityOrder: MaturityLevel[] = ['draft', 'verified', 'proven'];
230
+ const levels = group.map(e => maturityOrder.indexOf(e.maturity));
231
+ const maxLevel = Math.max(...levels);
232
+ const minLevel = Math.min(...levels);
233
+
234
+ // 成熟度差异 >= 2 级(如 proven vs draft)
235
+ if (maxLevel - minLevel >= 2) {
236
+ const lowEntries = group.filter((_, i) => levels[i] === minLevel);
237
+ for (const entry of lowEntries) {
238
+ issues.push({
239
+ type: 'contradiction',
240
+ entryId: entry.id,
241
+ severity: 'high',
242
+ description: `条目 ${entry.id} (${entry.title}) 与同标签的高成熟度条目存在潜在矛盾`,
243
+ suggestion: `审查标签 [${tagKey}] 下的所有条目,确认或更新`,
244
+ });
245
+ }
246
+ }
247
+ }
248
+
249
+ return issues;
250
+ }
251
+
252
+ /**
253
+ * P2.5: Validate a single entry before ingestion.
254
+ * Returns a list of issues (empty = valid, ready to ingest).
255
+ *
256
+ * Checks:
257
+ * - Content too short (< 20 chars) → reject
258
+ * - Title too vague (common stop words only) → flag
259
+ * - Contradicts a proven entry with same tags → reject
260
+ * - Near-duplicate of existing entry (title similarity > 80%) → flag merge
261
+ */
262
+ validateEntry(entry: { title: string; content: string; tags: string[]; type: string }): LintIssue[] {
263
+ const issues: LintIssue[] = [];
264
+
265
+ // Content too short
266
+ if ((entry.content || '').length < 20) {
267
+ issues.push({
268
+ type: 'orphan',
269
+ severity: 'high',
270
+ description: `Content too short (${entry.content.length} chars). LLM may have hallucinated.`,
271
+ suggestion: 'Reject — re-extract with better prompt or discard.',
272
+ });
273
+ }
274
+
275
+ // Title too vague
276
+ const vaguePatterns = /^(错误|失败|问题|异常|bug|error|fail|issue|problem|unknown|untitled)$/i;
277
+ if (vaguePatterns.test(entry.title.trim())) {
278
+ issues.push({
279
+ type: 'contradiction',
280
+ severity: 'medium',
281
+ description: `Title "${entry.title}" is too vague to be useful.`,
282
+ suggestion: 'Re-extract with root cause in title, not symptom.',
283
+ });
284
+ }
285
+
286
+ // Contradicts proven entry with same tags
287
+ if (entry.tags.length > 0) {
288
+ const allEntries = this.store.list({ excludeArchived: false });
289
+ for (const existing of allEntries) {
290
+ if (existing.maturity !== 'proven') continue;
291
+ if (existing.type !== entry.type) continue;
292
+ const sharedTags = entry.tags.filter(t => existing.tags.includes(t));
293
+ if (sharedTags.length >= 2) {
294
+ issues.push({
295
+ type: 'contradiction',
296
+ entryId: existing.id,
297
+ severity: 'high',
298
+ description: `New entry "${entry.title}" shares tags [${sharedTags.join(', ')}] with proven entry "${existing.title}" (${existing.id}). Contradiction risk.`,
299
+ suggestion: `Review against ${existing.id}. If aligned, merge. If contradictory, flag for human review.`,
300
+ });
301
+ }
302
+ }
303
+ }
304
+
305
+ // Near-duplicate title check (simple: case-insensitive substring match)
306
+ if (entry.title.length > 10) {
307
+ const allEntries = this.store.list({ excludeArchived: false });
308
+ for (const existing of allEntries) {
309
+ if (existing.id === entry.title) continue; // not same entry (entry doesn't have id yet)
310
+ const existingTitle = existing.title.toLowerCase();
311
+ const newTitle = entry.title.toLowerCase();
312
+ if (existingTitle === newTitle) {
313
+ issues.push({
314
+ type: 'duplicate',
315
+ entryId: existing.id,
316
+ severity: 'medium',
317
+ description: `Exact title match with existing entry "${existing.title}" (${existing.id}).`,
318
+ suggestion: `Merge into ${existing.id} instead of creating duplicate.`,
319
+ });
320
+ break;
321
+ }
322
+ // Check high similarity (either title contains the other)
323
+ if (existingTitle.includes(newTitle) || newTitle.includes(existingTitle)) {
324
+ issues.push({
325
+ type: 'duplicate',
326
+ entryId: existing.id,
327
+ severity: 'low',
328
+ description: `Title similarity with existing "${existing.title}" (${existing.id}).`,
329
+ suggestion: `Consider merging with ${existing.id}.`,
330
+ });
331
+ break;
332
+ }
333
+ }
334
+ }
335
+
336
+ return issues;
337
+ }
338
+
339
+ /**
340
+ * 自动修复可修复的问题
341
+ */
342
+ private autoFix(issues: LintIssue[]): number {
343
+ let fixed = 0;
344
+
345
+ for (const issue of issues) {
346
+ if (issue.type === 'index_inconsistent') {
347
+ this.store.rebuildIndex();
348
+ fixed++;
349
+ break; // rebuildIndex 修复所有索引问题
350
+ }
351
+
352
+ if (issue.type === 'outdated' && issue.entryId) {
353
+ this.store.update(issue.entryId, { maturity: 'archived' });
354
+ fixed++;
355
+ }
356
+ }
357
+
358
+ return fixed;
359
+ }
360
+ }
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Knowledge Query Engine
3
+ *
4
+ * Budget-aware query layer over KnowledgeStore.
5
+ * Supports filtering, sorting by maturity, and result caching.
6
+ */
7
+
8
+ import type {
9
+ KnowledgeEntry,
10
+ KnowledgeType,
11
+ MaturityLevel,
12
+ StorageLayer,
13
+ QueryBudget,
14
+ QueryResult,
15
+ QueryFilter,
16
+ IndexEntry,
17
+ } from './types';
18
+ import { KnowledgeStore } from './store';
19
+ import { KnowledgeLifecycle } from './lifecycle';
20
+
21
+ // ── Constants ──────────────────────────────────────────────
22
+
23
+ const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
24
+ const MATURITY_RANK: Record<MaturityLevel, number> = {
25
+ proven: 3,
26
+ verified: 2,
27
+ draft: 1,
28
+ archived: 0,
29
+ };
30
+
31
+ // ── Cache ──────────────────────────────────────────────────
32
+
33
+ interface CacheEntry {
34
+ result: QueryResult;
35
+ timestamp: number;
36
+ }
37
+
38
+ // ── Query Engine ───────────────────────────────────────────
39
+
40
+ export class KnowledgeQuery {
41
+ private store: KnowledgeStore;
42
+ private lifecycle: KnowledgeLifecycle;
43
+ private cache = new Map<string, CacheEntry>();
44
+
45
+ constructor(store: KnowledgeStore, lifecycle?: KnowledgeLifecycle) {
46
+ this.store = store;
47
+ this.lifecycle = lifecycle || new KnowledgeLifecycle(store);
48
+ }
49
+
50
+ /**
51
+ * Query knowledge entries within a token budget.
52
+ *
53
+ * - Filters by budget.focusTypes (and optional extra filter)
54
+ * - Sorts: maturity desc → lastReferenced desc
55
+ * - Truncates to budget.maxEntries and budget.maxTokens
56
+ * - Caches results per phase+budget key (TTL 5 min)
57
+ */
58
+ query(budget: QueryBudget, filter?: QueryFilter): QueryResult {
59
+ const cacheKey = this.cacheKey(budget, filter);
60
+ const cached = this.cache.get(cacheKey);
61
+ if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) {
62
+ return { ...cached.result, fromCache: true };
63
+ }
64
+
65
+ // Merge focusTypes from budget into filter
66
+ const mergedFilter: QueryFilter = {
67
+ ...filter,
68
+ types: budget.focusTypes.length > 0 ? budget.focusTypes : filter?.types,
69
+ excludeArchived: filter?.excludeArchived ?? true,
70
+ };
71
+
72
+ const candidates = this.store.list(mergedFilter);
73
+ const sorted = this.sortEntries(candidates);
74
+ const { entries, tokensUsed, truncated } = this.applyBudget(sorted, budget);
75
+
76
+ const result: QueryResult = { entries, tokensUsed, truncated, fromCache: false };
77
+ this.cache.set(cacheKey, { result, timestamp: Date.now() });
78
+
79
+ // P2a: Record references for all returned entries (drives maturity ladder)
80
+ for (const entry of entries) {
81
+ try {
82
+ this.lifecycle.recordReference(entry.id);
83
+ } catch { /* non-blocking */ }
84
+ }
85
+
86
+ return result;
87
+ }
88
+
89
+ /**
90
+ * Estimate token count for a piece of text.
91
+ * Rule of thumb: 1 CJK char ≈ 2 tokens, 1 ASCII char ≈ 0.25 tokens.
92
+ */
93
+ estimateTokens(text: string): number {
94
+ let tokens = 0;
95
+ for (const ch of text) {
96
+ // CJK Unified Ideographs + common CJK ranges
97
+ if (/[一-鿿㐀-䶿豈-﫿]/.test(ch)) {
98
+ tokens += 2;
99
+ } else {
100
+ tokens += 0.25;
101
+ }
102
+ }
103
+ return Math.ceil(tokens);
104
+ }
105
+
106
+ /** Clear the query cache. */
107
+ clearCache(): void {
108
+ this.cache.clear();
109
+ }
110
+
111
+ // ── Internal ───────────────────────────────────────────────
112
+
113
+ private sortEntries(entries: KnowledgeEntry[]): KnowledgeEntry[] {
114
+ return [...entries].sort((a, b) => {
115
+ // Primary: maturity descending
116
+ const maturityDiff = MATURITY_RANK[b.maturity] - MATURITY_RANK[a.maturity];
117
+ if (maturityDiff !== 0) return maturityDiff;
118
+ // Secondary: lastReferenced descending (most recently used first)
119
+ return (b.lastReferenced || '').localeCompare(a.lastReferenced || '');
120
+ });
121
+ }
122
+
123
+ private applyBudget(
124
+ entries: KnowledgeEntry[],
125
+ budget: QueryBudget,
126
+ ): { entries: KnowledgeEntry[]; tokensUsed: number; truncated: boolean } {
127
+ const result: KnowledgeEntry[] = [];
128
+ let tokensUsed = 0;
129
+
130
+ for (const entry of entries) {
131
+ if (result.length >= budget.maxEntries) break;
132
+
133
+ const entryTokens = this.estimateTokens(entry.content) + this.estimateTokens(entry.title);
134
+ if (tokensUsed + entryTokens > budget.maxTokens) break;
135
+
136
+ result.push(entry);
137
+ tokensUsed += entryTokens;
138
+ }
139
+
140
+ return {
141
+ entries: result,
142
+ tokensUsed,
143
+ truncated: result.length < entries.length,
144
+ };
145
+ }
146
+
147
+ private cacheKey(budget: QueryBudget, filter?: QueryFilter): string {
148
+ return JSON.stringify({ budget, filter });
149
+ }
150
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Reference Tracker
3
+ *
4
+ * Tracks which decisions reference which knowledge entries.
5
+ * Storage: append-only JSONL at .harness/knowledge/references.jsonl
6
+ */
7
+
8
+ import * as fs from 'fs';
9
+ import * as path from 'path';
10
+ import type { ReferenceRecord } from './types';
11
+ import { KnowledgeStore } from './store';
12
+
13
+ const REFERENCES_FILE = 'references.jsonl';
14
+
15
+ // ── Reference Tracker ──────────────────────────────────────
16
+
17
+ export class ReferenceTracker {
18
+ private filePath: string;
19
+ private store: KnowledgeStore;
20
+
21
+ constructor(store: KnowledgeStore, baseDir?: string) {
22
+ const dir = baseDir || '.harness/knowledge';
23
+ this.filePath = path.join(dir, REFERENCES_FILE);
24
+ this.store = store;
25
+ }
26
+
27
+ /**
28
+ * Record that a decision referenced a set of knowledge entries.
29
+ */
30
+ record(decisionId: string, entryIds: string[]): void {
31
+ const record: ReferenceRecord = {
32
+ decisionId,
33
+ entryIds,
34
+ timestamp: new Date().toISOString(),
35
+ };
36
+ fs.appendFileSync(this.filePath, JSON.stringify(record) + '\n', 'utf-8');
37
+ }
38
+
39
+ /**
40
+ * Get all decision IDs that referenced a given entry.
41
+ */
42
+ getReferencesForEntry(entryId: string): string[] {
43
+ const records = this.readAll();
44
+ return records
45
+ .filter(r => r.entryIds.includes(entryId))
46
+ .map(r => r.decisionId);
47
+ }
48
+
49
+ /**
50
+ * Get all entry IDs referenced by a given decision.
51
+ */
52
+ getReferencesForDecision(decisionId: string): string[] {
53
+ const records = this.readAll();
54
+ const record = records.find(r => r.decisionId === decisionId);
55
+ return record ? record.entryIds : [];
56
+ }
57
+
58
+ /**
59
+ * Batch-update referencedBy fields on all knowledge entries.
60
+ * Scans all reference records and populates entry.referencedBy.
61
+ */
62
+ updateReferencedBy(): void {
63
+ const records = this.readAll();
64
+ const entryToDecisions = new Map<string, Set<string>>();
65
+
66
+ for (const record of records) {
67
+ for (const entryId of record.entryIds) {
68
+ if (!entryToDecisions.has(entryId)) {
69
+ entryToDecisions.set(entryId, new Set());
70
+ }
71
+ entryToDecisions.get(entryId)!.add(record.decisionId);
72
+ }
73
+ }
74
+
75
+ for (const [entryId, decisions] of entryToDecisions) {
76
+ const entry = this.store.get(entryId);
77
+ if (entry) {
78
+ this.store.update(entryId, {
79
+ referencedBy: [...decisions],
80
+ });
81
+ }
82
+ }
83
+ }
84
+
85
+ // ── Internal ───────────────────────────────────────────────
86
+
87
+ private readAll(): ReferenceRecord[] {
88
+ if (!fs.existsSync(this.filePath)) return [];
89
+ try {
90
+ const raw = fs.readFileSync(this.filePath, 'utf-8');
91
+ return raw
92
+ .split('\n')
93
+ .filter(line => line.trim())
94
+ .map(line => JSON.parse(line) as ReferenceRecord);
95
+ } catch {
96
+ return [];
97
+ }
98
+ }
99
+ }