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.
- package/.onto/authority/core-lens-registry.yaml +134 -0
- package/.onto/authority/core-lexicon.yaml +1562 -0
- package/.onto/authority/diagnostic-codes.yaml +94 -0
- package/.onto/domains/accounting/competency_qs.md +384 -0
- package/.onto/domains/accounting/concepts.md +186 -0
- package/.onto/domains/accounting/conciseness_rules.md +160 -0
- package/.onto/domains/accounting/dependency_rules.md +239 -0
- package/.onto/domains/accounting/domain_scope.md +213 -0
- package/.onto/domains/accounting/extension_cases.md +416 -0
- package/.onto/domains/accounting/logic_rules.md +226 -0
- package/.onto/domains/accounting/structure_spec.md +298 -0
- package/.onto/domains/accounting-kr/competency_qs.md +562 -0
- package/.onto/domains/accounting-kr/concepts.md +187 -0
- package/.onto/domains/accounting-kr/conciseness_rules.md +125 -0
- package/.onto/domains/accounting-kr/dependency_rules.md +93 -0
- package/.onto/domains/accounting-kr/domain_scope.md +140 -0
- package/.onto/domains/accounting-kr/extension_cases.md +343 -0
- package/.onto/domains/accounting-kr/logic_rules.md +160 -0
- package/.onto/domains/accounting-kr/structure_spec.md +85 -0
- package/.onto/domains/business/competency_qs.md +263 -0
- package/.onto/domains/business/concepts.md +200 -0
- package/.onto/domains/business/conciseness_rules.md +135 -0
- package/.onto/domains/business/dependency_rules.md +113 -0
- package/.onto/domains/business/domain_scope.md +240 -0
- package/.onto/domains/business/extension_cases.md +249 -0
- package/.onto/domains/business/logic_rules.md +134 -0
- package/.onto/domains/business/structure_spec.md +114 -0
- package/.onto/domains/finance/competency_qs.md +362 -0
- package/.onto/domains/finance/concepts.md +194 -0
- package/.onto/domains/finance/conciseness_rules.md +155 -0
- package/.onto/domains/finance/dependency_rules.md +171 -0
- package/.onto/domains/finance/domain_scope.md +215 -0
- package/.onto/domains/finance/extension_cases.md +350 -0
- package/.onto/domains/finance/logic_rules.md +191 -0
- package/.onto/domains/finance/structure_spec.md +182 -0
- package/.onto/domains/llm-native-development/competency_qs.md +430 -0
- package/.onto/domains/llm-native-development/concepts.md +242 -0
- package/.onto/domains/llm-native-development/conciseness_rules.md +163 -0
- package/.onto/domains/llm-native-development/dependency_rules.md +216 -0
- package/.onto/domains/llm-native-development/domain_scope.md +197 -0
- package/.onto/domains/llm-native-development/extension_cases.md +474 -0
- package/.onto/domains/llm-native-development/logic_rules.md +123 -0
- package/.onto/domains/llm-native-development/prompt_interface.md +49 -0
- package/.onto/domains/llm-native-development/structure_spec.md +245 -0
- package/.onto/domains/market-intelligence/competency_qs.md +274 -0
- package/.onto/domains/market-intelligence/concepts.md +233 -0
- package/.onto/domains/market-intelligence/conciseness_rules.md +165 -0
- package/.onto/domains/market-intelligence/dependency_rules.md +197 -0
- package/.onto/domains/market-intelligence/domain_scope.md +231 -0
- package/.onto/domains/market-intelligence/extension_cases.md +425 -0
- package/.onto/domains/market-intelligence/logic_rules.md +247 -0
- package/.onto/domains/market-intelligence/structure_spec.md +209 -0
- package/.onto/domains/ontology/competency_qs.md +394 -0
- package/.onto/domains/ontology/concepts.md +172 -0
- package/.onto/domains/ontology/conciseness_rules.md +134 -0
- package/.onto/domains/ontology/dependency_rules.md +125 -0
- package/.onto/domains/ontology/domain_scope.md +114 -0
- package/.onto/domains/ontology/extension_cases.md +501 -0
- package/.onto/domains/ontology/logic_rules.md +114 -0
- package/.onto/domains/ontology/problem_framing_profile.md +67 -0
- package/.onto/domains/ontology/structure_spec.md +115 -0
- package/.onto/domains/palantir-foundry/RESEARCH_NOTES.md +911 -0
- package/.onto/domains/palantir-foundry/competency_qs.md +191 -0
- package/.onto/domains/palantir-foundry/competitive_comparison.md +329 -0
- package/.onto/domains/palantir-foundry/concepts.md +197 -0
- package/.onto/domains/palantir-foundry/conciseness_rules.md +245 -0
- package/.onto/domains/palantir-foundry/dependency_rules.md +135 -0
- package/.onto/domains/palantir-foundry/domain_scope.md +395 -0
- package/.onto/domains/palantir-foundry/extension_cases.md +210 -0
- package/.onto/domains/palantir-foundry/logic_rules.md +172 -0
- package/.onto/domains/palantir-foundry/structure_spec.md +291 -0
- package/.onto/domains/software-engineering/competency_qs.md +538 -0
- package/.onto/domains/software-engineering/concepts.md +238 -0
- package/.onto/domains/software-engineering/conciseness_rules.md +167 -0
- package/.onto/domains/software-engineering/dependency_rules.md +216 -0
- package/.onto/domains/software-engineering/domain_scope.md +183 -0
- package/.onto/domains/software-engineering/extension_cases.md +551 -0
- package/.onto/domains/software-engineering/logic_rules.md +240 -0
- package/.onto/domains/software-engineering/problem_framing_profile.md +68 -0
- package/.onto/domains/software-engineering/structure_spec.md +185 -0
- package/.onto/domains/ui-design/competency_qs.md +567 -0
- package/.onto/domains/ui-design/concepts.md +194 -0
- package/.onto/domains/ui-design/conciseness_rules.md +190 -0
- package/.onto/domains/ui-design/dependency_rules.md +323 -0
- package/.onto/domains/ui-design/domain_scope.md +340 -0
- package/.onto/domains/ui-design/extension_cases.md +563 -0
- package/.onto/domains/ui-design/logic_rules.md +349 -0
- package/.onto/domains/ui-design/structure_spec.md +252 -0
- package/.onto/domains/visual-design/competency_qs.md +472 -0
- package/.onto/domains/visual-design/concepts.md +147 -0
- package/.onto/domains/visual-design/conciseness_rules.md +186 -0
- package/.onto/domains/visual-design/dependency_rules.md +282 -0
- package/.onto/domains/visual-design/domain_scope.md +290 -0
- package/.onto/domains/visual-design/extension_cases.md +480 -0
- package/.onto/domains/visual-design/logic_rules.md +232 -0
- package/.onto/domains/visual-design/structure_spec.md +213 -0
- package/.onto/principles/llm-native-development-guideline.md +401 -0
- package/.onto/principles/llm-runtime-interface-principles.md +665 -0
- package/.onto/principles/non-specialist-communication-guideline.md +74 -0
- package/.onto/principles/ontology-as-code-guideline.md +243 -0
- package/.onto/principles/ontology-as-code-naming-charter.md +130 -0
- package/.onto/principles/product-locality-principle.md +129 -0
- package/.onto/principles/productization-charter.md +569 -0
- package/.onto/processes/evolve/material-kind-adapter-contract.md +113 -0
- package/.onto/processes/reconstruct/reconstruct-boundary-contract.md +366 -0
- package/.onto/processes/reconstruct/source-profile-contract.md +107 -0
- package/.onto/processes/reconstruct/source-profiles/code.md +72 -0
- package/.onto/processes/reconstruct/source-profiles/database.md +74 -0
- package/.onto/processes/reconstruct/source-profiles/document.md +71 -0
- package/.onto/processes/reconstruct/source-profiles/spreadsheet.md +79 -0
- package/.onto/processes/review/binding-contract.md +270 -0
- package/.onto/processes/review/execution-preparation-artifacts.md +281 -0
- package/.onto/processes/review/interpretation-contract.md +245 -0
- package/.onto/processes/review/issue-stance-deliberation-contract.md +761 -0
- package/.onto/processes/review/lens-prompt-contract.md +402 -0
- package/.onto/processes/review/lens-registry.md +127 -0
- package/.onto/processes/review/pre-dispatch-contracts.md +428 -0
- package/.onto/processes/review/productized-live-path.md +398 -0
- package/.onto/processes/review/prompt-execution-runner-contract.md +187 -0
- package/.onto/processes/review/record-contract.md +427 -0
- package/.onto/processes/review/record-field-mapping.md +337 -0
- package/.onto/processes/review/review-context-manifest-contract.md +356 -0
- package/.onto/processes/review/review-execution-ux-contract.md +809 -0
- package/.onto/processes/review/review-target-profile-contract.md +259 -0
- package/.onto/processes/review/shared-phenomenon-contract.md +129 -0
- package/.onto/processes/review/synthesize-prompt-contract.md +343 -0
- package/.onto/processes/shared/target-material-kind-contract.md +198 -0
- package/.onto/roles/axiology.md +81 -0
- package/.onto/roles/conciseness.md +36 -0
- package/.onto/roles/coverage.md +34 -0
- package/.onto/roles/dependency.md +37 -0
- package/.onto/roles/evolution.md +35 -0
- package/.onto/roles/logic.md +104 -0
- package/.onto/roles/pragmatics.md +32 -0
- package/.onto/roles/semantics.md +36 -0
- package/.onto/roles/structure.md +33 -0
- package/.onto/roles/synthesize.md +92 -0
- package/AGENTS.md +240 -0
- package/CLAUDE.md +39 -0
- package/README.md +287 -0
- package/bin/onto +92 -0
- package/dist/cli.js +101 -0
- package/dist/core-api/reconstruct-api.js +222 -0
- package/dist/core-api/review-api.js +1271 -0
- package/dist/core-runtime/cli/assemble-review-record.js +431 -0
- package/dist/core-runtime/cli/bootstrap-review-binding.js +186 -0
- package/dist/core-runtime/cli/codex-nested-dispatch.js +226 -0
- package/dist/core-runtime/cli/codex-nested-dispatch.test.js +390 -0
- package/dist/core-runtime/cli/codex-nested-teamlead-executor.js +464 -0
- package/dist/core-runtime/cli/codex-nested-teamlead-executor.test.js +335 -0
- package/dist/core-runtime/cli/codex-review-unit-executor.js +228 -0
- package/dist/core-runtime/cli/complete-review-session.js +64 -0
- package/dist/core-runtime/cli/complexity-assessment.js +153 -0
- package/dist/core-runtime/cli/coordinator-helpers.js +583 -0
- package/dist/core-runtime/cli/coordinator-state-machine-deliberation.test.js +167 -0
- package/dist/core-runtime/cli/coordinator-state-machine.js +794 -0
- package/dist/core-runtime/cli/e2e-codex-multi-agent-fixes.test.js +615 -0
- package/dist/core-runtime/cli/e2e-start-review-session.test.js +312 -0
- package/dist/core-runtime/cli/health.js +44 -0
- package/dist/core-runtime/cli/inline-http-review-unit-executor.js +656 -0
- package/dist/core-runtime/cli/inline-http-review-unit-executor.test.js +567 -0
- package/dist/core-runtime/cli/materialize-review-execution-preparation.js +104 -0
- package/dist/core-runtime/cli/materialize-review-prompt-packets.js +952 -0
- package/dist/core-runtime/cli/migrate-session-roots.js +118 -0
- package/dist/core-runtime/cli/mock-review-unit-executor.js +285 -0
- package/dist/core-runtime/cli/onto-tools.js +369 -0
- package/dist/core-runtime/cli/prepare-review-session.js +272 -0
- package/dist/core-runtime/cli/render-review-final-output.js +350 -0
- package/dist/core-runtime/cli/repo-layout-migration-replace.smoke.test.js +106 -0
- package/dist/core-runtime/cli/review-invoke-auto-resolution.test.js +268 -0
- package/dist/core-runtime/cli/review-invoke-coordinator-topology.test.js +136 -0
- package/dist/core-runtime/cli/review-invoke-resolver-caching.test.js +201 -0
- package/dist/core-runtime/cli/review-invoke-topology-dispatch.test.js +192 -0
- package/dist/core-runtime/cli/review-invoke.js +2030 -0
- package/dist/core-runtime/cli/run-review-prompt-execution.js +2152 -0
- package/dist/core-runtime/cli/session-root-guard.js +168 -0
- package/dist/core-runtime/cli/spawn-watcher.js +173 -0
- package/dist/core-runtime/cli/spawn-watcher.test.js +457 -0
- package/dist/core-runtime/cli/start-review-session.js +68 -0
- package/dist/core-runtime/cli/strip-wrapping-code-fence.js +56 -0
- package/dist/core-runtime/cli/strip-wrapping-code-fence.test.js +79 -0
- package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.js +412 -0
- package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.test.js +351 -0
- package/dist/core-runtime/cli/topology-executor-mapping.js +139 -0
- package/dist/core-runtime/cli/topology-executor-mapping.test.js +173 -0
- package/dist/core-runtime/cli/write-review-interpretation.js +81 -0
- package/dist/core-runtime/config/onto-config-cli.js +278 -0
- package/dist/core-runtime/config/onto-config-key-path.js +288 -0
- package/dist/core-runtime/config/onto-config-key-path.test.js +195 -0
- package/dist/core-runtime/config/onto-config-preview.js +108 -0
- package/dist/core-runtime/config/onto-config-preview.test.js +132 -0
- package/dist/core-runtime/discovery/config-chain.js +118 -0
- package/dist/core-runtime/discovery/config-chain.test.js +103 -0
- package/dist/core-runtime/discovery/config-profile.js +199 -0
- package/dist/core-runtime/discovery/config-profile.test.js +233 -0
- package/dist/core-runtime/discovery/host-detection.js +33 -0
- package/dist/core-runtime/discovery/host-detection.test.js +186 -0
- package/dist/core-runtime/discovery/installation-paths.js +21 -0
- package/dist/core-runtime/discovery/installation-paths.test.js +65 -0
- package/dist/core-runtime/discovery/lens-registry.js +60 -0
- package/dist/core-runtime/discovery/lens-registry.test.js +81 -0
- package/dist/core-runtime/discovery/onto-home.js +71 -0
- package/dist/core-runtime/discovery/path-normalization.js +28 -0
- package/dist/core-runtime/discovery/path-normalization.test.js +22 -0
- package/dist/core-runtime/discovery/plugin-path.js +72 -0
- package/dist/core-runtime/discovery/plugin-path.test.js +95 -0
- package/dist/core-runtime/discovery/project-root.js +47 -0
- package/dist/core-runtime/discovery/settings-chain.js +353 -0
- package/dist/core-runtime/discovery/walk-up.js +17 -0
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.js +344 -0
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.test.js +915 -0
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile.js +564 -0
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile.test.js +708 -0
- package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.js +165 -0
- package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.test.js +227 -0
- package/dist/core-runtime/evolve/adapters/code-product/validators/validate.js +59 -0
- package/dist/core-runtime/evolve/adapters/code-product/validators/validate.test.js +205 -0
- package/dist/core-runtime/evolve/adapters/methodology/adapter.js +16 -0
- package/dist/core-runtime/evolve/adapters/methodology/adapter.test.js +9 -0
- package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.js +298 -0
- package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.test.js +70 -0
- package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.js +46 -0
- package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.test.js +73 -0
- package/dist/core-runtime/evolve/adapters/registry.js +47 -0
- package/dist/core-runtime/evolve/adapters/registry.test.js +67 -0
- package/dist/core-runtime/evolve/cli.js +256 -0
- package/dist/core-runtime/evolve/commands/align.js +194 -0
- package/dist/core-runtime/evolve/commands/align.test.js +82 -0
- package/dist/core-runtime/evolve/commands/apply.js +161 -0
- package/dist/core-runtime/evolve/commands/apply.test.js +138 -0
- package/dist/core-runtime/evolve/commands/close.js +39 -0
- package/dist/core-runtime/evolve/commands/close.test.js +99 -0
- package/dist/core-runtime/evolve/commands/defer.js +40 -0
- package/dist/core-runtime/evolve/commands/defer.test.js +134 -0
- package/dist/core-runtime/evolve/commands/draft.js +323 -0
- package/dist/core-runtime/evolve/commands/draft.test.js +178 -0
- package/dist/core-runtime/evolve/commands/e2e-evolve-full-cycle.test.js +208 -0
- package/dist/core-runtime/evolve/commands/error-messages.js +125 -0
- package/dist/core-runtime/evolve/commands/error-messages.test.js +167 -0
- package/dist/core-runtime/evolve/commands/propose-align.js +222 -0
- package/dist/core-runtime/evolve/commands/propose-align.test.js +136 -0
- package/dist/core-runtime/evolve/commands/reconstruct.js +330 -0
- package/dist/core-runtime/evolve/commands/reconstruct.test.js +278 -0
- package/dist/core-runtime/evolve/commands/shared.js +22 -0
- package/dist/core-runtime/evolve/commands/stale-check.js +103 -0
- package/dist/core-runtime/evolve/commands/stale-check.test.js +84 -0
- package/dist/core-runtime/evolve/commands/start.js +887 -0
- package/dist/core-runtime/evolve/commands/start.test.js +396 -0
- package/dist/core-runtime/evolve/config/project-config.js +99 -0
- package/dist/core-runtime/evolve/config/project-config.test.js +170 -0
- package/dist/core-runtime/evolve/renderers/align-packet.js +280 -0
- package/dist/core-runtime/evolve/renderers/align-packet.test.js +332 -0
- package/dist/core-runtime/evolve/renderers/draft-packet.js +303 -0
- package/dist/core-runtime/evolve/renderers/draft-packet.test.js +377 -0
- package/dist/core-runtime/evolve/renderers/format.js +5 -0
- package/dist/core-runtime/evolve/renderers/scope-md.js +237 -0
- package/dist/core-runtime/evolve/renderers/scope-md.test.js +306 -0
- package/dist/core-runtime/govern/cli.js +369 -0
- package/dist/core-runtime/govern/cli.test.js +314 -0
- package/dist/core-runtime/govern/drift-engine.js +103 -0
- package/dist/core-runtime/govern/drift-engine.test.js +319 -0
- package/dist/core-runtime/govern/promote-principle.js +206 -0
- package/dist/core-runtime/govern/promote-principle.test.js +368 -0
- package/dist/core-runtime/govern/queue.js +81 -0
- package/dist/core-runtime/govern/types.js +16 -0
- package/dist/core-runtime/install/cli.js +530 -0
- package/dist/core-runtime/install/detect.js +128 -0
- package/dist/core-runtime/install/detect.test.js +155 -0
- package/dist/core-runtime/install/gitignore-update.js +74 -0
- package/dist/core-runtime/install/gitignore-update.test.js +64 -0
- package/dist/core-runtime/install/install-integration.test.js +373 -0
- package/dist/core-runtime/install/prompts.js +389 -0
- package/dist/core-runtime/install/prompts.test.js +293 -0
- package/dist/core-runtime/install/types.js +26 -0
- package/dist/core-runtime/install/validation.js +295 -0
- package/dist/core-runtime/install/validation.test.js +313 -0
- package/dist/core-runtime/install/writer.js +254 -0
- package/dist/core-runtime/install/writer.test.js +218 -0
- package/dist/core-runtime/learning/extractor.js +461 -0
- package/dist/core-runtime/learning/feedback.js +179 -0
- package/dist/core-runtime/learning/health-report.js +165 -0
- package/dist/core-runtime/learning/health-report.test.js +169 -0
- package/dist/core-runtime/learning/loader.js +388 -0
- package/dist/core-runtime/learning/loader.test.js +102 -0
- package/dist/core-runtime/learning/promote/apply-state.js +240 -0
- package/dist/core-runtime/learning/promote/audit-obligation.js +195 -0
- package/dist/core-runtime/learning/promote/collector.js +432 -0
- package/dist/core-runtime/learning/promote/degraded-state.js +125 -0
- package/dist/core-runtime/learning/promote/domain-doc-proposer.js +166 -0
- package/dist/core-runtime/learning/promote/e2e-promote.test.js +6385 -0
- package/dist/core-runtime/learning/promote/health-snapshot.js +150 -0
- package/dist/core-runtime/learning/promote/insight-reclassifier.js +544 -0
- package/dist/core-runtime/learning/promote/judgment-auditor.js +517 -0
- package/dist/core-runtime/learning/promote/panel-reviewer.js +1158 -0
- package/dist/core-runtime/learning/promote/promote-executor.js +1675 -0
- package/dist/core-runtime/learning/promote/promoter.js +307 -0
- package/dist/core-runtime/learning/promote/retirement.js +122 -0
- package/dist/core-runtime/learning/promote/types.js +23 -0
- package/dist/core-runtime/learning/prompt-sections.js +51 -0
- package/dist/core-runtime/learning/shared/artifact-registry-init.js +45 -0
- package/dist/core-runtime/learning/shared/artifact-registry.js +254 -0
- package/dist/core-runtime/learning/shared/audit-obligation-kernel.js +73 -0
- package/dist/core-runtime/learning/shared/audit-state.js +99 -0
- package/dist/core-runtime/learning/shared/duplicate-check.js +28 -0
- package/dist/core-runtime/learning/shared/llm-caller.js +831 -0
- package/dist/core-runtime/learning/shared/llm-caller.test.js +601 -0
- package/dist/core-runtime/learning/shared/llm-tool-loop.js +393 -0
- package/dist/core-runtime/learning/shared/mode.js +25 -0
- package/dist/core-runtime/learning/shared/paths.js +84 -0
- package/dist/core-runtime/learning/shared/paths.test.js +79 -0
- package/dist/core-runtime/learning/shared/patterns.js +37 -0
- package/dist/core-runtime/learning/shared/recoverability.js +355 -0
- package/dist/core-runtime/learning/shared/recovery-context.js +374 -0
- package/dist/core-runtime/learning/shared/scope.js +1 -0
- package/dist/core-runtime/learning/shared/semantic-classifier.js +94 -0
- package/dist/core-runtime/learning/shared/specs/apply-execution-state-spec.js +42 -0
- package/dist/core-runtime/learning/shared/specs/audit-state-spec.js +37 -0
- package/dist/core-runtime/learning/shared/specs/backup-metadata-spec.js +39 -0
- package/dist/core-runtime/learning/shared/specs/emergency-log-spec.js +41 -0
- package/dist/core-runtime/learning/shared/specs/layout-version-spec.js +38 -0
- package/dist/core-runtime/learning/shared/specs/promote-decisions-spec.js +43 -0
- package/dist/core-runtime/learning/shared/specs/promote-report-spec.js +113 -0
- package/dist/core-runtime/learning/shared/specs/prune-log-spec.js +36 -0
- package/dist/core-runtime/learning/shared/specs/recovery-resolution-spec.js +48 -0
- package/dist/core-runtime/learning/shared/specs/restore-manifest-spec.js +43 -0
- package/dist/core-runtime/learning/shared/specs/spec-helpers.js +64 -0
- package/dist/core-runtime/learning/usage-tracker.js +190 -0
- package/dist/core-runtime/learning/usage-tracker.test.js +176 -0
- package/dist/core-runtime/llm/llm-caller.js +649 -0
- package/dist/core-runtime/llm/llm-tool-loop.js +401 -0
- package/dist/core-runtime/llm/model-switcher.js +62 -0
- package/dist/core-runtime/logger.js +22 -0
- package/dist/core-runtime/onboard/detect-review-axes.js +122 -0
- package/dist/core-runtime/onboard/detect-review-axes.test.js +127 -0
- package/dist/core-runtime/onboard/write-review-block.js +188 -0
- package/dist/core-runtime/onboard/write-review-block.test.js +240 -0
- package/dist/core-runtime/readers/brownfield-builder.js +150 -0
- package/dist/core-runtime/readers/brownfield-builder.test.js +136 -0
- package/dist/core-runtime/readers/code-chunk-collector.js +53 -0
- package/dist/core-runtime/readers/code-chunk-collector.test.js +136 -0
- package/dist/core-runtime/readers/file-utils.js +240 -0
- package/dist/core-runtime/readers/file-utils.test.js +146 -0
- package/dist/core-runtime/readers/lexicon-citation-check.js +93 -0
- package/dist/core-runtime/readers/lexicon-citation-check.test.js +77 -0
- package/dist/core-runtime/readers/mcp-figma.js +30 -0
- package/dist/core-runtime/readers/mcp-figma.test.js +82 -0
- package/dist/core-runtime/readers/mcp-generic.js +31 -0
- package/dist/core-runtime/readers/mcp-generic.test.js +76 -0
- package/dist/core-runtime/readers/ontology-index.js +148 -0
- package/dist/core-runtime/readers/ontology-index.test.js +245 -0
- package/dist/core-runtime/readers/ontology-query.js +168 -0
- package/dist/core-runtime/readers/ontology-query.test.js +311 -0
- package/dist/core-runtime/readers/ontology-resolve.js +48 -0
- package/dist/core-runtime/readers/ontology-resolve.test.js +48 -0
- package/dist/core-runtime/readers/patterns/index.js +7 -0
- package/dist/core-runtime/readers/review-log.js +213 -0
- package/dist/core-runtime/readers/review-log.test.js +313 -0
- package/dist/core-runtime/readers/scan-local.js +102 -0
- package/dist/core-runtime/readers/scan-local.test.js +102 -0
- package/dist/core-runtime/readers/scan-tarball.js +121 -0
- package/dist/core-runtime/readers/scan-tarball.test.js +283 -0
- package/dist/core-runtime/readers/scan-vault.js +34 -0
- package/dist/core-runtime/readers/scan-vault.test.js +81 -0
- package/dist/core-runtime/readers/types.js +42 -0
- package/dist/core-runtime/readers/types.test.js +94 -0
- package/dist/core-runtime/readers/viewpoint-collectors.js +229 -0
- package/dist/core-runtime/reconstruct/artifact-types.js +1 -0
- package/dist/core-runtime/reconstruct/directive-validation.js +123 -0
- package/dist/core-runtime/reconstruct/materialize-preparation.js +251 -0
- package/dist/core-runtime/reconstruct/record.js +198 -0
- package/dist/core-runtime/reconstruct/run.js +578 -0
- package/dist/core-runtime/reconstruct/seed-candidate-validation.js +356 -0
- package/dist/core-runtime/reconstruct/source-observations.js +62 -0
- package/dist/core-runtime/reconstruct/source-profiles.js +73 -0
- package/dist/core-runtime/release-channel/release-channel.js +90 -0
- package/dist/core-runtime/review/artifact-types.js +13 -0
- package/dist/core-runtime/review/citation-audit.js +204 -0
- package/dist/core-runtime/review/citation-audit.test.js +165 -0
- package/dist/core-runtime/review/controlled-lens-deliberation.js +125 -0
- package/dist/core-runtime/review/execution-plan-resolver.js +247 -0
- package/dist/core-runtime/review/execution-plan-resolver.test.js +243 -0
- package/dist/core-runtime/review/execution-topology-resolver-axis-first.test.js +246 -0
- package/dist/core-runtime/review/execution-topology-resolver.js +401 -0
- package/dist/core-runtime/review/execution-topology-resolver.test.js +315 -0
- package/dist/core-runtime/review/failure-records.js +57 -0
- package/dist/core-runtime/review/inline-context-embedder.js +141 -0
- package/dist/core-runtime/review/inline-context-embedder.test.js +154 -0
- package/dist/core-runtime/review/issue-artifact-runtime.js +859 -0
- package/dist/core-runtime/review/legacy-mode-policy.js +88 -0
- package/dist/core-runtime/review/lens-completion-policy.js +17 -0
- package/dist/core-runtime/review/materializers-effort-persist.test.js +79 -0
- package/dist/core-runtime/review/materializers.js +963 -0
- package/dist/core-runtime/review/ontology-path-classifier.js +179 -0
- package/dist/core-runtime/review/ontology-path-classifier.test.js +216 -0
- package/dist/core-runtime/review/packet-boundary-policy.js +215 -0
- package/dist/core-runtime/review/packet-boundary-policy.test.js +107 -0
- package/dist/core-runtime/review/participating-lens-paths.js +61 -0
- package/dist/core-runtime/review/participating-lens-paths.test.js +73 -0
- package/dist/core-runtime/review/review-artifact-utils.js +287 -0
- package/dist/core-runtime/review/review-config-legacy-translate.js +244 -0
- package/dist/core-runtime/review/review-config-legacy-translate.test.js +161 -0
- package/dist/core-runtime/review/review-config-validator.js +289 -0
- package/dist/core-runtime/review/review-config-validator.test.js +236 -0
- package/dist/core-runtime/review/review-execution-profile.js +193 -0
- package/dist/core-runtime/review/review-execution-route.js +52 -0
- package/dist/core-runtime/review/review-progress-contract.js +123 -0
- package/dist/core-runtime/review/review-record-validation.js +251 -0
- package/dist/core-runtime/review/review-result-classification.js +379 -0
- package/dist/core-runtime/review/review-state-machine.js +39 -0
- package/dist/core-runtime/review/route-visibility.js +125 -0
- package/dist/core-runtime/review/shape-pipeline-audit.test.js +311 -0
- package/dist/core-runtime/review/shape-to-topology-id.js +117 -0
- package/dist/core-runtime/review/shape-to-topology-id.test.js +132 -0
- package/dist/core-runtime/review/topology-shape-derivation.js +155 -0
- package/dist/core-runtime/review/topology-shape-derivation.test.js +195 -0
- package/dist/core-runtime/scope-runtime/constants.js +12 -0
- package/dist/core-runtime/scope-runtime/constraint-pool.js +166 -0
- package/dist/core-runtime/scope-runtime/constraint-pool.test.js +674 -0
- package/dist/core-runtime/scope-runtime/domain-validation-log.js +135 -0
- package/dist/core-runtime/scope-runtime/domain-validation-log.test.js +156 -0
- package/dist/core-runtime/scope-runtime/eval-persistence.js +65 -0
- package/dist/core-runtime/scope-runtime/eval-persistence.test.js +84 -0
- package/dist/core-runtime/scope-runtime/event-pipeline.js +64 -0
- package/dist/core-runtime/scope-runtime/event-pipeline.test.js +450 -0
- package/dist/core-runtime/scope-runtime/event-store.js +39 -0
- package/dist/core-runtime/scope-runtime/event-store.test.js +95 -0
- package/dist/core-runtime/scope-runtime/gate-guard.js +348 -0
- package/dist/core-runtime/scope-runtime/gate-guard.test.js +1047 -0
- package/dist/core-runtime/scope-runtime/hash.js +4 -0
- package/dist/core-runtime/scope-runtime/hash.test.js +33 -0
- package/dist/core-runtime/scope-runtime/id.js +4 -0
- package/dist/core-runtime/scope-runtime/id.test.js +17 -0
- package/dist/core-runtime/scope-runtime/reducer.js +297 -0
- package/dist/core-runtime/scope-runtime/reducer.test.js +759 -0
- package/dist/core-runtime/scope-runtime/scope-manager.js +161 -0
- package/dist/core-runtime/scope-runtime/state-machine.js +309 -0
- package/dist/core-runtime/scope-runtime/state-machine.test.js +704 -0
- package/dist/core-runtime/scope-runtime/types.js +116 -0
- package/dist/core-runtime/scope-runtime/types.test.js +69 -0
- package/dist/core-runtime/target-material-kind.js +256 -0
- package/dist/core-runtime/translate/render-for-user.js +169 -0
- package/dist/core-runtime/translate/render-for-user.test.js +122 -0
- package/dist/mcp/server.js +1011 -0
- package/dist/mcp/tool-schemas.js +93 -0
- package/dist/providers/capability-contract.js +1 -0
- package/package.json +68 -0
- package/settings.example.json +33 -0
|
@@ -0,0 +1,2030 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execSync } from "node:child_process";
|
|
3
|
+
import fsSync from "node:fs";
|
|
4
|
+
import fs from "node:fs/promises";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { createInterface } from "node:readline/promises";
|
|
8
|
+
import { pathToFileURL } from "node:url";
|
|
9
|
+
import { completeReviewSession } from "./complete-review-session.js";
|
|
10
|
+
import { executeReviewPromptExecution, } from "./run-review-prompt-execution.js";
|
|
11
|
+
import { startReviewSession } from "./start-review-session.js";
|
|
12
|
+
import { spawnWatcherPane } from "./spawn-watcher.js";
|
|
13
|
+
import { generateReviewSessionId } from "../review/materializers.js";
|
|
14
|
+
import { fileExists, hasOptionFlag, normalizeDomainValue, readMultiOptionValuesFromArgv, readYamlDocument, readSingleOptionValueFromArgv, } from "../review/review-artifact-utils.js";
|
|
15
|
+
import { printOntoReleaseChannelNotice } from "../release-channel/release-channel.js";
|
|
16
|
+
import { resolveOntoHome } from "../discovery/onto-home.js";
|
|
17
|
+
import { resolveSettingsChain } from "../discovery/settings-chain.js";
|
|
18
|
+
import { loadCoreLensRegistry } from "../discovery/lens-registry.js";
|
|
19
|
+
import { normalizeLlmModelSwitcher } from "../llm/model-switcher.js";
|
|
20
|
+
import { resolveReviewExecutionProfile, } from "../review/review-execution-profile.js";
|
|
21
|
+
import { buildReviewExecutionRoute } from "../review/review-execution-route.js";
|
|
22
|
+
import { readValidatedReviewRecord } from "../review/review-record-validation.js";
|
|
23
|
+
import { readReviewResultClassification } from "../review/review-result-classification.js";
|
|
24
|
+
import { createStructuredFailureRecord, ReviewStructuredFailureError, writeAndThrowStructuredFailureRecord, } from "../review/failure-records.js";
|
|
25
|
+
import { assessComplexity, selectLenses } from "./complexity-assessment.js";
|
|
26
|
+
// Lens IDs derived from .onto/authority/core-lens-registry.yaml (single source of truth)
|
|
27
|
+
const _registry = loadCoreLensRegistry();
|
|
28
|
+
const FULL_REVIEW_LENS_IDS = _registry.full_review_lens_ids;
|
|
29
|
+
const CORE_AXIS_LENS_IDS = _registry.core_axis_lens_ids;
|
|
30
|
+
const KNOWN_PASSTHROUGH_OPTION_NAMES = [
|
|
31
|
+
"project-root",
|
|
32
|
+
"onto-home",
|
|
33
|
+
"session-id",
|
|
34
|
+
"requested-target",
|
|
35
|
+
"requested-domain-token",
|
|
36
|
+
"entrypoint",
|
|
37
|
+
"target-scope-kind",
|
|
38
|
+
"primary-ref",
|
|
39
|
+
"member-ref",
|
|
40
|
+
"bundle-kind",
|
|
41
|
+
"intent-summary",
|
|
42
|
+
"domain-recommendation",
|
|
43
|
+
"domain-selection-required",
|
|
44
|
+
"review-mode-recommendation",
|
|
45
|
+
"always-include-lens-id",
|
|
46
|
+
"recommended-lens-id",
|
|
47
|
+
"rationale",
|
|
48
|
+
"ambiguity-note",
|
|
49
|
+
"resolved-target-ref",
|
|
50
|
+
"domain-final-value",
|
|
51
|
+
"domain-selection-mode",
|
|
52
|
+
"review-mode",
|
|
53
|
+
"lens-id",
|
|
54
|
+
"binding-note",
|
|
55
|
+
"web-research-policy",
|
|
56
|
+
"repo-exploration-policy",
|
|
57
|
+
"recursive-reference-expansion-policy",
|
|
58
|
+
"filesystem-allowed-root",
|
|
59
|
+
"materialized-kind",
|
|
60
|
+
"materialized-ref",
|
|
61
|
+
"system-purpose-ref",
|
|
62
|
+
"domain-context-ref",
|
|
63
|
+
"role-definition-ref",
|
|
64
|
+
"execution-rule-ref",
|
|
65
|
+
"excluded-name",
|
|
66
|
+
"max-listing-depth",
|
|
67
|
+
"max-listing-entries",
|
|
68
|
+
"max-embed-lines",
|
|
69
|
+
];
|
|
70
|
+
const KNOWN_PASSTHROUGH_FLAG_NAMES = [
|
|
71
|
+
"codex",
|
|
72
|
+
"confirm-value-alignment",
|
|
73
|
+
];
|
|
74
|
+
const KNOWN_INVOKE_ONLY_OPTION_NAMES = [
|
|
75
|
+
"request-text",
|
|
76
|
+
"executor-realization",
|
|
77
|
+
"executor-bin",
|
|
78
|
+
"executor-arg",
|
|
79
|
+
"synthesize-executor-realization",
|
|
80
|
+
"synthesize-executor-bin",
|
|
81
|
+
"synthesize-executor-arg",
|
|
82
|
+
"filesystem-boundary-decision",
|
|
83
|
+
"diff-range",
|
|
84
|
+
"model",
|
|
85
|
+
"reasoning-effort",
|
|
86
|
+
"domain",
|
|
87
|
+
];
|
|
88
|
+
const KNOWN_INVOKE_ONLY_FLAG_NAMES = [
|
|
89
|
+
"codex",
|
|
90
|
+
"prepare-only",
|
|
91
|
+
"no-watch",
|
|
92
|
+
"no-domain",
|
|
93
|
+
];
|
|
94
|
+
function requireString(value, optionName) {
|
|
95
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
96
|
+
throw new Error(`Missing required option --${optionName}`);
|
|
97
|
+
}
|
|
98
|
+
return value;
|
|
99
|
+
}
|
|
100
|
+
const EXECUTOR_SCRIPT_FILENAMES = {
|
|
101
|
+
codex: "codex-review-unit-executor",
|
|
102
|
+
mock: "mock-review-unit-executor",
|
|
103
|
+
ts_inline_http: "inline-http-review-unit-executor",
|
|
104
|
+
};
|
|
105
|
+
function resolveDirectExecutorPath(realization, ontoHome) {
|
|
106
|
+
const filename = EXECUTOR_SCRIPT_FILENAMES[realization];
|
|
107
|
+
if (!filename)
|
|
108
|
+
return null;
|
|
109
|
+
const distPath = path.join(ontoHome, "dist", "core-runtime", "cli", `${filename}.js`);
|
|
110
|
+
const srcPath = path.join(ontoHome, "src", "core-runtime", "cli", `${filename}.ts`);
|
|
111
|
+
if (fsSync.existsSync(distPath)) {
|
|
112
|
+
if (fsSync.existsSync(srcPath)) {
|
|
113
|
+
const distStat = fsSync.statSync(distPath);
|
|
114
|
+
const srcStat = fsSync.statSync(srcPath);
|
|
115
|
+
if (srcStat.mtimeMs > distStat.mtimeMs) {
|
|
116
|
+
throw new Error(`dist/${filename}.js is older than src/${filename}.ts. Run npm run build before review execution.`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return { bin: "node", scriptPath: distPath };
|
|
120
|
+
}
|
|
121
|
+
const tsxBin = path.join(ontoHome, "node_modules", ".bin", "tsx");
|
|
122
|
+
if (fsSync.existsSync(srcPath) && fsSync.existsSync(tsxBin)) {
|
|
123
|
+
return { bin: tsxBin, scriptPath: srcPath };
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
function buildExecutorConfigFromRealization(realization, ontoHome) {
|
|
128
|
+
if (typeof ontoHome === "string" && ontoHome.length > 0) {
|
|
129
|
+
const direct = resolveDirectExecutorPath(realization, ontoHome);
|
|
130
|
+
if (direct) {
|
|
131
|
+
// No "--" separator for direct invocation. The "--" is only needed
|
|
132
|
+
// for npm run (to separate npm args from script args). With direct
|
|
133
|
+
// tsx/node invocation, "--" would be interpreted by parseArgs as
|
|
134
|
+
// end-of-options, causing all subsequent args to be treated as
|
|
135
|
+
// positional — triggering "Unexpected argument" errors.
|
|
136
|
+
return { bin: direct.bin, args: [direct.scriptPath] };
|
|
137
|
+
}
|
|
138
|
+
throw new Error(`Executor script not found for realization=${realization} under ${ontoHome}.`);
|
|
139
|
+
}
|
|
140
|
+
throw new Error("ontoHome is required to resolve review executor script paths.");
|
|
141
|
+
}
|
|
142
|
+
function inferExecutorRealization(config) {
|
|
143
|
+
const joinedArgs = config.args.join(" ");
|
|
144
|
+
for (const [realization, filename] of Object.entries(EXECUTOR_SCRIPT_FILENAMES)) {
|
|
145
|
+
if (joinedArgs.includes(filename)) {
|
|
146
|
+
return realization;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return "custom";
|
|
150
|
+
}
|
|
151
|
+
function applyExecutorOverrideToProfile(profile, argv) {
|
|
152
|
+
const explicitRealization = readSingleOptionValueFromArgv(argv, "executor-realization");
|
|
153
|
+
if (explicitRealization === "mock") {
|
|
154
|
+
return {
|
|
155
|
+
...profile,
|
|
156
|
+
worker_executor: "mock",
|
|
157
|
+
host: "standalone",
|
|
158
|
+
trace: [...profile.trace, "worker executor overridden by --executor-realization=mock"],
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
if (explicitRealization === "codex") {
|
|
162
|
+
return {
|
|
163
|
+
...profile,
|
|
164
|
+
worker_executor: "codex",
|
|
165
|
+
host: "codex",
|
|
166
|
+
trace: [...profile.trace, "worker executor overridden by --executor-realization=codex"],
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
if (explicitRealization === "ts_inline_http") {
|
|
170
|
+
return {
|
|
171
|
+
...profile,
|
|
172
|
+
worker_executor: "direct_call",
|
|
173
|
+
host: profile.provider ?? profile.host,
|
|
174
|
+
trace: [
|
|
175
|
+
...profile.trace,
|
|
176
|
+
"worker executor overridden by --executor-realization=ts_inline_http",
|
|
177
|
+
],
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return profile;
|
|
181
|
+
}
|
|
182
|
+
function isInsidePath(root, candidate) {
|
|
183
|
+
const relative = path.relative(path.resolve(root), path.resolve(candidate));
|
|
184
|
+
return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
|
|
185
|
+
}
|
|
186
|
+
function displayPathFromProject(projectRoot, candidate) {
|
|
187
|
+
if (!path.isAbsolute(candidate))
|
|
188
|
+
return candidate;
|
|
189
|
+
const relative = path.relative(projectRoot, candidate);
|
|
190
|
+
return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative))
|
|
191
|
+
? relative || "."
|
|
192
|
+
: candidate;
|
|
193
|
+
}
|
|
194
|
+
function displayMaybePathFromProject(projectRoot, value) {
|
|
195
|
+
return path.isAbsolute(value) ? displayPathFromProject(projectRoot, value) : value;
|
|
196
|
+
}
|
|
197
|
+
function displaySettingValue(value) {
|
|
198
|
+
return typeof value === "string" && value.length > 0 ? value : "(unset)";
|
|
199
|
+
}
|
|
200
|
+
function displayActorLlmRef(value) {
|
|
201
|
+
if (value === "inherit")
|
|
202
|
+
return "inherit";
|
|
203
|
+
return [
|
|
204
|
+
`auth=${displaySettingValue(value.auth)}`,
|
|
205
|
+
`provider=${displaySettingValue(value.provider)}`,
|
|
206
|
+
`model=${displaySettingValue(value.model)}`,
|
|
207
|
+
`effort=${displaySettingValue(value.effort)}`,
|
|
208
|
+
`service_tier=${displaySettingValue(value.service_tier)}`,
|
|
209
|
+
].join(", ");
|
|
210
|
+
}
|
|
211
|
+
function formatPreviewList(items, indent = " ") {
|
|
212
|
+
return items.length > 0
|
|
213
|
+
? items.map((item) => `${indent}- ${item}`)
|
|
214
|
+
: [`${indent}- (none)`];
|
|
215
|
+
}
|
|
216
|
+
function renderReviewStartPreview(args) {
|
|
217
|
+
const { projectRoot, sessionRoot, setup, reviewExecutionProfile } = args;
|
|
218
|
+
const inputs = setup.resolvedInvokeInputs;
|
|
219
|
+
const targetPath = path.resolve(inputs.targetPath);
|
|
220
|
+
const boundaryLabel = isInsidePath(projectRoot, targetPath)
|
|
221
|
+
? "project"
|
|
222
|
+
: "external";
|
|
223
|
+
const projectSettingsPath = path.join(projectRoot, ".onto", "settings.json");
|
|
224
|
+
const userSettingsPath = path.join(os.homedir(), ".onto", "settings.json");
|
|
225
|
+
const selectedDomain = inputs.domainFinalValue.length > 0 ? inputs.domainFinalValue : "no-domain";
|
|
226
|
+
const configuredLensIds = inputs.resolvedLensIds;
|
|
227
|
+
const profileTrace = reviewExecutionProfile.trace.length > 0
|
|
228
|
+
? reviewExecutionProfile.trace
|
|
229
|
+
: ["profile resolved from settings and host signals"];
|
|
230
|
+
return [
|
|
231
|
+
"[review start]",
|
|
232
|
+
"scope:",
|
|
233
|
+
` target: ${displayPathFromProject(projectRoot, targetPath)}`,
|
|
234
|
+
` boundary: ${boundaryLabel}`,
|
|
235
|
+
` target_scope_kind: ${inputs.targetScopeKind}`,
|
|
236
|
+
` materialized_kind: ${inputs.materializedKind}`,
|
|
237
|
+
" resolved_target_refs:",
|
|
238
|
+
...formatPreviewList(inputs.resolvedTargetRefs.map((ref) => displayMaybePathFromProject(projectRoot, ref))),
|
|
239
|
+
" filesystem_allowed_roots:",
|
|
240
|
+
...formatPreviewList(inputs.filesystemAllowedRoots.map((root) => displayMaybePathFromProject(projectRoot, root))),
|
|
241
|
+
` session_root: ${displayPathFromProject(projectRoot, sessionRoot)}`,
|
|
242
|
+
"intent:",
|
|
243
|
+
` request_text: ${inputs.requestText}`,
|
|
244
|
+
"domain:",
|
|
245
|
+
` requested_token: ${inputs.requestedDomainToken.length > 0 ? inputs.requestedDomainToken : "(none)"}`,
|
|
246
|
+
` selected: ${selectedDomain}`,
|
|
247
|
+
` selection_mode: ${inputs.domainSelectionMode}`,
|
|
248
|
+
` selection_required: ${String(inputs.domainSelectionRequired)}`,
|
|
249
|
+
"review_lenses:",
|
|
250
|
+
` review_mode: ${inputs.reviewMode}`,
|
|
251
|
+
` lens_count: ${configuredLensIds.length}`,
|
|
252
|
+
` lens_ids: ${configuredLensIds.join(", ")}`,
|
|
253
|
+
"execution:",
|
|
254
|
+
` mode: ${reviewExecutionProfile.mode}`,
|
|
255
|
+
` host_runtime: ${reviewExecutionProfile.host}`,
|
|
256
|
+
` worker_executor: ${reviewExecutionProfile.worker_executor}`,
|
|
257
|
+
` teamlead_seat: ${reviewExecutionProfile.teamlead.seat}`,
|
|
258
|
+
` lens_seat: ${reviewExecutionProfile.lens.seat}`,
|
|
259
|
+
` deliberation: ${reviewExecutionProfile.deliberation}`,
|
|
260
|
+
` max_concurrent_lenses: ${setup.maxConcurrentLenses} (all selected lenses)`,
|
|
261
|
+
"model:",
|
|
262
|
+
` auth: ${displaySettingValue(reviewExecutionProfile.auth)}`,
|
|
263
|
+
` provider: ${displaySettingValue(reviewExecutionProfile.provider)}`,
|
|
264
|
+
` model: ${displaySettingValue(reviewExecutionProfile.model)}`,
|
|
265
|
+
` effort: ${displaySettingValue(reviewExecutionProfile.effort)}`,
|
|
266
|
+
` service_tier: ${displaySettingValue(reviewExecutionProfile.service_tier)}`,
|
|
267
|
+
` teamlead_llm: ${displayActorLlmRef(reviewExecutionProfile.teamlead.llm)}`,
|
|
268
|
+
` lens_llm: ${displayActorLlmRef(reviewExecutionProfile.lens.llm)}`,
|
|
269
|
+
` synthesize_llm: ${displayActorLlmRef(reviewExecutionProfile.synthesize.llm)}`,
|
|
270
|
+
"configuration:",
|
|
271
|
+
` project_settings: ${displayPathFromProject(projectRoot, projectSettingsPath)}`,
|
|
272
|
+
` user_settings: ${userSettingsPath}`,
|
|
273
|
+
" mcp_arguments: domain/noDomain, reviewMode, lensIds",
|
|
274
|
+
" dev_harness_flags: --domain, --no-domain, --review-mode, --lens-id",
|
|
275
|
+
"profile_trace:",
|
|
276
|
+
...formatPreviewList(profileTrace),
|
|
277
|
+
].join("\n");
|
|
278
|
+
}
|
|
279
|
+
function stringValue(value, fallback = "unknown") {
|
|
280
|
+
return typeof value === "string" && value.trim().length > 0
|
|
281
|
+
? value.trim()
|
|
282
|
+
: fallback;
|
|
283
|
+
}
|
|
284
|
+
function countStringValues(values) {
|
|
285
|
+
const counts = {};
|
|
286
|
+
for (const value of values) {
|
|
287
|
+
counts[value] = (counts[value] ?? 0) + 1;
|
|
288
|
+
}
|
|
289
|
+
return counts;
|
|
290
|
+
}
|
|
291
|
+
function renderCountMap(counts) {
|
|
292
|
+
const entries = Object.entries(counts).sort(([left], [right]) => left.localeCompare(right));
|
|
293
|
+
if (entries.length === 0)
|
|
294
|
+
return "(none)";
|
|
295
|
+
return entries.map(([key, count]) => `${key}=${count}`).join(", ");
|
|
296
|
+
}
|
|
297
|
+
function markdownHeadingLevel(line) {
|
|
298
|
+
const match = /^(#{2,6})\s+/.exec(line.trim());
|
|
299
|
+
if (!match)
|
|
300
|
+
return null;
|
|
301
|
+
return match[1]?.length ?? null;
|
|
302
|
+
}
|
|
303
|
+
function extractMarkdownSectionByHeadings(markdownText, headings) {
|
|
304
|
+
const lines = markdownText.split("\n");
|
|
305
|
+
const accepted = new Set(headings.flatMap((heading) => [`## ${heading}`, `### ${heading}`]));
|
|
306
|
+
const startIndex = lines.findIndex((line) => accepted.has(line.trim()));
|
|
307
|
+
if (startIndex === -1)
|
|
308
|
+
return null;
|
|
309
|
+
const startLine = lines[startIndex];
|
|
310
|
+
const startHeadingLevel = typeof startLine === "string" ? markdownHeadingLevel(startLine) : null;
|
|
311
|
+
const collected = [];
|
|
312
|
+
for (let index = startIndex + 1; index < lines.length; index += 1) {
|
|
313
|
+
const line = lines[index];
|
|
314
|
+
if (line === undefined)
|
|
315
|
+
break;
|
|
316
|
+
const currentHeadingLevel = markdownHeadingLevel(line);
|
|
317
|
+
if (currentHeadingLevel !== null &&
|
|
318
|
+
startHeadingLevel !== null &&
|
|
319
|
+
currentHeadingLevel <= startHeadingLevel) {
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
collected.push(line);
|
|
323
|
+
}
|
|
324
|
+
const section = collected.join("\n").trim();
|
|
325
|
+
return section.length > 0 ? section : null;
|
|
326
|
+
}
|
|
327
|
+
function renderScreenBoundedLines(text, maxLines = 10) {
|
|
328
|
+
const lines = text
|
|
329
|
+
.split("\n")
|
|
330
|
+
.map((line) => line.trimEnd())
|
|
331
|
+
.filter((line) => line.trim().length > 0);
|
|
332
|
+
if (lines.length === 0)
|
|
333
|
+
return [" - (none)"];
|
|
334
|
+
const bounded = lines.slice(0, maxLines).map((line) => ` ${line}`);
|
|
335
|
+
if (lines.length > maxLines) {
|
|
336
|
+
bounded.push(" - ... see final_output for the complete explanation");
|
|
337
|
+
}
|
|
338
|
+
return bounded;
|
|
339
|
+
}
|
|
340
|
+
async function readReviewResultExplanationSummary(finalOutputPath) {
|
|
341
|
+
if (!(await fileExists(finalOutputPath))) {
|
|
342
|
+
const unavailable = "- final output unavailable";
|
|
343
|
+
return {
|
|
344
|
+
final_review_result: unavailable,
|
|
345
|
+
screen_lines: renderScreenBoundedLines(unavailable),
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
const finalOutputText = await fs.readFile(finalOutputPath, "utf8");
|
|
349
|
+
const finalReviewResult = extractMarkdownSectionByHeadings(finalOutputText, [
|
|
350
|
+
"Final Review Result",
|
|
351
|
+
"Comprehensive Result Explanation",
|
|
352
|
+
"Overall Result Explanation",
|
|
353
|
+
"Review Result Explanation",
|
|
354
|
+
]) ?? "- final review result section unavailable";
|
|
355
|
+
return {
|
|
356
|
+
final_review_result: finalReviewResult,
|
|
357
|
+
screen_lines: renderScreenBoundedLines(finalReviewResult),
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
async function readReviewResultClosureSummary(sessionRoot) {
|
|
361
|
+
const problemFramingPath = path.join(sessionRoot, "problem-framing.yaml");
|
|
362
|
+
const resultClassification = await readReviewResultClassification(sessionRoot);
|
|
363
|
+
const problemFraming = (await fileExists(problemFramingPath))
|
|
364
|
+
? await readYamlDocument(problemFramingPath)
|
|
365
|
+
: {};
|
|
366
|
+
const classifications = Array.isArray(problemFraming.classifications)
|
|
367
|
+
? problemFraming.classifications
|
|
368
|
+
: [];
|
|
369
|
+
const classificationRecords = classifications
|
|
370
|
+
.filter((classification) => classification !== null &&
|
|
371
|
+
typeof classification === "object" &&
|
|
372
|
+
!Array.isArray(classification));
|
|
373
|
+
return {
|
|
374
|
+
issue_count: Math.max(resultClassification.issue_count, classificationRecords.length),
|
|
375
|
+
material_issue_count: resultClassification.material_issue_count,
|
|
376
|
+
non_material_finding_count: resultClassification.non_material_finding_count,
|
|
377
|
+
highest_severity: resultClassification.highest_severity,
|
|
378
|
+
severity_counts: resultClassification.severity_counts,
|
|
379
|
+
timing_counts: countStringValues(classificationRecords.map((classification) => stringValue(classification.timing_class))),
|
|
380
|
+
closure_counts: countStringValues(classificationRecords.map((classification) => stringValue(classification.closure_class))),
|
|
381
|
+
action_candidates: resultClassification.action_candidates,
|
|
382
|
+
problem_definitions: classificationRecords.slice(0, 5).map((classification) => ({
|
|
383
|
+
issue_id: stringValue(classification.issue_id),
|
|
384
|
+
problem_definition: stringValue(classification.problem_definition),
|
|
385
|
+
issue_role: stringValue(classification.issue_role),
|
|
386
|
+
judgment_state: stringValue(classification.judgment_state),
|
|
387
|
+
timing_class: stringValue(classification.timing_class),
|
|
388
|
+
closure_class: stringValue(classification.closure_class),
|
|
389
|
+
})),
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
function renderReviewResultOverview(args) {
|
|
393
|
+
const degraded = args.degradedLensIds.length > 0 ? args.degradedLensIds.join(", ") : "none";
|
|
394
|
+
const problemLines = args.closureSummary.problem_definitions.length > 0
|
|
395
|
+
? args.closureSummary.problem_definitions.map((problem) => ` - ${problem.issue_id}: ${problem.problem_definition} (${problem.issue_role}, ${problem.judgment_state}, ${problem.timing_class}/${problem.closure_class})`)
|
|
396
|
+
: [" - (none)"];
|
|
397
|
+
const actionCandidateLines = args.closureSummary.action_candidates.length > 0
|
|
398
|
+
? args.closureSummary.action_candidates.slice(0, 5).map((candidate) => ` - ${candidate.issue_id}: ${candidate.candidates.join(", ") || "none"}`)
|
|
399
|
+
: [" - (none)"];
|
|
400
|
+
return [
|
|
401
|
+
"[review result]",
|
|
402
|
+
"outcome:",
|
|
403
|
+
` status: ${args.status ?? "unknown"}`,
|
|
404
|
+
` deliberation: ${args.deliberationStatus ?? "unknown"}`,
|
|
405
|
+
` review_mode: ${args.reviewMode}`,
|
|
406
|
+
"scope:",
|
|
407
|
+
` target: ${args.target}`,
|
|
408
|
+
` target_scope_kind: ${args.targetScopeKind}`,
|
|
409
|
+
` domain: ${args.domain.length > 0 ? args.domain : "none"}`,
|
|
410
|
+
"coverage:",
|
|
411
|
+
` lenses: ${args.participatingLensIds.length}/${args.plannedLensIds.length} participating`,
|
|
412
|
+
` degraded_lenses: ${degraded}`,
|
|
413
|
+
"result_explanation:",
|
|
414
|
+
" final_review_result:",
|
|
415
|
+
...args.explanationSummary.screen_lines,
|
|
416
|
+
"issues:",
|
|
417
|
+
` count: ${args.closureSummary.issue_count}`,
|
|
418
|
+
` highest_severity: ${args.closureSummary.highest_severity ?? "none"}`,
|
|
419
|
+
` material_issue_count: ${args.closureSummary.material_issue_count}`,
|
|
420
|
+
` non_material_finding_count: ${args.closureSummary.non_material_finding_count}`,
|
|
421
|
+
` severity: ${renderCountMap(args.closureSummary.severity_counts)}`,
|
|
422
|
+
` timing: ${renderCountMap(args.closureSummary.timing_counts)}`,
|
|
423
|
+
` closure: ${renderCountMap(args.closureSummary.closure_counts)}`,
|
|
424
|
+
" action_candidates:",
|
|
425
|
+
...actionCandidateLines,
|
|
426
|
+
" problem_definitions:",
|
|
427
|
+
...problemLines,
|
|
428
|
+
"artifacts:",
|
|
429
|
+
` final_output: ${displayPathFromProject(args.projectRoot, args.artifactRefs.final_output)}`,
|
|
430
|
+
` review_record: ${displayPathFromProject(args.projectRoot, args.artifactRefs.review_record)}`,
|
|
431
|
+
` execution_result: ${displayPathFromProject(args.projectRoot, args.artifactRefs.execution_result)}`,
|
|
432
|
+
` review_run_manifest: ${displayPathFromProject(args.projectRoot, args.artifactRefs.review_run_manifest)}`,
|
|
433
|
+
].join("\n");
|
|
434
|
+
}
|
|
435
|
+
function stripOptionsFromArgv(argv, optionNames, flagNames = []) {
|
|
436
|
+
const optionTokens = new Set(optionNames.map((optionName) => `--${optionName}`));
|
|
437
|
+
const flagTokens = new Set(flagNames.map((flagName) => `--${flagName}`));
|
|
438
|
+
const stripped = [];
|
|
439
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
440
|
+
const token = argv[index];
|
|
441
|
+
if (typeof token !== "string") {
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
if (flagTokens.has(token)) {
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
if (!optionTokens.has(token)) {
|
|
448
|
+
stripped.push(token);
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
const nextToken = argv[index + 1];
|
|
452
|
+
if (typeof nextToken === "string" && !nextToken.startsWith("--")) {
|
|
453
|
+
index += 1;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return stripped;
|
|
457
|
+
}
|
|
458
|
+
function splitArgvIntoOptionsAndPositionals(argv, optionNames, flagNames = []) {
|
|
459
|
+
const optionTokens = new Set(optionNames.map((optionName) => `--${optionName}`));
|
|
460
|
+
const flagTokens = new Set(flagNames.map((flagName) => `--${flagName}`));
|
|
461
|
+
const preservedOptions = [];
|
|
462
|
+
const positionals = [];
|
|
463
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
464
|
+
const token = argv[index];
|
|
465
|
+
if (typeof token !== "string") {
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
if (token === "--") {
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
if (flagTokens.has(token)) {
|
|
472
|
+
preservedOptions.push(token);
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
if (optionTokens.has(token)) {
|
|
476
|
+
preservedOptions.push(token);
|
|
477
|
+
const nextToken = argv[index + 1];
|
|
478
|
+
if (typeof nextToken === "string" && !nextToken.startsWith("--")) {
|
|
479
|
+
preservedOptions.push(nextToken);
|
|
480
|
+
index += 1;
|
|
481
|
+
}
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
positionals.push(token);
|
|
485
|
+
}
|
|
486
|
+
return {
|
|
487
|
+
optionTokens: preservedOptions,
|
|
488
|
+
positionals,
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
function ensureSessionIdArg(argv) {
|
|
492
|
+
const sessionId = readSingleOptionValueFromArgv(argv, "session-id");
|
|
493
|
+
if (typeof sessionId === "string" && sessionId.length > 0) {
|
|
494
|
+
return argv;
|
|
495
|
+
}
|
|
496
|
+
return [...argv, "--session-id", generateReviewSessionId()];
|
|
497
|
+
}
|
|
498
|
+
function requireOptionalTargetScopeKind(value) {
|
|
499
|
+
if (value === undefined)
|
|
500
|
+
return undefined;
|
|
501
|
+
if (value === "file" || value === "directory" || value === "bundle") {
|
|
502
|
+
return value;
|
|
503
|
+
}
|
|
504
|
+
throw new Error(`Invalid --target-scope-kind value: ${value}. Use file, directory, or bundle.`);
|
|
505
|
+
}
|
|
506
|
+
function throwTargetBindingFailure(args) {
|
|
507
|
+
throw new ReviewStructuredFailureError({
|
|
508
|
+
failureRecord: createStructuredFailureRecord({
|
|
509
|
+
phase: "pre_manifest.target_binding",
|
|
510
|
+
reasonCode: args.reasonCode,
|
|
511
|
+
humanMessage: args.humanMessage,
|
|
512
|
+
requiredUserAction: args.requiredUserAction,
|
|
513
|
+
retrySafety: "safe_after_input_change",
|
|
514
|
+
artifactTrust: "no_artifacts_trusted",
|
|
515
|
+
dispatchState: "not_dispatched",
|
|
516
|
+
artifactRefs: {},
|
|
517
|
+
mcpErrorCode: "ONTO_REVIEW_TARGET_BINDING_FAILED",
|
|
518
|
+
detailsKind: "schema_validation",
|
|
519
|
+
details: args.details,
|
|
520
|
+
}),
|
|
521
|
+
failureRecordPath: null,
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
function appendExecutorModelArgs(config, argv, ontoConfig, llmRef) {
|
|
525
|
+
// Mock executor does not accept --model/--reasoning-effort flags.
|
|
526
|
+
// Skip model/effort args when the executor targets the mock script.
|
|
527
|
+
// Note: with the direct-executor path strategy, bin is "node" / "tsx" and
|
|
528
|
+
// the mock filename lives in args[0] (the script path), so we have to
|
|
529
|
+
// probe both fields.
|
|
530
|
+
const isMock = config.bin.includes("mock-review-unit-executor") ||
|
|
531
|
+
config.args.some((arg) => arg.includes("mock-review-unit-executor"));
|
|
532
|
+
if (isMock)
|
|
533
|
+
return config;
|
|
534
|
+
const args = [...config.args];
|
|
535
|
+
const llmSettings = llmRef && llmRef !== "inherit" ? llmRef : ontoConfig?.llm;
|
|
536
|
+
const llmSelection = normalizeLlmModelSwitcher(llmSettings);
|
|
537
|
+
const model = readSingleOptionValueFromArgv(argv, "model") ?? llmSelection?.model_id;
|
|
538
|
+
if (typeof model === "string" && model.length > 0) {
|
|
539
|
+
args.push("--model", model);
|
|
540
|
+
}
|
|
541
|
+
const reasoningEffort = readSingleOptionValueFromArgv(argv, "reasoning-effort") ??
|
|
542
|
+
llmSelection?.reasoning_effort;
|
|
543
|
+
if (typeof reasoningEffort === "string" && reasoningEffort.length > 0) {
|
|
544
|
+
args.push("--reasoning-effort", reasoningEffort);
|
|
545
|
+
}
|
|
546
|
+
if (llmSelection?.service_tier) {
|
|
547
|
+
args.push("--config-override", `service_tier="${llmSelection.service_tier}"`);
|
|
548
|
+
}
|
|
549
|
+
return { bin: config.bin, args };
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Append canonical llm switcher fields as inline-http executor CLI flags.
|
|
553
|
+
*/
|
|
554
|
+
function appendDirectCallLlmArgs(config, ontoConfig, llmRef) {
|
|
555
|
+
const args = [...config.args];
|
|
556
|
+
const llmSettings = llmRef && llmRef !== "inherit" ? llmRef : ontoConfig?.llm;
|
|
557
|
+
const selection = normalizeLlmModelSwitcher(llmSettings);
|
|
558
|
+
if (selection && selection.provider !== "codex") {
|
|
559
|
+
args.push("--provider", selection.provider);
|
|
560
|
+
}
|
|
561
|
+
if (selection?.model_id) {
|
|
562
|
+
args.push("--model", selection.model_id);
|
|
563
|
+
}
|
|
564
|
+
if (selection?.base_url) {
|
|
565
|
+
args.push("--llm-base-url", selection.base_url);
|
|
566
|
+
}
|
|
567
|
+
if (selection?.api_key_env) {
|
|
568
|
+
args.push("--api-key-env", selection.api_key_env);
|
|
569
|
+
}
|
|
570
|
+
if (selection?.reasoning_effort) {
|
|
571
|
+
args.push("--reasoning-effort", selection.reasoning_effort);
|
|
572
|
+
}
|
|
573
|
+
return { bin: config.bin, args };
|
|
574
|
+
}
|
|
575
|
+
export function resolveExecutionProfile(args) {
|
|
576
|
+
const resolution = resolveReviewExecutionProfile({
|
|
577
|
+
explicitCodex: args.explicitCodex,
|
|
578
|
+
settings: args.ontoConfig,
|
|
579
|
+
...(args.forceMock ? { env: { ...process.env, ONTO_LLM_MOCK: "1" } } : {}),
|
|
580
|
+
});
|
|
581
|
+
if (resolution.type === "no_host") {
|
|
582
|
+
return { type: "no_host" };
|
|
583
|
+
}
|
|
584
|
+
const profile = resolution.profile;
|
|
585
|
+
const route = buildReviewExecutionRoute(profile);
|
|
586
|
+
return {
|
|
587
|
+
type: "resolved",
|
|
588
|
+
profile: {
|
|
589
|
+
execution_realization: route.execution_realization,
|
|
590
|
+
host_runtime: route.artifact_host_runtime,
|
|
591
|
+
review_execution_profile: profile,
|
|
592
|
+
},
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
export function resolveExecutionRealizationHandoff(args) {
|
|
596
|
+
const profile = resolveExecutionProfile({
|
|
597
|
+
explicitCodex: args.explicitCodex,
|
|
598
|
+
ontoConfig: args.ontoConfig,
|
|
599
|
+
});
|
|
600
|
+
if (profile.type === "no_host")
|
|
601
|
+
return { type: "no_host" };
|
|
602
|
+
return { type: "self", profile: profile.profile };
|
|
603
|
+
}
|
|
604
|
+
function buildNoHostDetectedError() {
|
|
605
|
+
return new Error([
|
|
606
|
+
"ReviewExecutionProfile을 해소할 수 없습니다.",
|
|
607
|
+
"현재 설정과 실행 환경에서 사용 가능한 worker 경로를 찾지 못했습니다.",
|
|
608
|
+
"",
|
|
609
|
+
"다음 중 한 가지로 해결하세요:",
|
|
610
|
+
" 1. `.onto/settings.json` 에 llm: { auth: api_key, provider, model } 설정",
|
|
611
|
+
" 2. local 실행은 llm.auth=local + llm.provider=lmstudio 로 설정",
|
|
612
|
+
" 3. OpenAI OAuth는 Codex worker가 필요하므로 codex 설치와 로그인을 확인",
|
|
613
|
+
" 4. 테스트 실행은 --executor-realization mock 사용",
|
|
614
|
+
].join("\n"));
|
|
615
|
+
}
|
|
616
|
+
function resolveExecutorConfig(argv, optionPrefix, ontoConfig, ontoHome, reviewExecutionProfile, actor = "lens") {
|
|
617
|
+
const optionPrefixLabel = optionPrefix.length > 0 ? optionPrefix : "";
|
|
618
|
+
const actorLlmRef = reviewExecutionProfile?.[actor].llm;
|
|
619
|
+
const explicitBin = readSingleOptionValueFromArgv(argv, `${optionPrefixLabel}executor-bin`);
|
|
620
|
+
const explicitArgs = readMultiOptionValuesFromArgv(argv, `${optionPrefixLabel}executor-arg`);
|
|
621
|
+
if (typeof explicitBin === "string" && explicitBin.length > 0) {
|
|
622
|
+
return appendExecutorModelArgs({ bin: explicitBin, args: explicitArgs }, argv, ontoConfig, actorLlmRef);
|
|
623
|
+
}
|
|
624
|
+
// Read the prefixed flag first; synthesize mode also accepts the shared flag.
|
|
625
|
+
const explicitRealization = readSingleOptionValueFromArgv(argv, `${optionPrefixLabel}executor-realization`) ??
|
|
626
|
+
(optionPrefixLabel.length > 0
|
|
627
|
+
? readSingleOptionValueFromArgv(argv, "executor-realization")
|
|
628
|
+
: undefined);
|
|
629
|
+
if (explicitRealization === "codex" || explicitRealization === "mock" || explicitRealization === "ts_inline_http") {
|
|
630
|
+
return appendExecutorModelArgs(buildExecutorConfigFromRealization(explicitRealization, ontoHome), argv, ontoConfig, actorLlmRef);
|
|
631
|
+
}
|
|
632
|
+
if (typeof explicitRealization === "string" &&
|
|
633
|
+
explicitRealization.length > 0) {
|
|
634
|
+
throw new Error(`Unsupported --${optionPrefixLabel}executor-realization: ${explicitRealization}. ` +
|
|
635
|
+
"Supported values: codex, mock, ts_inline_http.");
|
|
636
|
+
}
|
|
637
|
+
const profile = reviewExecutionProfile;
|
|
638
|
+
if (profile?.worker_executor === "mock") {
|
|
639
|
+
return buildExecutorConfigFromRealization("mock", ontoHome);
|
|
640
|
+
}
|
|
641
|
+
if (profile?.worker_executor === "direct_call") {
|
|
642
|
+
return appendDirectCallLlmArgs(buildExecutorConfigFromRealization("ts_inline_http", ontoHome), ontoConfig, actorLlmRef);
|
|
643
|
+
}
|
|
644
|
+
if (profile?.worker_executor === "codex") {
|
|
645
|
+
return appendExecutorModelArgs(buildExecutorConfigFromRealization("codex", ontoHome), argv, ontoConfig, actorLlmRef);
|
|
646
|
+
}
|
|
647
|
+
// Auto-select ts_inline_http executor when the canonical llm switcher
|
|
648
|
+
// selects an API-key or local provider.
|
|
649
|
+
const selection = normalizeLlmModelSwitcher(ontoConfig?.llm);
|
|
650
|
+
const hasExternalProvider = selection !== null && selection !== undefined && selection.provider !== "codex";
|
|
651
|
+
if (hasExternalProvider) {
|
|
652
|
+
return appendDirectCallLlmArgs(buildExecutorConfigFromRealization("ts_inline_http", ontoHome), ontoConfig, actorLlmRef);
|
|
653
|
+
}
|
|
654
|
+
return appendExecutorModelArgs(buildExecutorConfigFromRealization("codex", ontoHome), argv, ontoConfig, actorLlmRef);
|
|
655
|
+
}
|
|
656
|
+
function defaultCredentialEnvNames(provider) {
|
|
657
|
+
if (provider === "anthropic")
|
|
658
|
+
return ["ANTHROPIC_API_KEY"];
|
|
659
|
+
if (provider === "openai")
|
|
660
|
+
return ["OPENAI_API_KEY"];
|
|
661
|
+
if (provider === "grok")
|
|
662
|
+
return ["XAI_API_KEY", "GROK_API_KEY"];
|
|
663
|
+
return [];
|
|
664
|
+
}
|
|
665
|
+
function visibleCredentialEnvNames(selection) {
|
|
666
|
+
return selection.api_key_env
|
|
667
|
+
? [selection.api_key_env]
|
|
668
|
+
: defaultCredentialEnvNames(selection.provider);
|
|
669
|
+
}
|
|
670
|
+
function hasCredentialEnv(selection) {
|
|
671
|
+
return visibleCredentialEnvNames(selection).some((envName) => typeof process.env[envName] === "string" &&
|
|
672
|
+
process.env[envName].length > 0);
|
|
673
|
+
}
|
|
674
|
+
function assertValidLocalBaseUrl(baseUrl) {
|
|
675
|
+
if (baseUrl === undefined)
|
|
676
|
+
return;
|
|
677
|
+
try {
|
|
678
|
+
const parsed = new URL(baseUrl);
|
|
679
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
680
|
+
throw new Error("invalid protocol");
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
catch {
|
|
684
|
+
throw new Error(`Invalid local provider base_url: ${baseUrl}`);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
async function ensureProviderRouteReadyForDispatch(args) {
|
|
688
|
+
const profile = args.reviewExecutionProfile;
|
|
689
|
+
if (profile.worker_executor === "mock") {
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
const actorRefs = [
|
|
693
|
+
{ actor: "teamlead", llm: profile.teamlead.llm },
|
|
694
|
+
{ actor: "lens", llm: profile.lens.llm },
|
|
695
|
+
{ actor: "synthesize", llm: profile.synthesize.llm },
|
|
696
|
+
];
|
|
697
|
+
if (profile.worker_executor === "codex") {
|
|
698
|
+
for (const actorRef of actorRefs) {
|
|
699
|
+
const selection = actorRef.llm === "inherit"
|
|
700
|
+
? null
|
|
701
|
+
: normalizeLlmModelSwitcher(actorRef.llm);
|
|
702
|
+
const selectsCodexOauth = selection?.auth === "oauth" &&
|
|
703
|
+
(selection.provider === "codex" || selection.provider === "openai");
|
|
704
|
+
if (selection !== null &&
|
|
705
|
+
!selectsCodexOauth) {
|
|
706
|
+
await writeAndThrowStructuredFailureRecord({
|
|
707
|
+
sessionRoot: args.sessionRoot,
|
|
708
|
+
phase: "pre_dispatch.actor_route",
|
|
709
|
+
reasonCode: "codex_actor_route_mismatch",
|
|
710
|
+
humanMessage: "Review Codex worker route cannot dispatch because an actor selects a non-Codex provider route.",
|
|
711
|
+
requiredUserAction: "Use root/actor OAuth OpenAI settings for the Codex worker route, or select a direct-call route for API/local providers.",
|
|
712
|
+
retrySafety: "safe_after_input_change",
|
|
713
|
+
artifactTrust: "manifest_artifacts_trusted",
|
|
714
|
+
dispatchState: "dispatch_blocked",
|
|
715
|
+
artifactRefs: {
|
|
716
|
+
execution_plan: args.executionPlanPath,
|
|
717
|
+
},
|
|
718
|
+
mcpErrorCode: "ONTO_REVIEW_ACTOR_ROUTE_UNAVAILABLE",
|
|
719
|
+
detailsKind: "actor_route",
|
|
720
|
+
details: {
|
|
721
|
+
actor: actorRef.actor,
|
|
722
|
+
worker_executor: profile.worker_executor,
|
|
723
|
+
host: profile.host,
|
|
724
|
+
provider: selection.provider,
|
|
725
|
+
auth: selection.auth,
|
|
726
|
+
},
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
if (profile.worker_executor !== "direct_call") {
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
for (const actorRef of actorRefs) {
|
|
736
|
+
const selection = actorRef.llm === "inherit"
|
|
737
|
+
? null
|
|
738
|
+
: normalizeLlmModelSwitcher(actorRef.llm);
|
|
739
|
+
if (selection === null || selection.provider === "codex") {
|
|
740
|
+
await writeAndThrowStructuredFailureRecord({
|
|
741
|
+
sessionRoot: args.sessionRoot,
|
|
742
|
+
phase: "pre_dispatch.actor_route",
|
|
743
|
+
reasonCode: "direct_call_actor_provider_unresolved",
|
|
744
|
+
humanMessage: "Review direct-call route cannot dispatch because an actor does not resolve to an API/local provider.",
|
|
745
|
+
requiredUserAction: "Set .onto/settings.json llm to api_key/local provider settings, or use the Codex OAuth worker route.",
|
|
746
|
+
retrySafety: "safe_after_input_change",
|
|
747
|
+
artifactTrust: "manifest_artifacts_trusted",
|
|
748
|
+
dispatchState: "dispatch_blocked",
|
|
749
|
+
artifactRefs: {
|
|
750
|
+
execution_plan: args.executionPlanPath,
|
|
751
|
+
},
|
|
752
|
+
mcpErrorCode: "ONTO_REVIEW_ACTOR_ROUTE_UNAVAILABLE",
|
|
753
|
+
detailsKind: "actor_route",
|
|
754
|
+
details: {
|
|
755
|
+
actor: actorRef.actor,
|
|
756
|
+
worker_executor: profile.worker_executor,
|
|
757
|
+
host: profile.host,
|
|
758
|
+
provider: selection?.provider ?? null,
|
|
759
|
+
},
|
|
760
|
+
});
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
if (!selection.model_id) {
|
|
764
|
+
await writeAndThrowStructuredFailureRecord({
|
|
765
|
+
sessionRoot: args.sessionRoot,
|
|
766
|
+
phase: "pre_dispatch.actor_route",
|
|
767
|
+
reasonCode: "direct_call_actor_model_missing",
|
|
768
|
+
humanMessage: "Review direct-call route cannot dispatch because an actor model is missing.",
|
|
769
|
+
requiredUserAction: "Set llm.model in .onto/settings.json or in the actor-specific review.execution.*.llm block.",
|
|
770
|
+
retrySafety: "safe_after_input_change",
|
|
771
|
+
artifactTrust: "manifest_artifacts_trusted",
|
|
772
|
+
dispatchState: "dispatch_blocked",
|
|
773
|
+
artifactRefs: {
|
|
774
|
+
execution_plan: args.executionPlanPath,
|
|
775
|
+
},
|
|
776
|
+
mcpErrorCode: "ONTO_REVIEW_ACTOR_ROUTE_UNAVAILABLE",
|
|
777
|
+
detailsKind: "actor_route",
|
|
778
|
+
details: {
|
|
779
|
+
actor: actorRef.actor,
|
|
780
|
+
provider: selection.provider,
|
|
781
|
+
auth: selection.auth,
|
|
782
|
+
},
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
if (selection.auth === "api_key" && !hasCredentialEnv(selection)) {
|
|
786
|
+
await writeAndThrowStructuredFailureRecord({
|
|
787
|
+
sessionRoot: args.sessionRoot,
|
|
788
|
+
phase: "pre_dispatch.actor_route",
|
|
789
|
+
reasonCode: "direct_call_actor_credential_missing",
|
|
790
|
+
humanMessage: "Review direct-call route cannot dispatch because the provider credential environment variable is missing.",
|
|
791
|
+
requiredUserAction: "Export the required provider API key environment variable or change .onto/settings.json to an available route.",
|
|
792
|
+
retrySafety: "safe_after_environment_change",
|
|
793
|
+
artifactTrust: "manifest_artifacts_trusted",
|
|
794
|
+
dispatchState: "dispatch_blocked",
|
|
795
|
+
artifactRefs: {
|
|
796
|
+
execution_plan: args.executionPlanPath,
|
|
797
|
+
},
|
|
798
|
+
mcpErrorCode: "ONTO_REVIEW_ACTOR_ROUTE_UNAVAILABLE",
|
|
799
|
+
detailsKind: "actor_route",
|
|
800
|
+
details: {
|
|
801
|
+
actor: actorRef.actor,
|
|
802
|
+
provider: selection.provider,
|
|
803
|
+
auth: selection.auth,
|
|
804
|
+
credential_env_names: visibleCredentialEnvNames(selection),
|
|
805
|
+
},
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
if (selection.auth === "local") {
|
|
809
|
+
try {
|
|
810
|
+
assertValidLocalBaseUrl(selection.base_url);
|
|
811
|
+
}
|
|
812
|
+
catch (error) {
|
|
813
|
+
await writeAndThrowStructuredFailureRecord({
|
|
814
|
+
sessionRoot: args.sessionRoot,
|
|
815
|
+
phase: "pre_dispatch.actor_route",
|
|
816
|
+
reasonCode: "direct_call_local_base_url_invalid",
|
|
817
|
+
humanMessage: "Review local route cannot dispatch because the local provider base_url is invalid.",
|
|
818
|
+
requiredUserAction: "Set llm.base_url to a valid http(s) LM Studio endpoint or remove it to use the default.",
|
|
819
|
+
retrySafety: "safe_after_input_change",
|
|
820
|
+
artifactTrust: "manifest_artifacts_trusted",
|
|
821
|
+
dispatchState: "dispatch_blocked",
|
|
822
|
+
artifactRefs: {
|
|
823
|
+
execution_plan: args.executionPlanPath,
|
|
824
|
+
},
|
|
825
|
+
mcpErrorCode: "ONTO_REVIEW_ACTOR_ROUTE_UNAVAILABLE",
|
|
826
|
+
detailsKind: "actor_route",
|
|
827
|
+
details: {
|
|
828
|
+
actor: actorRef.actor,
|
|
829
|
+
provider: selection.provider,
|
|
830
|
+
auth: selection.auth,
|
|
831
|
+
base_url: selection.base_url ?? null,
|
|
832
|
+
error: error instanceof Error ? error.message : String(error),
|
|
833
|
+
},
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
async function readOntoConfig(projectRoot) {
|
|
840
|
+
return resolveSettingsChain("", projectRoot);
|
|
841
|
+
}
|
|
842
|
+
function parseHostFacingPositionals(positionals) {
|
|
843
|
+
if (positionals.length === 0) {
|
|
844
|
+
return {};
|
|
845
|
+
}
|
|
846
|
+
const [target, second, ...rest] = positionals;
|
|
847
|
+
if (typeof target !== "string" || target.length === 0) {
|
|
848
|
+
return {};
|
|
849
|
+
}
|
|
850
|
+
if (typeof second === "string" && second.startsWith("@")) {
|
|
851
|
+
throw new Error("Domain tokens must use --domain or --no-domain.");
|
|
852
|
+
}
|
|
853
|
+
return {
|
|
854
|
+
target,
|
|
855
|
+
intentText: [second, ...rest].filter((value) => typeof value === "string").join(" ").trim(),
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
function isPathInsideRoot(candidatePath, rootPath) {
|
|
859
|
+
let resolvedCandidate;
|
|
860
|
+
let resolvedRoot;
|
|
861
|
+
try {
|
|
862
|
+
resolvedCandidate = fsSync.realpathSync(candidatePath);
|
|
863
|
+
resolvedRoot = fsSync.realpathSync(rootPath);
|
|
864
|
+
}
|
|
865
|
+
catch {
|
|
866
|
+
resolvedCandidate = path.resolve(candidatePath);
|
|
867
|
+
resolvedRoot = path.resolve(rootPath);
|
|
868
|
+
}
|
|
869
|
+
const relative = path.relative(resolvedRoot, resolvedCandidate);
|
|
870
|
+
if (relative === "") {
|
|
871
|
+
return true;
|
|
872
|
+
}
|
|
873
|
+
if (relative.startsWith("..")) {
|
|
874
|
+
return false;
|
|
875
|
+
}
|
|
876
|
+
return !path.isAbsolute(relative);
|
|
877
|
+
}
|
|
878
|
+
function normalizeFilesystemAllowedRoot(root, defaultProjectRoot) {
|
|
879
|
+
if (path.isAbsolute(root)) {
|
|
880
|
+
return path.resolve(root);
|
|
881
|
+
}
|
|
882
|
+
return path.resolve(defaultProjectRoot, root);
|
|
883
|
+
}
|
|
884
|
+
function normalizeFilesystemAllowedRoots(filesystemAllowedRoots, defaultProjectRoot) {
|
|
885
|
+
const resolved = filesystemAllowedRoots.length > 0
|
|
886
|
+
? filesystemAllowedRoots.map((root) => normalizeFilesystemAllowedRoot(root, defaultProjectRoot))
|
|
887
|
+
: [path.resolve(defaultProjectRoot)];
|
|
888
|
+
const deduped = [];
|
|
889
|
+
for (const root of resolved) {
|
|
890
|
+
if (!deduped.includes(root)) {
|
|
891
|
+
deduped.push(root);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
return deduped;
|
|
895
|
+
}
|
|
896
|
+
function isInsideAnyDeclaredFilesystemRoot(targetPath, allowedRoots) {
|
|
897
|
+
return allowedRoots.some((allowedRoot) => isPathInsideRoot(targetPath, allowedRoot));
|
|
898
|
+
}
|
|
899
|
+
function deriveFilesystemBoundaryFromTarget(targetPath, targetScopeKind) {
|
|
900
|
+
return targetScopeKind === "file"
|
|
901
|
+
? path.dirname(targetPath)
|
|
902
|
+
: targetPath;
|
|
903
|
+
}
|
|
904
|
+
async function promptForFilesystemBoundaryDecision(requestedTarget, absoluteTargetPath, projectRoot) {
|
|
905
|
+
const promptText = [
|
|
906
|
+
"Requested review target is outside project root.",
|
|
907
|
+
`project-root: ${projectRoot}`,
|
|
908
|
+
`requested target: ${requestedTarget}`,
|
|
909
|
+
`resolved absolute target: ${absoluteTargetPath}`,
|
|
910
|
+
"This target is outside the default filesystem boundary and needs an explicit decision.",
|
|
911
|
+
"1) Continue with this exact target and approve an explicit filesystem boundary.",
|
|
912
|
+
"2) Cancel and rerun using a project-relative target path.",
|
|
913
|
+
"3) Cancel and stop execution.",
|
|
914
|
+
"Enter 1, 2, or 3:",
|
|
915
|
+
].join("\n");
|
|
916
|
+
const readline = createInterface({
|
|
917
|
+
input: process.stdin,
|
|
918
|
+
output: process.stdout,
|
|
919
|
+
});
|
|
920
|
+
try {
|
|
921
|
+
while (true) {
|
|
922
|
+
const answer = (await readline.question(`${promptText}\n> `)).trim();
|
|
923
|
+
if (answer === "1" || /^(approve|yes|y)$/i.test(answer)) {
|
|
924
|
+
return {
|
|
925
|
+
action: "approve_external_boundary",
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
if (answer === "2") {
|
|
929
|
+
return { action: "rerun_target" };
|
|
930
|
+
}
|
|
931
|
+
if (answer === "3" || /^(cancel|no|n)$/i.test(answer)) {
|
|
932
|
+
return { action: "cancel" };
|
|
933
|
+
}
|
|
934
|
+
console.error(`Invalid boundary decision: ${answer}. Enter 1, 2, or 3.`);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
finally {
|
|
938
|
+
readline.close();
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
function parseFilesystemBoundaryDecision(argv) {
|
|
942
|
+
const rawDecision = readSingleOptionValueFromArgv(argv, "filesystem-boundary-decision");
|
|
943
|
+
const decision = typeof rawDecision === "string" ? rawDecision.toLowerCase() : "";
|
|
944
|
+
if (decision === "approve" || decision === "approve_external_boundary") {
|
|
945
|
+
return "approve_external_boundary";
|
|
946
|
+
}
|
|
947
|
+
if (decision === "rerun" || decision === "rerun_target") {
|
|
948
|
+
return "rerun_target";
|
|
949
|
+
}
|
|
950
|
+
if (decision === "cancel") {
|
|
951
|
+
return "cancel";
|
|
952
|
+
}
|
|
953
|
+
if (decision.length > 0) {
|
|
954
|
+
throw new Error(`Invalid --filesystem-boundary-decision value: ${rawDecision}. Use approve, rerun, or cancel.`);
|
|
955
|
+
}
|
|
956
|
+
return undefined;
|
|
957
|
+
}
|
|
958
|
+
function normalizeDomainToken(domainValue) {
|
|
959
|
+
const trimmed = domainValue.trim();
|
|
960
|
+
if (trimmed.length === 0) {
|
|
961
|
+
return null;
|
|
962
|
+
}
|
|
963
|
+
if (["-", "@-", "none"].includes(trimmed)) {
|
|
964
|
+
return "@-";
|
|
965
|
+
}
|
|
966
|
+
return trimmed.startsWith("@") ? trimmed : `@${trimmed}`;
|
|
967
|
+
}
|
|
968
|
+
function collectConfiguredDomainTokens(ontoConfig) {
|
|
969
|
+
const collected = [];
|
|
970
|
+
const pushToken = (domainValue) => {
|
|
971
|
+
if (typeof domainValue !== "string") {
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
const normalized = normalizeDomainToken(domainValue);
|
|
975
|
+
if (!normalized || collected.includes(normalized)) {
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
collected.push(normalized);
|
|
979
|
+
};
|
|
980
|
+
const pushTokenList = (domainValues) => {
|
|
981
|
+
if (Array.isArray(domainValues)) {
|
|
982
|
+
for (const domainValue of domainValues) {
|
|
983
|
+
pushToken(domainValue);
|
|
984
|
+
}
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
if (typeof domainValues === "string") {
|
|
988
|
+
const splitValues = domainValues.includes(",")
|
|
989
|
+
? domainValues.split(",")
|
|
990
|
+
: [domainValues];
|
|
991
|
+
for (const domainValue of splitValues) {
|
|
992
|
+
pushToken(domainValue);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
};
|
|
996
|
+
pushTokenList(ontoConfig.domains);
|
|
997
|
+
return collected;
|
|
998
|
+
}
|
|
999
|
+
async function promptForDomainSelection(configuredDomainTokens) {
|
|
1000
|
+
const optionTokens = configuredDomainTokens.includes("@-")
|
|
1001
|
+
? [...configuredDomainTokens]
|
|
1002
|
+
: [...configuredDomainTokens, "@-"];
|
|
1003
|
+
const optionLines = optionTokens.map((domainToken, index) => `${index + 1}. ${domainToken}`);
|
|
1004
|
+
const promptText = [
|
|
1005
|
+
"Multiple configured domains are available for this review.",
|
|
1006
|
+
"Select a domain token for this session:",
|
|
1007
|
+
...optionLines,
|
|
1008
|
+
"Enter a number or domain token:",
|
|
1009
|
+
].join("\n");
|
|
1010
|
+
const readline = createInterface({
|
|
1011
|
+
input: process.stdin,
|
|
1012
|
+
output: process.stdout,
|
|
1013
|
+
});
|
|
1014
|
+
try {
|
|
1015
|
+
while (true) {
|
|
1016
|
+
const answer = (await readline.question(`${promptText}\n> `)).trim();
|
|
1017
|
+
if (answer.length === 0) {
|
|
1018
|
+
continue;
|
|
1019
|
+
}
|
|
1020
|
+
const numericIndex = Number.parseInt(answer, 10);
|
|
1021
|
+
if (Number.isFinite(numericIndex)) {
|
|
1022
|
+
const selectedToken = optionTokens[numericIndex - 1];
|
|
1023
|
+
if (selectedToken) {
|
|
1024
|
+
return selectedToken;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
const normalizedAnswer = normalizeDomainToken(answer);
|
|
1028
|
+
if (normalizedAnswer && optionTokens.includes(normalizedAnswer)) {
|
|
1029
|
+
return normalizedAnswer;
|
|
1030
|
+
}
|
|
1031
|
+
console.error(`Invalid domain selection: ${answer}. Choose one of ${optionTokens.join(", ")}`);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
finally {
|
|
1035
|
+
readline.close();
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
async function resolveDomainSelection(requestedDomainToken, ontoConfig) {
|
|
1039
|
+
if (requestedDomainToken.length > 0) {
|
|
1040
|
+
return {
|
|
1041
|
+
domainRecommendation: requestedDomainToken,
|
|
1042
|
+
domainFinalValue: normalizeDomainValue(requestedDomainToken),
|
|
1043
|
+
domainSelectionMode: "explicit_token",
|
|
1044
|
+
domainSelectionRequired: false,
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
const configuredDomainTokens = collectConfiguredDomainTokens(ontoConfig);
|
|
1048
|
+
if (configuredDomainTokens.length === 0) {
|
|
1049
|
+
return {
|
|
1050
|
+
domainRecommendation: "@-",
|
|
1051
|
+
domainFinalValue: "none",
|
|
1052
|
+
domainSelectionMode: "no_domain_default",
|
|
1053
|
+
domainSelectionRequired: false,
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
if (configuredDomainTokens.length === 1) {
|
|
1057
|
+
const selectedToken = configuredDomainTokens[0];
|
|
1058
|
+
return {
|
|
1059
|
+
domainRecommendation: selectedToken,
|
|
1060
|
+
domainFinalValue: normalizeDomainValue(selectedToken),
|
|
1061
|
+
domainSelectionMode: "project_default",
|
|
1062
|
+
domainSelectionRequired: false,
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
const domainRecommendation = configuredDomainTokens[0];
|
|
1066
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
1067
|
+
throw new Error([
|
|
1068
|
+
"Multiple configured domains are available, but interactive domain selection is unavailable in this non-interactive environment.",
|
|
1069
|
+
`Configured domains: ${configuredDomainTokens.join(", ")}`,
|
|
1070
|
+
"Pass an explicit domain token such as `@ontology` or `@-`.",
|
|
1071
|
+
].join("\n"));
|
|
1072
|
+
}
|
|
1073
|
+
const selectedToken = await promptForDomainSelection(configuredDomainTokens);
|
|
1074
|
+
return {
|
|
1075
|
+
domainRecommendation,
|
|
1076
|
+
domainFinalValue: normalizeDomainValue(selectedToken),
|
|
1077
|
+
domainSelectionMode: "interactive_selection",
|
|
1078
|
+
domainSelectionRequired: true,
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
function resolveReviewMode(argv, ontoConfig) {
|
|
1082
|
+
const explicitValue = readSingleOptionValueFromArgv(argv, "review-mode");
|
|
1083
|
+
if (explicitValue === "core-axis" || explicitValue === "full") {
|
|
1084
|
+
return explicitValue;
|
|
1085
|
+
}
|
|
1086
|
+
const configValue = ontoConfig?.review_mode;
|
|
1087
|
+
if (configValue === "core-axis" || configValue === "full") {
|
|
1088
|
+
return configValue;
|
|
1089
|
+
}
|
|
1090
|
+
return "full";
|
|
1091
|
+
}
|
|
1092
|
+
function resolveLensDefaultsForReviewMode(reviewMode) {
|
|
1093
|
+
if (reviewMode === "core-axis") {
|
|
1094
|
+
return {
|
|
1095
|
+
resolvedLensIds: [...CORE_AXIS_LENS_IDS],
|
|
1096
|
+
alwaysIncludeLensIds: [..._registry.always_include_lens_ids],
|
|
1097
|
+
recommendedLensIds: [...CORE_AXIS_LENS_IDS],
|
|
1098
|
+
rationale: [
|
|
1099
|
+
`host-facing positional invoke defaults core-axis review to the cost-constrained Pareto-optimal core lens set (${CORE_AXIS_LENS_IDS.join(", ")}) from .onto/authority/core-lens-registry.yaml.`,
|
|
1100
|
+
],
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
return {
|
|
1104
|
+
resolvedLensIds: [...FULL_REVIEW_LENS_IDS],
|
|
1105
|
+
alwaysIncludeLensIds: ["axiology"],
|
|
1106
|
+
recommendedLensIds: [...FULL_REVIEW_LENS_IDS],
|
|
1107
|
+
rationale: [
|
|
1108
|
+
"host-facing positional invoke currently defaults to full 9-lens review until interactive interpretation is productized.",
|
|
1109
|
+
],
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
async function resolveTargetInput(projectRoot, requestedTarget, explicitFilesystemAllowedRoots, argv, expectedTargetScopeKind) {
|
|
1113
|
+
const absoluteTargetPath = path.resolve(projectRoot, requestedTarget);
|
|
1114
|
+
const declaredFilesystemAllowedRoots = normalizeFilesystemAllowedRoots(explicitFilesystemAllowedRoots, projectRoot);
|
|
1115
|
+
const targetStats = await fs.stat(absoluteTargetPath);
|
|
1116
|
+
const targetScopeKind = targetStats.isDirectory() ? "directory" : "file";
|
|
1117
|
+
if (expectedTargetScopeKind !== undefined &&
|
|
1118
|
+
expectedTargetScopeKind !== targetScopeKind) {
|
|
1119
|
+
throwTargetBindingFailure({
|
|
1120
|
+
reasonCode: "explicit_target_scope_mismatch",
|
|
1121
|
+
humanMessage: "Explicit target scope mismatch.",
|
|
1122
|
+
requiredUserAction: "Change targetScopeKind to match the target, choose a matching target, or omit targetScopeKind to let runtime infer the shape.",
|
|
1123
|
+
details: {
|
|
1124
|
+
requested_target_scope_kind: expectedTargetScopeKind,
|
|
1125
|
+
actual_target_scope_kind: targetScopeKind,
|
|
1126
|
+
target: absoluteTargetPath,
|
|
1127
|
+
},
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
const materializedKind = targetStats.isDirectory()
|
|
1131
|
+
? "directory_listing"
|
|
1132
|
+
: "single_text";
|
|
1133
|
+
const derivedBoundaryRoot = deriveFilesystemBoundaryFromTarget(absoluteTargetPath, targetScopeKind);
|
|
1134
|
+
if (!isInsideAnyDeclaredFilesystemRoot(absoluteTargetPath, declaredFilesystemAllowedRoots)) {
|
|
1135
|
+
const nonInteractiveDecision = parseFilesystemBoundaryDecision(argv);
|
|
1136
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
1137
|
+
if (nonInteractiveDecision === "approve_external_boundary") {
|
|
1138
|
+
if (!declaredFilesystemAllowedRoots.includes(derivedBoundaryRoot)) {
|
|
1139
|
+
declaredFilesystemAllowedRoots.push(derivedBoundaryRoot);
|
|
1140
|
+
}
|
|
1141
|
+
return {
|
|
1142
|
+
absoluteTargetPath,
|
|
1143
|
+
targetScopeKind,
|
|
1144
|
+
materializedKind,
|
|
1145
|
+
filesystemAllowedRoots: declaredFilesystemAllowedRoots,
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1148
|
+
if (nonInteractiveDecision === "rerun_target") {
|
|
1149
|
+
throw new Error([
|
|
1150
|
+
"Please rerun review using a repo-relative target",
|
|
1151
|
+
`within ${projectRoot}, for example: ${path.relative(projectRoot, absoluteTargetPath)}`,
|
|
1152
|
+
"or pass --filesystem-boundary-decision=rerun_target with corrected target.",
|
|
1153
|
+
].join("\n"));
|
|
1154
|
+
}
|
|
1155
|
+
if (nonInteractiveDecision === "cancel") {
|
|
1156
|
+
throw new Error([
|
|
1157
|
+
"Review canceled by user decision.",
|
|
1158
|
+
"Re-run with an alternative target or explicit boundary decision.",
|
|
1159
|
+
].join("\n"));
|
|
1160
|
+
}
|
|
1161
|
+
console.error([
|
|
1162
|
+
"[onto] Auto-approving external filesystem boundary:",
|
|
1163
|
+
` project-root: ${projectRoot}`,
|
|
1164
|
+
` resolved target: ${absoluteTargetPath}`,
|
|
1165
|
+
` approved root: ${derivedBoundaryRoot}`,
|
|
1166
|
+
" (pass --filesystem-boundary-decision cancel to prevent this)",
|
|
1167
|
+
].join("\n"));
|
|
1168
|
+
if (!declaredFilesystemAllowedRoots.includes(derivedBoundaryRoot)) {
|
|
1169
|
+
declaredFilesystemAllowedRoots.push(derivedBoundaryRoot);
|
|
1170
|
+
}
|
|
1171
|
+
return {
|
|
1172
|
+
absoluteTargetPath,
|
|
1173
|
+
targetScopeKind,
|
|
1174
|
+
materializedKind,
|
|
1175
|
+
filesystemAllowedRoots: declaredFilesystemAllowedRoots,
|
|
1176
|
+
};
|
|
1177
|
+
}
|
|
1178
|
+
const boundaryDecision = await promptForFilesystemBoundaryDecision(requestedTarget, absoluteTargetPath, projectRoot);
|
|
1179
|
+
if (boundaryDecision.action === "rerun_target") {
|
|
1180
|
+
throw new Error([
|
|
1181
|
+
"Please rerun review using a repo-relative target",
|
|
1182
|
+
`within ${projectRoot}, for example: ${path.relative(projectRoot, absoluteTargetPath)}`,
|
|
1183
|
+
].join("\n"));
|
|
1184
|
+
}
|
|
1185
|
+
if (boundaryDecision.action === "cancel") {
|
|
1186
|
+
throw new Error([
|
|
1187
|
+
"Review canceled by user decision.",
|
|
1188
|
+
"If you want to review this target, choose option 1 in an interactive run.",
|
|
1189
|
+
].join("\n"));
|
|
1190
|
+
}
|
|
1191
|
+
if (!declaredFilesystemAllowedRoots.includes(derivedBoundaryRoot)) {
|
|
1192
|
+
declaredFilesystemAllowedRoots.push(derivedBoundaryRoot);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
if (targetStats.isDirectory()) {
|
|
1196
|
+
return {
|
|
1197
|
+
absoluteTargetPath,
|
|
1198
|
+
targetScopeKind,
|
|
1199
|
+
materializedKind,
|
|
1200
|
+
filesystemAllowedRoots: declaredFilesystemAllowedRoots,
|
|
1201
|
+
};
|
|
1202
|
+
}
|
|
1203
|
+
return {
|
|
1204
|
+
absoluteTargetPath,
|
|
1205
|
+
targetScopeKind,
|
|
1206
|
+
materializedKind,
|
|
1207
|
+
filesystemAllowedRoots: declaredFilesystemAllowedRoots,
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
async function assertBundleTargetRefInsideBoundary(args) {
|
|
1211
|
+
try {
|
|
1212
|
+
await fs.stat(args.ref);
|
|
1213
|
+
}
|
|
1214
|
+
catch (error) {
|
|
1215
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1216
|
+
throwTargetBindingFailure({
|
|
1217
|
+
reasonCode: "bundle_target_ref_missing",
|
|
1218
|
+
humanMessage: "Bundle target ref does not exist.",
|
|
1219
|
+
requiredUserAction: "Use existing primary/member refs or remove the missing ref from the explicit bundle.",
|
|
1220
|
+
details: {
|
|
1221
|
+
ref: args.ref,
|
|
1222
|
+
stat_error: message,
|
|
1223
|
+
},
|
|
1224
|
+
});
|
|
1225
|
+
}
|
|
1226
|
+
if (!isInsideAnyDeclaredFilesystemRoot(args.ref, args.allowedRoots)) {
|
|
1227
|
+
throwTargetBindingFailure({
|
|
1228
|
+
reasonCode: "bundle_target_ref_outside_boundary",
|
|
1229
|
+
humanMessage: "Bundle target ref is outside the filesystem boundary.",
|
|
1230
|
+
requiredUserAction: "Add an explicit filesystem allowed root for this ref or choose a target inside the project boundary.",
|
|
1231
|
+
details: {
|
|
1232
|
+
ref: args.ref,
|
|
1233
|
+
project_root: args.projectRoot,
|
|
1234
|
+
allowed_roots: args.allowedRoots,
|
|
1235
|
+
},
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
async function resolveBundleTargetInput(args) {
|
|
1240
|
+
const primaryRefRaw = args.explicitPrimaryRef ?? args.requestedTarget ?? args.explicitMemberRefs[0];
|
|
1241
|
+
if (typeof primaryRefRaw !== "string" || primaryRefRaw.length === 0) {
|
|
1242
|
+
throwTargetBindingFailure({
|
|
1243
|
+
reasonCode: "bundle_primary_ref_missing",
|
|
1244
|
+
humanMessage: "Bundle review target requires --primary-ref, target, or at least one --member-ref.",
|
|
1245
|
+
requiredUserAction: "Provide a primary bundle ref, a target, or at least one member ref.",
|
|
1246
|
+
details: {
|
|
1247
|
+
member_ref_count: args.explicitMemberRefs.length,
|
|
1248
|
+
},
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
const absoluteTargetPath = path.resolve(args.projectRoot, primaryRefRaw);
|
|
1252
|
+
const orderedRefs = [
|
|
1253
|
+
absoluteTargetPath,
|
|
1254
|
+
...args.explicitMemberRefs.map((memberRef) => path.resolve(args.projectRoot, memberRef)),
|
|
1255
|
+
];
|
|
1256
|
+
const resolvedTargetRefs = orderedRefs.filter((resolvedRef, index) => orderedRefs.indexOf(resolvedRef) === index);
|
|
1257
|
+
const filesystemAllowedRoots = normalizeFilesystemAllowedRoots(args.explicitFilesystemAllowedRoots, args.projectRoot);
|
|
1258
|
+
for (const resolvedRef of resolvedTargetRefs) {
|
|
1259
|
+
await assertBundleTargetRefInsideBoundary({
|
|
1260
|
+
ref: resolvedRef,
|
|
1261
|
+
projectRoot: args.projectRoot,
|
|
1262
|
+
allowedRoots: filesystemAllowedRoots,
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
return {
|
|
1266
|
+
absoluteTargetPath,
|
|
1267
|
+
resolvedTargetRefs,
|
|
1268
|
+
filesystemAllowedRoots,
|
|
1269
|
+
};
|
|
1270
|
+
}
|
|
1271
|
+
async function resolveReviewInvokeInputs(argv, ontoConfig, projectRoot, sessionId) {
|
|
1272
|
+
const parsedPositionals = parseHostFacingPositionals(splitArgvIntoOptionsAndPositionals(argv, [...KNOWN_INVOKE_ONLY_OPTION_NAMES, ...KNOWN_PASSTHROUGH_OPTION_NAMES], [...KNOWN_INVOKE_ONLY_FLAG_NAMES, ...KNOWN_PASSTHROUGH_FLAG_NAMES]).positionals);
|
|
1273
|
+
const explicitRequestedTarget = readSingleOptionValueFromArgv(argv, "requested-target");
|
|
1274
|
+
const explicitTargetScopeKind = requireOptionalTargetScopeKind(readSingleOptionValueFromArgv(argv, "target-scope-kind"));
|
|
1275
|
+
const explicitPrimaryRef = readSingleOptionValueFromArgv(argv, "primary-ref");
|
|
1276
|
+
const explicitMemberRefs = readMultiOptionValuesFromArgv(argv, "member-ref");
|
|
1277
|
+
const explicitBundleKind = readSingleOptionValueFromArgv(argv, "bundle-kind");
|
|
1278
|
+
const explicitFilesystemAllowedRoots = readMultiOptionValuesFromArgv(argv, "filesystem-allowed-root");
|
|
1279
|
+
const requestedTarget = explicitRequestedTarget ?? parsedPositionals.target;
|
|
1280
|
+
const bundleRequested = explicitTargetScopeKind === "bundle" || explicitMemberRefs.length > 0;
|
|
1281
|
+
if (explicitTargetScopeKind !== "bundle" &&
|
|
1282
|
+
explicitTargetScopeKind !== undefined &&
|
|
1283
|
+
explicitMemberRefs.length > 0) {
|
|
1284
|
+
throwTargetBindingFailure({
|
|
1285
|
+
reasonCode: "member_ref_without_bundle_scope",
|
|
1286
|
+
humanMessage: "--member-ref is only valid with --target-scope-kind bundle.",
|
|
1287
|
+
requiredUserAction: "Set targetScopeKind to bundle or remove memberRefs from the request.",
|
|
1288
|
+
details: {
|
|
1289
|
+
target_scope_kind: explicitTargetScopeKind,
|
|
1290
|
+
member_ref_count: explicitMemberRefs.length,
|
|
1291
|
+
},
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1294
|
+
if (explicitPrimaryRef !== undefined &&
|
|
1295
|
+
explicitTargetScopeKind !== "bundle" &&
|
|
1296
|
+
explicitMemberRefs.length === 0) {
|
|
1297
|
+
throwTargetBindingFailure({
|
|
1298
|
+
reasonCode: "primary_ref_without_bundle_scope",
|
|
1299
|
+
humanMessage: "--primary-ref is only valid for explicit bundle review targets.",
|
|
1300
|
+
requiredUserAction: "Set targetScopeKind to bundle or remove primaryRef from the request.",
|
|
1301
|
+
details: {
|
|
1302
|
+
target_scope_kind: explicitTargetScopeKind ?? null,
|
|
1303
|
+
primary_ref: explicitPrimaryRef,
|
|
1304
|
+
},
|
|
1305
|
+
});
|
|
1306
|
+
}
|
|
1307
|
+
if (explicitBundleKind !== undefined &&
|
|
1308
|
+
explicitTargetScopeKind !== "bundle" &&
|
|
1309
|
+
explicitMemberRefs.length === 0) {
|
|
1310
|
+
throwTargetBindingFailure({
|
|
1311
|
+
reasonCode: "bundle_kind_without_bundle_scope",
|
|
1312
|
+
humanMessage: "--bundle-kind is only valid for explicit bundle review targets.",
|
|
1313
|
+
requiredUserAction: "Set targetScopeKind to bundle or remove bundleKind from the request.",
|
|
1314
|
+
details: {
|
|
1315
|
+
target_scope_kind: explicitTargetScopeKind ?? null,
|
|
1316
|
+
bundle_kind: explicitBundleKind,
|
|
1317
|
+
},
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
if (!bundleRequested &&
|
|
1321
|
+
(typeof requestedTarget !== "string" || requestedTarget.length === 0)) {
|
|
1322
|
+
throw new Error("Missing review target. Use `npm run review:invoke -- <target> \"<intent>\"` or pass --requested-target.");
|
|
1323
|
+
}
|
|
1324
|
+
const MAX_REQUEST_TEXT_LENGTH = 2000;
|
|
1325
|
+
let requestText = readSingleOptionValueFromArgv(argv, "request-text") ??
|
|
1326
|
+
readSingleOptionValueFromArgv(argv, "intent-summary") ??
|
|
1327
|
+
parsedPositionals.intentText;
|
|
1328
|
+
if (typeof requestText !== "string" || requestText.length === 0) {
|
|
1329
|
+
throw new Error("Missing review intent. Use `npm run review:invoke -- <target> \"<intent>\"` or pass --request-text.");
|
|
1330
|
+
}
|
|
1331
|
+
if (requestText.length > MAX_REQUEST_TEXT_LENGTH) {
|
|
1332
|
+
console.warn(`[onto] Request text truncated from ${requestText.length} to ${MAX_REQUEST_TEXT_LENGTH} characters.`);
|
|
1333
|
+
requestText = requestText.slice(0, MAX_REQUEST_TEXT_LENGTH);
|
|
1334
|
+
}
|
|
1335
|
+
// Domain selection precedence: machine token, explicit no-domain/domain
|
|
1336
|
+
// flags, then interactive/default resolution.
|
|
1337
|
+
const noDomainFlag = hasOptionFlag(argv, "no-domain");
|
|
1338
|
+
const explicitDomainName = readSingleOptionValueFromArgv(argv, "domain");
|
|
1339
|
+
if (noDomainFlag && typeof explicitDomainName === "string" && explicitDomainName.length > 0) {
|
|
1340
|
+
throw new Error("Conflicting domain flags: --no-domain cannot be combined with --domain. Use exactly one.");
|
|
1341
|
+
}
|
|
1342
|
+
const canonicalDomainToken = noDomainFlag
|
|
1343
|
+
? "@-"
|
|
1344
|
+
: typeof explicitDomainName === "string" && explicitDomainName.length > 0
|
|
1345
|
+
? (normalizeDomainToken(explicitDomainName) ?? "")
|
|
1346
|
+
: "";
|
|
1347
|
+
const requestedDomainToken = readSingleOptionValueFromArgv(argv, "requested-domain-token") ??
|
|
1348
|
+
(canonicalDomainToken.length > 0 ? canonicalDomainToken : undefined) ??
|
|
1349
|
+
"";
|
|
1350
|
+
const resolvedDomainSelection = await resolveDomainSelection(requestedDomainToken, ontoConfig);
|
|
1351
|
+
let reviewMode = resolveReviewMode(argv, ontoConfig);
|
|
1352
|
+
const explicitLensIds = readMultiOptionValuesFromArgv(argv, "lens-id");
|
|
1353
|
+
// Phase 3: standalone LLM-based complexity assessment (Step 1.5)
|
|
1354
|
+
// When no explicit review-mode or lens-id is set AND the principal is
|
|
1355
|
+
// running against a direct-call external HTTP provider (env override or
|
|
1356
|
+
// canonical llm config), call main_llm to assess whether
|
|
1357
|
+
// core-axis review (cost-constrained Pareto-optimal core lens set from registry)
|
|
1358
|
+
// is appropriate vs full 9-lens.
|
|
1359
|
+
const envHostRuntime = process.env.ONTO_HOST_RUNTIME?.trim().toLowerCase();
|
|
1360
|
+
const isStandaloneHost = envHostRuntime === "standalone" ||
|
|
1361
|
+
envHostRuntime === "anthropic" ||
|
|
1362
|
+
envHostRuntime === "openai" ||
|
|
1363
|
+
envHostRuntime === "grok" ||
|
|
1364
|
+
envHostRuntime === "lmstudio" ||
|
|
1365
|
+
(normalizeLlmModelSwitcher(ontoConfig.llm)?.provider !== "codex" &&
|
|
1366
|
+
normalizeLlmModelSwitcher(ontoConfig.llm) !== null);
|
|
1367
|
+
const noExplicitMode = !readSingleOptionValueFromArgv(argv, "review-mode");
|
|
1368
|
+
const noExplicitLens = explicitLensIds.length === 0;
|
|
1369
|
+
let resolvedLensIds;
|
|
1370
|
+
const lensDefaults = resolveLensDefaultsForReviewMode(reviewMode);
|
|
1371
|
+
if (isStandaloneHost && noExplicitMode && noExplicitLens) {
|
|
1372
|
+
// Step 1.5: LLM-based assessment
|
|
1373
|
+
const targetDesc = typeof requestedTarget === "string" ? requestedTarget : "(bundle)";
|
|
1374
|
+
try {
|
|
1375
|
+
const assessment = await assessComplexity(targetDesc, requestText ?? "", ontoConfig);
|
|
1376
|
+
if (assessment.suggestCoreAxis) {
|
|
1377
|
+
reviewMode = "core-axis";
|
|
1378
|
+
const lensSelection = await selectLenses(targetDesc, requestText ?? "", ontoConfig);
|
|
1379
|
+
resolvedLensIds = lensSelection.selectedLensIds;
|
|
1380
|
+
console.error(`[onto] Step 1.5: core-axis review suggested (Q2: ${assessment.q2Rationale.slice(0, 80)}). Lenses: ${resolvedLensIds.join(", ")}`);
|
|
1381
|
+
}
|
|
1382
|
+
else {
|
|
1383
|
+
reviewMode = "full";
|
|
1384
|
+
resolvedLensIds = [...FULL_REVIEW_LENS_IDS];
|
|
1385
|
+
console.error(`[onto] Step 1.5: full review suggested (Q2: ${assessment.q2Rationale.slice(0, 80)})`);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
catch (err) {
|
|
1389
|
+
throw new Error(`Step 1.5 complexity assessment failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
else {
|
|
1393
|
+
resolvedLensIds = explicitLensIds.length > 0
|
|
1394
|
+
? explicitLensIds
|
|
1395
|
+
: lensDefaults.resolvedLensIds;
|
|
1396
|
+
}
|
|
1397
|
+
const diffRange = readSingleOptionValueFromArgv(argv, "diff-range");
|
|
1398
|
+
let absoluteTargetPath = "";
|
|
1399
|
+
let targetScopeKind;
|
|
1400
|
+
let materializedKind;
|
|
1401
|
+
let resolvedTargetRefs;
|
|
1402
|
+
let filesystemAllowedRoots = normalizeFilesystemAllowedRoots(explicitFilesystemAllowedRoots, projectRoot);
|
|
1403
|
+
let bundleKind;
|
|
1404
|
+
if (typeof diffRange === "string" && diffRange.length > 0) {
|
|
1405
|
+
if (explicitTargetScopeKind !== undefined &&
|
|
1406
|
+
explicitTargetScopeKind !== "file") {
|
|
1407
|
+
throwTargetBindingFailure({
|
|
1408
|
+
reasonCode: "diff_range_scope_conflict",
|
|
1409
|
+
humanMessage: "--diff-range materializes a file target and cannot be combined with the requested target scope.",
|
|
1410
|
+
requiredUserAction: "Use targetScopeKind=file with diffRange, or remove diffRange for bundle/directory review.",
|
|
1411
|
+
details: {
|
|
1412
|
+
target_scope_kind: explicitTargetScopeKind,
|
|
1413
|
+
diff_range: diffRange,
|
|
1414
|
+
},
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1417
|
+
if (explicitPrimaryRef !== undefined ||
|
|
1418
|
+
explicitMemberRefs.length > 0 ||
|
|
1419
|
+
explicitBundleKind !== undefined) {
|
|
1420
|
+
throwTargetBindingFailure({
|
|
1421
|
+
reasonCode: "diff_range_bundle_field_conflict",
|
|
1422
|
+
humanMessage: "--diff-range cannot be combined with bundle target fields.",
|
|
1423
|
+
requiredUserAction: "Run either a git diff review or an explicit bundle review, not both in one invocation.",
|
|
1424
|
+
details: {
|
|
1425
|
+
diff_range: diffRange,
|
|
1426
|
+
primary_ref: explicitPrimaryRef ?? null,
|
|
1427
|
+
member_ref_count: explicitMemberRefs.length,
|
|
1428
|
+
bundle_kind: explicitBundleKind ?? null,
|
|
1429
|
+
},
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
if (!/^[a-zA-Z0-9_.\/\-~^@{}:]+(?:\.\.[a-zA-Z0-9_.\/\-~^@{}:]+)?$/.test(diffRange)) {
|
|
1433
|
+
throw new Error(`Invalid --diff-range value: ${diffRange}. Expected a git ref range like "abc123..def456" or "HEAD~3".`);
|
|
1434
|
+
}
|
|
1435
|
+
const diffTargetDir = typeof requestedTarget === "string" && requestedTarget.length > 0
|
|
1436
|
+
? path.resolve(projectRoot, requestedTarget)
|
|
1437
|
+
: projectRoot;
|
|
1438
|
+
let diffOutput;
|
|
1439
|
+
try {
|
|
1440
|
+
diffOutput = execSync(`git diff ${diffRange}`, {
|
|
1441
|
+
cwd: diffTargetDir,
|
|
1442
|
+
encoding: "utf8",
|
|
1443
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
1444
|
+
});
|
|
1445
|
+
}
|
|
1446
|
+
catch (gitError) {
|
|
1447
|
+
const gitMessage = gitError instanceof Error ? gitError.message : String(gitError);
|
|
1448
|
+
if (gitMessage.includes("Not a git repository") || gitMessage.includes("not a git repository")) {
|
|
1449
|
+
throw new Error(`--diff-range requires a git repository. ${diffTargetDir} is not a git repository.`);
|
|
1450
|
+
}
|
|
1451
|
+
if (gitMessage.includes("unknown revision")) {
|
|
1452
|
+
throw new Error(`Invalid git revision in --diff-range "${diffRange}". Commit not found in ${diffTargetDir}.`);
|
|
1453
|
+
}
|
|
1454
|
+
throw new Error(`git diff failed in ${diffTargetDir}: ${gitMessage.split("\n")[0]}`);
|
|
1455
|
+
}
|
|
1456
|
+
if (diffOutput.trim().length === 0) {
|
|
1457
|
+
throw new Error(`git diff ${diffRange} produced empty output in ${diffTargetDir}`);
|
|
1458
|
+
}
|
|
1459
|
+
const diffFilePath = path.join(projectRoot, ".onto", "review", sessionId, "diff-target.patch");
|
|
1460
|
+
await fs.mkdir(path.dirname(diffFilePath), { recursive: true });
|
|
1461
|
+
await fs.writeFile(diffFilePath, diffOutput, "utf8");
|
|
1462
|
+
absoluteTargetPath = diffFilePath;
|
|
1463
|
+
targetScopeKind = "file";
|
|
1464
|
+
materializedKind = "single_text";
|
|
1465
|
+
resolvedTargetRefs = [diffFilePath];
|
|
1466
|
+
if (!filesystemAllowedRoots.includes(path.resolve(diffTargetDir))) {
|
|
1467
|
+
filesystemAllowedRoots.push(path.resolve(diffTargetDir));
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
else if (bundleRequested) {
|
|
1471
|
+
targetScopeKind = "bundle";
|
|
1472
|
+
materializedKind = "bundle_member_texts";
|
|
1473
|
+
bundleKind = explicitBundleKind && explicitBundleKind.length > 0
|
|
1474
|
+
? explicitBundleKind
|
|
1475
|
+
: "host_facing_bundle";
|
|
1476
|
+
const resolvedBundleTarget = await resolveBundleTargetInput({
|
|
1477
|
+
projectRoot,
|
|
1478
|
+
...(requestedTarget !== undefined ? { requestedTarget } : {}),
|
|
1479
|
+
...(explicitPrimaryRef !== undefined ? { explicitPrimaryRef } : {}),
|
|
1480
|
+
explicitMemberRefs,
|
|
1481
|
+
explicitFilesystemAllowedRoots,
|
|
1482
|
+
});
|
|
1483
|
+
absoluteTargetPath = resolvedBundleTarget.absoluteTargetPath;
|
|
1484
|
+
resolvedTargetRefs = resolvedBundleTarget.resolvedTargetRefs;
|
|
1485
|
+
filesystemAllowedRoots = resolvedBundleTarget.filesystemAllowedRoots;
|
|
1486
|
+
}
|
|
1487
|
+
else {
|
|
1488
|
+
const resolvedTargetInput = await resolveTargetInput(projectRoot, requestedTarget, explicitFilesystemAllowedRoots, argv, explicitTargetScopeKind === "file" || explicitTargetScopeKind === "directory"
|
|
1489
|
+
? explicitTargetScopeKind
|
|
1490
|
+
: undefined);
|
|
1491
|
+
absoluteTargetPath = resolvedTargetInput.absoluteTargetPath;
|
|
1492
|
+
targetScopeKind = resolvedTargetInput.targetScopeKind;
|
|
1493
|
+
materializedKind = resolvedTargetInput.materializedKind;
|
|
1494
|
+
resolvedTargetRefs = [absoluteTargetPath];
|
|
1495
|
+
filesystemAllowedRoots = resolvedTargetInput.filesystemAllowedRoots;
|
|
1496
|
+
}
|
|
1497
|
+
if (resolvedLensIds.length === 0) {
|
|
1498
|
+
throw new Error("No lens IDs resolved. Specify at least one --lens-id or use --review-mode full|core-axis.");
|
|
1499
|
+
}
|
|
1500
|
+
return {
|
|
1501
|
+
requestedTarget: requestedTarget ?? explicitPrimaryRef ?? absoluteTargetPath,
|
|
1502
|
+
targetPath: absoluteTargetPath,
|
|
1503
|
+
resolvedTargetRefs,
|
|
1504
|
+
targetScopeKind,
|
|
1505
|
+
materializedKind,
|
|
1506
|
+
requestText,
|
|
1507
|
+
requestedDomainToken,
|
|
1508
|
+
domainRecommendation: resolvedDomainSelection.domainRecommendation,
|
|
1509
|
+
domainFinalValue: resolvedDomainSelection.domainFinalValue,
|
|
1510
|
+
domainSelectionMode: resolvedDomainSelection.domainSelectionMode,
|
|
1511
|
+
domainSelectionRequired: resolvedDomainSelection.domainSelectionRequired,
|
|
1512
|
+
...(bundleKind ? { bundleKind } : {}),
|
|
1513
|
+
reviewMode,
|
|
1514
|
+
reviewModeRecommendation: reviewMode,
|
|
1515
|
+
resolvedLensIds,
|
|
1516
|
+
alwaysIncludeLensIds: explicitLensIds.length > 0 ? resolvedLensIds : lensDefaults.alwaysIncludeLensIds,
|
|
1517
|
+
recommendedLensIds: explicitLensIds.length > 0 ? resolvedLensIds : lensDefaults.recommendedLensIds,
|
|
1518
|
+
rationale: explicitLensIds.length > 0
|
|
1519
|
+
? ["host-facing invoke preserved the explicitly requested lens set."]
|
|
1520
|
+
: lensDefaults.rationale,
|
|
1521
|
+
filesystemAllowedRoots,
|
|
1522
|
+
};
|
|
1523
|
+
}
|
|
1524
|
+
function appendReviewInvokeDerivedArgs(argv, resolvedInputs) {
|
|
1525
|
+
const appended = [...argv];
|
|
1526
|
+
const appendSingleIfAbsent = (optionName, value) => {
|
|
1527
|
+
if (readSingleOptionValueFromArgv(appended, optionName) !== undefined) {
|
|
1528
|
+
return;
|
|
1529
|
+
}
|
|
1530
|
+
appended.push(`--${optionName}`, value);
|
|
1531
|
+
};
|
|
1532
|
+
const appendMultiIfAbsent = (optionName, values) => {
|
|
1533
|
+
if (readMultiOptionValuesFromArgv(appended, optionName).length > 0) {
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1536
|
+
for (const value of values) {
|
|
1537
|
+
appended.push(`--${optionName}`, value);
|
|
1538
|
+
}
|
|
1539
|
+
};
|
|
1540
|
+
appendSingleIfAbsent("requested-target", resolvedInputs.requestedTarget);
|
|
1541
|
+
appendSingleIfAbsent("target-scope-kind", resolvedInputs.targetScopeKind);
|
|
1542
|
+
appendSingleIfAbsent("primary-ref", resolvedInputs.targetPath);
|
|
1543
|
+
appendSingleIfAbsent("intent-summary", resolvedInputs.requestText);
|
|
1544
|
+
appendSingleIfAbsent("domain-recommendation", resolvedInputs.domainRecommendation);
|
|
1545
|
+
appendSingleIfAbsent("domain-selection-required", resolvedInputs.domainSelectionRequired ? "true" : "false");
|
|
1546
|
+
appendSingleIfAbsent("review-mode-recommendation", resolvedInputs.reviewModeRecommendation);
|
|
1547
|
+
appendSingleIfAbsent("domain-final-value", resolvedInputs.domainFinalValue);
|
|
1548
|
+
appendSingleIfAbsent("domain-selection-mode", resolvedInputs.domainSelectionMode);
|
|
1549
|
+
appendSingleIfAbsent("review-mode", resolvedInputs.reviewMode);
|
|
1550
|
+
appendSingleIfAbsent("materialized-kind", resolvedInputs.materializedKind);
|
|
1551
|
+
appendMultiIfAbsent("always-include-lens-id", resolvedInputs.alwaysIncludeLensIds);
|
|
1552
|
+
appendMultiIfAbsent("recommended-lens-id", resolvedInputs.recommendedLensIds);
|
|
1553
|
+
appendMultiIfAbsent("rationale", resolvedInputs.rationale);
|
|
1554
|
+
appendMultiIfAbsent("resolved-target-ref", resolvedInputs.resolvedTargetRefs);
|
|
1555
|
+
appendMultiIfAbsent("filesystem-allowed-root", resolvedInputs.filesystemAllowedRoots);
|
|
1556
|
+
appendMultiIfAbsent("lens-id", resolvedInputs.resolvedLensIds);
|
|
1557
|
+
appendMultiIfAbsent("materialized-ref", resolvedInputs.resolvedTargetRefs);
|
|
1558
|
+
if (resolvedInputs.targetScopeKind === "bundle") {
|
|
1559
|
+
appendMultiIfAbsent("member-ref", resolvedInputs.resolvedTargetRefs.slice(1));
|
|
1560
|
+
if (typeof resolvedInputs.bundleKind === "string" &&
|
|
1561
|
+
resolvedInputs.bundleKind.length > 0 &&
|
|
1562
|
+
readSingleOptionValueFromArgv(appended, "bundle-kind") === undefined) {
|
|
1563
|
+
appended.push("--bundle-kind", resolvedInputs.bundleKind);
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
if (resolvedInputs.requestedDomainToken.length > 0 &&
|
|
1567
|
+
readSingleOptionValueFromArgv(appended, "requested-domain-token") === undefined) {
|
|
1568
|
+
appended.push("--requested-domain-token", resolvedInputs.requestedDomainToken);
|
|
1569
|
+
}
|
|
1570
|
+
return appended;
|
|
1571
|
+
}
|
|
1572
|
+
async function readOptionalReviewSummary(sessionRoot) {
|
|
1573
|
+
const bindingPath = path.join(sessionRoot, "binding.yaml");
|
|
1574
|
+
const reviewRecordPath = path.join(sessionRoot, "review-record.yaml");
|
|
1575
|
+
const binding = (await fileExists(bindingPath))
|
|
1576
|
+
? await readYamlDocument(bindingPath)
|
|
1577
|
+
: null;
|
|
1578
|
+
const reviewRecord = (await fileExists(reviewRecordPath))
|
|
1579
|
+
? await readValidatedReviewRecord(reviewRecordPath)
|
|
1580
|
+
: null;
|
|
1581
|
+
const executionResultPath = binding?.execution_result_path ?? path.join(sessionRoot, "execution-result.yaml");
|
|
1582
|
+
const executionResult = (await fileExists(executionResultPath))
|
|
1583
|
+
? await readYamlDocument(executionResultPath)
|
|
1584
|
+
: null;
|
|
1585
|
+
return {
|
|
1586
|
+
reviewRecord,
|
|
1587
|
+
executionResult,
|
|
1588
|
+
binding,
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
function rejectRemovedFlags(argv) {
|
|
1592
|
+
const throwRetiredInput = (flag, message) => {
|
|
1593
|
+
throw new ReviewStructuredFailureError({
|
|
1594
|
+
failureRecord: createStructuredFailureRecord({
|
|
1595
|
+
phase: "pre_manifest.retired_entry",
|
|
1596
|
+
reasonCode: "retired_review_invoke_flag",
|
|
1597
|
+
humanMessage: message,
|
|
1598
|
+
requiredUserAction: "Remove the retired argument and use .onto/settings.json or MCP tool arguments for review execution settings.",
|
|
1599
|
+
retrySafety: "safe_after_input_change",
|
|
1600
|
+
artifactTrust: "no_artifacts_trusted",
|
|
1601
|
+
dispatchState: "not_dispatched",
|
|
1602
|
+
artifactRefs: {},
|
|
1603
|
+
mcpErrorCode: "ONTO_REVIEW_RETIRED_INPUT_DETECTED",
|
|
1604
|
+
detailsKind: "retired_config",
|
|
1605
|
+
details: {
|
|
1606
|
+
flag,
|
|
1607
|
+
},
|
|
1608
|
+
}),
|
|
1609
|
+
failureRecordPath: null,
|
|
1610
|
+
});
|
|
1611
|
+
};
|
|
1612
|
+
if (readSingleOptionValueFromArgv(argv, "max-concurrent-lenses") !== undefined) {
|
|
1613
|
+
throwRetiredInput("--max-concurrent-lenses", "--max-concurrent-lenses is not supported. Review runs all selected lenses in parallel.");
|
|
1614
|
+
}
|
|
1615
|
+
if (hasOptionFlag(argv, "claude")) {
|
|
1616
|
+
throwRetiredInput("--claude", "--claude is not supported by review:invoke. Use the MCP review path or project settings.");
|
|
1617
|
+
}
|
|
1618
|
+
for (const removed of ["host-runtime", "execution-realization", "execution-mode"]) {
|
|
1619
|
+
const optionToken = `--${removed}`;
|
|
1620
|
+
const present = hasOptionFlag(argv, removed) ||
|
|
1621
|
+
argv.some((token) => token.startsWith(`${optionToken}=`));
|
|
1622
|
+
if (present) {
|
|
1623
|
+
throwRetiredInput(optionToken, `--${removed} is not supported by review:invoke. Use .onto/settings.json for execution profile selection.`);
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
function appendCanonicalExecutionProfileArgs(argv, profile) {
|
|
1628
|
+
const result = [
|
|
1629
|
+
...argv,
|
|
1630
|
+
"--execution-realization",
|
|
1631
|
+
profile.execution_realization,
|
|
1632
|
+
"--host-runtime",
|
|
1633
|
+
profile.host_runtime,
|
|
1634
|
+
];
|
|
1635
|
+
return result;
|
|
1636
|
+
}
|
|
1637
|
+
function appendDirectoryListingConfigArgs(targetArgv, originalArgv, ontoConfig) {
|
|
1638
|
+
const result = [...targetArgv];
|
|
1639
|
+
if (readMultiOptionValuesFromArgv(result, "excluded-name").length === 0 &&
|
|
1640
|
+
Array.isArray(ontoConfig.excluded_names) &&
|
|
1641
|
+
ontoConfig.excluded_names.length > 0) {
|
|
1642
|
+
for (const name of ontoConfig.excluded_names) {
|
|
1643
|
+
result.push("--excluded-name", name);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
if (readSingleOptionValueFromArgv(result, "max-listing-depth") === undefined &&
|
|
1647
|
+
ontoConfig.max_listing_depth !== undefined) {
|
|
1648
|
+
result.push("--max-listing-depth", String(ontoConfig.max_listing_depth));
|
|
1649
|
+
}
|
|
1650
|
+
if (readSingleOptionValueFromArgv(result, "max-listing-entries") === undefined &&
|
|
1651
|
+
ontoConfig.max_listing_entries !== undefined) {
|
|
1652
|
+
result.push("--max-listing-entries", String(ontoConfig.max_listing_entries));
|
|
1653
|
+
}
|
|
1654
|
+
if (readSingleOptionValueFromArgv(result, "max-embed-lines") === undefined &&
|
|
1655
|
+
ontoConfig.max_embed_lines !== undefined) {
|
|
1656
|
+
result.push("--max-embed-lines", String(ontoConfig.max_embed_lines));
|
|
1657
|
+
}
|
|
1658
|
+
return result;
|
|
1659
|
+
}
|
|
1660
|
+
async function resolveReviewInvokeSetup(argv) {
|
|
1661
|
+
rejectRemovedFlags(argv);
|
|
1662
|
+
const argvWithSessionId = ensureSessionIdArg(argv);
|
|
1663
|
+
const sessionId = requireString(readSingleOptionValueFromArgv(argvWithSessionId, "session-id"), "session-id");
|
|
1664
|
+
const ontoHomeFlag = readSingleOptionValueFromArgv(argv, "onto-home");
|
|
1665
|
+
const ontoHome = resolveOntoHome(ontoHomeFlag);
|
|
1666
|
+
const projectRoot = path.resolve(readSingleOptionValueFromArgv(argv, "project-root") ?? ".");
|
|
1667
|
+
const ontoConfig = ontoHome
|
|
1668
|
+
? await resolveSettingsChain(ontoHome, projectRoot)
|
|
1669
|
+
: await readOntoConfig(projectRoot);
|
|
1670
|
+
const resolvedInvokeInputs = await resolveReviewInvokeInputs(argvWithSessionId, ontoConfig, projectRoot, sessionId);
|
|
1671
|
+
const maxConcurrentLenses = Math.max(1, resolvedInvokeInputs.resolvedLensIds.length);
|
|
1672
|
+
const { optionTokens: argvWithoutPositionals } = splitArgvIntoOptionsAndPositionals(argvWithSessionId, [...KNOWN_INVOKE_ONLY_OPTION_NAMES, ...KNOWN_PASSTHROUGH_OPTION_NAMES], [...KNOWN_INVOKE_ONLY_FLAG_NAMES, ...KNOWN_PASSTHROUGH_FLAG_NAMES]);
|
|
1673
|
+
const normalizedStartArgv = appendReviewInvokeDerivedArgs(stripOptionsFromArgv(argvWithoutPositionals, [...KNOWN_INVOKE_ONLY_OPTION_NAMES], [...KNOWN_INVOKE_ONLY_FLAG_NAMES]), resolvedInvokeInputs);
|
|
1674
|
+
// Resolve the effective profile before session preparation so artifacts,
|
|
1675
|
+
// dispatch, and API responses share one route identity.
|
|
1676
|
+
const explicitCodex = hasOptionFlag(argv, "codex");
|
|
1677
|
+
const profileResolution = resolveExecutionProfile({
|
|
1678
|
+
explicitCodex,
|
|
1679
|
+
ontoConfig,
|
|
1680
|
+
forceMock: readSingleOptionValueFromArgv(argv, "executor-realization") === "mock",
|
|
1681
|
+
});
|
|
1682
|
+
if (profileResolution.type === "no_host") {
|
|
1683
|
+
throw buildNoHostDetectedError();
|
|
1684
|
+
}
|
|
1685
|
+
const effectiveReviewExecutionProfile = applyExecutorOverrideToProfile(profileResolution.profile.review_execution_profile, argv);
|
|
1686
|
+
const effectiveRoute = buildReviewExecutionRoute(effectiveReviewExecutionProfile);
|
|
1687
|
+
const executionProfile = {
|
|
1688
|
+
execution_realization: effectiveRoute.execution_realization,
|
|
1689
|
+
host_runtime: effectiveRoute.artifact_host_runtime,
|
|
1690
|
+
review_execution_profile: effectiveReviewExecutionProfile,
|
|
1691
|
+
};
|
|
1692
|
+
const startArgvWithProfile = appendCanonicalExecutionProfileArgs(normalizedStartArgv, executionProfile);
|
|
1693
|
+
const startArgv = appendDirectoryListingConfigArgs(startArgvWithProfile, argv, ontoConfig);
|
|
1694
|
+
return {
|
|
1695
|
+
ontoHome,
|
|
1696
|
+
projectRoot,
|
|
1697
|
+
ontoConfig,
|
|
1698
|
+
resolvedInvokeInputs,
|
|
1699
|
+
maxConcurrentLenses,
|
|
1700
|
+
startArgv,
|
|
1701
|
+
executionProfile,
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
/**
|
|
1705
|
+
* Runs review preparation and returns the result directly (no console output).
|
|
1706
|
+
*
|
|
1707
|
+
* The execution_realization / host_runtime in the returned result mirror the
|
|
1708
|
+
* values written into the prepared session artifacts.
|
|
1709
|
+
*/
|
|
1710
|
+
export async function reviewPrepareOnly(argv) {
|
|
1711
|
+
const setup = await resolveReviewInvokeSetup(argv);
|
|
1712
|
+
const startResult = await startReviewSession(setup.startArgv);
|
|
1713
|
+
const sessionRoot = path.resolve(startResult.session_root);
|
|
1714
|
+
const profile = setup.executionProfile;
|
|
1715
|
+
return {
|
|
1716
|
+
prepare_only: true,
|
|
1717
|
+
session_root: sessionRoot,
|
|
1718
|
+
request_text: setup.resolvedInvokeInputs.requestText,
|
|
1719
|
+
execution_realization: profile.execution_realization,
|
|
1720
|
+
host_runtime: profile.host_runtime,
|
|
1721
|
+
review_mode: setup.resolvedInvokeInputs.reviewMode,
|
|
1722
|
+
};
|
|
1723
|
+
}
|
|
1724
|
+
export async function runReviewInvokeCli(argv) {
|
|
1725
|
+
const prepareOnly = hasOptionFlag(argv, "prepare-only");
|
|
1726
|
+
const setup = await resolveReviewInvokeSetup(argv);
|
|
1727
|
+
const resolvedProjectRoot = path.resolve(readSingleOptionValueFromArgv(setup.startArgv, "project-root") ?? ".");
|
|
1728
|
+
const rawOntoHome = readSingleOptionValueFromArgv(setup.startArgv, "onto-home");
|
|
1729
|
+
const resolvedOntoHome = rawOntoHome ? path.resolve(rawOntoHome) : undefined;
|
|
1730
|
+
const noWatch = hasOptionFlag(argv, "no-watch");
|
|
1731
|
+
const hasExplicitExecutorOverride = readSingleOptionValueFromArgv(argv, "executor-realization") !== undefined ||
|
|
1732
|
+
readSingleOptionValueFromArgv(argv, "executor-bin") !== undefined ||
|
|
1733
|
+
readSingleOptionValueFromArgv(argv, "synthesize-executor-realization") !== undefined ||
|
|
1734
|
+
readSingleOptionValueFromArgv(argv, "synthesize-executor-bin") !== undefined;
|
|
1735
|
+
const effectiveReviewExecutionProfile = setup.executionProfile.review_execution_profile;
|
|
1736
|
+
const plannedSessionId = requireString(readSingleOptionValueFromArgv(setup.startArgv, "session-id"), "session-id");
|
|
1737
|
+
const plannedSessionRoot = path.join(resolvedProjectRoot, ".onto", "review", plannedSessionId);
|
|
1738
|
+
console.log(renderReviewStartPreview({
|
|
1739
|
+
projectRoot: resolvedProjectRoot,
|
|
1740
|
+
sessionRoot: plannedSessionRoot,
|
|
1741
|
+
setup,
|
|
1742
|
+
reviewExecutionProfile: effectiveReviewExecutionProfile,
|
|
1743
|
+
}));
|
|
1744
|
+
console.log("[review invoke] step 1/3 start session");
|
|
1745
|
+
const startResult = await startReviewSession(setup.startArgv);
|
|
1746
|
+
if (prepareOnly) {
|
|
1747
|
+
const sessionRoot = path.resolve(startResult.session_root);
|
|
1748
|
+
const profile = setup.executionProfile;
|
|
1749
|
+
const result = {
|
|
1750
|
+
prepare_only: true,
|
|
1751
|
+
session_root: sessionRoot,
|
|
1752
|
+
request_text: setup.resolvedInvokeInputs.requestText,
|
|
1753
|
+
execution_realization: profile.execution_realization,
|
|
1754
|
+
host_runtime: profile.host_runtime,
|
|
1755
|
+
review_mode: setup.resolvedInvokeInputs.reviewMode,
|
|
1756
|
+
};
|
|
1757
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1758
|
+
return 0;
|
|
1759
|
+
}
|
|
1760
|
+
const sessionRoot = path.resolve(startResult.session_root);
|
|
1761
|
+
// Auto-attach the live watcher pane AFTER session creation so the watcher
|
|
1762
|
+
// receives the exact session-root as an explicit argument. Prior behaviour
|
|
1763
|
+
// spawned the watcher before startReviewSession and relied on the shared
|
|
1764
|
+
// `.onto/review/.latest-session` pointer — but that pointer is a project-
|
|
1765
|
+
// global single file, so concurrent review sessions (two or more
|
|
1766
|
+
// review invocations running in parallel) caused each
|
|
1767
|
+
// watcher to latch onto whichever session wrote `.latest-session` last.
|
|
1768
|
+
// Passing sessionRoot explicitly eliminates that race.
|
|
1769
|
+
if (!noWatch) {
|
|
1770
|
+
const watcherResult = spawnWatcherPane(resolvedProjectRoot, sessionRoot, resolvedOntoHome);
|
|
1771
|
+
if (watcherResult.spawned) {
|
|
1772
|
+
// Distinguish dry-run (mechanism detected, no osascript/tmux invoked)
|
|
1773
|
+
// from real attach (actual side pane / split / tab opened). Log
|
|
1774
|
+
// readers need both to verify "did the pane appear?" without
|
|
1775
|
+
// conflating it with "did detection logic reach the right branch?".
|
|
1776
|
+
const action = watcherResult.dry_run
|
|
1777
|
+
? "detection via"
|
|
1778
|
+
: "attached via";
|
|
1779
|
+
console.log(`[review runner] live watcher ${action} ${watcherResult.mechanism}`);
|
|
1780
|
+
}
|
|
1781
|
+
else {
|
|
1782
|
+
console.log(`[review runner] live progress: open another terminal and run \`npm run review:watch -- "${sessionRoot}"\`` +
|
|
1783
|
+
(watcherResult.reason ? ` (${watcherResult.reason})` : ""));
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
const resolvedRequestText = setup.resolvedInvokeInputs.requestText;
|
|
1787
|
+
await ensureProviderRouteReadyForDispatch({
|
|
1788
|
+
sessionRoot,
|
|
1789
|
+
executionPlanPath: path.join(sessionRoot, "execution-plan.yaml"),
|
|
1790
|
+
reviewExecutionProfile: effectiveReviewExecutionProfile,
|
|
1791
|
+
});
|
|
1792
|
+
const defaultExecutorConfig = resolveExecutorConfig(argv, "", setup.ontoConfig, setup.ontoHome, hasExplicitExecutorOverride
|
|
1793
|
+
? undefined
|
|
1794
|
+
: setup.executionProfile.review_execution_profile, "lens");
|
|
1795
|
+
const teamleadExecutorConfig = resolveExecutorConfig(argv, "", setup.ontoConfig, setup.ontoHome, hasExplicitExecutorOverride
|
|
1796
|
+
? undefined
|
|
1797
|
+
: setup.executionProfile.review_execution_profile, "teamlead");
|
|
1798
|
+
const synthesizeExecutorConfig = resolveExecutorConfig(argv, "synthesize-", setup.ontoConfig, setup.ontoHome, hasExplicitExecutorOverride
|
|
1799
|
+
? undefined
|
|
1800
|
+
: setup.executionProfile.review_execution_profile, "synthesize");
|
|
1801
|
+
console.log("[review invoke] step 2/3 prompt execution");
|
|
1802
|
+
const promptExecutionResult = await executeReviewPromptExecution({
|
|
1803
|
+
projectRoot: resolvedProjectRoot,
|
|
1804
|
+
sessionRoot,
|
|
1805
|
+
defaultExecutorConfig,
|
|
1806
|
+
...(teamleadExecutorConfig.bin === defaultExecutorConfig.bin &&
|
|
1807
|
+
JSON.stringify(teamleadExecutorConfig.args) ===
|
|
1808
|
+
JSON.stringify(defaultExecutorConfig.args)
|
|
1809
|
+
? {}
|
|
1810
|
+
: { teamleadExecutorConfig }),
|
|
1811
|
+
...(synthesizeExecutorConfig.bin === defaultExecutorConfig.bin &&
|
|
1812
|
+
JSON.stringify(synthesizeExecutorConfig.args) ===
|
|
1813
|
+
JSON.stringify(defaultExecutorConfig.args)
|
|
1814
|
+
? {}
|
|
1815
|
+
: { synthesizeExecutorConfig }),
|
|
1816
|
+
reviewExecutionProfile: effectiveReviewExecutionProfile,
|
|
1817
|
+
ontoConfig: setup.ontoConfig,
|
|
1818
|
+
});
|
|
1819
|
+
console.log("[review invoke] step 3/3 record assembly");
|
|
1820
|
+
await completeReviewSession([
|
|
1821
|
+
"--project-root",
|
|
1822
|
+
resolvedProjectRoot,
|
|
1823
|
+
"--session-root",
|
|
1824
|
+
sessionRoot,
|
|
1825
|
+
"--request-text",
|
|
1826
|
+
resolvedRequestText,
|
|
1827
|
+
]);
|
|
1828
|
+
console.log("[review invoke] completed 3/3 record assembly");
|
|
1829
|
+
const reviewSummary = await readOptionalReviewSummary(sessionRoot);
|
|
1830
|
+
const boundedInvokeSteps = [
|
|
1831
|
+
"review:start-session",
|
|
1832
|
+
"review:run-prompt-execution",
|
|
1833
|
+
"review:complete-session",
|
|
1834
|
+
];
|
|
1835
|
+
const finalRoute = buildReviewExecutionRoute(effectiveReviewExecutionProfile);
|
|
1836
|
+
const routeProfile = {
|
|
1837
|
+
...setup.executionProfile,
|
|
1838
|
+
execution_realization: finalRoute.execution_realization,
|
|
1839
|
+
host_runtime: finalRoute.artifact_host_runtime,
|
|
1840
|
+
review_execution_profile: effectiveReviewExecutionProfile,
|
|
1841
|
+
};
|
|
1842
|
+
const routeSummary = {
|
|
1843
|
+
combined_entrypoint: "review:invoke",
|
|
1844
|
+
bounded_invoke_steps: [...boundedInvokeSteps],
|
|
1845
|
+
execution_realization: routeProfile.execution_realization,
|
|
1846
|
+
host_runtime: routeProfile.host_runtime,
|
|
1847
|
+
review_execution_profile: {
|
|
1848
|
+
mode: routeProfile.review_execution_profile.mode,
|
|
1849
|
+
teamlead_seat: routeProfile.review_execution_profile.teamlead.seat,
|
|
1850
|
+
lens_seat: routeProfile.review_execution_profile.lens.seat,
|
|
1851
|
+
synthesize_seat: routeProfile.review_execution_profile.synthesize.seat,
|
|
1852
|
+
worker_executor: routeProfile.review_execution_profile.worker_executor,
|
|
1853
|
+
deliberation: routeProfile.review_execution_profile.deliberation,
|
|
1854
|
+
runtime_route: {
|
|
1855
|
+
execution_realization: finalRoute.execution_realization,
|
|
1856
|
+
host_runtime: finalRoute.artifact_host_runtime,
|
|
1857
|
+
worker_executor: finalRoute.executor,
|
|
1858
|
+
runtime_provider: finalRoute.resolved_provider,
|
|
1859
|
+
auth_mode: finalRoute.auth_mode,
|
|
1860
|
+
},
|
|
1861
|
+
...(routeProfile.review_execution_profile.model
|
|
1862
|
+
? { model: routeProfile.review_execution_profile.model }
|
|
1863
|
+
: {}),
|
|
1864
|
+
...(routeProfile.review_execution_profile.effort
|
|
1865
|
+
? { effort: routeProfile.review_execution_profile.effort }
|
|
1866
|
+
: {}),
|
|
1867
|
+
...(routeProfile.review_execution_profile.service_tier
|
|
1868
|
+
? { service_tier: routeProfile.review_execution_profile.service_tier }
|
|
1869
|
+
: {}),
|
|
1870
|
+
},
|
|
1871
|
+
review_mode: setup.resolvedInvokeInputs.reviewMode,
|
|
1872
|
+
max_concurrent_lenses: setup.maxConcurrentLenses,
|
|
1873
|
+
concurrency_strategy: "all_lenses_parallel",
|
|
1874
|
+
synthesize_waits_for_all_lenses: true,
|
|
1875
|
+
};
|
|
1876
|
+
const finalOutputPath = reviewSummary.binding?.final_output_path ?? path.join(sessionRoot, "final-output.md");
|
|
1877
|
+
const reviewRecordPath = reviewSummary.binding?.review_record_path ?? path.join(sessionRoot, "review-record.yaml");
|
|
1878
|
+
const executionResultPath = reviewSummary.binding?.execution_result_path ?? path.join(sessionRoot, "execution-result.yaml");
|
|
1879
|
+
const reviewRunManifestPath = path.join(sessionRoot, "review-run-manifest.yaml");
|
|
1880
|
+
const participatingLensIds = reviewSummary.reviewRecord?.participating_lens_ids ??
|
|
1881
|
+
promptExecutionResult.participating_lens_ids;
|
|
1882
|
+
const degradedLensIds = reviewSummary.reviewRecord?.degraded_lens_ids ??
|
|
1883
|
+
promptExecutionResult.degraded_lens_ids;
|
|
1884
|
+
const recordStatus = reviewSummary.reviewRecord?.record_status ??
|
|
1885
|
+
reviewSummary.executionResult?.execution_status ??
|
|
1886
|
+
null;
|
|
1887
|
+
const deliberationStatus = reviewSummary.reviewRecord?.deliberation_status ??
|
|
1888
|
+
reviewSummary.executionResult?.deliberation_status ??
|
|
1889
|
+
null;
|
|
1890
|
+
const haltSummary = reviewSummary.executionResult?.halt_reason || promptExecutionResult.halt_reason
|
|
1891
|
+
? {
|
|
1892
|
+
reason: reviewSummary.executionResult?.halt_reason ??
|
|
1893
|
+
promptExecutionResult.halt_reason ??
|
|
1894
|
+
null,
|
|
1895
|
+
phase: reviewSummary.executionResult?.halt_phase ??
|
|
1896
|
+
promptExecutionResult.halt_phase ??
|
|
1897
|
+
null,
|
|
1898
|
+
unit_id: reviewSummary.executionResult?.halt_unit_id ??
|
|
1899
|
+
promptExecutionResult.halt_unit_id ??
|
|
1900
|
+
null,
|
|
1901
|
+
unit_kind: reviewSummary.executionResult?.halt_unit_kind ??
|
|
1902
|
+
promptExecutionResult.halt_unit_kind ??
|
|
1903
|
+
null,
|
|
1904
|
+
lens_id: reviewSummary.executionResult?.halt_lens_id ??
|
|
1905
|
+
promptExecutionResult.halt_lens_id ??
|
|
1906
|
+
null,
|
|
1907
|
+
}
|
|
1908
|
+
: null;
|
|
1909
|
+
const executionSummary = {
|
|
1910
|
+
status: recordStatus,
|
|
1911
|
+
deliberation_status: deliberationStatus,
|
|
1912
|
+
halt: haltSummary,
|
|
1913
|
+
review_mode: setup.resolvedInvokeInputs.reviewMode,
|
|
1914
|
+
lens: {
|
|
1915
|
+
participating_count: participatingLensIds.length,
|
|
1916
|
+
degraded_count: degradedLensIds.length,
|
|
1917
|
+
participating_lens_ids: participatingLensIds,
|
|
1918
|
+
degraded_lens_ids: degradedLensIds,
|
|
1919
|
+
},
|
|
1920
|
+
executor: {
|
|
1921
|
+
max_concurrent_lenses: setup.maxConcurrentLenses,
|
|
1922
|
+
concurrency_strategy: "all_lenses_parallel",
|
|
1923
|
+
realization: inferExecutorRealization(defaultExecutorConfig),
|
|
1924
|
+
profile: routeSummary.review_execution_profile,
|
|
1925
|
+
},
|
|
1926
|
+
};
|
|
1927
|
+
const artifactRefs = {
|
|
1928
|
+
session_root: sessionRoot,
|
|
1929
|
+
final_output: finalOutputPath,
|
|
1930
|
+
review_record: reviewRecordPath,
|
|
1931
|
+
execution_result: executionResultPath,
|
|
1932
|
+
review_run_manifest: reviewRunManifestPath,
|
|
1933
|
+
};
|
|
1934
|
+
const closureSummary = await readReviewResultClosureSummary(sessionRoot);
|
|
1935
|
+
const explanationSummary = await readReviewResultExplanationSummary(finalOutputPath);
|
|
1936
|
+
const resultOverview = {
|
|
1937
|
+
outcome: {
|
|
1938
|
+
status: recordStatus,
|
|
1939
|
+
deliberation_status: deliberationStatus,
|
|
1940
|
+
halt: haltSummary,
|
|
1941
|
+
review_mode: setup.resolvedInvokeInputs.reviewMode,
|
|
1942
|
+
},
|
|
1943
|
+
scope: {
|
|
1944
|
+
target: setup.resolvedInvokeInputs.requestedTarget,
|
|
1945
|
+
target_scope_kind: setup.resolvedInvokeInputs.targetScopeKind,
|
|
1946
|
+
domain: setup.resolvedInvokeInputs.domainFinalValue,
|
|
1947
|
+
},
|
|
1948
|
+
coverage: {
|
|
1949
|
+
planned_lens_count: setup.resolvedInvokeInputs.resolvedLensIds.length,
|
|
1950
|
+
participating_lens_count: participatingLensIds.length,
|
|
1951
|
+
degraded_lens_count: degradedLensIds.length,
|
|
1952
|
+
participating_lens_ids: participatingLensIds,
|
|
1953
|
+
degraded_lens_ids: degradedLensIds,
|
|
1954
|
+
},
|
|
1955
|
+
explanation: {
|
|
1956
|
+
final_review_result: explanationSummary.final_review_result,
|
|
1957
|
+
},
|
|
1958
|
+
issues: closureSummary,
|
|
1959
|
+
artifacts: artifactRefs,
|
|
1960
|
+
};
|
|
1961
|
+
console.log(renderReviewResultOverview({
|
|
1962
|
+
projectRoot: resolvedProjectRoot,
|
|
1963
|
+
target: setup.resolvedInvokeInputs.requestedTarget,
|
|
1964
|
+
targetScopeKind: setup.resolvedInvokeInputs.targetScopeKind,
|
|
1965
|
+
domain: setup.resolvedInvokeInputs.domainFinalValue,
|
|
1966
|
+
status: recordStatus,
|
|
1967
|
+
deliberationStatus,
|
|
1968
|
+
reviewMode: setup.resolvedInvokeInputs.reviewMode,
|
|
1969
|
+
plannedLensIds: setup.resolvedInvokeInputs.resolvedLensIds,
|
|
1970
|
+
participatingLensIds,
|
|
1971
|
+
degradedLensIds,
|
|
1972
|
+
closureSummary,
|
|
1973
|
+
explanationSummary,
|
|
1974
|
+
artifactRefs,
|
|
1975
|
+
}));
|
|
1976
|
+
console.log(JSON.stringify({
|
|
1977
|
+
summary: executionSummary,
|
|
1978
|
+
result_overview: resultOverview,
|
|
1979
|
+
entrypoint_plan: {
|
|
1980
|
+
entrypoint: "review",
|
|
1981
|
+
target: setup.resolvedInvokeInputs.requestedTarget,
|
|
1982
|
+
target_scope_kind: setup.resolvedInvokeInputs.targetScopeKind,
|
|
1983
|
+
resolved_target_refs: setup.resolvedInvokeInputs.resolvedTargetRefs,
|
|
1984
|
+
request_text: resolvedRequestText,
|
|
1985
|
+
requested_domain_token: setup.resolvedInvokeInputs.requestedDomainToken.length > 0
|
|
1986
|
+
? setup.resolvedInvokeInputs.requestedDomainToken
|
|
1987
|
+
: null,
|
|
1988
|
+
domain_selection_required: setup.resolvedInvokeInputs.domainSelectionRequired,
|
|
1989
|
+
domain_selection_mode: setup.resolvedInvokeInputs.domainSelectionMode,
|
|
1990
|
+
domain_final_value: setup.resolvedInvokeInputs.domainFinalValue,
|
|
1991
|
+
review_mode: setup.resolvedInvokeInputs.reviewMode,
|
|
1992
|
+
},
|
|
1993
|
+
route_summary: routeSummary,
|
|
1994
|
+
artifacts: artifactRefs,
|
|
1995
|
+
review_result: {
|
|
1996
|
+
session_root: sessionRoot,
|
|
1997
|
+
final_output_path: finalOutputPath,
|
|
1998
|
+
review_record_path: reviewRecordPath,
|
|
1999
|
+
execution_result_path: executionResultPath,
|
|
2000
|
+
review_run_manifest_path: reviewRunManifestPath,
|
|
2001
|
+
record_status: recordStatus,
|
|
2002
|
+
deliberation_status: deliberationStatus,
|
|
2003
|
+
halt_reason: haltSummary?.reason ?? null,
|
|
2004
|
+
halt_phase: haltSummary?.phase ?? null,
|
|
2005
|
+
halt_unit_id: haltSummary?.unit_id ?? null,
|
|
2006
|
+
halt_unit_kind: haltSummary?.unit_kind ?? null,
|
|
2007
|
+
halt_lens_id: haltSummary?.lens_id ?? null,
|
|
2008
|
+
participating_lens_ids: participatingLensIds,
|
|
2009
|
+
degraded_lens_ids: degradedLensIds,
|
|
2010
|
+
summary: executionSummary,
|
|
2011
|
+
},
|
|
2012
|
+
bounded_invoke_steps: [...boundedInvokeSteps],
|
|
2013
|
+
completion: {
|
|
2014
|
+
status: recordStatus,
|
|
2015
|
+
final_output_path: finalOutputPath,
|
|
2016
|
+
review_record_path: reviewRecordPath,
|
|
2017
|
+
},
|
|
2018
|
+
}, null, 2));
|
|
2019
|
+
return 0;
|
|
2020
|
+
}
|
|
2021
|
+
async function main() {
|
|
2022
|
+
await printOntoReleaseChannelNotice();
|
|
2023
|
+
return runReviewInvokeCli(process.argv.slice(2));
|
|
2024
|
+
}
|
|
2025
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
2026
|
+
main().then((exitCode) => process.exit(exitCode), (error) => {
|
|
2027
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
2028
|
+
process.exit(1);
|
|
2029
|
+
});
|
|
2030
|
+
}
|