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,26 @@
1
+ /**
2
+ * Shared types for `onto install` — the interactive + non-interactive
3
+ * first-run setup command.
4
+ *
5
+ * Design reference: spec v3 laid out in the install command design
6
+ * discussion (2026-04-21 session). Key decisions codified here:
7
+ *
8
+ * 1. Two provider channels: review (for 9-lens execution) and learn
9
+ * (for background tasks — learn/govern/promote). They may share
10
+ * a provider or be configured separately.
11
+ *
12
+ * 2. `main-native` is a valid ReviewProvider but NOT a valid
13
+ * LearnProvider. The background ladder in llm-caller.ts does not
14
+ * support host main-model delegation (fail-fast on missing
15
+ * credentials). The type-level exclusion prevents accidentally
16
+ * writing a learn config that would always fail at runtime.
17
+ *
18
+ * 3. API keys are never captured into typed decision shape — they
19
+ * flow via environment (env var or `.env` file) only. This keeps
20
+ * secrets out of logs, serialized state, and command history.
21
+ *
22
+ * 4. Profile scope is atomic (per config-profile.ts adoption rule) —
23
+ * either global owns the full profile set or project does. The
24
+ * scope choice is what determines where every file writes.
25
+ */
26
+ export {};
@@ -0,0 +1,295 @@
1
+ /**
2
+ * Live provider validation for `onto install`.
3
+ *
4
+ * Given a freshly resolved `{ decisions, secrets, detection }`, this
5
+ * module sends a minimal reachability probe to each non-main-native
6
+ * provider the user selected. A failed probe produces a clear
7
+ * `ValidationCheck` result that the orchestrator surfaces alongside
8
+ * instructions (re-run with `--skip-validation` or fix the credential).
9
+ *
10
+ * # What "ping" means per provider
11
+ *
12
+ * - anthropic GET https://api.anthropic.com/v1/models with the
13
+ * key — models list is free and confirms the key.
14
+ * - openai GET https://api.openai.com/v1/models with the key
15
+ * — same rationale, zero token cost.
16
+ * - litellm GET {base_url}/models (OpenAI-compatible). The
17
+ * `/models` suffix is the OpenAI-compat standard;
18
+ * LiteLLM proxy and every listed local runtime
19
+ * (Ollama, LM Studio, vLLM, MLX) respond to it.
20
+ * - codex Local check only — binary present + auth.json
21
+ * present. No network call; the codex CLI handles
22
+ * its own OAuth dance.
23
+ * - main-native Skipped — there's nothing to probe; the runtime
24
+ * is the host session itself.
25
+ *
26
+ * # Why fetch directly instead of SDK
27
+ *
28
+ * The `@anthropic-ai/sdk` and `openai` SDKs carry non-trivial startup
29
+ * cost and change their response shapes between majors. A raw HTTP
30
+ * GET is dependency-free, gives a crisp HTTP status code (401 vs 200
31
+ * vs 5xx), and doesn't couple install's validation surface to SDK
32
+ * version drift. LiteLLM is already OpenAI-compatible HTTP, so the
33
+ * same pattern works there.
34
+ *
35
+ * # Testability
36
+ *
37
+ * All network and filesystem access flows through a `PingDependencies`
38
+ * struct. Tests inject a stub `fetch` that returns the desired
39
+ * `Response` shape, and stub codex-presence booleans directly.
40
+ */
41
+ // ---------------------------------------------------------------------------
42
+ // Shape guard
43
+ // ---------------------------------------------------------------------------
44
+ /**
45
+ * Runtime sanity check on the `InstallDecisions` shape.
46
+ *
47
+ * TypeScript already enforces most of this at compile time. The one
48
+ * thing that still benefits from a runtime check is the
49
+ * learn-provider exclusion (it's excluded at the type level via the
50
+ * `LearnProvider` union but a consumer could still construct
51
+ * decisions outside the normal flow).
52
+ */
53
+ export function checkDecisionShape(decisions) {
54
+ const checks = [];
55
+ if (decisions.learnProvider === "main-native") {
56
+ checks.push({
57
+ name: "decisions",
58
+ passed: false,
59
+ message: "learn provider는 main-native를 지원하지 않습니다. " +
60
+ "background ladder(llm-caller.ts)에서 main-native는 ladder의 일부가 아닙니다.",
61
+ });
62
+ }
63
+ return checks;
64
+ }
65
+ // ---------------------------------------------------------------------------
66
+ // Fetch helpers
67
+ // ---------------------------------------------------------------------------
68
+ async function fetchWithTimeout(fetchFn, url, init, timeoutMs) {
69
+ const controller = new AbortController();
70
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
71
+ try {
72
+ return await fetchFn(url, { ...init, signal: controller.signal });
73
+ }
74
+ finally {
75
+ clearTimeout(timer);
76
+ }
77
+ }
78
+ function resolveFetch(deps) {
79
+ return deps.fetch ?? globalThis.fetch;
80
+ }
81
+ // ---------------------------------------------------------------------------
82
+ // Per-provider pings
83
+ // ---------------------------------------------------------------------------
84
+ export async function pingAnthropic(apiKey, deps = {}) {
85
+ const fetchFn = resolveFetch(deps);
86
+ const timeoutMs = deps.timeoutMs ?? 5000;
87
+ try {
88
+ const res = await fetchWithTimeout(fetchFn, "https://api.anthropic.com/v1/models", {
89
+ method: "GET",
90
+ headers: {
91
+ "x-api-key": apiKey,
92
+ "anthropic-version": "2023-06-01",
93
+ },
94
+ }, timeoutMs);
95
+ if (res.status >= 200 && res.status < 300) {
96
+ return { name: "anthropic", passed: true };
97
+ }
98
+ if (res.status === 401 || res.status === 403) {
99
+ return {
100
+ name: "anthropic",
101
+ passed: false,
102
+ message: "인증 실패 (API key 거부). 키 값을 확인하세요.",
103
+ };
104
+ }
105
+ return {
106
+ name: "anthropic",
107
+ passed: false,
108
+ message: `api.anthropic.com 응답 HTTP ${res.status}`,
109
+ };
110
+ }
111
+ catch (err) {
112
+ return {
113
+ name: "anthropic",
114
+ passed: false,
115
+ message: `네트워크 오류: ${err instanceof Error ? err.message : String(err)}`,
116
+ };
117
+ }
118
+ }
119
+ export async function pingOpenai(apiKey, deps = {}) {
120
+ const fetchFn = resolveFetch(deps);
121
+ const timeoutMs = deps.timeoutMs ?? 5000;
122
+ try {
123
+ const res = await fetchWithTimeout(fetchFn, "https://api.openai.com/v1/models", {
124
+ method: "GET",
125
+ headers: { Authorization: `Bearer ${apiKey}` },
126
+ }, timeoutMs);
127
+ if (res.status >= 200 && res.status < 300) {
128
+ return { name: "openai", passed: true };
129
+ }
130
+ if (res.status === 401 || res.status === 403) {
131
+ return {
132
+ name: "openai",
133
+ passed: false,
134
+ message: "인증 실패 (API key 거부). 키 값을 확인하세요.",
135
+ };
136
+ }
137
+ return {
138
+ name: "openai",
139
+ passed: false,
140
+ message: `api.openai.com 응답 HTTP ${res.status}`,
141
+ };
142
+ }
143
+ catch (err) {
144
+ return {
145
+ name: "openai",
146
+ passed: false,
147
+ message: `네트워크 오류: ${err instanceof Error ? err.message : String(err)}`,
148
+ };
149
+ }
150
+ }
151
+ export async function pingLitellm(baseUrl, apiKey, deps = {}) {
152
+ const fetchFn = resolveFetch(deps);
153
+ const timeoutMs = deps.timeoutMs ?? 5000;
154
+ const url = baseUrl.replace(/\/+$/, "") + "/models";
155
+ try {
156
+ const headers = {};
157
+ if (apiKey)
158
+ headers.Authorization = `Bearer ${apiKey}`;
159
+ const res = await fetchWithTimeout(fetchFn, url, { method: "GET", headers }, timeoutMs);
160
+ if (res.status >= 200 && res.status < 300) {
161
+ return { name: "litellm", passed: true };
162
+ }
163
+ if (res.status === 401 || res.status === 403) {
164
+ return {
165
+ name: "litellm",
166
+ passed: false,
167
+ message: "인증 실패. 엔드포인트가 key를 요구합니다 — LITELLM_API_KEY를 설정하세요.",
168
+ };
169
+ }
170
+ return {
171
+ name: "litellm",
172
+ passed: false,
173
+ message: `${url} 응답 HTTP ${res.status}`,
174
+ };
175
+ }
176
+ catch (err) {
177
+ return {
178
+ name: "litellm",
179
+ passed: false,
180
+ message: `연결 실패 (${url}): ${err instanceof Error ? err.message : String(err)}`,
181
+ };
182
+ }
183
+ }
184
+ export function verifyCodex(detection, deps = {}) {
185
+ const binaryPresent = deps.codexBinaryPresent
186
+ ? deps.codexBinaryPresent()
187
+ : detection.hasCodexBinary;
188
+ const authPresent = deps.codexAuthPresent
189
+ ? deps.codexAuthPresent()
190
+ : detection.hasCodexAuth;
191
+ if (!binaryPresent) {
192
+ return {
193
+ name: "codex",
194
+ passed: false,
195
+ message: "codex binary가 PATH에 없습니다.",
196
+ };
197
+ }
198
+ if (!authPresent) {
199
+ return {
200
+ name: "codex",
201
+ passed: false,
202
+ message: "~/.codex/auth.json 없음. `codex login` 실행 필요.",
203
+ };
204
+ }
205
+ return { name: "codex", passed: true };
206
+ }
207
+ /**
208
+ * Validate the full install outcome.
209
+ *
210
+ * Dedupes the review + learn providers (when same, only pings once),
211
+ * reads credentials from `secrets` with `process.env` as the fallback
212
+ * (so a user who set ANTHROPIC_API_KEY in the shell gets validated
213
+ * without install having to re-capture the key).
214
+ *
215
+ * Never throws — all errors surface as failed `ValidationCheck`
216
+ * entries so the orchestrator can render a complete summary.
217
+ */
218
+ export async function validateInstall(args) {
219
+ const { decisions, secrets, detection, deps = {} } = args;
220
+ const checks = [];
221
+ checks.push(...checkDecisionShape(decisions));
222
+ const providers = new Set();
223
+ providers.add(decisions.reviewProvider);
224
+ providers.add(decisions.learnProvider);
225
+ for (const provider of providers) {
226
+ switch (provider) {
227
+ case "main-native":
228
+ // Nothing to probe — host session is the runtime.
229
+ break;
230
+ case "anthropic": {
231
+ const apiKey = secrets.anthropicApiKey ?? process.env.ANTHROPIC_API_KEY;
232
+ if (!apiKey) {
233
+ checks.push({
234
+ name: "anthropic",
235
+ passed: false,
236
+ message: "ANTHROPIC_API_KEY를 찾을 수 없습니다.",
237
+ });
238
+ }
239
+ else {
240
+ checks.push(await pingAnthropic(apiKey, deps));
241
+ }
242
+ break;
243
+ }
244
+ case "openai": {
245
+ const apiKey = secrets.openaiApiKey ?? process.env.OPENAI_API_KEY;
246
+ if (!apiKey) {
247
+ checks.push({
248
+ name: "openai",
249
+ passed: false,
250
+ message: "OPENAI_API_KEY를 찾을 수 없습니다.",
251
+ });
252
+ }
253
+ else {
254
+ checks.push(await pingOpenai(apiKey, deps));
255
+ }
256
+ break;
257
+ }
258
+ case "litellm": {
259
+ const baseUrl = secrets.litellmBaseUrl ?? process.env.LITELLM_BASE_URL;
260
+ const apiKey = secrets.litellmApiKey ?? process.env.LITELLM_API_KEY;
261
+ if (!baseUrl) {
262
+ checks.push({
263
+ name: "litellm",
264
+ passed: false,
265
+ message: "LITELLM_BASE_URL을 찾을 수 없습니다.",
266
+ });
267
+ }
268
+ else {
269
+ checks.push(await pingLitellm(baseUrl, apiKey, deps));
270
+ }
271
+ break;
272
+ }
273
+ case "codex":
274
+ checks.push(verifyCodex(detection, deps));
275
+ break;
276
+ }
277
+ }
278
+ return {
279
+ ok: checks.every((c) => c.passed),
280
+ checks,
281
+ };
282
+ }
283
+ /**
284
+ * Pretty-print a validation result as text. One line per check,
285
+ * `✓` / `✗` prefix, and indented error message on the same line.
286
+ */
287
+ export function formatValidationResult(result) {
288
+ const lines = [];
289
+ for (const check of result.checks) {
290
+ const mark = check.passed ? "✓" : "✗";
291
+ const suffix = check.message ? ` — ${check.message}` : "";
292
+ lines.push(` ${mark} ${check.name}${suffix}`);
293
+ }
294
+ return lines.join("\n");
295
+ }
@@ -0,0 +1,313 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { formatValidationResult, pingAnthropic, pingLitellm, pingOpenai, validateInstall, verifyCodex, } from "./validation.js";
3
+ // ---------------------------------------------------------------------------
4
+ // Helpers
5
+ // ---------------------------------------------------------------------------
6
+ const BLANK_DETECTION = {
7
+ existingGlobalConfig: false,
8
+ existingProjectConfig: false,
9
+ hasAnthropicKey: false,
10
+ hasOpenAiKey: false,
11
+ hasLitellmBaseUrl: false,
12
+ hasCodexBinary: false,
13
+ hasCodexAuth: false,
14
+ hostIsClaudeCode: false,
15
+ };
16
+ /** Build a stub fetch that returns a fixed Response for every call. */
17
+ function stubFetchReturning(status, body = {}) {
18
+ return (async () => new Response(JSON.stringify(body), {
19
+ status,
20
+ headers: { "content-type": "application/json" },
21
+ }));
22
+ }
23
+ /** Build a stub fetch that throws — network error scenario. */
24
+ function stubFetchThrowing(message) {
25
+ return (async () => {
26
+ throw new Error(message);
27
+ });
28
+ }
29
+ /** Capture the URL + headers of the first request. */
30
+ function spyFetch() {
31
+ const calls = [];
32
+ const fetchFn = async (url, init) => {
33
+ const headers = {};
34
+ const raw = init?.headers;
35
+ if (raw && !Array.isArray(raw) && !(raw instanceof Headers)) {
36
+ Object.assign(headers, raw);
37
+ }
38
+ calls.push({ url: String(url), headers });
39
+ return new Response("{}", { status: 200 });
40
+ };
41
+ return { fetch: fetchFn, calls };
42
+ }
43
+ // ---------------------------------------------------------------------------
44
+ // pingAnthropic
45
+ // ---------------------------------------------------------------------------
46
+ describe("pingAnthropic", () => {
47
+ it("returns passed=true on 200", async () => {
48
+ const check = await pingAnthropic("sk-ant-test", {
49
+ fetch: stubFetchReturning(200),
50
+ });
51
+ expect(check).toEqual({ name: "anthropic", passed: true });
52
+ });
53
+ it("reports auth failure on 401", async () => {
54
+ const check = await pingAnthropic("sk-ant-bad", {
55
+ fetch: stubFetchReturning(401),
56
+ });
57
+ expect(check.passed).toBe(false);
58
+ expect(check.message).toContain("인증 실패");
59
+ });
60
+ it("reports generic HTTP failure on 5xx", async () => {
61
+ const check = await pingAnthropic("sk-ant-test", {
62
+ fetch: stubFetchReturning(500),
63
+ });
64
+ expect(check.passed).toBe(false);
65
+ expect(check.message).toContain("500");
66
+ });
67
+ it("reports network error on fetch throw", async () => {
68
+ const check = await pingAnthropic("sk-ant-test", {
69
+ fetch: stubFetchThrowing("ECONNREFUSED"),
70
+ });
71
+ expect(check.passed).toBe(false);
72
+ expect(check.message).toContain("네트워크");
73
+ expect(check.message).toContain("ECONNREFUSED");
74
+ });
75
+ it("sends x-api-key header and anthropic-version", async () => {
76
+ const spy = spyFetch();
77
+ await pingAnthropic("sk-ant-xyz", { fetch: spy.fetch });
78
+ expect(spy.calls[0]?.url).toBe("https://api.anthropic.com/v1/models");
79
+ expect(spy.calls[0]?.headers["x-api-key"]).toBe("sk-ant-xyz");
80
+ expect(spy.calls[0]?.headers["anthropic-version"]).toBeTruthy();
81
+ });
82
+ });
83
+ // ---------------------------------------------------------------------------
84
+ // pingOpenai
85
+ // ---------------------------------------------------------------------------
86
+ describe("pingOpenai", () => {
87
+ it("returns passed=true on 200", async () => {
88
+ const check = await pingOpenai("sk-test", {
89
+ fetch: stubFetchReturning(200),
90
+ });
91
+ expect(check.passed).toBe(true);
92
+ });
93
+ it("sends Authorization: Bearer header", async () => {
94
+ const spy = spyFetch();
95
+ await pingOpenai("sk-test", { fetch: spy.fetch });
96
+ expect(spy.calls[0]?.url).toBe("https://api.openai.com/v1/models");
97
+ expect(spy.calls[0]?.headers.Authorization).toBe("Bearer sk-test");
98
+ });
99
+ it("reports 401 as auth failure", async () => {
100
+ const check = await pingOpenai("bad", {
101
+ fetch: stubFetchReturning(401),
102
+ });
103
+ expect(check.passed).toBe(false);
104
+ expect(check.message).toContain("인증 실패");
105
+ });
106
+ });
107
+ // ---------------------------------------------------------------------------
108
+ // pingLitellm
109
+ // ---------------------------------------------------------------------------
110
+ describe("pingLitellm", () => {
111
+ it("appends /models to the base URL", async () => {
112
+ const spy = spyFetch();
113
+ await pingLitellm("http://localhost:4000/v1", undefined, {
114
+ fetch: spy.fetch,
115
+ });
116
+ expect(spy.calls[0]?.url).toBe("http://localhost:4000/v1/models");
117
+ });
118
+ it("strips trailing slashes before appending /models", async () => {
119
+ const spy = spyFetch();
120
+ await pingLitellm("http://localhost:4000/v1/", undefined, {
121
+ fetch: spy.fetch,
122
+ });
123
+ expect(spy.calls[0]?.url).toBe("http://localhost:4000/v1/models");
124
+ });
125
+ it("omits Authorization when no apiKey given", async () => {
126
+ const spy = spyFetch();
127
+ await pingLitellm("http://localhost:11434/v1", undefined, {
128
+ fetch: spy.fetch,
129
+ });
130
+ expect(spy.calls[0]?.headers.Authorization).toBeUndefined();
131
+ });
132
+ it("sends Bearer token when apiKey provided", async () => {
133
+ const spy = spyFetch();
134
+ await pingLitellm("https://litellm.example.com/v1", "sk-proxy", {
135
+ fetch: spy.fetch,
136
+ });
137
+ expect(spy.calls[0]?.headers.Authorization).toBe("Bearer sk-proxy");
138
+ });
139
+ it("reports 401 with guidance to set LITELLM_API_KEY", async () => {
140
+ const check = await pingLitellm("http://localhost:4000/v1", undefined, {
141
+ fetch: stubFetchReturning(401),
142
+ });
143
+ expect(check.passed).toBe(false);
144
+ expect(check.message).toContain("LITELLM_API_KEY");
145
+ });
146
+ it("reports network failure on ECONNREFUSED", async () => {
147
+ const check = await pingLitellm("http://localhost:4000/v1", undefined, {
148
+ fetch: stubFetchThrowing("fetch failed"),
149
+ });
150
+ expect(check.passed).toBe(false);
151
+ expect(check.message).toContain("연결 실패");
152
+ });
153
+ });
154
+ // ---------------------------------------------------------------------------
155
+ // verifyCodex (filesystem-level, no network)
156
+ // ---------------------------------------------------------------------------
157
+ describe("verifyCodex", () => {
158
+ it("passes when both binary and auth present in detection", () => {
159
+ const check = verifyCodex({
160
+ ...BLANK_DETECTION,
161
+ hasCodexBinary: true,
162
+ hasCodexAuth: true,
163
+ });
164
+ expect(check).toEqual({ name: "codex", passed: true });
165
+ });
166
+ it("fails with binary missing message", () => {
167
+ const check = verifyCodex(BLANK_DETECTION);
168
+ expect(check.passed).toBe(false);
169
+ expect(check.message).toContain("binary");
170
+ });
171
+ it("fails with auth missing message when binary present", () => {
172
+ const check = verifyCodex({ ...BLANK_DETECTION, hasCodexBinary: true });
173
+ expect(check.passed).toBe(false);
174
+ expect(check.message).toContain("codex login");
175
+ });
176
+ it("dependency overrides win over detection values", () => {
177
+ const check = verifyCodex(BLANK_DETECTION, {
178
+ codexBinaryPresent: () => true,
179
+ codexAuthPresent: () => true,
180
+ });
181
+ expect(check.passed).toBe(true);
182
+ });
183
+ });
184
+ // ---------------------------------------------------------------------------
185
+ // validateInstall orchestrator
186
+ // ---------------------------------------------------------------------------
187
+ const ANTHROPIC_DECISIONS = {
188
+ profileScope: "project",
189
+ reviewProvider: "anthropic",
190
+ learnProvider: "anthropic",
191
+ outputLanguage: "ko",
192
+ };
193
+ describe("validateInstall", () => {
194
+ it("skips network probe for main-native review + anthropic learn", async () => {
195
+ const spy = spyFetch();
196
+ const result = await validateInstall({
197
+ decisions: {
198
+ ...ANTHROPIC_DECISIONS,
199
+ reviewProvider: "main-native",
200
+ },
201
+ secrets: { anthropicApiKey: "sk-ant-test" },
202
+ detection: BLANK_DETECTION,
203
+ deps: { fetch: spy.fetch },
204
+ });
205
+ // Only anthropic is probed — main-native contributes no network call.
206
+ expect(spy.calls.length).toBe(1);
207
+ expect(spy.calls[0]?.url).toContain("api.anthropic.com");
208
+ expect(result.ok).toBe(true);
209
+ });
210
+ it("dedupes when review and learn providers match", async () => {
211
+ const spy = spyFetch();
212
+ await validateInstall({
213
+ decisions: ANTHROPIC_DECISIONS,
214
+ secrets: { anthropicApiKey: "sk-ant-test" },
215
+ detection: BLANK_DETECTION,
216
+ deps: { fetch: spy.fetch },
217
+ });
218
+ expect(spy.calls.length).toBe(1);
219
+ });
220
+ it("probes both providers when they differ", async () => {
221
+ const spy = spyFetch();
222
+ await validateInstall({
223
+ decisions: {
224
+ ...ANTHROPIC_DECISIONS,
225
+ reviewProvider: "anthropic",
226
+ learnProvider: "openai",
227
+ },
228
+ secrets: { anthropicApiKey: "sk-ant", openaiApiKey: "sk-oai" },
229
+ detection: BLANK_DETECTION,
230
+ deps: { fetch: spy.fetch },
231
+ });
232
+ const urls = spy.calls.map((c) => c.url);
233
+ expect(urls.some((u) => u.includes("api.anthropic.com"))).toBe(true);
234
+ expect(urls.some((u) => u.includes("api.openai.com"))).toBe(true);
235
+ });
236
+ it("fails when credential is missing entirely", async () => {
237
+ const result = await validateInstall({
238
+ decisions: ANTHROPIC_DECISIONS,
239
+ secrets: {},
240
+ detection: BLANK_DETECTION,
241
+ deps: { fetch: stubFetchReturning(200) },
242
+ });
243
+ expect(result.ok).toBe(false);
244
+ expect(result.checks.some((c) => c.message?.includes("ANTHROPIC_API_KEY"))).toBe(true);
245
+ });
246
+ it("falls back to process.env when secrets are empty", async () => {
247
+ const prev = process.env.ANTHROPIC_API_KEY;
248
+ process.env.ANTHROPIC_API_KEY = "from-env";
249
+ try {
250
+ const spy = spyFetch();
251
+ const result = await validateInstall({
252
+ decisions: ANTHROPIC_DECISIONS,
253
+ secrets: {},
254
+ detection: BLANK_DETECTION,
255
+ deps: { fetch: spy.fetch },
256
+ });
257
+ expect(result.ok).toBe(true);
258
+ expect(spy.calls[0]?.headers["x-api-key"]).toBe("from-env");
259
+ }
260
+ finally {
261
+ if (prev === undefined)
262
+ delete process.env.ANTHROPIC_API_KEY;
263
+ else
264
+ process.env.ANTHROPIC_API_KEY = prev;
265
+ }
266
+ });
267
+ it("surfaces codex check in mixed-provider setup", async () => {
268
+ const result = await validateInstall({
269
+ decisions: {
270
+ ...ANTHROPIC_DECISIONS,
271
+ reviewProvider: "codex",
272
+ learnProvider: "anthropic",
273
+ },
274
+ secrets: { anthropicApiKey: "sk-ant" },
275
+ detection: BLANK_DETECTION,
276
+ deps: { fetch: stubFetchReturning(200) },
277
+ });
278
+ expect(result.checks.some((c) => c.name === "codex")).toBe(true);
279
+ expect(result.ok).toBe(false); // codex check fails on blank detection
280
+ });
281
+ it("catches learn-provider=main-native shape violation", async () => {
282
+ const result = await validateInstall({
283
+ decisions: {
284
+ ...ANTHROPIC_DECISIONS,
285
+ reviewProvider: "main-native",
286
+ // @ts-expect-error — intentional runtime-only invalid shape
287
+ learnProvider: "main-native",
288
+ },
289
+ secrets: {},
290
+ detection: BLANK_DETECTION,
291
+ deps: { fetch: stubFetchReturning(200) },
292
+ });
293
+ expect(result.ok).toBe(false);
294
+ expect(result.checks.some((c) => c.message?.includes("main-native"))).toBe(true);
295
+ });
296
+ });
297
+ // ---------------------------------------------------------------------------
298
+ // formatValidationResult
299
+ // ---------------------------------------------------------------------------
300
+ describe("formatValidationResult", () => {
301
+ it("marks passed checks with ✓ and failed with ✗", () => {
302
+ const text = formatValidationResult({
303
+ ok: false,
304
+ checks: [
305
+ { name: "anthropic", passed: true },
306
+ { name: "openai", passed: false, message: "oops" },
307
+ ],
308
+ });
309
+ expect(text).toContain("✓ anthropic");
310
+ expect(text).toContain("✗ openai");
311
+ expect(text).toContain("oops");
312
+ });
313
+ });