onto-mcp 0.3.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 (447) hide show
  1. package/.onto/authority/core-lens-registry.yaml +134 -0
  2. package/.onto/authority/core-lexicon.yaml +1562 -0
  3. package/.onto/authority/diagnostic-codes.yaml +94 -0
  4. package/.onto/domains/accounting/competency_qs.md +384 -0
  5. package/.onto/domains/accounting/concepts.md +186 -0
  6. package/.onto/domains/accounting/conciseness_rules.md +160 -0
  7. package/.onto/domains/accounting/dependency_rules.md +239 -0
  8. package/.onto/domains/accounting/domain_scope.md +213 -0
  9. package/.onto/domains/accounting/extension_cases.md +416 -0
  10. package/.onto/domains/accounting/logic_rules.md +226 -0
  11. package/.onto/domains/accounting/structure_spec.md +298 -0
  12. package/.onto/domains/accounting-kr/competency_qs.md +562 -0
  13. package/.onto/domains/accounting-kr/concepts.md +187 -0
  14. package/.onto/domains/accounting-kr/conciseness_rules.md +125 -0
  15. package/.onto/domains/accounting-kr/dependency_rules.md +93 -0
  16. package/.onto/domains/accounting-kr/domain_scope.md +140 -0
  17. package/.onto/domains/accounting-kr/extension_cases.md +343 -0
  18. package/.onto/domains/accounting-kr/logic_rules.md +160 -0
  19. package/.onto/domains/accounting-kr/structure_spec.md +85 -0
  20. package/.onto/domains/business/competency_qs.md +263 -0
  21. package/.onto/domains/business/concepts.md +200 -0
  22. package/.onto/domains/business/conciseness_rules.md +135 -0
  23. package/.onto/domains/business/dependency_rules.md +113 -0
  24. package/.onto/domains/business/domain_scope.md +240 -0
  25. package/.onto/domains/business/extension_cases.md +249 -0
  26. package/.onto/domains/business/logic_rules.md +134 -0
  27. package/.onto/domains/business/structure_spec.md +114 -0
  28. package/.onto/domains/finance/competency_qs.md +362 -0
  29. package/.onto/domains/finance/concepts.md +194 -0
  30. package/.onto/domains/finance/conciseness_rules.md +155 -0
  31. package/.onto/domains/finance/dependency_rules.md +171 -0
  32. package/.onto/domains/finance/domain_scope.md +215 -0
  33. package/.onto/domains/finance/extension_cases.md +350 -0
  34. package/.onto/domains/finance/logic_rules.md +191 -0
  35. package/.onto/domains/finance/structure_spec.md +182 -0
  36. package/.onto/domains/llm-native-development/competency_qs.md +430 -0
  37. package/.onto/domains/llm-native-development/concepts.md +242 -0
  38. package/.onto/domains/llm-native-development/conciseness_rules.md +163 -0
  39. package/.onto/domains/llm-native-development/dependency_rules.md +216 -0
  40. package/.onto/domains/llm-native-development/domain_scope.md +197 -0
  41. package/.onto/domains/llm-native-development/extension_cases.md +474 -0
  42. package/.onto/domains/llm-native-development/logic_rules.md +123 -0
  43. package/.onto/domains/llm-native-development/prompt_interface.md +49 -0
  44. package/.onto/domains/llm-native-development/structure_spec.md +245 -0
  45. package/.onto/domains/market-intelligence/competency_qs.md +274 -0
  46. package/.onto/domains/market-intelligence/concepts.md +233 -0
  47. package/.onto/domains/market-intelligence/conciseness_rules.md +165 -0
  48. package/.onto/domains/market-intelligence/dependency_rules.md +197 -0
  49. package/.onto/domains/market-intelligence/domain_scope.md +231 -0
  50. package/.onto/domains/market-intelligence/extension_cases.md +425 -0
  51. package/.onto/domains/market-intelligence/logic_rules.md +247 -0
  52. package/.onto/domains/market-intelligence/structure_spec.md +209 -0
  53. package/.onto/domains/ontology/competency_qs.md +394 -0
  54. package/.onto/domains/ontology/concepts.md +172 -0
  55. package/.onto/domains/ontology/conciseness_rules.md +134 -0
  56. package/.onto/domains/ontology/dependency_rules.md +125 -0
  57. package/.onto/domains/ontology/domain_scope.md +114 -0
  58. package/.onto/domains/ontology/extension_cases.md +501 -0
  59. package/.onto/domains/ontology/logic_rules.md +114 -0
  60. package/.onto/domains/ontology/problem_framing_profile.md +67 -0
  61. package/.onto/domains/ontology/structure_spec.md +115 -0
  62. package/.onto/domains/palantir-foundry/RESEARCH_NOTES.md +911 -0
  63. package/.onto/domains/palantir-foundry/competency_qs.md +191 -0
  64. package/.onto/domains/palantir-foundry/competitive_comparison.md +329 -0
  65. package/.onto/domains/palantir-foundry/concepts.md +197 -0
  66. package/.onto/domains/palantir-foundry/conciseness_rules.md +245 -0
  67. package/.onto/domains/palantir-foundry/dependency_rules.md +135 -0
  68. package/.onto/domains/palantir-foundry/domain_scope.md +395 -0
  69. package/.onto/domains/palantir-foundry/extension_cases.md +210 -0
  70. package/.onto/domains/palantir-foundry/logic_rules.md +172 -0
  71. package/.onto/domains/palantir-foundry/structure_spec.md +291 -0
  72. package/.onto/domains/software-engineering/competency_qs.md +538 -0
  73. package/.onto/domains/software-engineering/concepts.md +238 -0
  74. package/.onto/domains/software-engineering/conciseness_rules.md +167 -0
  75. package/.onto/domains/software-engineering/dependency_rules.md +216 -0
  76. package/.onto/domains/software-engineering/domain_scope.md +183 -0
  77. package/.onto/domains/software-engineering/extension_cases.md +551 -0
  78. package/.onto/domains/software-engineering/logic_rules.md +240 -0
  79. package/.onto/domains/software-engineering/problem_framing_profile.md +68 -0
  80. package/.onto/domains/software-engineering/structure_spec.md +185 -0
  81. package/.onto/domains/ui-design/competency_qs.md +567 -0
  82. package/.onto/domains/ui-design/concepts.md +194 -0
  83. package/.onto/domains/ui-design/conciseness_rules.md +190 -0
  84. package/.onto/domains/ui-design/dependency_rules.md +323 -0
  85. package/.onto/domains/ui-design/domain_scope.md +340 -0
  86. package/.onto/domains/ui-design/extension_cases.md +563 -0
  87. package/.onto/domains/ui-design/logic_rules.md +349 -0
  88. package/.onto/domains/ui-design/structure_spec.md +252 -0
  89. package/.onto/domains/visual-design/competency_qs.md +472 -0
  90. package/.onto/domains/visual-design/concepts.md +147 -0
  91. package/.onto/domains/visual-design/conciseness_rules.md +186 -0
  92. package/.onto/domains/visual-design/dependency_rules.md +282 -0
  93. package/.onto/domains/visual-design/domain_scope.md +290 -0
  94. package/.onto/domains/visual-design/extension_cases.md +480 -0
  95. package/.onto/domains/visual-design/logic_rules.md +232 -0
  96. package/.onto/domains/visual-design/structure_spec.md +213 -0
  97. package/.onto/principles/llm-native-development-guideline.md +401 -0
  98. package/.onto/principles/llm-runtime-interface-principles.md +665 -0
  99. package/.onto/principles/non-specialist-communication-guideline.md +74 -0
  100. package/.onto/principles/ontology-as-code-guideline.md +243 -0
  101. package/.onto/principles/ontology-as-code-naming-charter.md +130 -0
  102. package/.onto/principles/product-locality-principle.md +129 -0
  103. package/.onto/principles/productization-charter.md +569 -0
  104. package/.onto/processes/evolve/material-kind-adapter-contract.md +113 -0
  105. package/.onto/processes/reconstruct/reconstruct-boundary-contract.md +366 -0
  106. package/.onto/processes/reconstruct/source-profile-contract.md +107 -0
  107. package/.onto/processes/reconstruct/source-profiles/code.md +72 -0
  108. package/.onto/processes/reconstruct/source-profiles/database.md +74 -0
  109. package/.onto/processes/reconstruct/source-profiles/document.md +71 -0
  110. package/.onto/processes/reconstruct/source-profiles/spreadsheet.md +79 -0
  111. package/.onto/processes/review/binding-contract.md +270 -0
  112. package/.onto/processes/review/execution-preparation-artifacts.md +281 -0
  113. package/.onto/processes/review/interpretation-contract.md +245 -0
  114. package/.onto/processes/review/issue-stance-deliberation-contract.md +761 -0
  115. package/.onto/processes/review/lens-prompt-contract.md +402 -0
  116. package/.onto/processes/review/lens-registry.md +127 -0
  117. package/.onto/processes/review/pre-dispatch-contracts.md +428 -0
  118. package/.onto/processes/review/productized-live-path.md +398 -0
  119. package/.onto/processes/review/prompt-execution-runner-contract.md +187 -0
  120. package/.onto/processes/review/record-contract.md +427 -0
  121. package/.onto/processes/review/record-field-mapping.md +337 -0
  122. package/.onto/processes/review/review-context-manifest-contract.md +356 -0
  123. package/.onto/processes/review/review-execution-ux-contract.md +809 -0
  124. package/.onto/processes/review/review-target-profile-contract.md +259 -0
  125. package/.onto/processes/review/shared-phenomenon-contract.md +129 -0
  126. package/.onto/processes/review/synthesize-prompt-contract.md +343 -0
  127. package/.onto/processes/shared/target-material-kind-contract.md +198 -0
  128. package/.onto/roles/axiology.md +81 -0
  129. package/.onto/roles/conciseness.md +36 -0
  130. package/.onto/roles/coverage.md +34 -0
  131. package/.onto/roles/dependency.md +37 -0
  132. package/.onto/roles/evolution.md +35 -0
  133. package/.onto/roles/logic.md +104 -0
  134. package/.onto/roles/pragmatics.md +32 -0
  135. package/.onto/roles/semantics.md +36 -0
  136. package/.onto/roles/structure.md +33 -0
  137. package/.onto/roles/synthesize.md +92 -0
  138. package/AGENTS.md +240 -0
  139. package/CLAUDE.md +39 -0
  140. package/README.md +287 -0
  141. package/bin/onto +92 -0
  142. package/dist/cli.js +101 -0
  143. package/dist/core-api/reconstruct-api.js +222 -0
  144. package/dist/core-api/review-api.js +1271 -0
  145. package/dist/core-runtime/cli/assemble-review-record.js +431 -0
  146. package/dist/core-runtime/cli/bootstrap-review-binding.js +186 -0
  147. package/dist/core-runtime/cli/codex-nested-dispatch.js +226 -0
  148. package/dist/core-runtime/cli/codex-nested-dispatch.test.js +390 -0
  149. package/dist/core-runtime/cli/codex-nested-teamlead-executor.js +464 -0
  150. package/dist/core-runtime/cli/codex-nested-teamlead-executor.test.js +335 -0
  151. package/dist/core-runtime/cli/codex-review-unit-executor.js +228 -0
  152. package/dist/core-runtime/cli/complete-review-session.js +64 -0
  153. package/dist/core-runtime/cli/complexity-assessment.js +153 -0
  154. package/dist/core-runtime/cli/coordinator-helpers.js +583 -0
  155. package/dist/core-runtime/cli/coordinator-state-machine-deliberation.test.js +167 -0
  156. package/dist/core-runtime/cli/coordinator-state-machine.js +794 -0
  157. package/dist/core-runtime/cli/e2e-codex-multi-agent-fixes.test.js +615 -0
  158. package/dist/core-runtime/cli/e2e-start-review-session.test.js +312 -0
  159. package/dist/core-runtime/cli/health.js +44 -0
  160. package/dist/core-runtime/cli/inline-http-review-unit-executor.js +656 -0
  161. package/dist/core-runtime/cli/inline-http-review-unit-executor.test.js +567 -0
  162. package/dist/core-runtime/cli/materialize-review-execution-preparation.js +104 -0
  163. package/dist/core-runtime/cli/materialize-review-prompt-packets.js +952 -0
  164. package/dist/core-runtime/cli/migrate-session-roots.js +118 -0
  165. package/dist/core-runtime/cli/mock-review-unit-executor.js +285 -0
  166. package/dist/core-runtime/cli/onto-tools.js +369 -0
  167. package/dist/core-runtime/cli/prepare-review-session.js +272 -0
  168. package/dist/core-runtime/cli/render-review-final-output.js +350 -0
  169. package/dist/core-runtime/cli/repo-layout-migration-replace.smoke.test.js +106 -0
  170. package/dist/core-runtime/cli/review-invoke-auto-resolution.test.js +268 -0
  171. package/dist/core-runtime/cli/review-invoke-coordinator-topology.test.js +136 -0
  172. package/dist/core-runtime/cli/review-invoke-resolver-caching.test.js +201 -0
  173. package/dist/core-runtime/cli/review-invoke-topology-dispatch.test.js +192 -0
  174. package/dist/core-runtime/cli/review-invoke.js +2030 -0
  175. package/dist/core-runtime/cli/run-review-prompt-execution.js +2152 -0
  176. package/dist/core-runtime/cli/session-root-guard.js +168 -0
  177. package/dist/core-runtime/cli/spawn-watcher.js +173 -0
  178. package/dist/core-runtime/cli/spawn-watcher.test.js +457 -0
  179. package/dist/core-runtime/cli/start-review-session.js +68 -0
  180. package/dist/core-runtime/cli/strip-wrapping-code-fence.js +56 -0
  181. package/dist/core-runtime/cli/strip-wrapping-code-fence.test.js +79 -0
  182. package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.js +412 -0
  183. package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.test.js +351 -0
  184. package/dist/core-runtime/cli/topology-executor-mapping.js +139 -0
  185. package/dist/core-runtime/cli/topology-executor-mapping.test.js +173 -0
  186. package/dist/core-runtime/cli/write-review-interpretation.js +81 -0
  187. package/dist/core-runtime/config/onto-config-cli.js +278 -0
  188. package/dist/core-runtime/config/onto-config-key-path.js +288 -0
  189. package/dist/core-runtime/config/onto-config-key-path.test.js +195 -0
  190. package/dist/core-runtime/config/onto-config-preview.js +108 -0
  191. package/dist/core-runtime/config/onto-config-preview.test.js +132 -0
  192. package/dist/core-runtime/discovery/config-chain.js +118 -0
  193. package/dist/core-runtime/discovery/config-chain.test.js +103 -0
  194. package/dist/core-runtime/discovery/config-profile.js +199 -0
  195. package/dist/core-runtime/discovery/config-profile.test.js +233 -0
  196. package/dist/core-runtime/discovery/host-detection.js +33 -0
  197. package/dist/core-runtime/discovery/host-detection.test.js +186 -0
  198. package/dist/core-runtime/discovery/installation-paths.js +21 -0
  199. package/dist/core-runtime/discovery/installation-paths.test.js +65 -0
  200. package/dist/core-runtime/discovery/lens-registry.js +60 -0
  201. package/dist/core-runtime/discovery/lens-registry.test.js +81 -0
  202. package/dist/core-runtime/discovery/onto-home.js +71 -0
  203. package/dist/core-runtime/discovery/path-normalization.js +28 -0
  204. package/dist/core-runtime/discovery/path-normalization.test.js +22 -0
  205. package/dist/core-runtime/discovery/plugin-path.js +72 -0
  206. package/dist/core-runtime/discovery/plugin-path.test.js +95 -0
  207. package/dist/core-runtime/discovery/project-root.js +47 -0
  208. package/dist/core-runtime/discovery/settings-chain.js +353 -0
  209. package/dist/core-runtime/discovery/walk-up.js +17 -0
  210. package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.js +344 -0
  211. package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.test.js +915 -0
  212. package/dist/core-runtime/evolve/adapters/code-product/compile/compile.js +564 -0
  213. package/dist/core-runtime/evolve/adapters/code-product/compile/compile.test.js +708 -0
  214. package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.js +165 -0
  215. package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.test.js +227 -0
  216. package/dist/core-runtime/evolve/adapters/code-product/validators/validate.js +59 -0
  217. package/dist/core-runtime/evolve/adapters/code-product/validators/validate.test.js +205 -0
  218. package/dist/core-runtime/evolve/adapters/methodology/adapter.js +16 -0
  219. package/dist/core-runtime/evolve/adapters/methodology/adapter.test.js +9 -0
  220. package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.js +298 -0
  221. package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.test.js +70 -0
  222. package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.js +46 -0
  223. package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.test.js +73 -0
  224. package/dist/core-runtime/evolve/adapters/registry.js +47 -0
  225. package/dist/core-runtime/evolve/adapters/registry.test.js +67 -0
  226. package/dist/core-runtime/evolve/cli.js +256 -0
  227. package/dist/core-runtime/evolve/commands/align.js +194 -0
  228. package/dist/core-runtime/evolve/commands/align.test.js +82 -0
  229. package/dist/core-runtime/evolve/commands/apply.js +161 -0
  230. package/dist/core-runtime/evolve/commands/apply.test.js +138 -0
  231. package/dist/core-runtime/evolve/commands/close.js +39 -0
  232. package/dist/core-runtime/evolve/commands/close.test.js +99 -0
  233. package/dist/core-runtime/evolve/commands/defer.js +40 -0
  234. package/dist/core-runtime/evolve/commands/defer.test.js +134 -0
  235. package/dist/core-runtime/evolve/commands/draft.js +323 -0
  236. package/dist/core-runtime/evolve/commands/draft.test.js +178 -0
  237. package/dist/core-runtime/evolve/commands/e2e-evolve-full-cycle.test.js +208 -0
  238. package/dist/core-runtime/evolve/commands/error-messages.js +125 -0
  239. package/dist/core-runtime/evolve/commands/error-messages.test.js +167 -0
  240. package/dist/core-runtime/evolve/commands/propose-align.js +222 -0
  241. package/dist/core-runtime/evolve/commands/propose-align.test.js +136 -0
  242. package/dist/core-runtime/evolve/commands/reconstruct.js +330 -0
  243. package/dist/core-runtime/evolve/commands/reconstruct.test.js +278 -0
  244. package/dist/core-runtime/evolve/commands/shared.js +22 -0
  245. package/dist/core-runtime/evolve/commands/stale-check.js +103 -0
  246. package/dist/core-runtime/evolve/commands/stale-check.test.js +84 -0
  247. package/dist/core-runtime/evolve/commands/start.js +887 -0
  248. package/dist/core-runtime/evolve/commands/start.test.js +396 -0
  249. package/dist/core-runtime/evolve/config/project-config.js +99 -0
  250. package/dist/core-runtime/evolve/config/project-config.test.js +170 -0
  251. package/dist/core-runtime/evolve/renderers/align-packet.js +280 -0
  252. package/dist/core-runtime/evolve/renderers/align-packet.test.js +332 -0
  253. package/dist/core-runtime/evolve/renderers/draft-packet.js +303 -0
  254. package/dist/core-runtime/evolve/renderers/draft-packet.test.js +377 -0
  255. package/dist/core-runtime/evolve/renderers/format.js +5 -0
  256. package/dist/core-runtime/evolve/renderers/scope-md.js +237 -0
  257. package/dist/core-runtime/evolve/renderers/scope-md.test.js +306 -0
  258. package/dist/core-runtime/govern/cli.js +369 -0
  259. package/dist/core-runtime/govern/cli.test.js +314 -0
  260. package/dist/core-runtime/govern/drift-engine.js +103 -0
  261. package/dist/core-runtime/govern/drift-engine.test.js +319 -0
  262. package/dist/core-runtime/govern/promote-principle.js +206 -0
  263. package/dist/core-runtime/govern/promote-principle.test.js +368 -0
  264. package/dist/core-runtime/govern/queue.js +81 -0
  265. package/dist/core-runtime/govern/types.js +16 -0
  266. package/dist/core-runtime/install/cli.js +530 -0
  267. package/dist/core-runtime/install/detect.js +128 -0
  268. package/dist/core-runtime/install/detect.test.js +155 -0
  269. package/dist/core-runtime/install/gitignore-update.js +74 -0
  270. package/dist/core-runtime/install/gitignore-update.test.js +64 -0
  271. package/dist/core-runtime/install/install-integration.test.js +373 -0
  272. package/dist/core-runtime/install/prompts.js +389 -0
  273. package/dist/core-runtime/install/prompts.test.js +293 -0
  274. package/dist/core-runtime/install/types.js +26 -0
  275. package/dist/core-runtime/install/validation.js +295 -0
  276. package/dist/core-runtime/install/validation.test.js +313 -0
  277. package/dist/core-runtime/install/writer.js +254 -0
  278. package/dist/core-runtime/install/writer.test.js +218 -0
  279. package/dist/core-runtime/learning/extractor.js +461 -0
  280. package/dist/core-runtime/learning/feedback.js +179 -0
  281. package/dist/core-runtime/learning/health-report.js +165 -0
  282. package/dist/core-runtime/learning/health-report.test.js +169 -0
  283. package/dist/core-runtime/learning/loader.js +388 -0
  284. package/dist/core-runtime/learning/loader.test.js +102 -0
  285. package/dist/core-runtime/learning/promote/apply-state.js +240 -0
  286. package/dist/core-runtime/learning/promote/audit-obligation.js +195 -0
  287. package/dist/core-runtime/learning/promote/collector.js +432 -0
  288. package/dist/core-runtime/learning/promote/degraded-state.js +125 -0
  289. package/dist/core-runtime/learning/promote/domain-doc-proposer.js +166 -0
  290. package/dist/core-runtime/learning/promote/e2e-promote.test.js +6385 -0
  291. package/dist/core-runtime/learning/promote/health-snapshot.js +150 -0
  292. package/dist/core-runtime/learning/promote/insight-reclassifier.js +544 -0
  293. package/dist/core-runtime/learning/promote/judgment-auditor.js +517 -0
  294. package/dist/core-runtime/learning/promote/panel-reviewer.js +1158 -0
  295. package/dist/core-runtime/learning/promote/promote-executor.js +1675 -0
  296. package/dist/core-runtime/learning/promote/promoter.js +307 -0
  297. package/dist/core-runtime/learning/promote/retirement.js +122 -0
  298. package/dist/core-runtime/learning/promote/types.js +23 -0
  299. package/dist/core-runtime/learning/prompt-sections.js +51 -0
  300. package/dist/core-runtime/learning/shared/artifact-registry-init.js +45 -0
  301. package/dist/core-runtime/learning/shared/artifact-registry.js +254 -0
  302. package/dist/core-runtime/learning/shared/audit-obligation-kernel.js +73 -0
  303. package/dist/core-runtime/learning/shared/audit-state.js +99 -0
  304. package/dist/core-runtime/learning/shared/duplicate-check.js +28 -0
  305. package/dist/core-runtime/learning/shared/llm-caller.js +831 -0
  306. package/dist/core-runtime/learning/shared/llm-caller.test.js +601 -0
  307. package/dist/core-runtime/learning/shared/llm-tool-loop.js +393 -0
  308. package/dist/core-runtime/learning/shared/mode.js +25 -0
  309. package/dist/core-runtime/learning/shared/paths.js +84 -0
  310. package/dist/core-runtime/learning/shared/paths.test.js +79 -0
  311. package/dist/core-runtime/learning/shared/patterns.js +37 -0
  312. package/dist/core-runtime/learning/shared/recoverability.js +355 -0
  313. package/dist/core-runtime/learning/shared/recovery-context.js +374 -0
  314. package/dist/core-runtime/learning/shared/scope.js +1 -0
  315. package/dist/core-runtime/learning/shared/semantic-classifier.js +94 -0
  316. package/dist/core-runtime/learning/shared/specs/apply-execution-state-spec.js +42 -0
  317. package/dist/core-runtime/learning/shared/specs/audit-state-spec.js +37 -0
  318. package/dist/core-runtime/learning/shared/specs/backup-metadata-spec.js +39 -0
  319. package/dist/core-runtime/learning/shared/specs/emergency-log-spec.js +41 -0
  320. package/dist/core-runtime/learning/shared/specs/layout-version-spec.js +38 -0
  321. package/dist/core-runtime/learning/shared/specs/promote-decisions-spec.js +43 -0
  322. package/dist/core-runtime/learning/shared/specs/promote-report-spec.js +113 -0
  323. package/dist/core-runtime/learning/shared/specs/prune-log-spec.js +36 -0
  324. package/dist/core-runtime/learning/shared/specs/recovery-resolution-spec.js +48 -0
  325. package/dist/core-runtime/learning/shared/specs/restore-manifest-spec.js +43 -0
  326. package/dist/core-runtime/learning/shared/specs/spec-helpers.js +64 -0
  327. package/dist/core-runtime/learning/usage-tracker.js +190 -0
  328. package/dist/core-runtime/learning/usage-tracker.test.js +176 -0
  329. package/dist/core-runtime/llm/llm-caller.js +649 -0
  330. package/dist/core-runtime/llm/llm-tool-loop.js +401 -0
  331. package/dist/core-runtime/llm/model-switcher.js +62 -0
  332. package/dist/core-runtime/logger.js +22 -0
  333. package/dist/core-runtime/onboard/detect-review-axes.js +122 -0
  334. package/dist/core-runtime/onboard/detect-review-axes.test.js +127 -0
  335. package/dist/core-runtime/onboard/write-review-block.js +188 -0
  336. package/dist/core-runtime/onboard/write-review-block.test.js +240 -0
  337. package/dist/core-runtime/readers/brownfield-builder.js +150 -0
  338. package/dist/core-runtime/readers/brownfield-builder.test.js +136 -0
  339. package/dist/core-runtime/readers/code-chunk-collector.js +53 -0
  340. package/dist/core-runtime/readers/code-chunk-collector.test.js +136 -0
  341. package/dist/core-runtime/readers/file-utils.js +240 -0
  342. package/dist/core-runtime/readers/file-utils.test.js +146 -0
  343. package/dist/core-runtime/readers/lexicon-citation-check.js +93 -0
  344. package/dist/core-runtime/readers/lexicon-citation-check.test.js +77 -0
  345. package/dist/core-runtime/readers/mcp-figma.js +30 -0
  346. package/dist/core-runtime/readers/mcp-figma.test.js +82 -0
  347. package/dist/core-runtime/readers/mcp-generic.js +31 -0
  348. package/dist/core-runtime/readers/mcp-generic.test.js +76 -0
  349. package/dist/core-runtime/readers/ontology-index.js +148 -0
  350. package/dist/core-runtime/readers/ontology-index.test.js +245 -0
  351. package/dist/core-runtime/readers/ontology-query.js +168 -0
  352. package/dist/core-runtime/readers/ontology-query.test.js +311 -0
  353. package/dist/core-runtime/readers/ontology-resolve.js +48 -0
  354. package/dist/core-runtime/readers/ontology-resolve.test.js +48 -0
  355. package/dist/core-runtime/readers/patterns/index.js +7 -0
  356. package/dist/core-runtime/readers/review-log.js +213 -0
  357. package/dist/core-runtime/readers/review-log.test.js +313 -0
  358. package/dist/core-runtime/readers/scan-local.js +102 -0
  359. package/dist/core-runtime/readers/scan-local.test.js +102 -0
  360. package/dist/core-runtime/readers/scan-tarball.js +121 -0
  361. package/dist/core-runtime/readers/scan-tarball.test.js +283 -0
  362. package/dist/core-runtime/readers/scan-vault.js +34 -0
  363. package/dist/core-runtime/readers/scan-vault.test.js +81 -0
  364. package/dist/core-runtime/readers/types.js +42 -0
  365. package/dist/core-runtime/readers/types.test.js +94 -0
  366. package/dist/core-runtime/readers/viewpoint-collectors.js +229 -0
  367. package/dist/core-runtime/reconstruct/artifact-types.js +1 -0
  368. package/dist/core-runtime/reconstruct/directive-validation.js +123 -0
  369. package/dist/core-runtime/reconstruct/materialize-preparation.js +251 -0
  370. package/dist/core-runtime/reconstruct/record.js +198 -0
  371. package/dist/core-runtime/reconstruct/run.js +578 -0
  372. package/dist/core-runtime/reconstruct/seed-candidate-validation.js +356 -0
  373. package/dist/core-runtime/reconstruct/source-observations.js +62 -0
  374. package/dist/core-runtime/reconstruct/source-profiles.js +73 -0
  375. package/dist/core-runtime/release-channel/release-channel.js +90 -0
  376. package/dist/core-runtime/review/artifact-types.js +13 -0
  377. package/dist/core-runtime/review/citation-audit.js +204 -0
  378. package/dist/core-runtime/review/citation-audit.test.js +165 -0
  379. package/dist/core-runtime/review/controlled-lens-deliberation.js +125 -0
  380. package/dist/core-runtime/review/execution-plan-resolver.js +247 -0
  381. package/dist/core-runtime/review/execution-plan-resolver.test.js +243 -0
  382. package/dist/core-runtime/review/execution-topology-resolver-axis-first.test.js +246 -0
  383. package/dist/core-runtime/review/execution-topology-resolver.js +401 -0
  384. package/dist/core-runtime/review/execution-topology-resolver.test.js +315 -0
  385. package/dist/core-runtime/review/failure-records.js +57 -0
  386. package/dist/core-runtime/review/inline-context-embedder.js +141 -0
  387. package/dist/core-runtime/review/inline-context-embedder.test.js +154 -0
  388. package/dist/core-runtime/review/issue-artifact-runtime.js +859 -0
  389. package/dist/core-runtime/review/legacy-mode-policy.js +88 -0
  390. package/dist/core-runtime/review/lens-completion-policy.js +17 -0
  391. package/dist/core-runtime/review/materializers-effort-persist.test.js +79 -0
  392. package/dist/core-runtime/review/materializers.js +963 -0
  393. package/dist/core-runtime/review/ontology-path-classifier.js +179 -0
  394. package/dist/core-runtime/review/ontology-path-classifier.test.js +216 -0
  395. package/dist/core-runtime/review/packet-boundary-policy.js +215 -0
  396. package/dist/core-runtime/review/packet-boundary-policy.test.js +107 -0
  397. package/dist/core-runtime/review/participating-lens-paths.js +61 -0
  398. package/dist/core-runtime/review/participating-lens-paths.test.js +73 -0
  399. package/dist/core-runtime/review/review-artifact-utils.js +287 -0
  400. package/dist/core-runtime/review/review-config-legacy-translate.js +244 -0
  401. package/dist/core-runtime/review/review-config-legacy-translate.test.js +161 -0
  402. package/dist/core-runtime/review/review-config-validator.js +289 -0
  403. package/dist/core-runtime/review/review-config-validator.test.js +236 -0
  404. package/dist/core-runtime/review/review-execution-profile.js +193 -0
  405. package/dist/core-runtime/review/review-execution-route.js +52 -0
  406. package/dist/core-runtime/review/review-progress-contract.js +123 -0
  407. package/dist/core-runtime/review/review-record-validation.js +251 -0
  408. package/dist/core-runtime/review/review-result-classification.js +379 -0
  409. package/dist/core-runtime/review/review-state-machine.js +39 -0
  410. package/dist/core-runtime/review/route-visibility.js +125 -0
  411. package/dist/core-runtime/review/shape-pipeline-audit.test.js +311 -0
  412. package/dist/core-runtime/review/shape-to-topology-id.js +117 -0
  413. package/dist/core-runtime/review/shape-to-topology-id.test.js +132 -0
  414. package/dist/core-runtime/review/topology-shape-derivation.js +155 -0
  415. package/dist/core-runtime/review/topology-shape-derivation.test.js +195 -0
  416. package/dist/core-runtime/scope-runtime/constants.js +12 -0
  417. package/dist/core-runtime/scope-runtime/constraint-pool.js +166 -0
  418. package/dist/core-runtime/scope-runtime/constraint-pool.test.js +674 -0
  419. package/dist/core-runtime/scope-runtime/domain-validation-log.js +135 -0
  420. package/dist/core-runtime/scope-runtime/domain-validation-log.test.js +156 -0
  421. package/dist/core-runtime/scope-runtime/eval-persistence.js +65 -0
  422. package/dist/core-runtime/scope-runtime/eval-persistence.test.js +84 -0
  423. package/dist/core-runtime/scope-runtime/event-pipeline.js +64 -0
  424. package/dist/core-runtime/scope-runtime/event-pipeline.test.js +450 -0
  425. package/dist/core-runtime/scope-runtime/event-store.js +39 -0
  426. package/dist/core-runtime/scope-runtime/event-store.test.js +95 -0
  427. package/dist/core-runtime/scope-runtime/gate-guard.js +348 -0
  428. package/dist/core-runtime/scope-runtime/gate-guard.test.js +1047 -0
  429. package/dist/core-runtime/scope-runtime/hash.js +4 -0
  430. package/dist/core-runtime/scope-runtime/hash.test.js +33 -0
  431. package/dist/core-runtime/scope-runtime/id.js +4 -0
  432. package/dist/core-runtime/scope-runtime/id.test.js +17 -0
  433. package/dist/core-runtime/scope-runtime/reducer.js +297 -0
  434. package/dist/core-runtime/scope-runtime/reducer.test.js +759 -0
  435. package/dist/core-runtime/scope-runtime/scope-manager.js +161 -0
  436. package/dist/core-runtime/scope-runtime/state-machine.js +309 -0
  437. package/dist/core-runtime/scope-runtime/state-machine.test.js +704 -0
  438. package/dist/core-runtime/scope-runtime/types.js +116 -0
  439. package/dist/core-runtime/scope-runtime/types.test.js +69 -0
  440. package/dist/core-runtime/target-material-kind.js +256 -0
  441. package/dist/core-runtime/translate/render-for-user.js +169 -0
  442. package/dist/core-runtime/translate/render-for-user.test.js +122 -0
  443. package/dist/mcp/server.js +1011 -0
  444. package/dist/mcp/tool-schemas.js +93 -0
  445. package/dist/providers/capability-contract.js +1 -0
  446. package/package.json +68 -0
  447. package/settings.example.json +33 -0
@@ -0,0 +1,127 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { detectReviewAxes } from "./detect-review-axes.js";
3
+ // ---------------------------------------------------------------------------
4
+ // detectReviewAxes — Review UX Redesign P4 (2026-04-21)
5
+ // ---------------------------------------------------------------------------
6
+ //
7
+ // These tests exercise the projection of env signals into the onboard
8
+ // axis vocabulary. The underlying detection helpers (from discovery/) are
9
+ // covered by their own suite; here we only verify:
10
+ //
11
+ // (1) Host priority ordering — Claude Code > Codex CLI > plain.
12
+ // (2) agent_teams_available reads CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS.
13
+ // (3) litellm_endpoint returns the URL string (not just a boolean).
14
+ // (4) codex_available is sourced from the shared discovery helper.
15
+ //
16
+ // The codex binary / auth.json probe is filesystem-backed, so we mock
17
+ // `detectCodexBinaryAvailable` from the discovery module to keep the tests
18
+ // hermetic.
19
+ // ---------------------------------------------------------------------------
20
+ vi.mock("../discovery/host-detection.js", async (importOriginal) => {
21
+ const actual = (await importOriginal());
22
+ return {
23
+ ...actual,
24
+ // Override only the filesystem-dependent probe. The env-signal helpers
25
+ // remain real so we can control behaviour via process.env.
26
+ detectCodexBinaryAvailable: vi.fn(() => false),
27
+ };
28
+ });
29
+ const savedEnv = {};
30
+ const VOLATILE_ENV_KEYS = [
31
+ "CLAUDECODE",
32
+ "CLAUDE_PROJECT_DIR",
33
+ "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS",
34
+ "CODEX_THREAD_ID",
35
+ "CODEX_CI",
36
+ "LITELLM_BASE_URL",
37
+ ];
38
+ beforeEach(() => {
39
+ for (const key of VOLATILE_ENV_KEYS) {
40
+ savedEnv[key] = process.env[key];
41
+ delete process.env[key];
42
+ }
43
+ });
44
+ afterEach(() => {
45
+ for (const key of VOLATILE_ENV_KEYS) {
46
+ const original = savedEnv[key];
47
+ if (original === undefined) {
48
+ delete process.env[key];
49
+ }
50
+ else {
51
+ process.env[key] = original;
52
+ }
53
+ }
54
+ vi.resetAllMocks();
55
+ });
56
+ describe("detectReviewAxes — host category", () => {
57
+ it("returns plain-terminal when no host signal is present", () => {
58
+ const result = detectReviewAxes();
59
+ expect(result.detected.host).toBe("plain-terminal");
60
+ });
61
+ it("returns claude-code when CLAUDECODE=1", () => {
62
+ process.env.CLAUDECODE = "1";
63
+ expect(detectReviewAxes().detected.host).toBe("claude-code");
64
+ });
65
+ it("returns claude-code when CLAUDE_PROJECT_DIR is set", () => {
66
+ process.env.CLAUDE_PROJECT_DIR = "/tmp/proj";
67
+ expect(detectReviewAxes().detected.host).toBe("claude-code");
68
+ });
69
+ it("returns codex-cli when CODEX_THREAD_ID is set", () => {
70
+ process.env.CODEX_THREAD_ID = "thr-123";
71
+ expect(detectReviewAxes().detected.host).toBe("codex-cli");
72
+ });
73
+ it("prefers claude-code over codex-cli when both signals are present", () => {
74
+ // An inner Codex exec inside a Claude Code session — onboard context
75
+ // is Claude Code; codex availability is surfaced separately.
76
+ process.env.CLAUDECODE = "1";
77
+ process.env.CODEX_THREAD_ID = "thr-123";
78
+ expect(detectReviewAxes().detected.host).toBe("claude-code");
79
+ });
80
+ });
81
+ describe("detectReviewAxes — agent_teams_available (strict =1)", () => {
82
+ // The resolver uses `env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === "1"`.
83
+ // Onboard MUST use the same check so the two layers never disagree on
84
+ // whether teams are available — otherwise onboard writes a config the
85
+ // runtime silently rejects (P3 would degrade it, violating the UX
86
+ // promise that "what onboard accepts is what runs").
87
+ it("is false when env var is absent", () => {
88
+ expect(detectReviewAxes().detected.agent_teams_available).toBe(false);
89
+ });
90
+ it('is true only when CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === "1"', () => {
91
+ process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = "1";
92
+ expect(detectReviewAxes().detected.agent_teams_available).toBe(true);
93
+ });
94
+ it('is false for truthy-looking strings that are not "1"', () => {
95
+ // These would pass a naive Boolean() check but must NOT activate teams.
96
+ // The resolver rejects them; onboard must match.
97
+ for (const value of ["true", "yes", "on", "enabled", "TRUE", "2"]) {
98
+ process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = value;
99
+ expect(detectReviewAxes().detected.agent_teams_available).toBe(false);
100
+ }
101
+ });
102
+ it('is false for falsy-looking strings ("0", "false", empty)', () => {
103
+ for (const value of ["0", "false", ""]) {
104
+ process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = value;
105
+ expect(detectReviewAxes().detected.agent_teams_available).toBe(false);
106
+ }
107
+ });
108
+ });
109
+ describe("detectReviewAxes — litellm_endpoint", () => {
110
+ it("is null when LITELLM_BASE_URL is unset", () => {
111
+ expect(detectReviewAxes().detected.litellm_endpoint).toBeNull();
112
+ });
113
+ it("returns the URL string when LITELLM_BASE_URL is set", () => {
114
+ process.env.LITELLM_BASE_URL = "http://localhost:4000";
115
+ expect(detectReviewAxes().detected.litellm_endpoint).toBe("http://localhost:4000");
116
+ });
117
+ });
118
+ describe("detectReviewAxes — codex_available", () => {
119
+ it("surfaces the discovery helper verdict (mocked false by default)", async () => {
120
+ const mod = await import("../discovery/host-detection.js");
121
+ const spy = vi.mocked(mod.detectCodexBinaryAvailable);
122
+ spy.mockReturnValue(false);
123
+ expect(detectReviewAxes().detected.codex_available).toBe(false);
124
+ spy.mockReturnValue(true);
125
+ expect(detectReviewAxes().detected.codex_available).toBe(true);
126
+ });
127
+ });
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Review UX Redesign P4 — write/update the `review:` block in `.onto/config.yml`.
3
+ *
4
+ * # What this module is
5
+ *
6
+ * A small helper that takes a validated `OntoReviewConfig` plus a path to
7
+ * an `.onto/config.yml` file and either (a) adds a `review:` block to the
8
+ * file or (b) replaces an existing one.
9
+ *
10
+ * # Why it exists
11
+ *
12
+ * Onboard stage 7 (design doc §5.2) writes the user's chosen review axes
13
+ * into `.onto/config.yml`. Without a dedicated seat this would require the
14
+ * prose to embed YAML serialization instructions, which is error-prone — a
15
+ * stray indent produces a silently invalid config. Centralizing the write
16
+ * path means the onboard prose can describe the intent ("record the user's
17
+ * answers in the review block") and delegate formatting to this helper.
18
+ *
19
+ * We use `yaml`'s `parseDocument` / `Document` API (not `parse` +
20
+ * `stringify`) because the document round-trip preserves comments and
21
+ * formatting where the existing file has them. That matters for configs
22
+ * authored by humans — they often annotate fields with rationale.
23
+ *
24
+ * # How it relates
25
+ *
26
+ * - Consumes: `OntoReviewConfig` type from `discovery/config-chain.ts`.
27
+ * - Validates with: `validateReviewConfig` from
28
+ * `review/review-config-validator.ts` — we re-validate to catch caller
29
+ * errors early (the onboard prose is a weak integrator).
30
+ * - Exposed via: `npm run onboard:write-review-block -- <path> <json>`.
31
+ *
32
+ * # Guarantees
33
+ *
34
+ * 1. Existing top-level fields are preserved in order.
35
+ * 2. Comments attached to preserved fields survive the round-trip.
36
+ * 3. If the file does not exist, it is created with a minimal document
37
+ * containing only the `review:` block.
38
+ * 4. If the input is not a valid `OntoReviewConfig`, the function returns a
39
+ * result object with `ok: false` and no write is performed.
40
+ */
41
+ import fs from "node:fs";
42
+ import path from "node:path";
43
+ import { Document, parseDocument } from "yaml";
44
+ import { validateReviewConfig, } from "../review/review-config-validator.js";
45
+ /**
46
+ * Write (or update) the `review:` block in the given config file.
47
+ *
48
+ * The function re-validates `review` with `validateReviewConfig` before
49
+ * touching the file — if validation fails, nothing is written and the
50
+ * caller receives the structured error list.
51
+ */
52
+ export function writeReviewBlock(configPath, review) {
53
+ // Re-validate. The type system alone cannot catch callers who constructed
54
+ // the object manually from JSON input (the most common P4 path — the
55
+ // onboard prose builds the object from interactive answers).
56
+ const validation = validateReviewConfig(review);
57
+ if (!validation.ok) {
58
+ return { ok: false, errors: validation.errors };
59
+ }
60
+ const absolute = path.resolve(configPath);
61
+ const exists = fs.existsSync(absolute);
62
+ // Load the existing document (or a fresh empty one). `parseDocument`
63
+ // returns a `Document` node the YAML library can mutate and re-serialize
64
+ // while preserving source formatting where practical.
65
+ let doc;
66
+ if (exists) {
67
+ const raw = fs.readFileSync(absolute, "utf8");
68
+ doc = parseDocument(raw, { keepSourceTokens: false });
69
+ }
70
+ else {
71
+ // Ensure the parent directory exists — `.onto/` may not be present on
72
+ // a brand-new project until onboard creates it.
73
+ fs.mkdirSync(path.dirname(absolute), { recursive: true });
74
+ doc = new Document({});
75
+ }
76
+ // Detect the prior state of the document so we can report it back to the
77
+ // onboard prose (for the user-facing summary).
78
+ const replacedExistingBlock = exists && doc.has("review");
79
+ // The yaml library accepts a plain object for `set` — it converts that
80
+ // into the internal Node graph. We filter out undefined leaves so the
81
+ // output does not carry `key: null` artifacts for absent axes.
82
+ const serializable = pruneUndefined(review);
83
+ doc.set("review", serializable);
84
+ const serialized = doc.toString();
85
+ fs.writeFileSync(absolute, serialized, "utf8");
86
+ return {
87
+ ok: true,
88
+ path: absolute,
89
+ created: !exists,
90
+ replacedExistingBlock,
91
+ };
92
+ }
93
+ // ---------------------------------------------------------------------------
94
+ // Internal helpers
95
+ // ---------------------------------------------------------------------------
96
+ /**
97
+ * Strip `undefined` leaves from a nested object. The `yaml` library would
98
+ * otherwise serialize them as `null`, which is semantically different from
99
+ * "absent" in the review block (an absent key = use review defaults).
100
+ */
101
+ function pruneUndefined(input) {
102
+ if (input === null || input === undefined)
103
+ return input;
104
+ if (Array.isArray(input)) {
105
+ return input.map((v) => pruneUndefined(v));
106
+ }
107
+ if (typeof input !== "object")
108
+ return input;
109
+ const out = {};
110
+ for (const [key, value] of Object.entries(input)) {
111
+ if (value === undefined)
112
+ continue;
113
+ out[key] = pruneUndefined(value);
114
+ }
115
+ return out;
116
+ }
117
+ // ---------------------------------------------------------------------------
118
+ // CLI entry — `npm run onboard:write-review-block -- <path> <json>`
119
+ // ---------------------------------------------------------------------------
120
+ function printHelp() {
121
+ const lines = [
122
+ "onboard:write-review-block",
123
+ "",
124
+ "Write or update the `review:` block in a .onto/config.yml file.",
125
+ "",
126
+ "Usage:",
127
+ " npm run onboard:write-review-block -- <config-path> <review-json>",
128
+ " npm run onboard:write-review-block -- --help",
129
+ "",
130
+ "Arguments:",
131
+ " <config-path> Path to .onto/config.yml (created if missing).",
132
+ " <review-json> JSON string representing an OntoReviewConfig.",
133
+ "",
134
+ "Example:",
135
+ " npm run onboard:write-review-block -- .onto/config.yml \\",
136
+ " '{\"teamlead\":{\"model\":\"main\"},\"subagent\":{\"provider\":\"main-native\"}}'",
137
+ "",
138
+ "Output: single-line JSON describing the write result on stdout.",
139
+ "Exit code 0 on success, 1 on validation/IO failure.",
140
+ ];
141
+ console.log(lines.join("\n"));
142
+ }
143
+ function isMainModule() {
144
+ const entry = process.argv[1];
145
+ if (typeof entry !== "string" || entry.length === 0)
146
+ return false;
147
+ try {
148
+ const entryUrl = new URL(`file://${entry}`).href;
149
+ return import.meta.url === entryUrl;
150
+ }
151
+ catch {
152
+ return false;
153
+ }
154
+ }
155
+ function runCli(argv) {
156
+ if (argv.length === 0 || argv.includes("--help") || argv.includes("-h")) {
157
+ printHelp();
158
+ return argv.length === 0 ? 1 : 0;
159
+ }
160
+ const unsupportedFlags = argv.filter((a) => a.startsWith("--"));
161
+ if (unsupportedFlags.length > 0) {
162
+ console.error(`error: unsupported option(s): ${unsupportedFlags.join(", ")}`);
163
+ return 1;
164
+ }
165
+ const positional = argv.filter((a) => !a.startsWith("--"));
166
+ if (positional.length < 2) {
167
+ console.error("error: two positional arguments required: <config-path> <review-json>. " +
168
+ "Run with --help for usage.");
169
+ return 1;
170
+ }
171
+ const [configPath, reviewJson] = positional;
172
+ let parsed;
173
+ try {
174
+ parsed = JSON.parse(reviewJson);
175
+ }
176
+ catch (err) {
177
+ const message = err instanceof Error ? err.message : String(err);
178
+ console.error(`error: <review-json> is not valid JSON: ${message}`);
179
+ return 1;
180
+ }
181
+ const result = writeReviewBlock(configPath, parsed);
182
+ console.log(JSON.stringify(result));
183
+ return result.ok ? 0 : 1;
184
+ }
185
+ if (isMainModule()) {
186
+ const exitCode = runCli(process.argv.slice(2));
187
+ process.exit(exitCode);
188
+ }
@@ -0,0 +1,240 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
+ import { writeReviewBlock } from "./write-review-block.js";
6
+ // ---------------------------------------------------------------------------
7
+ // writeReviewBlock — Review UX Redesign P4 (2026-04-21)
8
+ // ---------------------------------------------------------------------------
9
+ //
10
+ // These tests cover the four behaviours the onboard prose flow depends on:
11
+ //
12
+ // (1) Fresh-file creation — onboard on a brand-new project must create
13
+ // the file + parent directory + write the review block.
14
+ // (2) Round-trip preservation — existing top-level fields (e.g.
15
+ // output_language, domains) and their comments must survive the
16
+ // write.
17
+ // (3) Replace semantics — a pre-existing `review:` block is REPLACED,
18
+ // not merged. The caller's config object is the authoritative shape.
19
+ // (4) Legacy stripping — when stripLegacyPriority=true, the
20
+ // execution_topology_priority field is removed and reported.
21
+ //
22
+ // Validation failure paths (foreign provider without model_id, etc.) are
23
+ // covered indirectly via validateReviewConfig's own tests — here we spot-
24
+ // check that invalid input blocks the write entirely.
25
+ // ---------------------------------------------------------------------------
26
+ let tmpDir;
27
+ beforeEach(() => {
28
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "onto-onboard-p4-"));
29
+ });
30
+ afterEach(() => {
31
+ fs.rmSync(tmpDir, { recursive: true, force: true });
32
+ });
33
+ function makeConfigPath(name = "config.yml") {
34
+ return path.join(tmpDir, ".onto", name);
35
+ }
36
+ function read(p) {
37
+ return fs.readFileSync(p, "utf8");
38
+ }
39
+ describe("writeReviewBlock — fresh file", () => {
40
+ it("creates the parent directory + file when neither exists", () => {
41
+ const configPath = makeConfigPath();
42
+ const review = {
43
+ teamlead: { model: "main" },
44
+ subagent: { provider: "main-native" },
45
+ };
46
+ const result = writeReviewBlock(configPath, review);
47
+ expect(result.ok).toBe(true);
48
+ if (!result.ok)
49
+ return;
50
+ expect(result.created).toBe(true);
51
+ expect(result.replacedExistingBlock).toBe(false);
52
+ expect(result.strippedLegacyPriority).toBe(false);
53
+ const written = read(configPath);
54
+ expect(written).toContain("review:");
55
+ expect(written).toContain("teamlead:");
56
+ expect(written).toContain("model: main");
57
+ expect(written).toContain("provider: main-native");
58
+ });
59
+ it("serializes foreign-provider subagent with model_id + effort", () => {
60
+ const configPath = makeConfigPath();
61
+ const review = {
62
+ teamlead: { model: "main" },
63
+ subagent: { provider: "codex", model_id: "gpt-5.4", effort: "high" },
64
+ max_concurrent_lenses: 6,
65
+ lens_deliberation: "synthesizer-only",
66
+ };
67
+ const result = writeReviewBlock(configPath, review);
68
+ expect(result.ok).toBe(true);
69
+ const written = read(configPath);
70
+ expect(written).toContain("provider: codex");
71
+ expect(written).toContain("model_id: gpt-5.4");
72
+ expect(written).toContain("effort: high");
73
+ expect(written).toContain("max_concurrent_lenses: 6");
74
+ expect(written).toContain("lens_deliberation: synthesizer-only");
75
+ });
76
+ });
77
+ describe("writeReviewBlock — existing file", () => {
78
+ it("preserves top-level fields + trailing content when adding review", () => {
79
+ const configPath = makeConfigPath();
80
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
81
+ const original = [
82
+ "# Project config — hand-written",
83
+ "output_language: en",
84
+ "",
85
+ "domains:",
86
+ " - software-engineering",
87
+ " - ontology",
88
+ "",
89
+ ].join("\n");
90
+ fs.writeFileSync(configPath, original, "utf8");
91
+ const review = {
92
+ teamlead: { model: "main" },
93
+ subagent: { provider: "main-native" },
94
+ };
95
+ const result = writeReviewBlock(configPath, review);
96
+ expect(result.ok).toBe(true);
97
+ if (!result.ok)
98
+ return;
99
+ expect(result.created).toBe(false);
100
+ expect(result.replacedExistingBlock).toBe(false);
101
+ const written = read(configPath);
102
+ expect(written).toContain("output_language: en");
103
+ expect(written).toContain("software-engineering");
104
+ expect(written).toContain("ontology");
105
+ expect(written).toContain("review:");
106
+ expect(written).toContain("provider: main-native");
107
+ });
108
+ it("replaces (not merges) a pre-existing review block", () => {
109
+ const configPath = makeConfigPath();
110
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
111
+ const original = [
112
+ "output_language: en",
113
+ "review:",
114
+ " teamlead:",
115
+ " model: main",
116
+ " subagent:",
117
+ " provider: codex",
118
+ " model_id: gpt-5.4",
119
+ " effort: high",
120
+ " max_concurrent_lenses: 6",
121
+ "",
122
+ ].join("\n");
123
+ fs.writeFileSync(configPath, original, "utf8");
124
+ // New config chooses main-native — previous codex fields must not leak.
125
+ const review = {
126
+ teamlead: { model: "main" },
127
+ subagent: { provider: "main-native" },
128
+ };
129
+ const result = writeReviewBlock(configPath, review);
130
+ expect(result.ok).toBe(true);
131
+ if (!result.ok)
132
+ return;
133
+ expect(result.replacedExistingBlock).toBe(true);
134
+ const written = read(configPath);
135
+ expect(written).toContain("provider: main-native");
136
+ expect(written).not.toContain("gpt-5.4");
137
+ expect(written).not.toContain("effort: high");
138
+ expect(written).not.toMatch(/max_concurrent_lenses:\s*6/);
139
+ });
140
+ });
141
+ describe("writeReviewBlock — legacy stripping", () => {
142
+ it("strips execution_topology_priority when stripLegacyPriority=true", () => {
143
+ const configPath = makeConfigPath();
144
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
145
+ const original = [
146
+ "output_language: en",
147
+ "execution_topology_priority:",
148
+ " - cc-teams-codex-subprocess",
149
+ " - cc-main-agent-subagent",
150
+ "",
151
+ ].join("\n");
152
+ fs.writeFileSync(configPath, original, "utf8");
153
+ const review = {
154
+ teamlead: { model: "main" },
155
+ subagent: { provider: "codex", model_id: "gpt-5.4", effort: "high" },
156
+ };
157
+ const result = writeReviewBlock(configPath, review, {
158
+ stripLegacyPriority: true,
159
+ });
160
+ expect(result.ok).toBe(true);
161
+ if (!result.ok)
162
+ return;
163
+ expect(result.strippedLegacyPriority).toBe(true);
164
+ const written = read(configPath);
165
+ expect(written).not.toContain("execution_topology_priority");
166
+ expect(written).not.toContain("cc-teams-codex-subprocess");
167
+ expect(written).toContain("review:");
168
+ expect(written).toContain("provider: codex");
169
+ });
170
+ it("leaves legacy field alone when stripLegacyPriority is false/absent", () => {
171
+ const configPath = makeConfigPath();
172
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
173
+ const original = [
174
+ "output_language: en",
175
+ "execution_topology_priority:",
176
+ " - cc-main-agent-subagent",
177
+ "",
178
+ ].join("\n");
179
+ fs.writeFileSync(configPath, original, "utf8");
180
+ const review = {
181
+ teamlead: { model: "main" },
182
+ subagent: { provider: "main-native" },
183
+ };
184
+ const result = writeReviewBlock(configPath, review);
185
+ expect(result.ok).toBe(true);
186
+ if (!result.ok)
187
+ return;
188
+ expect(result.strippedLegacyPriority).toBe(false);
189
+ const written = read(configPath);
190
+ expect(written).toContain("execution_topology_priority");
191
+ expect(written).toContain("cc-main-agent-subagent");
192
+ });
193
+ });
194
+ describe("writeReviewBlock — validation failure", () => {
195
+ it("returns errors without writing when config is invalid", () => {
196
+ const configPath = makeConfigPath();
197
+ // provider=codex is a foreign provider, so model_id is required.
198
+ // The validator catches this; writeReviewBlock must propagate.
199
+ const invalid = {
200
+ subagent: { provider: "codex" },
201
+ };
202
+ const result = writeReviewBlock(configPath, invalid);
203
+ expect(result.ok).toBe(false);
204
+ if (result.ok)
205
+ return;
206
+ expect(result.errors.length).toBeGreaterThan(0);
207
+ expect(result.errors.some((e) => e.path.includes("subagent"))).toBe(true);
208
+ expect(fs.existsSync(configPath)).toBe(false);
209
+ });
210
+ it("rejects mismatched deliberation + teamlead combination", () => {
211
+ const configPath = makeConfigPath();
212
+ const invalid = {
213
+ teamlead: {
214
+ model: { provider: "codex", model_id: "gpt-5.4" },
215
+ },
216
+ lens_deliberation: "sendmessage-a2a",
217
+ };
218
+ const result = writeReviewBlock(configPath, invalid);
219
+ expect(result.ok).toBe(false);
220
+ if (result.ok)
221
+ return;
222
+ expect(result.errors.some((e) => e.path === "review.lens_deliberation")).toBe(true);
223
+ expect(fs.existsSync(configPath)).toBe(false);
224
+ });
225
+ });
226
+ describe("writeReviewBlock — pruneUndefined behaviour", () => {
227
+ it("does not emit null keys for undefined axes", () => {
228
+ const configPath = makeConfigPath();
229
+ const review = {
230
+ teamlead: { model: "main" },
231
+ // subagent, max_concurrent_lenses, lens_deliberation intentionally absent
232
+ };
233
+ const result = writeReviewBlock(configPath, review);
234
+ expect(result.ok).toBe(true);
235
+ const written = read(configPath);
236
+ expect(written).not.toContain("subagent: null");
237
+ expect(written).not.toContain("max_concurrent_lenses: null");
238
+ expect(written).not.toContain("lens_deliberation: null");
239
+ });
240
+ });