onto-mcp 0.4.7 → 0.4.8

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.
@@ -19,7 +19,7 @@ import { synthesisLedgerPath, synthesisWorkItemsPath, } from "../core-runtime/re
19
19
  import { readValidatedReviewRecord } from "../core-runtime/review/review-record-validation.js";
20
20
  import { readReviewResultClassification } from "../core-runtime/review/review-result-classification.js";
21
21
  import { REVIEW_EXECUTION_STEP_IDS, REVIEW_PROGRESS_STEPS, REVIEW_PROGRESS_TOTAL_STEPS, reviewProgressStepById, reviewProgressStepIdFromHalt, } from "../core-runtime/review/review-progress-contract.js";
22
- import { collectReviewInvocationArtifactRefs, prepareReviewInvocationRequest, runReviewInvocation, } from "../core-runtime/review/review-invocation-runner.js";
22
+ import { collectReviewInvocationArtifactRefs, prepareReviewInvocationRequest, runReviewInvocation, } from "../core-runtime/cli/review-invocation-runner.js";
23
23
  import { completeReviewSession } from "../core-runtime/cli/complete-review-session.js";
24
24
  import { buildExecutorConfigFromRealization, ensureProviderRouteReadyForDispatch, resolveExecutorConfig, } from "../core-runtime/cli/review-invoke.js";
25
25
  import { writeAndThrowStructuredFailureRecord, } from "../core-runtime/review/failure-records.js";
@@ -1,10 +1,14 @@
1
+ #!/usr/bin/env node
1
2
  import path from "node:path";
2
- import { completeReviewSession } from "../cli/complete-review-session.js";
3
- import { ensureProviderRouteReadyForDispatch, inferExecutorRealization, readOptionalReviewSummary, readReviewResultClosureSummary, readReviewResultExplanationSummary, resolveExecutorConfig, resolveReviewInvokeSetup, } from "../cli/review-invoke.js";
4
- import { executeReviewPromptExecution } from "../cli/run-review-prompt-execution.js";
5
- import { startReviewSession } from "../cli/start-review-session.js";
6
- import { buildReviewExecutionRoute, buildReviewRuntimeRouteArtifactProjection, } from "./review-execution-route.js";
7
- import { fileExists, normalizeDomainValue, readSingleOptionValueFromArgv, } from "./review-artifact-utils.js";
3
+ import { pathToFileURL } from "node:url";
4
+ import { completeReviewSession } from "./complete-review-session.js";
5
+ import { ensureProviderRouteReadyForDispatch, inferExecutorRealization, readOptionalReviewSummary, readReviewResultClosureSummary, readReviewResultExplanationSummary, resolveExecutorConfig, resolveReviewInvokeSetup, concurrencyStrategyFor, renderReviewResultOverview, renderReviewStartPreview, requireString, } from "./review-invoke.js";
6
+ import { executeReviewPromptExecution } from "./run-review-prompt-execution.js";
7
+ import { startReviewSession } from "./start-review-session.js";
8
+ import { spawnWatcherPane } from "./spawn-watcher.js";
9
+ import { printOntoReleaseChannelNotice } from "../release-channel/release-channel.js";
10
+ import { buildReviewExecutionRoute, buildReviewRuntimeRouteArtifactProjection, } from "../review/review-execution-route.js";
11
+ import { fileExists, normalizeDomainValue, hasOptionFlag, readSingleOptionValueFromArgv, } from "../review/review-artifact-utils.js";
8
12
  export function appendReviewInvocationRequestArgs(args, request, options) {
9
13
  if (request.domain && request.noDomain) {
10
14
  throw new Error("Use either domain or noDomain, not both.");
@@ -625,3 +629,329 @@ async function projectReviewInvocationCliOutput(args) {
625
629
  },
626
630
  };
627
631
  }
632
+ /**
633
+ * Runs review preparation and returns the result directly (no console output).
634
+ *
635
+ * The execution_realization / host_runtime in the returned result mirror the
636
+ * values written into the prepared session artifacts.
637
+ */
638
+ export async function reviewPrepareOnly(argv) {
639
+ return prepareReviewInvocationArgv(argv);
640
+ }
641
+ export async function runReviewInvokeCli(argv) {
642
+ const prepareOnly = hasOptionFlag(argv, "prepare-only");
643
+ if (!prepareOnly) {
644
+ const output = await runReviewInvocationArgv(argv);
645
+ console.log(JSON.stringify(output, null, 2));
646
+ return 0;
647
+ }
648
+ const setup = await resolveReviewInvokeSetup(argv);
649
+ const resolvedProjectRoot = path.resolve(readSingleOptionValueFromArgv(setup.startArgv, "project-root") ?? ".");
650
+ const rawOntoHome = readSingleOptionValueFromArgv(setup.startArgv, "onto-home");
651
+ const resolvedOntoHome = rawOntoHome ? path.resolve(rawOntoHome) : undefined;
652
+ const noWatch = hasOptionFlag(argv, "no-watch");
653
+ const hasExplicitExecutorBinOverride = readSingleOptionValueFromArgv(argv, "executor-bin") !== undefined ||
654
+ readSingleOptionValueFromArgv(argv, "synthesize-executor-bin") !== undefined;
655
+ const effectiveReviewExecutionProfile = setup.executionProfile.review_execution_profile;
656
+ const plannedSessionId = requireString(readSingleOptionValueFromArgv(setup.startArgv, "session-id"), "session-id");
657
+ const plannedSessionRoot = path.join(resolvedProjectRoot, ".onto", "review", plannedSessionId);
658
+ console.log(renderReviewStartPreview({
659
+ projectRoot: resolvedProjectRoot,
660
+ sessionRoot: plannedSessionRoot,
661
+ setup,
662
+ reviewExecutionProfile: effectiveReviewExecutionProfile,
663
+ }));
664
+ console.log("[review invoke] step 1/3 start session");
665
+ const startResult = await startReviewSession(setup.startArgv);
666
+ if (prepareOnly) {
667
+ const sessionRoot = path.resolve(startResult.session_root);
668
+ const profile = setup.executionProfile;
669
+ const result = {
670
+ prepare_only: true,
671
+ session_root: sessionRoot,
672
+ request_text: setup.resolvedInvokeInputs.requestText,
673
+ execution_realization: profile.execution_realization,
674
+ host_runtime: profile.host_runtime,
675
+ review_mode: setup.resolvedInvokeInputs.reviewMode,
676
+ };
677
+ console.log(JSON.stringify(result, null, 2));
678
+ return 0;
679
+ }
680
+ const sessionRoot = path.resolve(startResult.session_root);
681
+ // Auto-attach the live watcher pane AFTER session creation so the watcher
682
+ // receives the exact session-root as an explicit argument. Prior behaviour
683
+ // spawned the watcher before startReviewSession and relied on the shared
684
+ // `.onto/review/.latest-session` pointer — but that pointer is a project-
685
+ // global single file, so concurrent review sessions (two or more
686
+ // review invocations running in parallel) caused each
687
+ // watcher to latch onto whichever session wrote `.latest-session` last.
688
+ // Passing sessionRoot explicitly eliminates that race.
689
+ if (!noWatch) {
690
+ const watcherResult = spawnWatcherPane(resolvedProjectRoot, sessionRoot, resolvedOntoHome);
691
+ if (watcherResult.spawned) {
692
+ // Distinguish dry-run (mechanism detected, no osascript/tmux invoked)
693
+ // from real attach (actual side pane / split / tab opened). Log
694
+ // readers need both to verify "did the pane appear?" without
695
+ // conflating it with "did detection logic reach the right branch?".
696
+ const action = watcherResult.dry_run
697
+ ? "detection via"
698
+ : "attached via";
699
+ console.log(`[review runner] live watcher ${action} ${watcherResult.mechanism}`);
700
+ }
701
+ else {
702
+ console.log(`[review runner] live progress: open another terminal and run \`bash scripts/onto-review-watch.sh "${sessionRoot}"\`` +
703
+ (watcherResult.reason ? ` (${watcherResult.reason})` : ""));
704
+ }
705
+ }
706
+ const resolvedRequestText = setup.resolvedInvokeInputs.requestText;
707
+ await ensureProviderRouteReadyForDispatch({
708
+ sessionRoot,
709
+ executionPlanPath: path.join(sessionRoot, "execution-plan.yaml"),
710
+ reviewExecutionProfile: effectiveReviewExecutionProfile,
711
+ });
712
+ const defaultExecutorConfig = resolveExecutorConfig(argv, "", setup.ontoConfig, setup.ontoHome, hasExplicitExecutorBinOverride
713
+ ? undefined
714
+ : setup.executionProfile.review_execution_profile, "lens");
715
+ const teamleadExecutorConfig = resolveExecutorConfig(argv, "", setup.ontoConfig, setup.ontoHome, hasExplicitExecutorBinOverride
716
+ ? undefined
717
+ : setup.executionProfile.review_execution_profile, "teamlead");
718
+ const synthesizeExecutorConfig = resolveExecutorConfig(argv, "synthesize-", setup.ontoConfig, setup.ontoHome, hasExplicitExecutorBinOverride
719
+ ? undefined
720
+ : setup.executionProfile.review_execution_profile, "synthesize");
721
+ console.log("[review invoke] step 2/3 prompt execution");
722
+ const promptExecutionResult = await executeReviewPromptExecution({
723
+ projectRoot: resolvedProjectRoot,
724
+ sessionRoot,
725
+ defaultExecutorConfig,
726
+ ...(teamleadExecutorConfig.bin === defaultExecutorConfig.bin &&
727
+ JSON.stringify(teamleadExecutorConfig.args) ===
728
+ JSON.stringify(defaultExecutorConfig.args)
729
+ ? {}
730
+ : { teamleadExecutorConfig }),
731
+ ...(synthesizeExecutorConfig.bin === defaultExecutorConfig.bin &&
732
+ JSON.stringify(synthesizeExecutorConfig.args) ===
733
+ JSON.stringify(defaultExecutorConfig.args)
734
+ ? {}
735
+ : { synthesizeExecutorConfig }),
736
+ reviewExecutionProfile: effectiveReviewExecutionProfile,
737
+ ontoConfig: setup.ontoConfig,
738
+ });
739
+ console.log("[review invoke] step 3/3 record assembly");
740
+ await completeReviewSession([
741
+ "--project-root",
742
+ resolvedProjectRoot,
743
+ "--session-root",
744
+ sessionRoot,
745
+ "--request-text",
746
+ resolvedRequestText,
747
+ ]);
748
+ console.log("[review invoke] completed 3/3 record assembly");
749
+ const reviewSummary = await readOptionalReviewSummary(sessionRoot);
750
+ const boundedInvokeSteps = [
751
+ "start_review_session",
752
+ "run_review_prompt_execution",
753
+ "complete_review_session",
754
+ ];
755
+ const finalRoute = buildReviewExecutionRoute(effectiveReviewExecutionProfile);
756
+ const routeProfile = {
757
+ ...setup.executionProfile,
758
+ execution_realization: finalRoute.execution_realization,
759
+ host_runtime: finalRoute.artifact_host_runtime,
760
+ review_execution_profile: effectiveReviewExecutionProfile,
761
+ };
762
+ const routeSummary = {
763
+ combined_entrypoint: "review_invocation",
764
+ bounded_invoke_steps: [...boundedInvokeSteps],
765
+ execution_realization: routeProfile.execution_realization,
766
+ host_runtime: routeProfile.host_runtime,
767
+ review_execution_profile: {
768
+ mode: routeProfile.review_execution_profile.mode,
769
+ teamlead_seat: routeProfile.review_execution_profile.teamlead.seat,
770
+ lens_seat: routeProfile.review_execution_profile.lens.seat,
771
+ synthesize_seat: routeProfile.review_execution_profile.synthesize.seat,
772
+ worker_executor: routeProfile.review_execution_profile.worker_executor,
773
+ deliberation: routeProfile.review_execution_profile.deliberation,
774
+ runtime_route: buildReviewRuntimeRouteArtifactProjection(finalRoute),
775
+ ...(routeProfile.review_execution_profile.model
776
+ ? { model: routeProfile.review_execution_profile.model }
777
+ : {}),
778
+ ...(routeProfile.review_execution_profile.effort
779
+ ? { effort: routeProfile.review_execution_profile.effort }
780
+ : {}),
781
+ ...(routeProfile.review_execution_profile.service_tier
782
+ ? { service_tier: routeProfile.review_execution_profile.service_tier }
783
+ : {}),
784
+ ...(routeProfile.review_execution_profile.retry
785
+ ? { retry: routeProfile.review_execution_profile.retry }
786
+ : {}),
787
+ },
788
+ review_mode: setup.resolvedInvokeInputs.reviewMode,
789
+ max_concurrent_lenses: setup.maxConcurrentLenses,
790
+ concurrency_strategy: concurrencyStrategyFor({
791
+ plannedLensCount: setup.resolvedInvokeInputs.resolvedLensIds.length,
792
+ maxConcurrentLenses: setup.maxConcurrentLenses,
793
+ }),
794
+ synthesize_waits_for_all_lenses: true,
795
+ };
796
+ const finalOutputPath = reviewSummary.binding?.final_output_path ?? path.join(sessionRoot, "final-output.md");
797
+ const reviewRecordPath = reviewSummary.binding?.review_record_path ?? path.join(sessionRoot, "review-record.yaml");
798
+ const executionResultPath = reviewSummary.binding?.execution_result_path ?? path.join(sessionRoot, "execution-result.yaml");
799
+ const reviewRunManifestPath = path.join(sessionRoot, "review-run-manifest.yaml");
800
+ const participatingLensIds = reviewSummary.reviewRecord?.participating_lens_ids ??
801
+ promptExecutionResult.participating_lens_ids;
802
+ const degradedLensIds = reviewSummary.reviewRecord?.degraded_lens_ids ??
803
+ promptExecutionResult.degraded_lens_ids;
804
+ const recordStatus = reviewSummary.reviewRecord?.record_status ??
805
+ reviewSummary.executionResult?.execution_status ??
806
+ null;
807
+ const deliberationStatus = reviewSummary.reviewRecord?.deliberation_status ??
808
+ reviewSummary.executionResult?.deliberation_status ??
809
+ null;
810
+ const haltSummary = reviewSummary.executionResult?.halt_reason || promptExecutionResult.halt_reason
811
+ ? {
812
+ reason: reviewSummary.executionResult?.halt_reason ??
813
+ promptExecutionResult.halt_reason ??
814
+ null,
815
+ phase: reviewSummary.executionResult?.halt_phase ??
816
+ promptExecutionResult.halt_phase ??
817
+ null,
818
+ unit_id: reviewSummary.executionResult?.halt_unit_id ??
819
+ promptExecutionResult.halt_unit_id ??
820
+ null,
821
+ unit_kind: reviewSummary.executionResult?.halt_unit_kind ??
822
+ promptExecutionResult.halt_unit_kind ??
823
+ null,
824
+ lens_id: reviewSummary.executionResult?.halt_lens_id ??
825
+ promptExecutionResult.halt_lens_id ??
826
+ null,
827
+ }
828
+ : null;
829
+ const executionSummary = {
830
+ status: recordStatus,
831
+ deliberation_status: deliberationStatus,
832
+ halt: haltSummary,
833
+ review_mode: setup.resolvedInvokeInputs.reviewMode,
834
+ lens: {
835
+ participating_count: participatingLensIds.length,
836
+ degraded_count: degradedLensIds.length,
837
+ participating_lens_ids: participatingLensIds,
838
+ degraded_lens_ids: degradedLensIds,
839
+ },
840
+ executor: {
841
+ max_concurrent_lenses: setup.maxConcurrentLenses,
842
+ concurrency_strategy: concurrencyStrategyFor({
843
+ plannedLensCount: setup.resolvedInvokeInputs.resolvedLensIds.length,
844
+ maxConcurrentLenses: setup.maxConcurrentLenses,
845
+ }),
846
+ realization: inferExecutorRealization(defaultExecutorConfig),
847
+ profile: routeSummary.review_execution_profile,
848
+ },
849
+ };
850
+ const artifactRefs = {
851
+ session_root: sessionRoot,
852
+ final_output: finalOutputPath,
853
+ review_record: reviewRecordPath,
854
+ execution_result: executionResultPath,
855
+ review_run_manifest: reviewRunManifestPath,
856
+ };
857
+ const closureSummary = await readReviewResultClosureSummary(sessionRoot);
858
+ const explanationSummary = await readReviewResultExplanationSummary(finalOutputPath);
859
+ const resultOverview = {
860
+ outcome: {
861
+ status: recordStatus,
862
+ deliberation_status: deliberationStatus,
863
+ halt: haltSummary,
864
+ review_mode: setup.resolvedInvokeInputs.reviewMode,
865
+ },
866
+ scope: {
867
+ target: setup.resolvedInvokeInputs.requestedTarget,
868
+ target_scope_kind: setup.resolvedInvokeInputs.targetScopeKind,
869
+ domain: setup.resolvedInvokeInputs.domainFinalValue,
870
+ domain_selection_reason: setup.resolvedInvokeInputs.domainSelectionReason,
871
+ },
872
+ coverage: {
873
+ planned_lens_count: setup.resolvedInvokeInputs.resolvedLensIds.length,
874
+ participating_lens_count: participatingLensIds.length,
875
+ degraded_lens_count: degradedLensIds.length,
876
+ participating_lens_ids: participatingLensIds,
877
+ degraded_lens_ids: degradedLensIds,
878
+ },
879
+ explanation: {
880
+ final_review_result: explanationSummary.final_review_result,
881
+ boundary_notes: explanationSummary.boundary_notes,
882
+ },
883
+ issues: closureSummary,
884
+ artifacts: artifactRefs,
885
+ };
886
+ console.log(renderReviewResultOverview({
887
+ projectRoot: resolvedProjectRoot,
888
+ target: setup.resolvedInvokeInputs.requestedTarget,
889
+ targetScopeKind: setup.resolvedInvokeInputs.targetScopeKind,
890
+ domain: setup.resolvedInvokeInputs.domainFinalValue,
891
+ domainSelectionReason: setup.resolvedInvokeInputs.domainSelectionReason,
892
+ status: recordStatus,
893
+ deliberationStatus,
894
+ reviewMode: setup.resolvedInvokeInputs.reviewMode,
895
+ plannedLensIds: setup.resolvedInvokeInputs.resolvedLensIds,
896
+ participatingLensIds,
897
+ degradedLensIds,
898
+ closureSummary,
899
+ explanationSummary,
900
+ artifactRefs,
901
+ }));
902
+ console.log(JSON.stringify({
903
+ summary: executionSummary,
904
+ result_overview: resultOverview,
905
+ entrypoint_plan: {
906
+ entrypoint: "review",
907
+ target: setup.resolvedInvokeInputs.requestedTarget,
908
+ target_scope_kind: setup.resolvedInvokeInputs.targetScopeKind,
909
+ resolved_target_refs: setup.resolvedInvokeInputs.resolvedTargetRefs,
910
+ request_text: resolvedRequestText,
911
+ requested_domain_token: setup.resolvedInvokeInputs.requestedDomainToken.length > 0
912
+ ? setup.resolvedInvokeInputs.requestedDomainToken
913
+ : null,
914
+ domain_selection_required: setup.resolvedInvokeInputs.domainSelectionRequired,
915
+ domain_selection_mode: setup.resolvedInvokeInputs.domainSelectionMode,
916
+ domain_selection_reason: setup.resolvedInvokeInputs.domainSelectionReason,
917
+ domain_final_value: setup.resolvedInvokeInputs.domainFinalValue,
918
+ review_mode: setup.resolvedInvokeInputs.reviewMode,
919
+ },
920
+ route_summary: routeSummary,
921
+ artifacts: artifactRefs,
922
+ review_result: {
923
+ session_root: sessionRoot,
924
+ final_output_path: finalOutputPath,
925
+ review_record_path: reviewRecordPath,
926
+ execution_result_path: executionResultPath,
927
+ review_run_manifest_path: reviewRunManifestPath,
928
+ record_status: recordStatus,
929
+ deliberation_status: deliberationStatus,
930
+ halt_reason: haltSummary?.reason ?? null,
931
+ halt_phase: haltSummary?.phase ?? null,
932
+ halt_unit_id: haltSummary?.unit_id ?? null,
933
+ halt_unit_kind: haltSummary?.unit_kind ?? null,
934
+ halt_lens_id: haltSummary?.lens_id ?? null,
935
+ participating_lens_ids: participatingLensIds,
936
+ degraded_lens_ids: degradedLensIds,
937
+ summary: executionSummary,
938
+ },
939
+ bounded_invoke_steps: [...boundedInvokeSteps],
940
+ completion: {
941
+ status: recordStatus,
942
+ final_output_path: finalOutputPath,
943
+ review_record_path: reviewRecordPath,
944
+ },
945
+ }, null, 2));
946
+ return 0;
947
+ }
948
+ async function main() {
949
+ await printOntoReleaseChannelNotice();
950
+ return runReviewInvokeCli(process.argv.slice(2));
951
+ }
952
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
953
+ main().then((exitCode) => process.exit(exitCode), (error) => {
954
+ console.error(error instanceof Error ? error.message : String(error));
955
+ process.exit(1);
956
+ });
957
+ }