onto-mcp 0.3.0 → 0.3.2
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-lexicon.yaml +12 -0
- package/.onto/domains/software-engineering/competency_qs.md +192 -63
- package/.onto/domains/software-engineering/concepts.md +67 -5
- package/.onto/domains/software-engineering/conciseness_rules.md +22 -2
- package/.onto/domains/software-engineering/dependency_rules.md +78 -8
- package/.onto/domains/software-engineering/domain_scope.md +181 -150
- package/.onto/domains/software-engineering/extension_cases.md +318 -542
- package/.onto/domains/software-engineering/logic_rules.md +75 -3
- package/.onto/domains/software-engineering/problem_framing_profile.md +29 -2
- package/.onto/domains/software-engineering/prompt_interface.md +122 -0
- package/.onto/domains/software-engineering/structure_spec.md +53 -4
- package/.onto/principles/llm-native-development-guideline.md +20 -0
- package/.onto/principles/productization-charter.md +6 -0
- package/.onto/processes/evolve/material-kind-adapter-contract.md +6 -0
- package/.onto/processes/reconstruct/reconstruct-boundary-contract.md +468 -81
- package/.onto/processes/reconstruct/reconstruct-execution-ux-contract.md +177 -0
- package/.onto/processes/reconstruct/source-profile-contract.md +39 -6
- package/.onto/processes/reconstruct/top-level-concept-discovery-contract.md +387 -0
- package/.onto/processes/review/binding-contract.md +8 -0
- package/.onto/processes/review/lens-registry.md +16 -0
- package/.onto/processes/review/pre-dispatch-contracts.md +34 -13
- package/.onto/processes/review/productized-live-path.md +3 -1
- package/.onto/processes/shared/pipeline-execution-ledger-contract.md +185 -0
- package/.onto/processes/shared/target-material-kind-contract.md +24 -2
- package/.onto/roles/axiology.md +7 -2
- package/AGENTS.md +4 -2
- package/README.md +52 -29
- package/dist/core-api/reconstruct-api.js +92 -5
- package/dist/core-api/review-api.js +1744 -371
- package/dist/core-runtime/cli/mock-review-unit-executor.js +17 -0
- package/dist/core-runtime/cli/render-review-final-output.js +9 -0
- package/dist/core-runtime/cli/review-invoke.js +387 -55
- package/dist/core-runtime/cli/run-review-prompt-execution.js +361 -90
- package/dist/core-runtime/path-boundary.js +58 -0
- package/dist/core-runtime/pipeline-execution-ledger.js +100 -0
- package/dist/core-runtime/reconstruct/artifact-types.js +33 -1
- package/dist/core-runtime/reconstruct/materialize-preparation.js +54 -4
- package/dist/core-runtime/reconstruct/pipeline-execution-ledger.js +342 -0
- package/dist/core-runtime/reconstruct/post-seed-validation.js +630 -0
- package/dist/core-runtime/reconstruct/record.js +105 -1
- package/dist/core-runtime/reconstruct/run.js +1594 -38
- package/dist/core-runtime/reconstruct/seed-candidate-validation.js +29 -0
- package/dist/core-runtime/review/continuation-plan.js +160 -0
- package/dist/core-runtime/review/execution-plan-boundary.js +123 -0
- package/dist/core-runtime/review/materializers.js +8 -3
- package/dist/core-runtime/review/pipeline-execution-ledger.js +250 -0
- package/dist/core-runtime/review/review-artifact-utils.js +15 -2
- package/dist/core-runtime/review/review-invocation-runner.js +604 -0
- package/dist/core-runtime/target-material-kind.js +43 -5
- package/dist/mcp/server.js +289 -59
- package/dist/mcp/tool-schemas.js +28 -2
- package/package.json +4 -2
- package/.onto/domains/llm-native-development/competency_qs.md +0 -430
- package/.onto/domains/llm-native-development/concepts.md +0 -242
- package/.onto/domains/llm-native-development/conciseness_rules.md +0 -163
- package/.onto/domains/llm-native-development/dependency_rules.md +0 -216
- package/.onto/domains/llm-native-development/domain_scope.md +0 -197
- package/.onto/domains/llm-native-development/extension_cases.md +0 -474
- package/.onto/domains/llm-native-development/logic_rules.md +0 -123
- package/.onto/domains/llm-native-development/prompt_interface.md +0 -49
- package/.onto/domains/llm-native-development/structure_spec.md +0 -245
package/dist/mcp/server.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import fs from "node:fs/promises";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import { pathToFileURL } from "node:url";
|
|
5
|
-
import { createOntoReviewCoreApi, } from "../core-api/review-api.js";
|
|
4
|
+
import { createOntoReviewCoreApi, ReviewContinuationError, } from "../core-api/review-api.js";
|
|
6
5
|
import { createOntoReconstructCoreApi, } from "../core-api/reconstruct-api.js";
|
|
7
6
|
import { OntoSettingsValidationError, UnsupportedOntoConfigFilesError, } from "../core-runtime/discovery/settings-chain.js";
|
|
8
7
|
import { readOntoVersion } from "../core-runtime/release-channel/release-channel.js";
|
|
9
8
|
import { createStructuredFailureRecord, ReviewStructuredFailureError, } from "../core-runtime/review/failure-records.js";
|
|
10
9
|
import { buildReviewRouteVisibilityFromFailure, } from "../core-runtime/review/route-visibility.js";
|
|
11
10
|
import { fileExists, readYamlDocument } from "../core-runtime/review/review-artifact-utils.js";
|
|
12
|
-
import {
|
|
11
|
+
import { isPathInsideRoot, realpathIfExists, } from "../core-runtime/path-boundary.js";
|
|
12
|
+
import { OntoListDomainsToolInputSchema, OntoListSourceProfilesToolInputSchema, OntoObserveSourceToolInputSchema, OntoPrepareReviewToolInputSchema, OntoReconstructSessionInputSchema, OntoReconstructToolInputSchema, OntoReviewCancelToolInputSchema, OntoReviewContinueToolInputSchema, OntoReviewResultInputSchema, OntoReviewStatusInputSchema, OntoReviewToolInputSchema, OntoValidateReconstructDirectiveToolInputSchema, } from "./tool-schemas.js";
|
|
13
13
|
const reviewApi = createOntoReviewCoreApi();
|
|
14
14
|
const reconstructApi = createOntoReconstructCoreApi();
|
|
15
15
|
const REVIEW_INPUT_SCHEMA = {
|
|
@@ -87,6 +87,10 @@ const REVIEW_INPUT_SCHEMA = {
|
|
|
87
87
|
type: "boolean",
|
|
88
88
|
description: "When true, materialize artifacts without executing lens units.",
|
|
89
89
|
},
|
|
90
|
+
returnRunningAfterMs: {
|
|
91
|
+
type: "number",
|
|
92
|
+
description: "Optional synchronous wait budget in milliseconds. When exceeded after session planning, onto.review returns a running handle and background execution continues.",
|
|
93
|
+
},
|
|
90
94
|
},
|
|
91
95
|
};
|
|
92
96
|
const SESSION_INPUT_SCHEMA = {
|
|
@@ -104,6 +108,101 @@ const SESSION_INPUT_SCHEMA = {
|
|
|
104
108
|
},
|
|
105
109
|
},
|
|
106
110
|
};
|
|
111
|
+
const REVIEW_STATUS_INPUT_SCHEMA = {
|
|
112
|
+
type: "object",
|
|
113
|
+
additionalProperties: false,
|
|
114
|
+
properties: {
|
|
115
|
+
sessionRoot: {
|
|
116
|
+
type: "string",
|
|
117
|
+
description: "Absolute or project-relative review session root. Omit only when latest=true.",
|
|
118
|
+
},
|
|
119
|
+
projectRoot: {
|
|
120
|
+
type: "string",
|
|
121
|
+
description: "Project root that owns the review session. Defaults to the MCP server working directory.",
|
|
122
|
+
},
|
|
123
|
+
latest: {
|
|
124
|
+
type: "boolean",
|
|
125
|
+
description: "When true, recover the newest matching review session under projectRoot.",
|
|
126
|
+
},
|
|
127
|
+
target: {
|
|
128
|
+
type: "string",
|
|
129
|
+
description: "Optional latest-session target filter.",
|
|
130
|
+
},
|
|
131
|
+
domain: {
|
|
132
|
+
type: "string",
|
|
133
|
+
description: "Optional latest-session canonical or alias domain filter.",
|
|
134
|
+
},
|
|
135
|
+
requestHash: {
|
|
136
|
+
type: "string",
|
|
137
|
+
description: "Optional latest-session request hash filter returned by a run handle.",
|
|
138
|
+
},
|
|
139
|
+
limit: {
|
|
140
|
+
type: "number",
|
|
141
|
+
description: "Maximum latest-session matches to include. Defaults to 5.",
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
const REVIEW_RESULT_INPUT_SCHEMA = {
|
|
146
|
+
type: "object",
|
|
147
|
+
additionalProperties: false,
|
|
148
|
+
required: ["sessionRoot"],
|
|
149
|
+
properties: {
|
|
150
|
+
...(SESSION_INPUT_SCHEMA.properties),
|
|
151
|
+
projectionLevel: {
|
|
152
|
+
type: "string",
|
|
153
|
+
enum: ["compact", "standard", "full"],
|
|
154
|
+
description: "Result projection size. compact omits final output text and ReviewRecord; full includes complete artifacts.",
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
const REVIEW_CONTINUE_INPUT_SCHEMA = {
|
|
159
|
+
type: "object",
|
|
160
|
+
additionalProperties: false,
|
|
161
|
+
required: ["sessionRoot"],
|
|
162
|
+
properties: {
|
|
163
|
+
sessionRoot: {
|
|
164
|
+
type: "string",
|
|
165
|
+
description: "Absolute or project-relative review session root.",
|
|
166
|
+
},
|
|
167
|
+
projectRoot: {
|
|
168
|
+
type: "string",
|
|
169
|
+
description: "Project root that owns the review session. Defaults to the MCP server working directory.",
|
|
170
|
+
},
|
|
171
|
+
targetUnits: {
|
|
172
|
+
type: "array",
|
|
173
|
+
items: { type: "string" },
|
|
174
|
+
description: "Optional current frontier unit ids or public aliases such as lens:logic and deliberation:logic. Omit to use the full ledger-derived first untrusted frontier.",
|
|
175
|
+
},
|
|
176
|
+
requestText: {
|
|
177
|
+
type: "string",
|
|
178
|
+
description: "Optional original request text for final ReviewRecord assembly when the session was only prepared.",
|
|
179
|
+
},
|
|
180
|
+
executorRealization: {
|
|
181
|
+
type: "string",
|
|
182
|
+
enum: ["codex", "mock", "ts_inline_http"],
|
|
183
|
+
description: "Executor realization for resumed units. Required for prepared sessions that have no prior review-run-manifest.",
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
const REVIEW_CANCEL_INPUT_SCHEMA = {
|
|
188
|
+
type: "object",
|
|
189
|
+
additionalProperties: false,
|
|
190
|
+
required: ["sessionRoot"],
|
|
191
|
+
properties: {
|
|
192
|
+
sessionRoot: {
|
|
193
|
+
type: "string",
|
|
194
|
+
description: "Absolute or project-relative review session root.",
|
|
195
|
+
},
|
|
196
|
+
projectRoot: {
|
|
197
|
+
type: "string",
|
|
198
|
+
description: "Project root that owns the review session. Defaults to the MCP server working directory.",
|
|
199
|
+
},
|
|
200
|
+
reason: {
|
|
201
|
+
type: "string",
|
|
202
|
+
description: "Optional cancellation reason recorded in the session.",
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
};
|
|
107
206
|
const LIST_DOMAINS_INPUT_SCHEMA = {
|
|
108
207
|
type: "object",
|
|
109
208
|
additionalProperties: false,
|
|
@@ -160,8 +259,6 @@ const RECONSTRUCT_INPUT_SCHEMA = {
|
|
|
160
259
|
required: [
|
|
161
260
|
"targetRefs",
|
|
162
261
|
"intent",
|
|
163
|
-
"semanticAuthorRealization",
|
|
164
|
-
"confirmationProviderRealization",
|
|
165
262
|
],
|
|
166
263
|
properties: {
|
|
167
264
|
targetRefs: {
|
|
@@ -193,13 +290,13 @@ const RECONSTRUCT_INPUT_SCHEMA = {
|
|
|
193
290
|
},
|
|
194
291
|
semanticAuthorRealization: {
|
|
195
292
|
type: "string",
|
|
196
|
-
enum: ["mock"],
|
|
197
|
-
description: "Explicit semantic author realization.
|
|
293
|
+
enum: ["mock", "direct_call"],
|
|
294
|
+
description: "Explicit semantic author realization. direct_call uses configured llm provider; mock is a test/fixture realization.",
|
|
198
295
|
},
|
|
199
296
|
confirmationProviderRealization: {
|
|
200
297
|
type: "string",
|
|
201
|
-
enum: ["mock"],
|
|
202
|
-
description: "Explicit confirmation provider realization.
|
|
298
|
+
enum: ["mock", "direct_call"],
|
|
299
|
+
description: "Explicit confirmation provider realization. direct_call uses configured llm provider; mock is a test/fixture realization.",
|
|
203
300
|
},
|
|
204
301
|
},
|
|
205
302
|
};
|
|
@@ -269,15 +366,25 @@ const TOOL_DEFINITIONS = [
|
|
|
269
366
|
description: "Prepare an onto review session and prompt packets without executing lens units.",
|
|
270
367
|
inputSchema: REVIEW_INPUT_SCHEMA,
|
|
271
368
|
},
|
|
369
|
+
{
|
|
370
|
+
name: "onto.review_continue",
|
|
371
|
+
description: "Continue a review session when runControl.continuationAvailable is true by reusing trusted PipelineExecutionLedger units and rerunning only the continuation frontier and downstream units.",
|
|
372
|
+
inputSchema: REVIEW_CONTINUE_INPUT_SCHEMA,
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
name: "onto.review_cancel",
|
|
376
|
+
description: "Request cancellation for a running review session. The runner writes a halted cancellation result at the next runtime cancellation checkpoint.",
|
|
377
|
+
inputSchema: REVIEW_CANCEL_INPUT_SCHEMA,
|
|
378
|
+
},
|
|
272
379
|
{
|
|
273
380
|
name: "onto.review_status",
|
|
274
|
-
description: "Read structured status and artifact refs for a review session.",
|
|
275
|
-
inputSchema:
|
|
381
|
+
description: "Read structured status and artifact refs for a review session, or recover the latest matching session.",
|
|
382
|
+
inputSchema: REVIEW_STATUS_INPUT_SCHEMA,
|
|
276
383
|
},
|
|
277
384
|
{
|
|
278
385
|
name: "onto.review_result",
|
|
279
|
-
description: "Read the ReviewRecord and rendered final output for a completed review session.",
|
|
280
|
-
inputSchema:
|
|
386
|
+
description: "Read the ReviewRecord and rendered final output for a completed review session with compact/standard/full projections.",
|
|
387
|
+
inputSchema: REVIEW_RESULT_INPUT_SCHEMA,
|
|
281
388
|
},
|
|
282
389
|
{
|
|
283
390
|
name: "onto.list_lenses",
|
|
@@ -306,17 +413,17 @@ const TOOL_DEFINITIONS = [
|
|
|
306
413
|
},
|
|
307
414
|
{
|
|
308
415
|
name: "onto.reconstruct",
|
|
309
|
-
description: "Run the material-aware reconstruct
|
|
416
|
+
description: "Run the material-aware reconstruct path with live semantic authoring, runtime validation gates, final-output.md, and reconstruct-record.yaml refs.",
|
|
310
417
|
inputSchema: RECONSTRUCT_INPUT_SCHEMA,
|
|
311
418
|
},
|
|
312
419
|
{
|
|
313
420
|
name: "onto.reconstruct_status",
|
|
314
|
-
description: "Read structured status and artifact refs for a reconstruct session.",
|
|
421
|
+
description: "Read structured status, stage progress, liveness, count summary, and artifact refs for a reconstruct session.",
|
|
315
422
|
inputSchema: RECONSTRUCT_SESSION_INPUT_SCHEMA,
|
|
316
423
|
},
|
|
317
424
|
{
|
|
318
425
|
name: "onto.reconstruct_result",
|
|
319
|
-
description: "Read the reconstruct record, run manifest,
|
|
426
|
+
description: "Read the reconstruct record, run manifest, stage progress, final output, and artifact refs for a reconstruct session.",
|
|
320
427
|
inputSchema: RECONSTRUCT_SESSION_INPUT_SCHEMA,
|
|
321
428
|
},
|
|
322
429
|
];
|
|
@@ -371,6 +478,13 @@ function progressTokenFromToolCallParams(params) {
|
|
|
371
478
|
const token = meta.progressToken;
|
|
372
479
|
return typeof token === "string" || typeof token === "number" ? token : null;
|
|
373
480
|
}
|
|
481
|
+
function defaultReviewReturnRunningAfterMs() {
|
|
482
|
+
const raw = process.env.ONTO_MCP_REVIEW_RETURN_RUNNING_AFTER_MS;
|
|
483
|
+
if (raw === undefined || raw.trim().length === 0)
|
|
484
|
+
return 25_000;
|
|
485
|
+
const parsed = Number.parseInt(raw, 10);
|
|
486
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : 25_000;
|
|
487
|
+
}
|
|
374
488
|
function sendMcpProgressNotification(progressToken, event) {
|
|
375
489
|
writeMessage({
|
|
376
490
|
jsonrpc: "2.0",
|
|
@@ -409,6 +523,15 @@ function structuredFailureFromError(error) {
|
|
|
409
523
|
}
|
|
410
524
|
async function formatToolError(error) {
|
|
411
525
|
const message = error instanceof Error ? error.message : String(error);
|
|
526
|
+
if (error instanceof ReviewContinuationError) {
|
|
527
|
+
return {
|
|
528
|
+
isError: true,
|
|
529
|
+
content: [{ type: "text", text: message }],
|
|
530
|
+
structuredContent: {
|
|
531
|
+
continuationFailure: error.failureContent,
|
|
532
|
+
},
|
|
533
|
+
};
|
|
534
|
+
}
|
|
412
535
|
const structuredFailure = structuredFailureFromError(error);
|
|
413
536
|
const routeVisibility = structuredFailure
|
|
414
537
|
? await buildReviewRouteVisibilityFromFailure(structuredFailure.failure, structuredFailure.failureRecordPath)
|
|
@@ -429,18 +552,6 @@ async function formatToolError(error) {
|
|
|
429
552
|
: {}),
|
|
430
553
|
};
|
|
431
554
|
}
|
|
432
|
-
function isInsidePath(root, candidate) {
|
|
433
|
-
const relative = path.relative(path.resolve(root), path.resolve(candidate));
|
|
434
|
-
return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
|
|
435
|
-
}
|
|
436
|
-
async function realpathIfExists(targetPath) {
|
|
437
|
-
try {
|
|
438
|
-
return await fs.realpath(targetPath);
|
|
439
|
-
}
|
|
440
|
-
catch {
|
|
441
|
-
return null;
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
555
|
function throwSessionDisclosureBlocked(args) {
|
|
445
556
|
throw new ReviewStructuredFailureError({
|
|
446
557
|
failureRecord: createStructuredFailureRecord({
|
|
@@ -500,7 +611,7 @@ async function resolveAllowedSessionRoot(args) {
|
|
|
500
611
|
const resolvedSessionRoot = path.resolve(projectRoot, args.sessionRoot);
|
|
501
612
|
const realProjectRoot = await realpathIfExists(projectRoot);
|
|
502
613
|
const realAllowedRoot = await realpathIfExists(allowedRoot);
|
|
503
|
-
if (!
|
|
614
|
+
if (!isPathInsideRoot(allowedRoot, resolvedSessionRoot)) {
|
|
504
615
|
throwSessionDisclosureBlocked({
|
|
505
616
|
requestedSessionRoot: args.sessionRoot,
|
|
506
617
|
resolvedSessionRoot,
|
|
@@ -516,7 +627,7 @@ async function resolveAllowedSessionRoot(args) {
|
|
|
516
627
|
const realSessionRoot = await realpathIfExists(resolvedSessionRoot);
|
|
517
628
|
if (realSessionRoot &&
|
|
518
629
|
realAllowedRoot &&
|
|
519
|
-
!
|
|
630
|
+
!isPathInsideRoot(realAllowedRoot, realSessionRoot)) {
|
|
520
631
|
throwSessionDisclosureBlocked({
|
|
521
632
|
requestedSessionRoot: args.sessionRoot,
|
|
522
633
|
resolvedSessionRoot,
|
|
@@ -565,7 +676,7 @@ function resolveInsideProject(args) {
|
|
|
565
676
|
const resolved = path.isAbsolute(args.ref)
|
|
566
677
|
? path.resolve(args.ref)
|
|
567
678
|
: path.resolve(args.projectRoot, args.ref);
|
|
568
|
-
if (!
|
|
679
|
+
if (!isPathInsideRoot(args.projectRoot, resolved)) {
|
|
569
680
|
throw new Error(`${args.label} must stay inside projectRoot.`);
|
|
570
681
|
}
|
|
571
682
|
return resolved;
|
|
@@ -577,7 +688,7 @@ function resolveReconstructSessionRoot(args) {
|
|
|
577
688
|
const resolved = path.isAbsolute(args.sessionRoot)
|
|
578
689
|
? path.resolve(args.sessionRoot)
|
|
579
690
|
: path.resolve(args.projectRoot, args.sessionRoot);
|
|
580
|
-
if (!
|
|
691
|
+
if (!isPathInsideRoot(allowedRoot, resolved)) {
|
|
581
692
|
throw new Error("sessionRoot must stay inside projectRoot/.onto/reconstruct.");
|
|
582
693
|
}
|
|
583
694
|
return resolved;
|
|
@@ -597,7 +708,7 @@ async function resolveAllowedReconstructSessionRoot(args) {
|
|
|
597
708
|
: path.resolve(projectRoot, args.sessionRoot);
|
|
598
709
|
const realProjectRoot = await realpathIfExists(projectRoot);
|
|
599
710
|
const realAllowedRoot = await realpathIfExists(allowedRoot);
|
|
600
|
-
if (!
|
|
711
|
+
if (!isPathInsideRoot(allowedRoot, resolvedSessionRoot)) {
|
|
601
712
|
throwReconstructSessionDisclosureBlocked({
|
|
602
713
|
requestedSessionRoot: args.sessionRoot,
|
|
603
714
|
resolvedSessionRoot,
|
|
@@ -613,7 +724,7 @@ async function resolveAllowedReconstructSessionRoot(args) {
|
|
|
613
724
|
const realSessionRoot = await realpathIfExists(resolvedSessionRoot);
|
|
614
725
|
if (realSessionRoot &&
|
|
615
726
|
realAllowedRoot &&
|
|
616
|
-
!
|
|
727
|
+
!isPathInsideRoot(realAllowedRoot, realSessionRoot)) {
|
|
617
728
|
throwReconstructSessionDisclosureBlocked({
|
|
618
729
|
requestedSessionRoot: args.sessionRoot,
|
|
619
730
|
resolvedSessionRoot,
|
|
@@ -651,7 +762,7 @@ async function resolveAllowedReconstructSessionRoot(args) {
|
|
|
651
762
|
if (typeof artifactRef !== "string" || artifactRef.length === 0)
|
|
652
763
|
continue;
|
|
653
764
|
const resolvedArtifactRef = path.resolve(artifactRef);
|
|
654
|
-
if (!
|
|
765
|
+
if (!isPathInsideRoot(resolvedSessionRoot, resolvedArtifactRef)) {
|
|
655
766
|
throwReconstructSessionDisclosureBlocked({
|
|
656
767
|
requestedSessionRoot: args.sessionRoot,
|
|
657
768
|
resolvedSessionRoot,
|
|
@@ -671,7 +782,7 @@ async function resolveAllowedReconstructSessionRoot(args) {
|
|
|
671
782
|
const realArtifactRef = await realpathIfExists(resolvedArtifactRef);
|
|
672
783
|
if (realArtifactRef &&
|
|
673
784
|
realSessionRoot &&
|
|
674
|
-
!
|
|
785
|
+
!isPathInsideRoot(realSessionRoot, realArtifactRef)) {
|
|
675
786
|
throwReconstructSessionDisclosureBlocked({
|
|
676
787
|
requestedSessionRoot: args.sessionRoot,
|
|
677
788
|
resolvedSessionRoot,
|
|
@@ -706,6 +817,7 @@ async function callTool(name, args, options = {}) {
|
|
|
706
817
|
const progressToken = options.progressToken;
|
|
707
818
|
const result = await reviewApi.runReview({
|
|
708
819
|
...request,
|
|
820
|
+
returnRunningAfterMs: parsed.returnRunningAfterMs ?? defaultReviewReturnRunningAfterMs(),
|
|
709
821
|
...(progressToken !== undefined && progressToken !== null
|
|
710
822
|
? {
|
|
711
823
|
progressObserver: (event) => sendMcpProgressNotification(progressToken, event),
|
|
@@ -719,15 +831,87 @@ async function callTool(name, args, options = {}) {
|
|
|
719
831
|
const result = await reviewApi.prepareReview(toReviewRequest(parsed));
|
|
720
832
|
return formatToolResult(result);
|
|
721
833
|
}
|
|
834
|
+
case "onto.review_continue": {
|
|
835
|
+
const parsed = OntoReviewContinueToolInputSchema.parse(args);
|
|
836
|
+
const projectRoot = resolveProjectRoot(parsed.projectRoot);
|
|
837
|
+
const sessionRoot = await resolveAllowedSessionRoot({
|
|
838
|
+
sessionRoot: parsed.sessionRoot,
|
|
839
|
+
projectRoot,
|
|
840
|
+
});
|
|
841
|
+
const result = await reviewApi.continueReview({
|
|
842
|
+
projectRoot,
|
|
843
|
+
sessionRoot,
|
|
844
|
+
...(parsed.targetUnits !== undefined
|
|
845
|
+
? { targetUnits: parsed.targetUnits }
|
|
846
|
+
: {}),
|
|
847
|
+
...(parsed.requestText !== undefined
|
|
848
|
+
? { requestText: parsed.requestText }
|
|
849
|
+
: {}),
|
|
850
|
+
...(parsed.executorRealization !== undefined
|
|
851
|
+
? { executorRealization: parsed.executorRealization }
|
|
852
|
+
: {}),
|
|
853
|
+
});
|
|
854
|
+
return formatToolResult(result);
|
|
855
|
+
}
|
|
856
|
+
case "onto.review_cancel": {
|
|
857
|
+
const parsed = OntoReviewCancelToolInputSchema.parse(args);
|
|
858
|
+
const projectRoot = resolveProjectRoot(parsed.projectRoot);
|
|
859
|
+
const sessionRoot = await resolveAllowedSessionRoot({
|
|
860
|
+
sessionRoot: parsed.sessionRoot,
|
|
861
|
+
projectRoot,
|
|
862
|
+
});
|
|
863
|
+
return formatToolResult(await reviewApi.cancelReview({
|
|
864
|
+
projectRoot,
|
|
865
|
+
sessionRoot,
|
|
866
|
+
...(parsed.reason !== undefined ? { reason: parsed.reason } : {}),
|
|
867
|
+
}));
|
|
868
|
+
}
|
|
722
869
|
case "onto.review_status": {
|
|
723
|
-
const parsed =
|
|
724
|
-
const
|
|
725
|
-
|
|
870
|
+
const parsed = OntoReviewStatusInputSchema.parse(args);
|
|
871
|
+
const projectRoot = resolveProjectRoot(parsed.projectRoot);
|
|
872
|
+
if (parsed.sessionRoot) {
|
|
873
|
+
const sessionRoot = await resolveAllowedSessionRoot({
|
|
874
|
+
sessionRoot: parsed.sessionRoot,
|
|
875
|
+
projectRoot,
|
|
876
|
+
});
|
|
877
|
+
return formatToolResult(await reviewApi.getReviewStatus(sessionRoot));
|
|
878
|
+
}
|
|
879
|
+
const latestSessionMatches = await reviewApi.findLatestReviewSessions({
|
|
880
|
+
projectRoot,
|
|
881
|
+
...(parsed.target !== undefined ? { target: parsed.target } : {}),
|
|
882
|
+
...(parsed.domain !== undefined ? { domain: parsed.domain } : {}),
|
|
883
|
+
...(parsed.requestHash !== undefined
|
|
884
|
+
? { requestHash: parsed.requestHash }
|
|
885
|
+
: {}),
|
|
886
|
+
...(parsed.limit !== undefined ? { limit: parsed.limit } : {}),
|
|
887
|
+
});
|
|
888
|
+
const latest = latestSessionMatches[0];
|
|
889
|
+
if (!latest) {
|
|
890
|
+
return formatToolResult({
|
|
891
|
+
sessionId: null,
|
|
892
|
+
sessionRoot: null,
|
|
893
|
+
status: "unknown",
|
|
894
|
+
artifactRefs: {},
|
|
895
|
+
failureRefs: [],
|
|
896
|
+
structuredFailures: [],
|
|
897
|
+
latestSessionMatches,
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
const sessionRoot = await resolveAllowedSessionRoot({
|
|
901
|
+
sessionRoot: latest.sessionRoot,
|
|
902
|
+
projectRoot,
|
|
903
|
+
});
|
|
904
|
+
return formatToolResult({
|
|
905
|
+
...(await reviewApi.getReviewStatus(sessionRoot)),
|
|
906
|
+
latestSessionMatches,
|
|
907
|
+
});
|
|
726
908
|
}
|
|
727
909
|
case "onto.review_result": {
|
|
728
|
-
const parsed =
|
|
910
|
+
const parsed = OntoReviewResultInputSchema.parse(args);
|
|
729
911
|
const sessionRoot = await resolveAllowedSessionRoot(parsed);
|
|
730
|
-
return formatToolResult(await reviewApi.getReviewResult(sessionRoot
|
|
912
|
+
return formatToolResult(await reviewApi.getReviewResult(sessionRoot, {
|
|
913
|
+
projectionLevel: parsed.projectionLevel ?? "standard",
|
|
914
|
+
}));
|
|
731
915
|
}
|
|
732
916
|
case "onto.list_lenses":
|
|
733
917
|
return formatToolResult(await reviewApi.listLenses());
|
|
@@ -931,9 +1115,62 @@ async function handleRequest(message) {
|
|
|
931
1115
|
return jsonRpcError(message.id, -32601, `Method not found: ${message.method ?? "(missing)"}`);
|
|
932
1116
|
}
|
|
933
1117
|
}
|
|
934
|
-
|
|
1118
|
+
let stdioResponseFraming = "jsonl";
|
|
1119
|
+
function writeMessage(message, framing = stdioResponseFraming) {
|
|
935
1120
|
const body = JSON.stringify(message);
|
|
936
|
-
|
|
1121
|
+
if (framing === "content-length") {
|
|
1122
|
+
process.stdout.write(`Content-Length: ${Buffer.byteLength(body, "utf8")}\r\n\r\n${body}`);
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
1125
|
+
process.stdout.write(`${body}\n`);
|
|
1126
|
+
}
|
|
1127
|
+
function lineEndIndex(buffer) {
|
|
1128
|
+
const lf = buffer.indexOf("\n");
|
|
1129
|
+
if (lf < 0)
|
|
1130
|
+
return null;
|
|
1131
|
+
const crlf = lf > 0 && buffer[lf - 1] === 13;
|
|
1132
|
+
return { index: crlf ? lf - 1 : lf, length: crlf ? 2 : 1 };
|
|
1133
|
+
}
|
|
1134
|
+
function shouldReadContentLengthFrame(buffer) {
|
|
1135
|
+
const firstLineEnd = lineEndIndex(buffer);
|
|
1136
|
+
const firstLine = buffer
|
|
1137
|
+
.subarray(0, firstLineEnd?.index ?? buffer.length)
|
|
1138
|
+
.toString("utf8");
|
|
1139
|
+
return /^Content-Length:/i.test(firstLine);
|
|
1140
|
+
}
|
|
1141
|
+
function readNextStdioMessage(buffer) {
|
|
1142
|
+
if (buffer.length === 0)
|
|
1143
|
+
return null;
|
|
1144
|
+
if (!shouldReadContentLengthFrame(buffer)) {
|
|
1145
|
+
const lineEnd = lineEndIndex(buffer);
|
|
1146
|
+
if (!lineEnd)
|
|
1147
|
+
return null;
|
|
1148
|
+
const body = buffer.subarray(0, lineEnd.index).toString("utf8");
|
|
1149
|
+
return {
|
|
1150
|
+
body,
|
|
1151
|
+
framing: "jsonl",
|
|
1152
|
+
rest: buffer.subarray(lineEnd.index + lineEnd.length),
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
const headerEnd = headerEndIndex(buffer);
|
|
1156
|
+
if (!headerEnd)
|
|
1157
|
+
return null;
|
|
1158
|
+
const header = buffer.subarray(0, headerEnd.index).toString("utf8");
|
|
1159
|
+
const contentLength = parseContentLength(header);
|
|
1160
|
+
const totalLength = headerEnd.index + headerEnd.length + contentLength;
|
|
1161
|
+
if (buffer.length < totalLength)
|
|
1162
|
+
return null;
|
|
1163
|
+
const body = buffer
|
|
1164
|
+
.subarray(headerEnd.index + headerEnd.length, totalLength)
|
|
1165
|
+
.toString("utf8");
|
|
1166
|
+
return {
|
|
1167
|
+
body,
|
|
1168
|
+
framing: "content-length",
|
|
1169
|
+
rest: buffer.subarray(totalLength),
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
function writeParseError(error, framing) {
|
|
1173
|
+
writeMessage(jsonRpcError(null, -32700, error instanceof Error ? error.message : String(error)), framing);
|
|
937
1174
|
}
|
|
938
1175
|
function headerEndIndex(buffer) {
|
|
939
1176
|
const crlf = buffer.indexOf("\r\n\r\n");
|
|
@@ -957,38 +1194,31 @@ export async function startMcpServer() {
|
|
|
957
1194
|
process.stdin.on("data", (chunk) => {
|
|
958
1195
|
buffer = Buffer.concat([buffer, chunk]);
|
|
959
1196
|
while (true) {
|
|
960
|
-
|
|
961
|
-
if (!headerEnd)
|
|
962
|
-
return;
|
|
963
|
-
const header = buffer.subarray(0, headerEnd.index).toString("utf8");
|
|
964
|
-
let contentLength;
|
|
1197
|
+
let frame;
|
|
965
1198
|
try {
|
|
966
|
-
|
|
1199
|
+
frame = readNextStdioMessage(buffer);
|
|
967
1200
|
}
|
|
968
1201
|
catch (error) {
|
|
969
|
-
|
|
1202
|
+
writeParseError(error, stdioResponseFraming);
|
|
970
1203
|
buffer = Buffer.alloc(0);
|
|
971
1204
|
return;
|
|
972
1205
|
}
|
|
973
|
-
|
|
974
|
-
if (buffer.length < totalLength)
|
|
1206
|
+
if (!frame)
|
|
975
1207
|
return;
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
.toString("utf8");
|
|
979
|
-
buffer = buffer.subarray(totalLength);
|
|
1208
|
+
buffer = frame.rest;
|
|
1209
|
+
stdioResponseFraming = frame.framing;
|
|
980
1210
|
chain = chain.then(async () => {
|
|
981
1211
|
let request;
|
|
982
1212
|
try {
|
|
983
|
-
request = JSON.parse(body);
|
|
1213
|
+
request = JSON.parse(frame.body);
|
|
984
1214
|
}
|
|
985
1215
|
catch (error) {
|
|
986
|
-
writeMessage(jsonRpcError(null, -32700, error instanceof Error ? error.message : String(error)));
|
|
1216
|
+
writeMessage(jsonRpcError(null, -32700, error instanceof Error ? error.message : String(error)), frame.framing);
|
|
987
1217
|
return;
|
|
988
1218
|
}
|
|
989
1219
|
const response = await handleRequest(request);
|
|
990
1220
|
if (response)
|
|
991
|
-
writeMessage(response);
|
|
1221
|
+
writeMessage(response, frame.framing);
|
|
992
1222
|
}).catch((error) => {
|
|
993
1223
|
process.stderr.write(`[onto-mcp] request failed: ${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
|
|
994
1224
|
});
|
package/dist/mcp/tool-schemas.js
CHANGED
|
@@ -2,6 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
const ReviewModeSchema = z.enum(["core-axis", "full"]);
|
|
3
3
|
const ReviewTargetScopeKindSchema = z.enum(["file", "directory", "bundle"]);
|
|
4
4
|
const ExecutorRealizationSchema = z.enum(["codex", "mock", "ts_inline_http"]);
|
|
5
|
+
const ReviewResultProjectionLevelSchema = z.enum(["compact", "standard", "full"]);
|
|
5
6
|
const DeliberationModeSchema = z.enum([
|
|
6
7
|
"controlled_lens_deliberation",
|
|
7
8
|
]);
|
|
@@ -22,6 +23,7 @@ const OntoReviewToolInputBaseSchema = z.object({
|
|
|
22
23
|
executorRealization: ExecutorRealizationSchema.optional(),
|
|
23
24
|
confirmValueAlignment: z.boolean().optional(),
|
|
24
25
|
prepareOnly: z.boolean().optional(),
|
|
26
|
+
returnRunningAfterMs: z.number().int().min(0).optional(),
|
|
25
27
|
}).strict();
|
|
26
28
|
export const OntoReviewToolInputSchema = OntoReviewToolInputBaseSchema.refine((input) => !(input.domain && input.noDomain), {
|
|
27
29
|
message: "Use either domain or noDomain, not both.",
|
|
@@ -35,6 +37,28 @@ export const OntoReviewSessionInputSchema = z.object({
|
|
|
35
37
|
sessionRoot: z.string().min(1),
|
|
36
38
|
projectRoot: z.string().min(1).optional(),
|
|
37
39
|
});
|
|
40
|
+
export const OntoReviewStatusInputSchema = z.object({
|
|
41
|
+
sessionRoot: z.string().min(1).optional(),
|
|
42
|
+
projectRoot: z.string().min(1).optional(),
|
|
43
|
+
latest: z.boolean().optional(),
|
|
44
|
+
target: z.string().min(1).optional(),
|
|
45
|
+
domain: z.string().min(1).optional(),
|
|
46
|
+
requestHash: z.string().min(1).optional(),
|
|
47
|
+
limit: z.number().int().min(1).max(20).optional(),
|
|
48
|
+
}).strict().refine((input) => (typeof input.sessionRoot === "string" || input.latest === true), {
|
|
49
|
+
message: "Pass sessionRoot, or latest=true with optional target/domain/requestHash filters.",
|
|
50
|
+
});
|
|
51
|
+
export const OntoReviewResultInputSchema = OntoReviewSessionInputSchema.extend({
|
|
52
|
+
projectionLevel: ReviewResultProjectionLevelSchema.optional(),
|
|
53
|
+
}).strict();
|
|
54
|
+
export const OntoReviewCancelToolInputSchema = OntoReviewSessionInputSchema.extend({
|
|
55
|
+
reason: z.string().min(1).optional(),
|
|
56
|
+
}).strict();
|
|
57
|
+
export const OntoReviewContinueToolInputSchema = OntoReviewSessionInputSchema.extend({
|
|
58
|
+
targetUnits: z.array(z.string().min(1)).optional(),
|
|
59
|
+
requestText: z.string().min(1).optional(),
|
|
60
|
+
executorRealization: ExecutorRealizationSchema.optional(),
|
|
61
|
+
}).strict();
|
|
38
62
|
export const OntoListDomainsToolInputSchema = z.object({
|
|
39
63
|
projectRoot: z.string().min(1).optional(),
|
|
40
64
|
});
|
|
@@ -50,8 +74,8 @@ export const OntoObserveSourceToolInputSchema = z.object({
|
|
|
50
74
|
}).strict();
|
|
51
75
|
export const OntoReconstructToolInputSchema = OntoObserveSourceToolInputSchema.extend({
|
|
52
76
|
intent: z.string().min(1),
|
|
53
|
-
semanticAuthorRealization: z.
|
|
54
|
-
confirmationProviderRealization: z.
|
|
77
|
+
semanticAuthorRealization: z.enum(["mock", "direct_call"]).default("direct_call"),
|
|
78
|
+
confirmationProviderRealization: z.enum(["mock", "direct_call"]).default("direct_call"),
|
|
55
79
|
}).strict();
|
|
56
80
|
export const OntoReconstructSessionInputSchema = z.object({
|
|
57
81
|
sessionRoot: z.string().min(1),
|
|
@@ -80,6 +104,8 @@ export const OntoValidateReconstructDirectiveToolInputSchema = z.discriminatedUn
|
|
|
80
104
|
export const OntoToolNames = [
|
|
81
105
|
"onto.review",
|
|
82
106
|
"onto.prepare_review",
|
|
107
|
+
"onto.review_continue",
|
|
108
|
+
"onto.review_cancel",
|
|
83
109
|
"onto.review_status",
|
|
84
110
|
"onto.review_result",
|
|
85
111
|
"onto.list_lenses",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "onto-mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
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": {
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"prepare": "npm run build:ts-core",
|
|
33
33
|
"build:ts-core": "tsc -p tsconfig.json",
|
|
34
34
|
"check:ts-core": "tsc -p tsconfig.json --noEmit",
|
|
35
|
+
"test:review:invocation-runner": "tsx scripts/review-invocation-runner-conformance.ts",
|
|
35
36
|
"test:mcp:review": "tsx scripts/mcp-review-conformance.ts",
|
|
36
37
|
"test:review:hardening": "tsx scripts/review-runtime-hardening.ts",
|
|
37
38
|
"test:e2e": "bash src/core-runtime/cli/e2e-review-invoke.test.sh",
|
|
@@ -44,6 +45,7 @@
|
|
|
44
45
|
"review:codex-unit-executor": "tsx src/core-runtime/cli/codex-review-unit-executor.ts",
|
|
45
46
|
"review:inline-http-unit-executor": "tsx src/core-runtime/cli/inline-http-review-unit-executor.ts",
|
|
46
47
|
"review:invoke": "tsx src/core-runtime/cli/review-invoke.ts",
|
|
48
|
+
"review:watch": "bash scripts/onto-review-watch.sh",
|
|
47
49
|
"mcp:server": "tsx src/mcp/server.ts",
|
|
48
50
|
"review:render-final-output": "tsx src/core-runtime/cli/render-review-final-output.ts",
|
|
49
51
|
"review:finalize-session": "tsx src/core-runtime/cli/assemble-review-record.ts",
|
|
@@ -51,7 +53,7 @@
|
|
|
51
53
|
"review:assemble-record": "tsx src/core-runtime/cli/assemble-review-record.ts"
|
|
52
54
|
},
|
|
53
55
|
"dependencies": {
|
|
54
|
-
"@anthropic-ai/sdk": "^0.
|
|
56
|
+
"@anthropic-ai/sdk": "^0.99.0",
|
|
55
57
|
"openai": "^6.33.0",
|
|
56
58
|
"yaml": "^2.8.2",
|
|
57
59
|
"zod": "^4.3.6"
|