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.
@@ -1,18 +1,11 @@
1
- #!/usr/bin/env node
2
1
  import { execSync } from "node:child_process";
3
2
  import fsSync from "node:fs";
4
3
  import fs from "node:fs/promises";
5
4
  import os from "node:os";
6
5
  import path from "node:path";
7
6
  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
7
  import { generateReviewSessionId } from "../review/materializers.js";
14
8
  import { fileExists, hasOptionFlag, isDeprecatedDomainAlias, normalizeDomainValue, readMultiOptionValuesFromArgv, readYamlDocument, readSingleOptionValueFromArgv, } from "../review/review-artifact-utils.js";
15
- import { printOntoReleaseChannelNotice } from "../release-channel/release-channel.js";
16
9
  import { isOntoRoot, resolveOntoHome } from "../discovery/onto-home.js";
17
10
  import { resolveInstallationPath } from "../discovery/installation-paths.js";
18
11
  import { REVIEW_EXECUTION_UNIT_IDS, resolveSettingsChain, } from "../discovery/settings-chain.js";
@@ -20,8 +13,7 @@ import { loadCoreLensRegistry } from "../discovery/lens-registry.js";
20
13
  import { isPathInsideRoot, isPathInsideRootRealpathAwareSync, } from "../path-boundary.js";
21
14
  import { isDirectModelCallSelection, isExternalOauthWorkerSelection, normalizeLlmModelSwitcher, } from "../llm/model-switcher.js";
22
15
  import { effectiveReviewUnitLlmRef, resolveReviewExecutionProfile, } from "../review/review-execution-profile.js";
23
- import { buildReviewExecutionRoute, buildReviewRuntimeRouteArtifactProjection, } from "../review/review-execution-route.js";
24
- import { prepareReviewInvocationArgv, runReviewInvocationArgv, } from "../review/review-invocation-runner.js";
16
+ import { buildReviewExecutionRoute, } from "../review/review-execution-route.js";
25
17
  import { readValidatedReviewRecord } from "../review/review-record-validation.js";
26
18
  import { readReviewResultClassification } from "../review/review-result-classification.js";
27
19
  import { createStructuredFailureRecord, ReviewStructuredFailureError, writeAndThrowStructuredFailureRecord, } from "../review/failure-records.js";
@@ -94,7 +86,7 @@ const KNOWN_INVOKE_ONLY_FLAG_NAMES = [
94
86
  "no-watch",
95
87
  "no-domain",
96
88
  ];
97
- function requireString(value, optionName) {
89
+ export function requireString(value, optionName) {
98
90
  if (typeof value !== "string" || value.length === 0) {
99
91
  throw new Error(`Missing required option --${optionName}`);
100
92
  }
@@ -207,7 +199,7 @@ function formatPreviewList(items, indent = " ") {
207
199
  ? items.map((item) => `${indent}- ${item}`)
208
200
  : [`${indent}- (none)`];
209
201
  }
210
- function renderReviewStartPreview(args) {
202
+ export function renderReviewStartPreview(args) {
211
203
  const { projectRoot, sessionRoot, setup, reviewExecutionProfile } = args;
212
204
  const inputs = setup.resolvedInvokeInputs;
213
205
  const targetPath = path.resolve(inputs.targetPath);
@@ -393,7 +385,7 @@ export async function readReviewResultClosureSummary(sessionRoot) {
393
385
  })),
394
386
  };
395
387
  }
396
- function renderReviewResultOverview(args) {
388
+ export function renderReviewResultOverview(args) {
397
389
  const degraded = args.degradedLensIds.length > 0 ? args.degradedLensIds.join(", ") : "none";
398
390
  const problemLines = args.closureSummary.problem_definitions.length > 0
399
391
  ? args.closureSummary.problem_definitions.map((problem) => ` - ${problem.issue_id}: ${problem.problem_definition} (${problem.issue_role}, ${problem.judgment_state}, ${problem.timing_class}/${problem.closure_class})`)
@@ -2049,7 +2041,7 @@ function resolveMaxConcurrentLenses(args) {
2049
2041
  : Math.min(configured, args.plannedLensCount);
2050
2042
  return Math.max(1, bounded);
2051
2043
  }
2052
- function concurrencyStrategyFor(args) {
2044
+ export function concurrencyStrategyFor(args) {
2053
2045
  return args.maxConcurrentLenses >= args.plannedLensCount
2054
2046
  ? "all_lenses_parallel"
2055
2047
  : "bounded_lens_parallel";
@@ -2100,329 +2092,3 @@ export async function resolveReviewInvokeSetup(argv) {
2100
2092
  executionProfile,
2101
2093
  };
2102
2094
  }
2103
- /**
2104
- * Runs review preparation and returns the result directly (no console output).
2105
- *
2106
- * The execution_realization / host_runtime in the returned result mirror the
2107
- * values written into the prepared session artifacts.
2108
- */
2109
- export async function reviewPrepareOnly(argv) {
2110
- return prepareReviewInvocationArgv(argv);
2111
- }
2112
- export async function runReviewInvokeCli(argv) {
2113
- const prepareOnly = hasOptionFlag(argv, "prepare-only");
2114
- if (!prepareOnly) {
2115
- const output = await runReviewInvocationArgv(argv);
2116
- console.log(JSON.stringify(output, null, 2));
2117
- return 0;
2118
- }
2119
- const setup = await resolveReviewInvokeSetup(argv);
2120
- const resolvedProjectRoot = path.resolve(readSingleOptionValueFromArgv(setup.startArgv, "project-root") ?? ".");
2121
- const rawOntoHome = readSingleOptionValueFromArgv(setup.startArgv, "onto-home");
2122
- const resolvedOntoHome = rawOntoHome ? path.resolve(rawOntoHome) : undefined;
2123
- const noWatch = hasOptionFlag(argv, "no-watch");
2124
- const hasExplicitExecutorBinOverride = readSingleOptionValueFromArgv(argv, "executor-bin") !== undefined ||
2125
- readSingleOptionValueFromArgv(argv, "synthesize-executor-bin") !== undefined;
2126
- const effectiveReviewExecutionProfile = setup.executionProfile.review_execution_profile;
2127
- const plannedSessionId = requireString(readSingleOptionValueFromArgv(setup.startArgv, "session-id"), "session-id");
2128
- const plannedSessionRoot = path.join(resolvedProjectRoot, ".onto", "review", plannedSessionId);
2129
- console.log(renderReviewStartPreview({
2130
- projectRoot: resolvedProjectRoot,
2131
- sessionRoot: plannedSessionRoot,
2132
- setup,
2133
- reviewExecutionProfile: effectiveReviewExecutionProfile,
2134
- }));
2135
- console.log("[review invoke] step 1/3 start session");
2136
- const startResult = await startReviewSession(setup.startArgv);
2137
- if (prepareOnly) {
2138
- const sessionRoot = path.resolve(startResult.session_root);
2139
- const profile = setup.executionProfile;
2140
- const result = {
2141
- prepare_only: true,
2142
- session_root: sessionRoot,
2143
- request_text: setup.resolvedInvokeInputs.requestText,
2144
- execution_realization: profile.execution_realization,
2145
- host_runtime: profile.host_runtime,
2146
- review_mode: setup.resolvedInvokeInputs.reviewMode,
2147
- };
2148
- console.log(JSON.stringify(result, null, 2));
2149
- return 0;
2150
- }
2151
- const sessionRoot = path.resolve(startResult.session_root);
2152
- // Auto-attach the live watcher pane AFTER session creation so the watcher
2153
- // receives the exact session-root as an explicit argument. Prior behaviour
2154
- // spawned the watcher before startReviewSession and relied on the shared
2155
- // `.onto/review/.latest-session` pointer — but that pointer is a project-
2156
- // global single file, so concurrent review sessions (two or more
2157
- // review invocations running in parallel) caused each
2158
- // watcher to latch onto whichever session wrote `.latest-session` last.
2159
- // Passing sessionRoot explicitly eliminates that race.
2160
- if (!noWatch) {
2161
- const watcherResult = spawnWatcherPane(resolvedProjectRoot, sessionRoot, resolvedOntoHome);
2162
- if (watcherResult.spawned) {
2163
- // Distinguish dry-run (mechanism detected, no osascript/tmux invoked)
2164
- // from real attach (actual side pane / split / tab opened). Log
2165
- // readers need both to verify "did the pane appear?" without
2166
- // conflating it with "did detection logic reach the right branch?".
2167
- const action = watcherResult.dry_run
2168
- ? "detection via"
2169
- : "attached via";
2170
- console.log(`[review runner] live watcher ${action} ${watcherResult.mechanism}`);
2171
- }
2172
- else {
2173
- console.log(`[review runner] live progress: open another terminal and run \`bash scripts/onto-review-watch.sh "${sessionRoot}"\`` +
2174
- (watcherResult.reason ? ` (${watcherResult.reason})` : ""));
2175
- }
2176
- }
2177
- const resolvedRequestText = setup.resolvedInvokeInputs.requestText;
2178
- await ensureProviderRouteReadyForDispatch({
2179
- sessionRoot,
2180
- executionPlanPath: path.join(sessionRoot, "execution-plan.yaml"),
2181
- reviewExecutionProfile: effectiveReviewExecutionProfile,
2182
- });
2183
- const defaultExecutorConfig = resolveExecutorConfig(argv, "", setup.ontoConfig, setup.ontoHome, hasExplicitExecutorBinOverride
2184
- ? undefined
2185
- : setup.executionProfile.review_execution_profile, "lens");
2186
- const teamleadExecutorConfig = resolveExecutorConfig(argv, "", setup.ontoConfig, setup.ontoHome, hasExplicitExecutorBinOverride
2187
- ? undefined
2188
- : setup.executionProfile.review_execution_profile, "teamlead");
2189
- const synthesizeExecutorConfig = resolveExecutorConfig(argv, "synthesize-", setup.ontoConfig, setup.ontoHome, hasExplicitExecutorBinOverride
2190
- ? undefined
2191
- : setup.executionProfile.review_execution_profile, "synthesize");
2192
- console.log("[review invoke] step 2/3 prompt execution");
2193
- const promptExecutionResult = await executeReviewPromptExecution({
2194
- projectRoot: resolvedProjectRoot,
2195
- sessionRoot,
2196
- defaultExecutorConfig,
2197
- ...(teamleadExecutorConfig.bin === defaultExecutorConfig.bin &&
2198
- JSON.stringify(teamleadExecutorConfig.args) ===
2199
- JSON.stringify(defaultExecutorConfig.args)
2200
- ? {}
2201
- : { teamleadExecutorConfig }),
2202
- ...(synthesizeExecutorConfig.bin === defaultExecutorConfig.bin &&
2203
- JSON.stringify(synthesizeExecutorConfig.args) ===
2204
- JSON.stringify(defaultExecutorConfig.args)
2205
- ? {}
2206
- : { synthesizeExecutorConfig }),
2207
- reviewExecutionProfile: effectiveReviewExecutionProfile,
2208
- ontoConfig: setup.ontoConfig,
2209
- });
2210
- console.log("[review invoke] step 3/3 record assembly");
2211
- await completeReviewSession([
2212
- "--project-root",
2213
- resolvedProjectRoot,
2214
- "--session-root",
2215
- sessionRoot,
2216
- "--request-text",
2217
- resolvedRequestText,
2218
- ]);
2219
- console.log("[review invoke] completed 3/3 record assembly");
2220
- const reviewSummary = await readOptionalReviewSummary(sessionRoot);
2221
- const boundedInvokeSteps = [
2222
- "start_review_session",
2223
- "run_review_prompt_execution",
2224
- "complete_review_session",
2225
- ];
2226
- const finalRoute = buildReviewExecutionRoute(effectiveReviewExecutionProfile);
2227
- const routeProfile = {
2228
- ...setup.executionProfile,
2229
- execution_realization: finalRoute.execution_realization,
2230
- host_runtime: finalRoute.artifact_host_runtime,
2231
- review_execution_profile: effectiveReviewExecutionProfile,
2232
- };
2233
- const routeSummary = {
2234
- combined_entrypoint: "review_invocation",
2235
- bounded_invoke_steps: [...boundedInvokeSteps],
2236
- execution_realization: routeProfile.execution_realization,
2237
- host_runtime: routeProfile.host_runtime,
2238
- review_execution_profile: {
2239
- mode: routeProfile.review_execution_profile.mode,
2240
- teamlead_seat: routeProfile.review_execution_profile.teamlead.seat,
2241
- lens_seat: routeProfile.review_execution_profile.lens.seat,
2242
- synthesize_seat: routeProfile.review_execution_profile.synthesize.seat,
2243
- worker_executor: routeProfile.review_execution_profile.worker_executor,
2244
- deliberation: routeProfile.review_execution_profile.deliberation,
2245
- runtime_route: buildReviewRuntimeRouteArtifactProjection(finalRoute),
2246
- ...(routeProfile.review_execution_profile.model
2247
- ? { model: routeProfile.review_execution_profile.model }
2248
- : {}),
2249
- ...(routeProfile.review_execution_profile.effort
2250
- ? { effort: routeProfile.review_execution_profile.effort }
2251
- : {}),
2252
- ...(routeProfile.review_execution_profile.service_tier
2253
- ? { service_tier: routeProfile.review_execution_profile.service_tier }
2254
- : {}),
2255
- ...(routeProfile.review_execution_profile.retry
2256
- ? { retry: routeProfile.review_execution_profile.retry }
2257
- : {}),
2258
- },
2259
- review_mode: setup.resolvedInvokeInputs.reviewMode,
2260
- max_concurrent_lenses: setup.maxConcurrentLenses,
2261
- concurrency_strategy: concurrencyStrategyFor({
2262
- plannedLensCount: setup.resolvedInvokeInputs.resolvedLensIds.length,
2263
- maxConcurrentLenses: setup.maxConcurrentLenses,
2264
- }),
2265
- synthesize_waits_for_all_lenses: true,
2266
- };
2267
- const finalOutputPath = reviewSummary.binding?.final_output_path ?? path.join(sessionRoot, "final-output.md");
2268
- const reviewRecordPath = reviewSummary.binding?.review_record_path ?? path.join(sessionRoot, "review-record.yaml");
2269
- const executionResultPath = reviewSummary.binding?.execution_result_path ?? path.join(sessionRoot, "execution-result.yaml");
2270
- const reviewRunManifestPath = path.join(sessionRoot, "review-run-manifest.yaml");
2271
- const participatingLensIds = reviewSummary.reviewRecord?.participating_lens_ids ??
2272
- promptExecutionResult.participating_lens_ids;
2273
- const degradedLensIds = reviewSummary.reviewRecord?.degraded_lens_ids ??
2274
- promptExecutionResult.degraded_lens_ids;
2275
- const recordStatus = reviewSummary.reviewRecord?.record_status ??
2276
- reviewSummary.executionResult?.execution_status ??
2277
- null;
2278
- const deliberationStatus = reviewSummary.reviewRecord?.deliberation_status ??
2279
- reviewSummary.executionResult?.deliberation_status ??
2280
- null;
2281
- const haltSummary = reviewSummary.executionResult?.halt_reason || promptExecutionResult.halt_reason
2282
- ? {
2283
- reason: reviewSummary.executionResult?.halt_reason ??
2284
- promptExecutionResult.halt_reason ??
2285
- null,
2286
- phase: reviewSummary.executionResult?.halt_phase ??
2287
- promptExecutionResult.halt_phase ??
2288
- null,
2289
- unit_id: reviewSummary.executionResult?.halt_unit_id ??
2290
- promptExecutionResult.halt_unit_id ??
2291
- null,
2292
- unit_kind: reviewSummary.executionResult?.halt_unit_kind ??
2293
- promptExecutionResult.halt_unit_kind ??
2294
- null,
2295
- lens_id: reviewSummary.executionResult?.halt_lens_id ??
2296
- promptExecutionResult.halt_lens_id ??
2297
- null,
2298
- }
2299
- : null;
2300
- const executionSummary = {
2301
- status: recordStatus,
2302
- deliberation_status: deliberationStatus,
2303
- halt: haltSummary,
2304
- review_mode: setup.resolvedInvokeInputs.reviewMode,
2305
- lens: {
2306
- participating_count: participatingLensIds.length,
2307
- degraded_count: degradedLensIds.length,
2308
- participating_lens_ids: participatingLensIds,
2309
- degraded_lens_ids: degradedLensIds,
2310
- },
2311
- executor: {
2312
- max_concurrent_lenses: setup.maxConcurrentLenses,
2313
- concurrency_strategy: concurrencyStrategyFor({
2314
- plannedLensCount: setup.resolvedInvokeInputs.resolvedLensIds.length,
2315
- maxConcurrentLenses: setup.maxConcurrentLenses,
2316
- }),
2317
- realization: inferExecutorRealization(defaultExecutorConfig),
2318
- profile: routeSummary.review_execution_profile,
2319
- },
2320
- };
2321
- const artifactRefs = {
2322
- session_root: sessionRoot,
2323
- final_output: finalOutputPath,
2324
- review_record: reviewRecordPath,
2325
- execution_result: executionResultPath,
2326
- review_run_manifest: reviewRunManifestPath,
2327
- };
2328
- const closureSummary = await readReviewResultClosureSummary(sessionRoot);
2329
- const explanationSummary = await readReviewResultExplanationSummary(finalOutputPath);
2330
- const resultOverview = {
2331
- outcome: {
2332
- status: recordStatus,
2333
- deliberation_status: deliberationStatus,
2334
- halt: haltSummary,
2335
- review_mode: setup.resolvedInvokeInputs.reviewMode,
2336
- },
2337
- scope: {
2338
- target: setup.resolvedInvokeInputs.requestedTarget,
2339
- target_scope_kind: setup.resolvedInvokeInputs.targetScopeKind,
2340
- domain: setup.resolvedInvokeInputs.domainFinalValue,
2341
- domain_selection_reason: setup.resolvedInvokeInputs.domainSelectionReason,
2342
- },
2343
- coverage: {
2344
- planned_lens_count: setup.resolvedInvokeInputs.resolvedLensIds.length,
2345
- participating_lens_count: participatingLensIds.length,
2346
- degraded_lens_count: degradedLensIds.length,
2347
- participating_lens_ids: participatingLensIds,
2348
- degraded_lens_ids: degradedLensIds,
2349
- },
2350
- explanation: {
2351
- final_review_result: explanationSummary.final_review_result,
2352
- boundary_notes: explanationSummary.boundary_notes,
2353
- },
2354
- issues: closureSummary,
2355
- artifacts: artifactRefs,
2356
- };
2357
- console.log(renderReviewResultOverview({
2358
- projectRoot: resolvedProjectRoot,
2359
- target: setup.resolvedInvokeInputs.requestedTarget,
2360
- targetScopeKind: setup.resolvedInvokeInputs.targetScopeKind,
2361
- domain: setup.resolvedInvokeInputs.domainFinalValue,
2362
- domainSelectionReason: setup.resolvedInvokeInputs.domainSelectionReason,
2363
- status: recordStatus,
2364
- deliberationStatus,
2365
- reviewMode: setup.resolvedInvokeInputs.reviewMode,
2366
- plannedLensIds: setup.resolvedInvokeInputs.resolvedLensIds,
2367
- participatingLensIds,
2368
- degradedLensIds,
2369
- closureSummary,
2370
- explanationSummary,
2371
- artifactRefs,
2372
- }));
2373
- console.log(JSON.stringify({
2374
- summary: executionSummary,
2375
- result_overview: resultOverview,
2376
- entrypoint_plan: {
2377
- entrypoint: "review",
2378
- target: setup.resolvedInvokeInputs.requestedTarget,
2379
- target_scope_kind: setup.resolvedInvokeInputs.targetScopeKind,
2380
- resolved_target_refs: setup.resolvedInvokeInputs.resolvedTargetRefs,
2381
- request_text: resolvedRequestText,
2382
- requested_domain_token: setup.resolvedInvokeInputs.requestedDomainToken.length > 0
2383
- ? setup.resolvedInvokeInputs.requestedDomainToken
2384
- : null,
2385
- domain_selection_required: setup.resolvedInvokeInputs.domainSelectionRequired,
2386
- domain_selection_mode: setup.resolvedInvokeInputs.domainSelectionMode,
2387
- domain_selection_reason: setup.resolvedInvokeInputs.domainSelectionReason,
2388
- domain_final_value: setup.resolvedInvokeInputs.domainFinalValue,
2389
- review_mode: setup.resolvedInvokeInputs.reviewMode,
2390
- },
2391
- route_summary: routeSummary,
2392
- artifacts: artifactRefs,
2393
- review_result: {
2394
- session_root: sessionRoot,
2395
- final_output_path: finalOutputPath,
2396
- review_record_path: reviewRecordPath,
2397
- execution_result_path: executionResultPath,
2398
- review_run_manifest_path: reviewRunManifestPath,
2399
- record_status: recordStatus,
2400
- deliberation_status: deliberationStatus,
2401
- halt_reason: haltSummary?.reason ?? null,
2402
- halt_phase: haltSummary?.phase ?? null,
2403
- halt_unit_id: haltSummary?.unit_id ?? null,
2404
- halt_unit_kind: haltSummary?.unit_kind ?? null,
2405
- halt_lens_id: haltSummary?.lens_id ?? null,
2406
- participating_lens_ids: participatingLensIds,
2407
- degraded_lens_ids: degradedLensIds,
2408
- summary: executionSummary,
2409
- },
2410
- bounded_invoke_steps: [...boundedInvokeSteps],
2411
- completion: {
2412
- status: recordStatus,
2413
- final_output_path: finalOutputPath,
2414
- review_record_path: reviewRecordPath,
2415
- },
2416
- }, null, 2));
2417
- return 0;
2418
- }
2419
- async function main() {
2420
- await printOntoReleaseChannelNotice();
2421
- return runReviewInvokeCli(process.argv.slice(2));
2422
- }
2423
- if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
2424
- main().then((exitCode) => process.exit(exitCode), (error) => {
2425
- console.error(error instanceof Error ? error.message : String(error));
2426
- process.exit(1);
2427
- });
2428
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "onto-mcp",
3
- "version": "0.4.7",
3
+ "version": "0.4.8",
4
4
  "description": "MCP-native ontology review runtime with context-isolated lenses and controlled deliberation",
5
5
  "homepage": "https://github.com/kangminlee-maker/onto-mcp#readme",
6
6
  "bugs": {
@@ -43,6 +43,10 @@
43
43
  "check:retired-root-paths": "bash scripts/check-retired-root-paths.sh",
44
44
  "check:mcp:review": "tsx scripts/mcp-review-conformance.ts",
45
45
  "check:review:route": "tsx scripts/review-runtime-hardening.ts",
46
+ "check:import-boundary": "tsx scripts/check-import-boundary.ts",
47
+ "check:spec-defaults": "tsx scripts/check-no-hardcoded-spec-defaults.ts",
48
+ "check:invariant-change": "tsx scripts/check-invariant-change-marker.ts",
49
+ "check:invariant-drift": "tsx scripts/check-invariant-drift.ts",
46
50
  "test": "npm run test:e2e",
47
51
  "test:review:live": "npm run build:ts-core && tsx scripts/review-mcp-live-e2e.ts",
48
52
  "test:review:live:cli": "npm run build:ts-core && tsx scripts/review-live-e2e.ts",