onto-mcp 0.3.2 → 0.4.1

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 (300) hide show
  1. package/.onto/processes/reconstruct/actionable-ontology-seed-recomposition-design.md +447 -0
  2. package/.onto/processes/reconstruct/foundry-style-ontology-seed-contract.md +934 -0
  3. package/.onto/processes/reconstruct/reconstruct-boundary-contract.md +303 -725
  4. package/.onto/processes/reconstruct/reconstruct-contract-registry.yaml +1645 -0
  5. package/.onto/processes/reconstruct/reconstruct-execution-ux-contract.md +26 -22
  6. package/.onto/processes/reconstruct/source-profile-contract.md +49 -23
  7. package/.onto/processes/reconstruct/source-profiles/code.md +6 -3
  8. package/.onto/processes/reconstruct/source-profiles/database.md +5 -2
  9. package/.onto/processes/reconstruct/source-profiles/document.md +5 -2
  10. package/.onto/processes/reconstruct/source-profiles/spreadsheet.md +5 -4
  11. package/.onto/processes/review/review-execution-ux-contract.md +40 -0
  12. package/.onto/processes/shared/pipeline-execution-ledger-contract.md +26 -10
  13. package/.onto/processes/shared/target-material-kind-contract.md +29 -16
  14. package/AGENTS.md +6 -4
  15. package/README.md +149 -76
  16. package/dist/cli.js +8 -8
  17. package/dist/core-api/reconstruct-api.js +117 -31
  18. package/dist/core-api/review-api.js +47 -0
  19. package/dist/core-runtime/cli/codex-review-unit-executor.js +39 -2
  20. package/dist/core-runtime/cli/complete-review-session.js +2 -2
  21. package/dist/core-runtime/cli/mock-review-unit-executor.js +1 -1
  22. package/dist/core-runtime/cli/review-invoke.js +9 -9
  23. package/dist/core-runtime/cli/run-review-prompt-execution.js +39 -5
  24. package/dist/core-runtime/cli/spawn-watcher.js +266 -47
  25. package/dist/core-runtime/cli/start-review-session.js +3 -3
  26. package/dist/core-runtime/llm/llm-caller.js +11 -0
  27. package/dist/core-runtime/llm/llm-tool-loop.js +2 -0
  28. package/dist/core-runtime/observability/runtime-stream-observation.js +118 -0
  29. package/dist/core-runtime/onboard/cli-host.js +174 -0
  30. package/dist/core-runtime/onboard/host-target.js +22 -0
  31. package/dist/core-runtime/onboard/json-config-host.js +122 -0
  32. package/dist/core-runtime/onboard/path-scan.js +26 -0
  33. package/dist/core-runtime/onboard/prompt.js +51 -0
  34. package/dist/core-runtime/onboard/register.js +214 -0
  35. package/dist/core-runtime/onboard/types.js +27 -0
  36. package/dist/core-runtime/reconstruct/actionable-seed-validation.js +1777 -0
  37. package/dist/core-runtime/reconstruct/artifact-types.js +10 -4
  38. package/dist/core-runtime/reconstruct/contract-registry.js +623 -0
  39. package/dist/core-runtime/reconstruct/domain-id.js +10 -0
  40. package/dist/core-runtime/reconstruct/governing-snapshot.js +716 -0
  41. package/dist/core-runtime/reconstruct/material-profile-validation.js +191 -0
  42. package/dist/core-runtime/reconstruct/materialize-preparation.js +49 -11
  43. package/dist/core-runtime/reconstruct/pipeline-execution-ledger.js +269 -79
  44. package/dist/core-runtime/reconstruct/post-seed-validation.js +1194 -51
  45. package/dist/core-runtime/reconstruct/record.js +104 -20
  46. package/dist/core-runtime/reconstruct/run.js +2107 -413
  47. package/dist/core-runtime/reconstruct/seed-claim-projections.js +268 -0
  48. package/dist/core-runtime/reconstruct/source-profiles.js +93 -4
  49. package/dist/core-runtime/reconstruct/terminal-validation.js +807 -0
  50. package/dist/core-runtime/review/review-invocation-runner.js +4 -4
  51. package/dist/mcp/server.js +110 -38
  52. package/dist/mcp/tool-schemas.js +20 -6
  53. package/package.json +8 -17
  54. package/scripts/onto-review-watch.sh +486 -0
  55. package/scripts/onto-runtime-watch.sh +122 -0
  56. package/scripts/postinstall-hint.js +22 -0
  57. package/.onto/processes/reconstruct/top-level-concept-discovery-contract.md +0 -387
  58. package/dist/core-runtime/cli/bootstrap-review-binding.js +0 -186
  59. package/dist/core-runtime/cli/codex-nested-dispatch.test.js +0 -390
  60. package/dist/core-runtime/cli/codex-nested-teamlead-executor.test.js +0 -335
  61. package/dist/core-runtime/cli/coordinator-helpers.js +0 -583
  62. package/dist/core-runtime/cli/coordinator-state-machine-deliberation.test.js +0 -167
  63. package/dist/core-runtime/cli/coordinator-state-machine.js +0 -794
  64. package/dist/core-runtime/cli/e2e-codex-multi-agent-fixes.test.js +0 -615
  65. package/dist/core-runtime/cli/e2e-start-review-session.test.js +0 -312
  66. package/dist/core-runtime/cli/health.js +0 -44
  67. package/dist/core-runtime/cli/inline-http-review-unit-executor.test.js +0 -567
  68. package/dist/core-runtime/cli/materialize-review-execution-preparation.js +0 -104
  69. package/dist/core-runtime/cli/migrate-session-roots.js +0 -118
  70. package/dist/core-runtime/cli/repo-layout-migration-replace.smoke.test.js +0 -106
  71. package/dist/core-runtime/cli/review-invoke-auto-resolution.test.js +0 -268
  72. package/dist/core-runtime/cli/review-invoke-coordinator-topology.test.js +0 -136
  73. package/dist/core-runtime/cli/review-invoke-resolver-caching.test.js +0 -201
  74. package/dist/core-runtime/cli/review-invoke-topology-dispatch.test.js +0 -192
  75. package/dist/core-runtime/cli/session-root-guard.js +0 -168
  76. package/dist/core-runtime/cli/spawn-watcher.test.js +0 -457
  77. package/dist/core-runtime/cli/strip-wrapping-code-fence.test.js +0 -79
  78. package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.js +0 -412
  79. package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.test.js +0 -351
  80. package/dist/core-runtime/cli/topology-executor-mapping.js +0 -139
  81. package/dist/core-runtime/cli/topology-executor-mapping.test.js +0 -173
  82. package/dist/core-runtime/cli/write-review-interpretation.js +0 -81
  83. package/dist/core-runtime/config/onto-config-cli.js +0 -278
  84. package/dist/core-runtime/config/onto-config-key-path.js +0 -288
  85. package/dist/core-runtime/config/onto-config-key-path.test.js +0 -195
  86. package/dist/core-runtime/config/onto-config-preview.js +0 -108
  87. package/dist/core-runtime/config/onto-config-preview.test.js +0 -132
  88. package/dist/core-runtime/discovery/config-chain.js +0 -118
  89. package/dist/core-runtime/discovery/config-chain.test.js +0 -103
  90. package/dist/core-runtime/discovery/config-profile.js +0 -199
  91. package/dist/core-runtime/discovery/config-profile.test.js +0 -233
  92. package/dist/core-runtime/discovery/host-detection.test.js +0 -186
  93. package/dist/core-runtime/discovery/installation-paths.test.js +0 -65
  94. package/dist/core-runtime/discovery/lens-registry.test.js +0 -81
  95. package/dist/core-runtime/discovery/path-normalization.test.js +0 -22
  96. package/dist/core-runtime/discovery/plugin-path.js +0 -72
  97. package/dist/core-runtime/discovery/plugin-path.test.js +0 -95
  98. package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.js +0 -344
  99. package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.test.js +0 -915
  100. package/dist/core-runtime/evolve/adapters/code-product/compile/compile.js +0 -564
  101. package/dist/core-runtime/evolve/adapters/code-product/compile/compile.test.js +0 -708
  102. package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.js +0 -165
  103. package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.test.js +0 -227
  104. package/dist/core-runtime/evolve/adapters/code-product/validators/validate.js +0 -59
  105. package/dist/core-runtime/evolve/adapters/code-product/validators/validate.test.js +0 -205
  106. package/dist/core-runtime/evolve/adapters/methodology/adapter.js +0 -16
  107. package/dist/core-runtime/evolve/adapters/methodology/adapter.test.js +0 -9
  108. package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.js +0 -298
  109. package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.test.js +0 -70
  110. package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.js +0 -46
  111. package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.test.js +0 -73
  112. package/dist/core-runtime/evolve/adapters/registry.js +0 -47
  113. package/dist/core-runtime/evolve/adapters/registry.test.js +0 -67
  114. package/dist/core-runtime/evolve/cli.js +0 -256
  115. package/dist/core-runtime/evolve/commands/align.js +0 -194
  116. package/dist/core-runtime/evolve/commands/align.test.js +0 -82
  117. package/dist/core-runtime/evolve/commands/apply.js +0 -161
  118. package/dist/core-runtime/evolve/commands/apply.test.js +0 -138
  119. package/dist/core-runtime/evolve/commands/close.js +0 -39
  120. package/dist/core-runtime/evolve/commands/close.test.js +0 -99
  121. package/dist/core-runtime/evolve/commands/defer.js +0 -40
  122. package/dist/core-runtime/evolve/commands/defer.test.js +0 -134
  123. package/dist/core-runtime/evolve/commands/draft.js +0 -323
  124. package/dist/core-runtime/evolve/commands/draft.test.js +0 -178
  125. package/dist/core-runtime/evolve/commands/e2e-evolve-full-cycle.test.js +0 -208
  126. package/dist/core-runtime/evolve/commands/error-messages.js +0 -125
  127. package/dist/core-runtime/evolve/commands/error-messages.test.js +0 -167
  128. package/dist/core-runtime/evolve/commands/propose-align.js +0 -222
  129. package/dist/core-runtime/evolve/commands/propose-align.test.js +0 -136
  130. package/dist/core-runtime/evolve/commands/reconstruct.js +0 -330
  131. package/dist/core-runtime/evolve/commands/reconstruct.test.js +0 -278
  132. package/dist/core-runtime/evolve/commands/shared.js +0 -22
  133. package/dist/core-runtime/evolve/commands/stale-check.js +0 -103
  134. package/dist/core-runtime/evolve/commands/stale-check.test.js +0 -84
  135. package/dist/core-runtime/evolve/commands/start.js +0 -887
  136. package/dist/core-runtime/evolve/commands/start.test.js +0 -396
  137. package/dist/core-runtime/evolve/config/project-config.js +0 -99
  138. package/dist/core-runtime/evolve/config/project-config.test.js +0 -170
  139. package/dist/core-runtime/evolve/renderers/align-packet.js +0 -280
  140. package/dist/core-runtime/evolve/renderers/align-packet.test.js +0 -332
  141. package/dist/core-runtime/evolve/renderers/draft-packet.js +0 -303
  142. package/dist/core-runtime/evolve/renderers/draft-packet.test.js +0 -377
  143. package/dist/core-runtime/evolve/renderers/format.js +0 -5
  144. package/dist/core-runtime/evolve/renderers/scope-md.js +0 -237
  145. package/dist/core-runtime/evolve/renderers/scope-md.test.js +0 -306
  146. package/dist/core-runtime/govern/cli.js +0 -369
  147. package/dist/core-runtime/govern/cli.test.js +0 -314
  148. package/dist/core-runtime/govern/drift-engine.js +0 -103
  149. package/dist/core-runtime/govern/drift-engine.test.js +0 -319
  150. package/dist/core-runtime/govern/promote-principle.js +0 -206
  151. package/dist/core-runtime/govern/promote-principle.test.js +0 -368
  152. package/dist/core-runtime/govern/queue.js +0 -81
  153. package/dist/core-runtime/govern/types.js +0 -16
  154. package/dist/core-runtime/install/cli.js +0 -530
  155. package/dist/core-runtime/install/detect.js +0 -128
  156. package/dist/core-runtime/install/detect.test.js +0 -155
  157. package/dist/core-runtime/install/gitignore-update.js +0 -74
  158. package/dist/core-runtime/install/gitignore-update.test.js +0 -64
  159. package/dist/core-runtime/install/install-integration.test.js +0 -373
  160. package/dist/core-runtime/install/prompts.js +0 -389
  161. package/dist/core-runtime/install/prompts.test.js +0 -293
  162. package/dist/core-runtime/install/types.js +0 -26
  163. package/dist/core-runtime/install/validation.js +0 -295
  164. package/dist/core-runtime/install/validation.test.js +0 -313
  165. package/dist/core-runtime/install/writer.js +0 -254
  166. package/dist/core-runtime/install/writer.test.js +0 -218
  167. package/dist/core-runtime/learning/extractor.js +0 -461
  168. package/dist/core-runtime/learning/feedback.js +0 -179
  169. package/dist/core-runtime/learning/health-report.js +0 -165
  170. package/dist/core-runtime/learning/health-report.test.js +0 -169
  171. package/dist/core-runtime/learning/loader.js +0 -388
  172. package/dist/core-runtime/learning/loader.test.js +0 -102
  173. package/dist/core-runtime/learning/promote/apply-state.js +0 -240
  174. package/dist/core-runtime/learning/promote/audit-obligation.js +0 -195
  175. package/dist/core-runtime/learning/promote/collector.js +0 -432
  176. package/dist/core-runtime/learning/promote/degraded-state.js +0 -125
  177. package/dist/core-runtime/learning/promote/domain-doc-proposer.js +0 -166
  178. package/dist/core-runtime/learning/promote/e2e-promote.test.js +0 -6385
  179. package/dist/core-runtime/learning/promote/health-snapshot.js +0 -150
  180. package/dist/core-runtime/learning/promote/insight-reclassifier.js +0 -544
  181. package/dist/core-runtime/learning/promote/judgment-auditor.js +0 -517
  182. package/dist/core-runtime/learning/promote/panel-reviewer.js +0 -1158
  183. package/dist/core-runtime/learning/promote/promote-executor.js +0 -1675
  184. package/dist/core-runtime/learning/promote/promoter.js +0 -307
  185. package/dist/core-runtime/learning/promote/retirement.js +0 -122
  186. package/dist/core-runtime/learning/promote/types.js +0 -23
  187. package/dist/core-runtime/learning/prompt-sections.js +0 -51
  188. package/dist/core-runtime/learning/shared/artifact-registry-init.js +0 -45
  189. package/dist/core-runtime/learning/shared/artifact-registry.js +0 -254
  190. package/dist/core-runtime/learning/shared/audit-obligation-kernel.js +0 -73
  191. package/dist/core-runtime/learning/shared/audit-state.js +0 -99
  192. package/dist/core-runtime/learning/shared/duplicate-check.js +0 -28
  193. package/dist/core-runtime/learning/shared/llm-caller.js +0 -831
  194. package/dist/core-runtime/learning/shared/llm-caller.test.js +0 -601
  195. package/dist/core-runtime/learning/shared/llm-tool-loop.js +0 -393
  196. package/dist/core-runtime/learning/shared/mode.js +0 -25
  197. package/dist/core-runtime/learning/shared/paths.js +0 -84
  198. package/dist/core-runtime/learning/shared/paths.test.js +0 -79
  199. package/dist/core-runtime/learning/shared/patterns.js +0 -37
  200. package/dist/core-runtime/learning/shared/recoverability.js +0 -355
  201. package/dist/core-runtime/learning/shared/recovery-context.js +0 -374
  202. package/dist/core-runtime/learning/shared/scope.js +0 -1
  203. package/dist/core-runtime/learning/shared/semantic-classifier.js +0 -94
  204. package/dist/core-runtime/learning/shared/specs/apply-execution-state-spec.js +0 -42
  205. package/dist/core-runtime/learning/shared/specs/audit-state-spec.js +0 -37
  206. package/dist/core-runtime/learning/shared/specs/backup-metadata-spec.js +0 -39
  207. package/dist/core-runtime/learning/shared/specs/emergency-log-spec.js +0 -41
  208. package/dist/core-runtime/learning/shared/specs/layout-version-spec.js +0 -38
  209. package/dist/core-runtime/learning/shared/specs/promote-decisions-spec.js +0 -43
  210. package/dist/core-runtime/learning/shared/specs/promote-report-spec.js +0 -113
  211. package/dist/core-runtime/learning/shared/specs/prune-log-spec.js +0 -36
  212. package/dist/core-runtime/learning/shared/specs/recovery-resolution-spec.js +0 -48
  213. package/dist/core-runtime/learning/shared/specs/restore-manifest-spec.js +0 -43
  214. package/dist/core-runtime/learning/shared/specs/spec-helpers.js +0 -64
  215. package/dist/core-runtime/learning/usage-tracker.js +0 -190
  216. package/dist/core-runtime/learning/usage-tracker.test.js +0 -176
  217. package/dist/core-runtime/onboard/detect-review-axes.js +0 -122
  218. package/dist/core-runtime/onboard/detect-review-axes.test.js +0 -127
  219. package/dist/core-runtime/onboard/write-review-block.js +0 -188
  220. package/dist/core-runtime/onboard/write-review-block.test.js +0 -240
  221. package/dist/core-runtime/readers/brownfield-builder.js +0 -150
  222. package/dist/core-runtime/readers/brownfield-builder.test.js +0 -136
  223. package/dist/core-runtime/readers/code-chunk-collector.js +0 -53
  224. package/dist/core-runtime/readers/code-chunk-collector.test.js +0 -136
  225. package/dist/core-runtime/readers/file-utils.js +0 -240
  226. package/dist/core-runtime/readers/file-utils.test.js +0 -146
  227. package/dist/core-runtime/readers/lexicon-citation-check.js +0 -93
  228. package/dist/core-runtime/readers/lexicon-citation-check.test.js +0 -77
  229. package/dist/core-runtime/readers/mcp-figma.js +0 -30
  230. package/dist/core-runtime/readers/mcp-figma.test.js +0 -82
  231. package/dist/core-runtime/readers/mcp-generic.js +0 -31
  232. package/dist/core-runtime/readers/mcp-generic.test.js +0 -76
  233. package/dist/core-runtime/readers/ontology-index.js +0 -148
  234. package/dist/core-runtime/readers/ontology-index.test.js +0 -245
  235. package/dist/core-runtime/readers/ontology-query.js +0 -168
  236. package/dist/core-runtime/readers/ontology-query.test.js +0 -311
  237. package/dist/core-runtime/readers/ontology-resolve.js +0 -48
  238. package/dist/core-runtime/readers/ontology-resolve.test.js +0 -48
  239. package/dist/core-runtime/readers/patterns/index.js +0 -7
  240. package/dist/core-runtime/readers/review-log.js +0 -213
  241. package/dist/core-runtime/readers/review-log.test.js +0 -313
  242. package/dist/core-runtime/readers/scan-local.js +0 -102
  243. package/dist/core-runtime/readers/scan-local.test.js +0 -102
  244. package/dist/core-runtime/readers/scan-tarball.js +0 -121
  245. package/dist/core-runtime/readers/scan-tarball.test.js +0 -283
  246. package/dist/core-runtime/readers/scan-vault.js +0 -34
  247. package/dist/core-runtime/readers/scan-vault.test.js +0 -81
  248. package/dist/core-runtime/readers/types.js +0 -42
  249. package/dist/core-runtime/readers/types.test.js +0 -94
  250. package/dist/core-runtime/readers/viewpoint-collectors.js +0 -229
  251. package/dist/core-runtime/reconstruct/seed-candidate-validation.js +0 -385
  252. package/dist/core-runtime/review/citation-audit.test.js +0 -165
  253. package/dist/core-runtime/review/execution-plan-resolver.js +0 -247
  254. package/dist/core-runtime/review/execution-plan-resolver.test.js +0 -243
  255. package/dist/core-runtime/review/execution-topology-resolver-axis-first.test.js +0 -246
  256. package/dist/core-runtime/review/execution-topology-resolver.js +0 -401
  257. package/dist/core-runtime/review/execution-topology-resolver.test.js +0 -315
  258. package/dist/core-runtime/review/inline-context-embedder.test.js +0 -154
  259. package/dist/core-runtime/review/legacy-mode-policy.js +0 -88
  260. package/dist/core-runtime/review/materializers-effort-persist.test.js +0 -79
  261. package/dist/core-runtime/review/ontology-path-classifier.js +0 -179
  262. package/dist/core-runtime/review/ontology-path-classifier.test.js +0 -216
  263. package/dist/core-runtime/review/packet-boundary-policy.test.js +0 -107
  264. package/dist/core-runtime/review/participating-lens-paths.test.js +0 -73
  265. package/dist/core-runtime/review/review-config-legacy-translate.js +0 -244
  266. package/dist/core-runtime/review/review-config-legacy-translate.test.js +0 -161
  267. package/dist/core-runtime/review/review-config-validator.js +0 -289
  268. package/dist/core-runtime/review/review-config-validator.test.js +0 -236
  269. package/dist/core-runtime/review/shape-pipeline-audit.test.js +0 -311
  270. package/dist/core-runtime/review/shape-to-topology-id.js +0 -117
  271. package/dist/core-runtime/review/shape-to-topology-id.test.js +0 -132
  272. package/dist/core-runtime/review/topology-shape-derivation.js +0 -155
  273. package/dist/core-runtime/review/topology-shape-derivation.test.js +0 -195
  274. package/dist/core-runtime/scope-runtime/constants.js +0 -12
  275. package/dist/core-runtime/scope-runtime/constraint-pool.js +0 -166
  276. package/dist/core-runtime/scope-runtime/constraint-pool.test.js +0 -674
  277. package/dist/core-runtime/scope-runtime/domain-validation-log.js +0 -135
  278. package/dist/core-runtime/scope-runtime/domain-validation-log.test.js +0 -156
  279. package/dist/core-runtime/scope-runtime/eval-persistence.js +0 -65
  280. package/dist/core-runtime/scope-runtime/eval-persistence.test.js +0 -84
  281. package/dist/core-runtime/scope-runtime/event-pipeline.js +0 -64
  282. package/dist/core-runtime/scope-runtime/event-pipeline.test.js +0 -450
  283. package/dist/core-runtime/scope-runtime/event-store.js +0 -39
  284. package/dist/core-runtime/scope-runtime/event-store.test.js +0 -95
  285. package/dist/core-runtime/scope-runtime/gate-guard.js +0 -348
  286. package/dist/core-runtime/scope-runtime/gate-guard.test.js +0 -1047
  287. package/dist/core-runtime/scope-runtime/hash.js +0 -4
  288. package/dist/core-runtime/scope-runtime/hash.test.js +0 -33
  289. package/dist/core-runtime/scope-runtime/id.js +0 -4
  290. package/dist/core-runtime/scope-runtime/id.test.js +0 -17
  291. package/dist/core-runtime/scope-runtime/reducer.js +0 -297
  292. package/dist/core-runtime/scope-runtime/reducer.test.js +0 -759
  293. package/dist/core-runtime/scope-runtime/scope-manager.js +0 -161
  294. package/dist/core-runtime/scope-runtime/state-machine.js +0 -309
  295. package/dist/core-runtime/scope-runtime/state-machine.test.js +0 -704
  296. package/dist/core-runtime/scope-runtime/types.js +0 -116
  297. package/dist/core-runtime/scope-runtime/types.test.js +0 -69
  298. package/dist/core-runtime/translate/render-for-user.js +0 -169
  299. package/dist/core-runtime/translate/render-for-user.test.js +0 -122
  300. package/dist/providers/capability-contract.js +0 -1
@@ -1,176 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
- import { mkdirSync, writeFileSync, rmSync } from "node:fs";
3
- import { join } from "node:path";
4
- import { tmpdir } from "node:os";
5
- import { stringify } from "yaml";
6
- import { collectLearningUsage, computeAggregate } from "./usage-tracker.js";
7
- // ─── Fixture helpers ───
8
- function makeManifest(overrides = {}) {
9
- return {
10
- session_domain: "none",
11
- agents_loaded: 2,
12
- total_items_loaded: 90,
13
- total_items_parsed: 200,
14
- total_items_skipped: 10,
15
- degraded: false,
16
- degradation_reason: null,
17
- per_agent: [
18
- {
19
- agent_id: "logic",
20
- loaded: 46,
21
- parsed: 120,
22
- skipped: 4,
23
- truncated: 74,
24
- role_distribution: { guardrail: 15, foundation: 21, convention: 1, unclassified: 9 },
25
- tier_distribution: { "1": 15, "2": 11, "3": 19, "4": 1 },
26
- cross_domain_included: 0,
27
- cross_domain_excluded: 0,
28
- tokens_used: 6259,
29
- tokens_budget: 4000,
30
- budget_truncated_count: 48,
31
- },
32
- {
33
- agent_id: "structure",
34
- loaded: 44,
35
- parsed: 80,
36
- skipped: 6,
37
- truncated: 36,
38
- role_distribution: { guardrail: 12, foundation: 4, convention: 0, unclassified: 28 },
39
- tier_distribution: { "1": 12, "2": 16, "3": 4, "4": 12 },
40
- cross_domain_included: 0,
41
- cross_domain_excluded: 0,
42
- tokens_used: 5666,
43
- tokens_budget: 4000,
44
- budget_truncated_count: 32,
45
- },
46
- ],
47
- learning_file_paths: [],
48
- ...overrides,
49
- };
50
- }
51
- let testDir;
52
- function createSessionManifest(reviewRoot, sessionId, manifestOverrides = {}) {
53
- const prepDir = join(reviewRoot, sessionId, "execution-preparation");
54
- mkdirSync(prepDir, { recursive: true });
55
- writeFileSync(join(prepDir, "learning-manifest.yaml"), stringify(makeManifest(manifestOverrides)));
56
- }
57
- // ─── Tests ───
58
- describe("usage-tracker", () => {
59
- beforeEach(() => {
60
- testDir = join(tmpdir(), `usage-tracker-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
61
- mkdirSync(testDir, { recursive: true });
62
- });
63
- afterEach(() => {
64
- rmSync(testDir, { recursive: true, force: true });
65
- });
66
- describe("collectLearningUsage", () => {
67
- it("빈 디렉터리에서 빈 summary 를 반환한다", () => {
68
- const result = collectLearningUsage(testDir);
69
- expect(result.total_sessions).toBe(0);
70
- expect(result.entries).toHaveLength(0);
71
- });
72
- it("존재하지 않는 경로에서 빈 summary 를 반환한다", () => {
73
- const result = collectLearningUsage("/nonexistent/path");
74
- expect(result.total_sessions).toBe(0);
75
- });
76
- it("단일 세션의 learning manifest 를 수집한다", () => {
77
- createSessionManifest(testDir, "20260413-aaa00001");
78
- const result = collectLearningUsage(testDir);
79
- expect(result.total_sessions).toBe(1);
80
- const entry = result.entries[0];
81
- expect(entry.session_id).toBe("20260413-aaa00001");
82
- expect(entry.total_items_loaded).toBe(90);
83
- expect(entry.total_items_parsed).toBe(200);
84
- expect(entry.agents_loaded).toBe(2);
85
- });
86
- it("per-agent tier/role 분포를 합산한다", () => {
87
- createSessionManifest(testDir, "20260413-aaa00001");
88
- const result = collectLearningUsage(testDir);
89
- const entry = result.entries[0];
90
- // logic t1:15 + structure t1:12 = 27
91
- expect(entry.tier_distribution.t1).toBe(27);
92
- // logic guardrail:15 + structure guardrail:12 = 27
93
- expect(entry.role_distribution.guardrail).toBe(27);
94
- });
95
- it("tokens_used 와 budget_truncated 를 합산한다", () => {
96
- createSessionManifest(testDir, "20260413-aaa00001");
97
- const result = collectLearningUsage(testDir);
98
- const entry = result.entries[0];
99
- expect(entry.total_tokens_used).toBe(6259 + 5666);
100
- expect(entry.total_budget_truncated).toBe(48 + 32);
101
- });
102
- it("learning-manifest.yaml 없는 세션은 건너뛴다", () => {
103
- const sessionDir = join(testDir, "20260413-bbb00002");
104
- mkdirSync(sessionDir, { recursive: true });
105
- const result = collectLearningUsage(testDir);
106
- expect(result.total_sessions).toBe(0);
107
- });
108
- it("여러 세션을 session_id 순 정렬한다", () => {
109
- createSessionManifest(testDir, "20260413-bbb00002");
110
- createSessionManifest(testDir, "20260413-aaa00001");
111
- const result = collectLearningUsage(testDir);
112
- expect(result.entries[0].session_id).toBe("20260413-aaa00001");
113
- expect(result.entries[1].session_id).toBe("20260413-bbb00002");
114
- });
115
- });
116
- describe("computeAggregate", () => {
117
- it("빈 entries 에서 zero aggregate 를 반환한다", () => {
118
- const agg = computeAggregate([]);
119
- expect(agg.avg_items_loaded).toBe(0);
120
- expect(agg.supply_ratio).toBe(0);
121
- });
122
- it("단일 세션의 supply_ratio 를 정확히 산출한다", () => {
123
- const entries = [
124
- makeUsageEntry("s1", { loaded: 90, parsed: 200 }),
125
- ];
126
- const agg = computeAggregate(entries);
127
- expect(agg.supply_ratio).toBe(0.45); // 90/200
128
- expect(agg.avg_items_loaded).toBe(90);
129
- });
130
- it("여러 세션의 평균을 산출한다", () => {
131
- const entries = [
132
- makeUsageEntry("s1", { loaded: 100, parsed: 200, tokens: 10000 }),
133
- makeUsageEntry("s2", { loaded: 200, parsed: 400, tokens: 20000 }),
134
- ];
135
- const agg = computeAggregate(entries);
136
- expect(agg.avg_items_loaded).toBe(150);
137
- expect(agg.avg_items_parsed).toBe(300);
138
- expect(agg.supply_ratio).toBe(0.5); // 300/600
139
- expect(agg.avg_tokens_used).toBe(15000);
140
- });
141
- it("degradation_ratio 를 정확히 산출한다", () => {
142
- const entries = [
143
- makeUsageEntry("s1", { degraded: true }),
144
- makeUsageEntry("s2", { degraded: false }),
145
- makeUsageEntry("s3", { degraded: false }),
146
- ];
147
- const agg = computeAggregate(entries);
148
- expect(agg.degradation_ratio).toBe(0.333);
149
- });
150
- it("tier/role 분포를 합산한다", () => {
151
- const entries = [
152
- makeUsageEntry("s1", { tier: { t1: 10, t2: 5, t3: 3, t4: 2 } }),
153
- makeUsageEntry("s2", { tier: { t1: 8, t2: 4, t3: 2, t4: 1 } }),
154
- ];
155
- const agg = computeAggregate(entries);
156
- expect(agg.total_tier_distribution.t1).toBe(18);
157
- expect(agg.total_tier_distribution.t2).toBe(9);
158
- });
159
- });
160
- });
161
- // ─── Test helper ───
162
- function makeUsageEntry(session_id, overrides = {}) {
163
- return {
164
- session_id,
165
- session_domain: "none",
166
- agents_loaded: 9,
167
- total_items_loaded: overrides.loaded ?? 100,
168
- total_items_parsed: overrides.parsed ?? 200,
169
- total_items_skipped: 10,
170
- total_tokens_used: overrides.tokens ?? 10000,
171
- total_budget_truncated: 5,
172
- degraded: overrides.degraded ?? false,
173
- tier_distribution: overrides.tier ?? { t1: 10, t2: 5, t3: 3, t4: 2 },
174
- role_distribution: { guardrail: 10, foundation: 5, convention: 2, unclassified: 3 },
175
- };
176
- }
@@ -1,122 +0,0 @@
1
- /**
2
- * Review UX Redesign P4 — onboard-time detection of review axes.
3
- *
4
- * # What this module is
5
- *
6
- * A small pure function that aggregates the environmental signals relevant
7
- * to the review execution configuration (design doc §5.2, stages 1–4) into
8
- * a single `DetectedReviewAxes` result. The onboard prose flow
9
- * (`.onto/processes/onboard.md`) invokes this via `npm run onboard:detect-review-axes`
10
- * and uses the printed JSON as the input to the subsequent interactive
11
- * questions (stages 5–7).
12
- *
13
- * # Why it exists
14
- *
15
- * Onboard is prose-driven: the LLM session reads `.onto/processes/onboard.md` and
16
- * executes each stage textually. Stages 1–4 are purely automatic environment
17
- * probes, so pulling them into a single deterministic TS entry point keeps
18
- * the prose stage short ("run this script and read the JSON") and avoids
19
- * duplicating env-var + binary checks in natural-language instructions. The
20
- * detection logic itself is reused from
21
- * `src/core-runtime/discovery/host-detection.ts` — this module is a thin
22
- * projection into the P4 axis vocabulary (host, agent_teams_available,
23
- * codex_available).
24
- *
25
- * # How it relates
26
- *
27
- * - Inputs: process.env (read via the detection helpers from discovery/).
28
- * - Output: pure data (`DetectedReviewAxes`) — onboard prose renders it and
29
- * asks the user axis-by-axis questions.
30
- * - Write-back seat: `write-review-block.ts` (sibling module).
31
- * - Consumed by: `.onto/processes/onboard.md` §§ 3.7/3.8 (added in P4).
32
- */
33
- import { detectClaudeCodeEnvSignal, detectCodexBinaryAvailable, detectCodexEnvSignal, } from "../discovery/host-detection.js";
34
- // ---------------------------------------------------------------------------
35
- // Core detection
36
- // ---------------------------------------------------------------------------
37
- const ENV_AGENT_TEAMS = "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS";
38
- /**
39
- * Map the discovery-layer env signals into the onboard host vocabulary.
40
- *
41
- * Priority: Claude Code > Codex CLI > plain terminal. Same ordering as
42
- * `detectHostRuntime` but projected into the simpler three-value domain.
43
- * Claude Code takes precedence because an inner Codex process inside a
44
- * Claude Code session still reports CLAUDECODE=1 — in that case the onboard
45
- * context is the Claude Code session, and codex availability is surfaced
46
- * separately as a subagent option.
47
- */
48
- function detectHost() {
49
- if (detectClaudeCodeEnvSignal())
50
- return "claude-code";
51
- if (detectCodexEnvSignal())
52
- return "codex-cli";
53
- return "plain-terminal";
54
- }
55
- /**
56
- * Detect the four review axes observable from environment alone.
57
- *
58
- * Pure w.r.t. process.env — no file writes, no network. Deterministic given
59
- * the same env snapshot + filesystem state (codex binary + auth.json).
60
- */
61
- export function detectReviewAxes() {
62
- const host = detectHost();
63
- // Exact-match against `"1"` to stay consistent with the resolver's strict
64
- // check (`execution-topology-resolver.ts:506`). A loose `Boolean(...)` here
65
- // would disagree with the resolver when the user sets the variable to
66
- // `"0"` / `"false"` / `""`. Both layers must read the same signal the
67
- // same way so the onboard UX promise survives the runtime.
68
- const agent_teams_available = process.env[ENV_AGENT_TEAMS] === "1";
69
- const codex_available = detectCodexBinaryAvailable();
70
- return {
71
- detected: {
72
- host,
73
- agent_teams_available,
74
- codex_available,
75
- },
76
- };
77
- }
78
- // ---------------------------------------------------------------------------
79
- // CLI entry — `npm run onboard:detect-review-axes`
80
- // ---------------------------------------------------------------------------
81
- function isMainModule() {
82
- // tsx executes this module directly; the ESM equivalent of
83
- // `require.main === module` is comparing import.meta.url to argv[1].
84
- const entry = process.argv[1];
85
- if (typeof entry !== "string" || entry.length === 0)
86
- return false;
87
- try {
88
- const entryUrl = new URL(`file://${entry}`).href;
89
- return import.meta.url === entryUrl;
90
- }
91
- catch {
92
- return false;
93
- }
94
- }
95
- function printHelp() {
96
- const lines = [
97
- "onboard:detect-review-axes",
98
- "",
99
- "Detects the environmental axes consumed by the onboard prose flow:",
100
- " - host (claude-code | codex-cli | plain-terminal)",
101
- " - agent_teams (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1)",
102
- " - codex_available (codex on PATH + ~/.codex/auth.json)",
103
- "",
104
- "Usage:",
105
- " npm run onboard:detect-review-axes",
106
- " npm run onboard:detect-review-axes -- --help",
107
- "",
108
- "Output: single-line JSON { detected: { ... } } on stdout.",
109
- ];
110
- console.log(lines.join("\n"));
111
- }
112
- if (isMainModule()) {
113
- const argv = process.argv.slice(2);
114
- if (argv.includes("--help") || argv.includes("-h")) {
115
- printHelp();
116
- process.exit(0);
117
- }
118
- const result = detectReviewAxes();
119
- // Compact single-line JSON so the prose caller can forward it as-is into
120
- // the LLM context without re-parsing.
121
- console.log(JSON.stringify(result));
122
- }
@@ -1,127 +0,0 @@
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
- });
@@ -1,188 +0,0 @@
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
- }