@wowok/agent-mcp 2.5.1 → 2.5.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/dist/knowledge/mcp-schema-audit.js +3 -2
- package/dist/project/business-puzzle.d.ts +1 -0
- package/dist/project/business-puzzle.js +11 -0
- package/dist/project/deployment-doc.d.ts +11 -0
- package/dist/project/deployment-doc.js +37 -0
- package/dist/project/index.d.ts +25 -0
- package/dist/project/index.js +42 -0
- package/dist/project/risk-aggregator.d.ts +7 -0
- package/dist/project/risk-aggregator.js +15 -0
- package/dist/schema/call/base.js +2 -2
- package/dist/schema/project/index.d.ts +203 -3
- package/dist/schema/project/index.js +45 -0
- package/dist/schemas/index.json +1 -1
- package/dist/schemas/onchain_operations_guard.schema.json +0 -577
- package/dist/schemas/project_operation.output.json +157 -0
- package/dist/schemas/project_operation.schema.json +2 -1
- package/dist/tools/handlers/project.js +47 -2
- package/dist/tools/index.js +346 -37
- package/dist/tools/wrap.js +61 -7
- package/package.json +1 -1
- package/dist/schemas/onchain_operations.output.json +0 -2819
package/dist/tools/index.js
CHANGED
|
@@ -286,6 +286,10 @@ export const TOOL_REGISTRY = [
|
|
|
286
286
|
" → Input: substeps (from deployment doc), network (testnet/mainnet).\n" +
|
|
287
287
|
" → Output: coherence check, D-10 substep linkage, can_proceed.\n" +
|
|
288
288
|
" → Execute each substep via onchain_operations, record outcomes.\n\n" +
|
|
289
|
+
" Status Query (action='get_project_status')\n" +
|
|
290
|
+
" → Input: project, version.\n" +
|
|
291
|
+
" → Output: current stage (1-5), stage_name, next_action, can_proceed.\n" +
|
|
292
|
+
" → Call anytime to check which stage the project is in and what to do next.\n\n" +
|
|
289
293
|
"Correct object creation order (topological): Permission → Allocation → Guard → Machine → Service.\n" +
|
|
290
294
|
"All objects created as draft (publish=false) first; publish Machine before Service (last).\n\n" +
|
|
291
295
|
"═══════════════════════════════════════════════════════════════\n" +
|
|
@@ -372,7 +376,123 @@ export const TOOL_REGISTRY = [
|
|
|
372
376
|
},
|
|
373
377
|
];
|
|
374
378
|
export const TOOL_REGISTRY_MAP = new Map(TOOL_REGISTRY.map(t => [t.name, t]));
|
|
379
|
+
const SUB_TOOL_NAMES = TOOL_REGISTRY.map(t => t.name);
|
|
380
|
+
const WowokToolRuntimeSchema = z.unknown().describe("WoWok unified tool input. Expected: { tool: \"<sub-tool>\", data: {<params>} }. " +
|
|
381
|
+
"Aliases accepted: tool_name→tool, args→data, name→tool, params→data. " +
|
|
382
|
+
"If parameters don't match the sub-tool's schema, the response includes the correct schema for self-correction.");
|
|
383
|
+
const WowokToolDisplaySchema = z.object({
|
|
384
|
+
tool: z.enum(SUB_TOOL_NAMES).optional().describe("The sub-tool to execute. Each sub-tool has its own parameter schema."),
|
|
385
|
+
data: z.record(z.unknown()).optional().describe("Sub-tool specific parameters. If validation fails, the response includes the correct schema for this sub-tool — read it, fix your params, and retry."),
|
|
386
|
+
tool_name: z.enum(SUB_TOOL_NAMES).optional().describe("DEPRECATED alias for 'tool'. Use 'tool' instead."),
|
|
387
|
+
args: z.record(z.unknown()).optional().describe("DEPRECATED alias for 'data'. Use 'data' instead."),
|
|
388
|
+
name: z.enum(SUB_TOOL_NAMES).optional().describe("DEPRECATED alias for 'tool'. Use 'tool' instead."),
|
|
389
|
+
params: z.record(z.unknown()).optional().describe("DEPRECATED alias for 'data'. Use 'data' instead."),
|
|
390
|
+
}).describe("WoWok unified tool input. Call with { tool: \"<sub-tool>\", data: {<params>} }. " +
|
|
391
|
+
"Aliases: tool_name/name→tool, args/params→data.");
|
|
392
|
+
const WOWOK_TOOL_DESCRIPTION = [
|
|
393
|
+
"WoWok MCP unified interface. Call with { tool: \"<sub-tool>\", data: {<params>} }.",
|
|
394
|
+
"",
|
|
395
|
+
" tool: name of the sub-tool (string)",
|
|
396
|
+
" data: sub-tool parameters (object)",
|
|
397
|
+
"",
|
|
398
|
+
" Aliases accepted (deprecated): tool_name/name for tool, args/params for data.",
|
|
399
|
+
" Inline params also accepted: { tool: \"<sub-tool>\", <param1>: ..., <param2>: ... }",
|
|
400
|
+
"",
|
|
401
|
+
" EXAMPLE: wowok({ tool: \"schema_query\", data: { action: \"get\", name: \"onchain_operations\" } })",
|
|
402
|
+
" EXAMPLE: wowok({ tool: \"wowok_buildin_info\", data: { info: \"mainnet bridge tokens\" } })",
|
|
403
|
+
" EXAMPLE (inline params): wowok({ tool: \"schema_query\", action: \"get\", name: \"onchain_operations\" })",
|
|
404
|
+
"",
|
|
405
|
+
"Available sub-tools:",
|
|
406
|
+
" onchain_operations — On-chain ops: service, machine, progress, repository, arbitration, etc.",
|
|
407
|
+
" account_operation — LOCAL wallet management (generate, suspend, faucet, sign).",
|
|
408
|
+
" local_mark_operation — LOCAL address book (name/tag for addresses and object IDs).",
|
|
409
|
+
" local_info_operation — LOCAL private data (delivery addresses, phone numbers).",
|
|
410
|
+
" wip_file — Work-in-progress file management.",
|
|
411
|
+
" messenger_operation — End-to-end encrypted messaging.",
|
|
412
|
+
" guard2file — Export guard rules to file.",
|
|
413
|
+
" machineNode2file — Export machine nodes to file.",
|
|
414
|
+
" query_toolkit — Query on-chain objects by ID/type/owner.",
|
|
415
|
+
" onchain_table_data — Query on-chain dynamic field tables with pagination.",
|
|
416
|
+
" onchain_events — Watch on-chain events (arbitration, order, progress, demand).",
|
|
417
|
+
" wowok_buildin_info — Protocol constants, built-in permissions, bridge tokens.",
|
|
418
|
+
" schema_query — Query JSON schemas for any sub-tool (action: list/get/get_output/search).",
|
|
419
|
+
" bridge_operation — Cross-chain bridge between WOW and EVM (mainnet only).",
|
|
420
|
+
" project_operation — 5-stage project deployment workflow (C1-C4 + graph queries).",
|
|
421
|
+
" config_operation — Runtime service toggles (confirm_gate, harness, etc.).",
|
|
422
|
+
" trust_score — Service trust/risk assessment (0-100 score, 5 dimensions).",
|
|
423
|
+
"",
|
|
424
|
+
"SCHEMA-GATED EXECUTION:",
|
|
425
|
+
" If your parameters don't match the sub-tool's schema, the response will include:",
|
|
426
|
+
" result.status = \"schema_mismatch\"",
|
|
427
|
+
" result.errors = specific validation errors (field path + expected type)",
|
|
428
|
+
" result.hint = instructions to fix and retry",
|
|
429
|
+
" schema.input = the correct JSON schema for the sub-tool",
|
|
430
|
+
" schema.tool = which sub-tool this schema belongs to",
|
|
431
|
+
" Read the schema, fix your params, and retry. This is normal — no need to call schema_query separately.",
|
|
432
|
+
"",
|
|
433
|
+
"SCHEMA CACHING:",
|
|
434
|
+
" Each sub-tool has a DIFFERENT schema. When you receive a schema in a mismatch response:",
|
|
435
|
+
" 1. Read the schema carefully",
|
|
436
|
+
" 2. Fix your parameters",
|
|
437
|
+
" 3. Retry the call",
|
|
438
|
+
" 4. CACHE the schema in your context for future calls to the SAME sub-tool",
|
|
439
|
+
" You should only need to see each sub-tool's schema once per conversation.",
|
|
440
|
+
"",
|
|
441
|
+
"PROJECT-BASED DEPLOYMENT (5 stages):",
|
|
442
|
+
" Stage 1: Project naming (provide project + version params)",
|
|
443
|
+
" Stage 2: project_operation action='analyze_intent' → ODG + puzzles",
|
|
444
|
+
" Stage 3: project_operation action='aggregate_risks' → risk findings",
|
|
445
|
+
" Stage 4: project_operation action='generate_deployment_doc' → deployment doc",
|
|
446
|
+
" Stage 5: project_operation action='trace_substeps' → substep verification",
|
|
447
|
+
" Status: project_operation action='get_project_status' → current stage + next action",
|
|
448
|
+
"",
|
|
449
|
+
"Correct object creation order: Permission → Allocation → Guard → Machine → Service.",
|
|
450
|
+
"All objects created as draft (publish=false) first; publish Machine before Service (last).",
|
|
451
|
+
].join("\n");
|
|
452
|
+
function formatZodErrors(error) {
|
|
453
|
+
return error.issues.map(issue => {
|
|
454
|
+
const path = issue.path.length > 0 ? issue.path.join(".") : "(root)";
|
|
455
|
+
return `${path}: ${issue.message}`;
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
function checkUnknownFields(schema, input) {
|
|
459
|
+
let innerSchema = schema;
|
|
460
|
+
while (true) {
|
|
461
|
+
const def = innerSchema._def;
|
|
462
|
+
if (!def || def.typeName !== "ZodEffects")
|
|
463
|
+
break;
|
|
464
|
+
innerSchema = def.schema ?? innerSchema;
|
|
465
|
+
}
|
|
466
|
+
const def = innerSchema._def;
|
|
467
|
+
const shape = def?.shape?.();
|
|
468
|
+
if (!shape || typeof input !== "object" || input === null)
|
|
469
|
+
return [];
|
|
470
|
+
const allowedFields = Object.keys(shape);
|
|
471
|
+
const inputFields = Object.keys(input);
|
|
472
|
+
return inputFields.filter(f => !allowedFields.includes(f));
|
|
473
|
+
}
|
|
474
|
+
function extractRelevantSchema(fullSchema, toolName, data) {
|
|
475
|
+
if (toolName === "onchain_operations" && typeof data === "object" && data !== null) {
|
|
476
|
+
const opType = data.operation_type;
|
|
477
|
+
if (typeof opType === "string") {
|
|
478
|
+
const subSchemaName = `onchain_operations_${opType}`;
|
|
479
|
+
const subSchema = loadPreGeneratedSchema(subSchemaName);
|
|
480
|
+
if (subSchema)
|
|
481
|
+
return subSchema;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
return fullSchema;
|
|
485
|
+
}
|
|
486
|
+
function isSchemaValidationError(message) {
|
|
487
|
+
return (message.startsWith("Unknown ") && message.includes("field") ||
|
|
488
|
+
message.includes("expected") && message.includes("received") ||
|
|
489
|
+
message.includes("Invalid input") ||
|
|
490
|
+
message.includes("Required"));
|
|
491
|
+
}
|
|
375
492
|
export async function dispatchToolCall(name, args, options) {
|
|
493
|
+
if (name === "wowok") {
|
|
494
|
+
return handleWowok(args);
|
|
495
|
+
}
|
|
376
496
|
const entry = TOOL_REGISTRY_MAP.get(name);
|
|
377
497
|
if (!entry) {
|
|
378
498
|
throw new Error(`Unknown tool: ${name}. Available: ${TOOL_REGISTRY.map(t => t.name).join(", ")}`);
|
|
@@ -387,6 +507,206 @@ export async function dispatchToolCall(name, args, options) {
|
|
|
387
507
|
const wrapped = wrapHandlerWithErrorShape(harnessWrapped, timeoutMs, name, entry.errorShapeBuilder);
|
|
388
508
|
return wrapped(args);
|
|
389
509
|
}
|
|
510
|
+
const TOOL_FIELD_ALIASES = ["tool", "tool_name", "name"];
|
|
511
|
+
const DATA_FIELD_ALIASES = ["data", "args", "params", "parameters"];
|
|
512
|
+
const RESERVED_FIELD_NAMES = new Set([
|
|
513
|
+
...TOOL_FIELD_ALIASES,
|
|
514
|
+
...DATA_FIELD_ALIASES,
|
|
515
|
+
]);
|
|
516
|
+
function normalizeInput(args) {
|
|
517
|
+
const notes = [];
|
|
518
|
+
if (!args || typeof args !== "object" || Array.isArray(args)) {
|
|
519
|
+
return { tool: undefined, data: {}, normalizationNotes: ["input is not an object"] };
|
|
520
|
+
}
|
|
521
|
+
const obj = args;
|
|
522
|
+
let tool;
|
|
523
|
+
for (const alias of TOOL_FIELD_ALIASES) {
|
|
524
|
+
if (typeof obj[alias] === "string" && obj[alias]) {
|
|
525
|
+
tool = obj[alias];
|
|
526
|
+
if (alias !== "tool") {
|
|
527
|
+
notes.push(`normalized '${alias}' → 'tool'`);
|
|
528
|
+
}
|
|
529
|
+
break;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
let data;
|
|
533
|
+
for (const alias of DATA_FIELD_ALIASES) {
|
|
534
|
+
const v = obj[alias];
|
|
535
|
+
if (v !== undefined && v !== null && typeof v === "object" && !Array.isArray(v)) {
|
|
536
|
+
data = v;
|
|
537
|
+
if (alias !== "data") {
|
|
538
|
+
notes.push(`normalized '${alias}' → 'data'`);
|
|
539
|
+
}
|
|
540
|
+
break;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
if (!data) {
|
|
544
|
+
const inlineParams = {};
|
|
545
|
+
let hasInline = false;
|
|
546
|
+
for (const key of Object.keys(obj)) {
|
|
547
|
+
if (!RESERVED_FIELD_NAMES.has(key)) {
|
|
548
|
+
inlineParams[key] = obj[key];
|
|
549
|
+
hasInline = true;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
if (hasInline) {
|
|
553
|
+
data = inlineParams;
|
|
554
|
+
notes.push("extracted inline params → 'data' (no data wrapper was provided)");
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
data = {};
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
return { tool, data, normalizationNotes: notes };
|
|
561
|
+
}
|
|
562
|
+
async function handleWowok(args) {
|
|
563
|
+
const { tool: normalizedToolName, data: normalizedData, normalizationNotes } = normalizeInput(args);
|
|
564
|
+
if (!normalizedToolName) {
|
|
565
|
+
const receivedKeys = (args && typeof args === "object" && !Array.isArray(args))
|
|
566
|
+
? Object.keys(args).join(", ") || "(none)"
|
|
567
|
+
: `(non-object input: ${typeof args})`;
|
|
568
|
+
const errors = [
|
|
569
|
+
`Missing 'tool' field. Received keys: ${receivedKeys}`,
|
|
570
|
+
`Expected one of: ${SUB_TOOL_NAMES.join(", ")}`,
|
|
571
|
+
];
|
|
572
|
+
return {
|
|
573
|
+
content: [{
|
|
574
|
+
type: "text",
|
|
575
|
+
text: `Missing 'tool' field. Call format: wowok({ tool: "<sub-tool>", data: {<params>} }). Received keys: ${receivedKeys}. Available sub-tools: ${SUB_TOOL_NAMES.join(", ")}`,
|
|
576
|
+
}],
|
|
577
|
+
structuredContent: {
|
|
578
|
+
result: {
|
|
579
|
+
status: "schema_mismatch",
|
|
580
|
+
errors,
|
|
581
|
+
hint: `Provide 'tool' (one of: ${SUB_TOOL_NAMES.join(", ")}) and 'data' (sub-tool parameters). Aliases accepted: tool_name/name→tool, args/params→data.`,
|
|
582
|
+
received: args,
|
|
583
|
+
},
|
|
584
|
+
schema: {
|
|
585
|
+
input: zodToJsonSchemaSafe(WowokToolDisplaySchema, "wowok"),
|
|
586
|
+
tool: "wowok",
|
|
587
|
+
},
|
|
588
|
+
},
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
const entry = TOOL_REGISTRY_MAP.get(normalizedToolName);
|
|
592
|
+
if (!entry) {
|
|
593
|
+
const suggestions = TOOL_REGISTRY
|
|
594
|
+
.map(t => t.name)
|
|
595
|
+
.filter(name => name.includes(normalizedToolName) || normalizedToolName.includes(name))
|
|
596
|
+
.slice(0, 5);
|
|
597
|
+
return {
|
|
598
|
+
content: [{
|
|
599
|
+
type: "text",
|
|
600
|
+
text: `Unknown sub-tool: '${normalizedToolName}'. Available: ${TOOL_REGISTRY.map(t => t.name).join(", ")}${suggestions.length > 0 ? `. Did you mean: ${suggestions.join(", ")}?` : ""}`,
|
|
601
|
+
}],
|
|
602
|
+
structuredContent: {
|
|
603
|
+
result: {
|
|
604
|
+
status: "error",
|
|
605
|
+
errors: [`Unknown sub-tool: ${normalizedToolName}`],
|
|
606
|
+
hint: `Available sub-tools: ${TOOL_REGISTRY.map(t => t.name).join(", ")}${suggestions.length > 0 ? `. Did you mean: ${suggestions.join(", ")}?` : ""}`,
|
|
607
|
+
suggestions,
|
|
608
|
+
},
|
|
609
|
+
schema: null,
|
|
610
|
+
},
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
if (normalizationNotes.length > 0) {
|
|
614
|
+
console.warn(`[wowok] input normalization for '${normalizedToolName}': ${normalizationNotes.join("; ")}`);
|
|
615
|
+
}
|
|
616
|
+
const validationResult = entry.config.inputSchema.safeParse(normalizedData);
|
|
617
|
+
const unknownFields = checkUnknownFields(entry.config.inputSchema, normalizedData);
|
|
618
|
+
if (!validationResult.success || unknownFields.length > 0) {
|
|
619
|
+
const allErrors = [];
|
|
620
|
+
if (!validationResult.success) {
|
|
621
|
+
allErrors.push(...formatZodErrors(validationResult.error));
|
|
622
|
+
}
|
|
623
|
+
if (unknownFields.length > 0) {
|
|
624
|
+
allErrors.push(`Unknown field(s): ${unknownFields.join(", ")}`);
|
|
625
|
+
}
|
|
626
|
+
const fullSchema = loadPreGeneratedSchema(normalizedToolName) ?? zodToJsonSchemaSafe(entry.config.inputSchema, normalizedToolName);
|
|
627
|
+
const relevantSchema = extractRelevantSchema(fullSchema, normalizedToolName, normalizedData);
|
|
628
|
+
return {
|
|
629
|
+
content: [{
|
|
630
|
+
type: "text",
|
|
631
|
+
text: `Schema mismatch for ${normalizedToolName}. ${allErrors.length} error(s). Read the schema below, fix your params, and retry.`,
|
|
632
|
+
}],
|
|
633
|
+
structuredContent: {
|
|
634
|
+
result: {
|
|
635
|
+
status: "schema_mismatch",
|
|
636
|
+
errors: allErrors,
|
|
637
|
+
hint: `Fix your parameters based on the schema below and retry. CACHE THIS SCHEMA for future ${normalizedToolName} calls — you don't need to query it again.`,
|
|
638
|
+
},
|
|
639
|
+
schema: {
|
|
640
|
+
input: relevantSchema,
|
|
641
|
+
tool: normalizedToolName,
|
|
642
|
+
},
|
|
643
|
+
},
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
try {
|
|
647
|
+
const subResult = await dispatchToolCall(normalizedToolName, normalizedData);
|
|
648
|
+
const sc = subResult.structuredContent;
|
|
649
|
+
const resultField = sc?.result;
|
|
650
|
+
const isErrorResponse = resultField?.status === "error" || resultField?.operation === "error";
|
|
651
|
+
if (isErrorResponse) {
|
|
652
|
+
return {
|
|
653
|
+
content: subResult.content,
|
|
654
|
+
structuredContent: {
|
|
655
|
+
result: {
|
|
656
|
+
status: "error",
|
|
657
|
+
data: subResult.structuredContent,
|
|
658
|
+
errors: [subResult.content[0]?.text ?? "Sub-tool returned an error"],
|
|
659
|
+
},
|
|
660
|
+
schema: null,
|
|
661
|
+
},
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
return {
|
|
665
|
+
content: subResult.content,
|
|
666
|
+
structuredContent: {
|
|
667
|
+
result: {
|
|
668
|
+
status: "success",
|
|
669
|
+
data: subResult.structuredContent,
|
|
670
|
+
},
|
|
671
|
+
schema: null,
|
|
672
|
+
},
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
catch (error) {
|
|
676
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
677
|
+
if (isSchemaValidationError(errorMessage)) {
|
|
678
|
+
const fullSchema = loadPreGeneratedSchema(normalizedToolName) ?? zodToJsonSchemaSafe(entry.config.inputSchema, normalizedToolName);
|
|
679
|
+
const relevantSchema = extractRelevantSchema(fullSchema, normalizedToolName, normalizedData);
|
|
680
|
+
return {
|
|
681
|
+
content: [{
|
|
682
|
+
type: "text",
|
|
683
|
+
text: `Schema mismatch for ${normalizedToolName}: ${errorMessage}`,
|
|
684
|
+
}],
|
|
685
|
+
structuredContent: {
|
|
686
|
+
result: {
|
|
687
|
+
status: "schema_mismatch",
|
|
688
|
+
errors: [errorMessage],
|
|
689
|
+
hint: `Fix your parameters based on the schema below and retry. CACHE THIS SCHEMA for future ${normalizedToolName} calls.`,
|
|
690
|
+
},
|
|
691
|
+
schema: {
|
|
692
|
+
input: relevantSchema,
|
|
693
|
+
tool: normalizedToolName,
|
|
694
|
+
},
|
|
695
|
+
},
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
return {
|
|
699
|
+
content: [{ type: "text", text: `Error: ${errorMessage}` }],
|
|
700
|
+
structuredContent: {
|
|
701
|
+
result: {
|
|
702
|
+
status: "error",
|
|
703
|
+
errors: [errorMessage],
|
|
704
|
+
},
|
|
705
|
+
schema: null,
|
|
706
|
+
},
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
}
|
|
390
710
|
function zodToJsonSchemaSafe(schema, name) {
|
|
391
711
|
try {
|
|
392
712
|
const jsonSchema = zodToJsonSchema(schema, {
|
|
@@ -498,49 +818,38 @@ function loadPreGeneratedOutputSchema(toolName) {
|
|
|
498
818
|
return null;
|
|
499
819
|
}
|
|
500
820
|
export function listTools() {
|
|
501
|
-
return
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
description: entry.config.description,
|
|
508
|
-
inputSchema,
|
|
509
|
-
};
|
|
510
|
-
});
|
|
821
|
+
return [{
|
|
822
|
+
name: "wowok",
|
|
823
|
+
title: "WoWok MCP",
|
|
824
|
+
description: WOWOK_TOOL_DESCRIPTION,
|
|
825
|
+
inputSchema: zodToJsonSchemaSafe(WowokToolDisplaySchema, "wowok"),
|
|
826
|
+
}];
|
|
511
827
|
}
|
|
512
828
|
export function registerAllTools(server) {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
}
|
|
829
|
+
const timeoutMs = 120000;
|
|
830
|
+
const wrapped = wrapHandlerWithErrorShape(handleWowok, timeoutMs, "wowok", undefined);
|
|
831
|
+
server.registerTool("wowok", {
|
|
832
|
+
title: "WoWok MCP",
|
|
833
|
+
description: WOWOK_TOOL_DESCRIPTION,
|
|
834
|
+
inputSchema: WowokToolRuntimeSchema,
|
|
835
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
|
|
836
|
+
}, withTelemetry("wowok", wrapped));
|
|
521
837
|
overrideToolsListHandler(server);
|
|
522
838
|
}
|
|
523
839
|
function overrideToolsListHandler(server) {
|
|
524
840
|
server.server.setRequestHandler(ListToolsRequestSchema, () => ({
|
|
525
|
-
tools:
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
}
|
|
537
|
-
if (entry.config.outputSchema) {
|
|
538
|
-
const outputSchema = loadPreGeneratedOutputSchema(entry.name) ??
|
|
539
|
-
zodToJsonSchemaSafe(entry.config.outputSchema, `${entry.name}_output`);
|
|
540
|
-
toolDef.outputSchema = outputSchema;
|
|
541
|
-
}
|
|
542
|
-
return toolDef;
|
|
543
|
-
}),
|
|
841
|
+
tools: [{
|
|
842
|
+
name: "wowok",
|
|
843
|
+
title: "WoWok MCP",
|
|
844
|
+
description: WOWOK_TOOL_DESCRIPTION,
|
|
845
|
+
inputSchema: ensureObjectType(zodToJsonSchemaSafe(WowokToolDisplaySchema, "wowok")),
|
|
846
|
+
annotations: {
|
|
847
|
+
readOnlyHint: false,
|
|
848
|
+
destructiveHint: true,
|
|
849
|
+
idempotentHint: false,
|
|
850
|
+
openWorldHint: true,
|
|
851
|
+
},
|
|
852
|
+
}],
|
|
544
853
|
}));
|
|
545
854
|
}
|
|
546
855
|
function ensureObjectType(schema) {
|
package/dist/tools/wrap.js
CHANGED
|
@@ -4,6 +4,7 @@ import { shouldRunLightHooks, shouldRunHeavyHooks, recordOperationFailure, } fro
|
|
|
4
4
|
import { getHarness } from "../harness/index.js";
|
|
5
5
|
import { recordOperationOutcome } from "../experience/index.js";
|
|
6
6
|
import { recordIndustrySignal } from "../knowledge/flywheel-loop.js";
|
|
7
|
+
import { getStageCache } from "../project/index.js";
|
|
7
8
|
export function withTimeout(promise, timeoutMs = 30000, operationName = "operation") {
|
|
8
9
|
let timer;
|
|
9
10
|
return Promise.race([
|
|
@@ -57,6 +58,34 @@ export const operationErrorShape = (error, classified, ctx) => ({
|
|
|
57
58
|
export const strictStatusErrorShape = (error, _classified, _ctx) => ({
|
|
58
59
|
result: { status: "error", error },
|
|
59
60
|
});
|
|
61
|
+
function checkProjectStage(action, project, version) {
|
|
62
|
+
const entry = getStageCache(project, version);
|
|
63
|
+
if (!entry) {
|
|
64
|
+
if (action === "analyze_intent" || action === "get_project_status") {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return `project_stage: calling '${action}' before 'analyze_intent' — recommend calling analyze_intent first for project '${project}:${version}'`;
|
|
68
|
+
}
|
|
69
|
+
const stageOrder = {
|
|
70
|
+
analyze_intent: 2,
|
|
71
|
+
aggregate_risks: 3,
|
|
72
|
+
generate_deployment_doc: 4,
|
|
73
|
+
trace_substeps: 5,
|
|
74
|
+
};
|
|
75
|
+
const requiredStage = stageOrder[action];
|
|
76
|
+
if (!requiredStage)
|
|
77
|
+
return null;
|
|
78
|
+
if (entry.stage < requiredStage - 1) {
|
|
79
|
+
return `project_stage: calling '${action}' (stage ${requiredStage}) but project is at stage ${entry.stage} — recommend completing prior stages first for '${project}:${version}'`;
|
|
80
|
+
}
|
|
81
|
+
if (action === "generate_deployment_doc" && entry.risk_can_proceed === false) {
|
|
82
|
+
return `project_stage: calling 'generate_deployment_doc' but CRITICAL risks are unresolved — recommend fixing risks first for '${project}:${version}'`;
|
|
83
|
+
}
|
|
84
|
+
if (action === "trace_substeps" && entry.doc_error_count && entry.doc_error_count > 0) {
|
|
85
|
+
return `project_stage: calling 'trace_substeps' but deployment doc has ${entry.doc_error_count} D-error(s) — recommend fixing doc errors first for '${project}:${version}'`;
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
60
89
|
export function dispatchWithHarness(handler, toolName) {
|
|
61
90
|
return async (args) => {
|
|
62
91
|
const harnessWarnings = [];
|
|
@@ -78,6 +107,22 @@ export function dispatchWithHarness(handler, toolName) {
|
|
|
78
107
|
harnessWarnings.push(`pre_call hook failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
79
108
|
}
|
|
80
109
|
}
|
|
110
|
+
if (toolName === "project_operation" && runLight) {
|
|
111
|
+
try {
|
|
112
|
+
const projArgs = args;
|
|
113
|
+
const action = projArgs?.action;
|
|
114
|
+
const project = projArgs?.project;
|
|
115
|
+
const version = projArgs?.version;
|
|
116
|
+
if (action && project && version) {
|
|
117
|
+
const stageCheck = checkProjectStage(action, project, version);
|
|
118
|
+
if (stageCheck) {
|
|
119
|
+
harnessWarnings.push(stageCheck);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
}
|
|
125
|
+
}
|
|
81
126
|
if (isPublishOp) {
|
|
82
127
|
try {
|
|
83
128
|
harnessWarnings.push("pre_publish: full-tier check engaged");
|
|
@@ -141,15 +186,24 @@ export function dispatchWithHarness(handler, toolName) {
|
|
|
141
186
|
harnessWarnings.push(`signal collection failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
142
187
|
}
|
|
143
188
|
}
|
|
144
|
-
if (harnessWarnings.length > 0
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
189
|
+
if (harnessWarnings.length > 0) {
|
|
190
|
+
if (result?.structuredContent) {
|
|
191
|
+
const sc = result.structuredContent;
|
|
192
|
+
const semantic = sc.semantic;
|
|
193
|
+
if (semantic) {
|
|
194
|
+
const existing = Array.isArray(semantic.warnings) ? semantic.warnings : [];
|
|
195
|
+
semantic.warnings = [...existing, ...harnessWarnings];
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
for (const w of harnessWarnings) {
|
|
199
|
+
console.warn(`[harness] ${w}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
150
202
|
}
|
|
151
203
|
else {
|
|
152
|
-
|
|
204
|
+
for (const w of harnessWarnings) {
|
|
205
|
+
console.warn(`[harness] ${w}`);
|
|
206
|
+
}
|
|
153
207
|
}
|
|
154
208
|
}
|
|
155
209
|
return result;
|