@wowok/agent-mcp 2.5.1 → 2.5.3

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.
Files changed (107) hide show
  1. package/dist/index.js +46 -6
  2. package/dist/knowledge/guard-design-patterns.js +104 -1
  3. package/dist/knowledge/guard-ledger.js +3 -3
  4. package/dist/knowledge/guard-lint.js +3 -3
  5. package/dist/knowledge/guard-risk.js +23 -15
  6. package/dist/knowledge/guard-templates.js +174 -2
  7. package/dist/knowledge/guard-translation.js +3 -3
  8. package/dist/knowledge/index.d.ts +3 -0
  9. package/dist/knowledge/index.js +9 -0
  10. package/dist/knowledge/machine-context.d.ts +1 -1
  11. package/dist/knowledge/machine-context.js +21 -0
  12. package/dist/knowledge/machine-ledger.d.ts +1 -0
  13. package/dist/knowledge/machine-ledger.js +31 -11
  14. package/dist/knowledge/machine-templates.js +32 -78
  15. package/dist/knowledge/mcp-schema-audit.js +3 -2
  16. package/dist/knowledge/overrides-loader.d.ts +13 -0
  17. package/dist/knowledge/overrides-loader.js +67 -0
  18. package/dist/knowledge/payment-risk.d.ts +4 -0
  19. package/dist/knowledge/payment-risk.js +67 -0
  20. package/dist/knowledge/repository-confirm.d.ts +4 -0
  21. package/dist/knowledge/repository-confirm.js +44 -0
  22. package/dist/knowledge/repository-risk.d.ts +8 -2
  23. package/dist/knowledge/repository-risk.js +61 -0
  24. package/dist/knowledge/repository-translation.js +23 -0
  25. package/dist/knowledge/scenario-modes.js +22 -5
  26. package/dist/knowledge/service-templates.js +38 -0
  27. package/dist/knowledge/treasury-templates.js +42 -0
  28. package/dist/loop-engineering/context-collect.d.ts +7 -0
  29. package/dist/loop-engineering/context-collect.js +83 -0
  30. package/dist/loop-engineering/improve.d.ts +29 -0
  31. package/dist/loop-engineering/improve.js +178 -0
  32. package/dist/project/business-puzzle.d.ts +1 -0
  33. package/dist/project/business-puzzle.js +11 -0
  34. package/dist/project/context-assembly.d.ts +16 -0
  35. package/dist/project/context-assembly.js +130 -0
  36. package/dist/project/deployment-doc.d.ts +126 -0
  37. package/dist/project/deployment-doc.js +632 -0
  38. package/dist/project/index.d.ts +25 -0
  39. package/dist/project/index.js +78 -0
  40. package/dist/project/migration.d.ts +22 -0
  41. package/dist/project/migration.js +125 -0
  42. package/dist/project/project-store.d.ts +110 -0
  43. package/dist/project/project-store.js +425 -0
  44. package/dist/project/risk-aggregator.d.ts +7 -0
  45. package/dist/project/risk-aggregator.js +15 -0
  46. package/dist/project/rollback-policy.d.ts +45 -0
  47. package/dist/project/rollback-policy.js +290 -0
  48. package/dist/project/stage-gate.d.ts +49 -0
  49. package/dist/project/stage-gate.js +310 -0
  50. package/dist/schema/call/allocation.d.ts +5 -0
  51. package/dist/schema/call/arbitration.d.ts +5 -0
  52. package/dist/schema/call/base.d.ts +3 -0
  53. package/dist/schema/call/base.js +3 -2
  54. package/dist/schema/call/bridge.d.ts +24 -0
  55. package/dist/schema/call/contact.d.ts +5 -0
  56. package/dist/schema/call/demand.d.ts +5 -0
  57. package/dist/schema/call/guard.d.ts +15 -0
  58. package/dist/schema/call/machine.d.ts +10 -0
  59. package/dist/schema/call/order.d.ts +5 -0
  60. package/dist/schema/call/payment.d.ts +5 -0
  61. package/dist/schema/call/permission.d.ts +5 -0
  62. package/dist/schema/call/personal.d.ts +5 -0
  63. package/dist/schema/call/progress.d.ts +5 -0
  64. package/dist/schema/call/proof.d.ts +10 -0
  65. package/dist/schema/call/repository.d.ts +5 -0
  66. package/dist/schema/call/reward.d.ts +5 -0
  67. package/dist/schema/call/service.d.ts +5 -0
  68. package/dist/schema/call/treasury.d.ts +5 -0
  69. package/dist/schema/operations.d.ts +210 -0
  70. package/dist/schema/operations.js +24 -0
  71. package/dist/schema/project/index.d.ts +2798 -85
  72. package/dist/schema/project/index.js +667 -2
  73. package/dist/schema/query/index.d.ts +601 -0
  74. package/dist/schema/query/index.js +61 -0
  75. package/dist/schemas/bridge_operation.schema.json +4 -0
  76. package/dist/schemas/guard2file.schema.json +4 -0
  77. package/dist/schemas/index.json +1 -1
  78. package/dist/schemas/machineNode2file.schema.json +4 -0
  79. package/dist/schemas/onchain_operations.schema.json +20 -0
  80. package/dist/schemas/onchain_operations_allocation.schema.json +4 -0
  81. package/dist/schemas/onchain_operations_arbitration.schema.json +4 -0
  82. package/dist/schemas/onchain_operations_contact.schema.json +4 -0
  83. package/dist/schemas/onchain_operations_demand.schema.json +4 -0
  84. package/dist/schemas/onchain_operations_gen_passport.schema.json +8 -0
  85. package/dist/schemas/onchain_operations_gen_proof.schema.json +8 -0
  86. package/dist/schemas/onchain_operations_guard.schema.json +4 -577
  87. package/dist/schemas/onchain_operations_machine.schema.json +4 -0
  88. package/dist/schemas/onchain_operations_order.schema.json +4 -0
  89. package/dist/schemas/onchain_operations_payment.schema.json +4 -0
  90. package/dist/schemas/onchain_operations_permission.schema.json +4 -0
  91. package/dist/schemas/onchain_operations_personal.schema.json +4 -0
  92. package/dist/schemas/onchain_operations_progress.schema.json +4 -0
  93. package/dist/schemas/onchain_operations_proof.schema.json +4 -0
  94. package/dist/schemas/onchain_operations_repository.schema.json +4 -0
  95. package/dist/schemas/onchain_operations_reward.schema.json +4 -0
  96. package/dist/schemas/onchain_operations_service.schema.json +4 -0
  97. package/dist/schemas/onchain_operations_treasury.schema.json +4 -0
  98. package/dist/schemas/project_operation.output.json +1955 -0
  99. package/dist/schemas/project_operation.schema.json +133 -2
  100. package/dist/schemas/query_toolkit.output.json +407 -1
  101. package/dist/schemas/query_toolkit.schema.json +132 -0
  102. package/dist/tools/handlers/project.js +788 -2
  103. package/dist/tools/handlers/query.js +38 -2
  104. package/dist/tools/index.js +346 -37
  105. package/dist/tools/wrap.js +61 -7
  106. package/package.json +2 -2
  107. package/dist/schemas/onchain_operations.output.json +0 -2819
@@ -1,8 +1,16 @@
1
- import { queryProjects, queryProjectObjects, queryShareableObjects, queryDependencies, queryReferencedBy, queryPrePublishCheck, queryCrossProjectReferences, queryGraphStats, saveGraph, loadGraph, } from "../../project/index.js";
1
+ import { queryProjects, queryProjectObjects, queryShareableObjects, queryDependencies, queryReferencedBy, queryPrePublishCheck, queryCrossProjectReferences, queryGraphStats, saveGraph, loadGraph, updateStageCache, getProjectStatus, } from "../../project/index.js";
2
2
  import { analyzeBusinessIntent } from "../../project/business-puzzle.js";
3
3
  import { aggregateProjectRisks } from "../../project/risk-aggregator.js";
4
- import { generateDeploymentDoc, validateDeploymentDoc, } from "../../project/deployment-doc.js";
4
+ import { generateDeploymentDoc, generateDeploymentDocSet, validateDeploymentDoc, estimateDeploymentGas, } from "../../project/deployment-doc.js";
5
5
  import { traceSubsteps } from "../../project/substep-trace.js";
6
+ import * as ProjectStore from "../../project/project-store.js";
7
+ import { migrateProject } from "../../project/migration.js";
8
+ import { validateStageGate } from "../../project/stage-gate.js";
9
+ import { rollbackStageWithPolicy, evaluateRollbackPolicy, queryReversibility, getReversibilityForType, REVERSIBILITY_MATRIX, } from "../../project/rollback-policy.js";
10
+ import { assembleContext } from "../../project/context-assembly.js";
11
+ import { loadImprovementQueue, updateProposalReviewStatus, applyConfigOverride, produceSourcePatch, getFlywheelConfigSummary, } from "../../loop-engineering/improve.js";
12
+ import { clearOverrideCache } from "../../knowledge/overrides-loader.js";
13
+ import { refreshKnowledgeOverrides } from "../../knowledge/index.js";
6
14
  import { strictParse } from "../../schema/index.js";
7
15
  import { ProjectOperationInputSchema } from "../../schema/project/index.js";
8
16
  import { injectEvolutionContext } from "../../knowledge/flywheel-loop.js";
@@ -63,6 +71,22 @@ function requireSubsteps(v) {
63
71
  substeps: v.substeps,
64
72
  };
65
73
  }
74
+ function appendGateAudit(prefix, version, stage, gate) {
75
+ try {
76
+ ProjectStore.appendAudit(prefix, version, {
77
+ timestamp: new Date().toISOString(),
78
+ event: "gate_validation",
79
+ stage,
80
+ reason: gate.passed
81
+ ? `stage ${stage} gate passed (${gate.checks.filter((c) => c.status === "PASS").length}/${gate.checks.length} checks)`
82
+ : `stage ${stage} gate BLOCKED: ${gate.blocking_issues.join("; ")}`,
83
+ affected_files: ["stage.json"],
84
+ user_confirmed: gate.passed,
85
+ });
86
+ }
87
+ catch {
88
+ }
89
+ }
66
90
  async function handleAnalyzeIntent(validated) {
67
91
  const { prefix, version } = requireProject(validated);
68
92
  const userIntent = requireUserIntent(validated);
@@ -87,16 +111,30 @@ async function handleAnalyzeIntent(validated) {
87
111
  catch {
88
112
  experienceFeedback = undefined;
89
113
  }
114
+ updateStageCache(prefix, version, {
115
+ stage: 2,
116
+ puzzles: result.puzzles,
117
+ business_intent: userIntent,
118
+ industry,
119
+ });
120
+ const gate2 = validateStageGate({
121
+ stage: 2, prefix, version,
122
+ puzzles: result.puzzles,
123
+ puzzles_completeness: result.overall_completeness,
124
+ });
125
+ appendGateAudit(prefix, version, 2, gate2);
90
126
  return {
91
127
  action: "analyze_intent",
92
128
  intent_parsed: result.intent_parsed,
93
129
  puzzles: result.puzzles,
94
130
  overall_completeness: result.overall_completeness,
95
131
  next_step: result.next_step,
132
+ recommended_creation_order: result.recommended_creation_order,
96
133
  next_action: result.overall_completeness === "complete" ? "aggregate_risks" : "none",
97
134
  warnings: result.warnings,
98
135
  evolution_context: evolutionContext,
99
136
  experience_feedback: experienceFeedback,
137
+ gate_validation: gate2,
100
138
  };
101
139
  }
102
140
  async function handleAggregateRisks(validated) {
@@ -112,6 +150,17 @@ async function handleAggregateRisks(validated) {
112
150
  });
113
151
  const hasCritical = result.severity_summary.CRITICAL > 0;
114
152
  const unconfirmedHigh = result.findings.filter((r) => r.severity === "HIGH").length;
153
+ updateStageCache(prefix, version, {
154
+ stage: 3,
155
+ risk_status: result.status,
156
+ risk_can_proceed: !hasCritical,
157
+ });
158
+ const gate3 = validateStageGate({
159
+ stage: 3, prefix, version,
160
+ risk_status: result.status,
161
+ risk_can_proceed: !hasCritical,
162
+ });
163
+ appendGateAudit(prefix, version, 3, gate3);
115
164
  return {
116
165
  action: "aggregate_risks",
117
166
  namespace: result.namespace,
@@ -119,6 +168,7 @@ async function handleAggregateRisks(validated) {
119
168
  severity_summary: result.severity_summary,
120
169
  status: result.status,
121
170
  pending_confirmations: result.pending_confirmations,
171
+ fix_suggestions_grouped: result.fix_suggestions_grouped,
122
172
  calibrated_at: result.calibrated_at,
123
173
  warnings: result.warnings,
124
174
  can_proceed: !hasCritical,
@@ -128,6 +178,7 @@ async function handleAggregateRisks(validated) {
128
178
  : unconfirmedHigh > 0
129
179
  ? `Review ${unconfirmedHigh} HIGH risk(s). You may proceed at your own risk.`
130
180
  : "All risks reviewed. You may proceed.",
181
+ gate_validation: gate3,
131
182
  };
132
183
  }
133
184
  async function handleGenerateDeploymentDoc(validated) {
@@ -165,6 +216,40 @@ async function handleGenerateDeploymentDoc(validated) {
165
216
  const warningCount = validationResult
166
217
  ? validationResult.checks.filter((c) => c.status === "WARN").length
167
218
  : 0;
219
+ const gasEstimate = estimateDeploymentGas({ objects: required.objects });
220
+ let docSetResult;
221
+ try {
222
+ const persisted = generateDeploymentDocSet(prefix, version, docInput);
223
+ docSetResult = {
224
+ all_files: persisted.all_files,
225
+ all_stages_passed: persisted.all_stages_passed,
226
+ };
227
+ }
228
+ catch {
229
+ docSetResult = undefined;
230
+ }
231
+ updateStageCache(prefix, version, {
232
+ stage: 4,
233
+ doc_generated: true,
234
+ doc_error_count: errorCount,
235
+ });
236
+ const gasBudgetInput = validated.gas_budget
237
+ ? {
238
+ network: validated.gas_budget.network,
239
+ already_spent_gas: validated.gas_budget.already_spent_gas ?? 0,
240
+ estimated_rerun_gas: validated.gas_budget.estimated_rerun_gas ?? gasEstimate.total_gas_mist,
241
+ warning: validated.gas_budget.warning,
242
+ }
243
+ : undefined;
244
+ const gate4 = validateStageGate({
245
+ stage: 4, prefix, version,
246
+ doc_error_count: errorCount,
247
+ objects: required.objects,
248
+ edges: required.edges,
249
+ risk_status: validated.risk_status,
250
+ gas_budget: gasBudgetInput,
251
+ });
252
+ appendGateAudit(prefix, version, 4, gate4);
168
253
  return {
169
254
  action: "generate_deployment_doc",
170
255
  markdown,
@@ -176,6 +261,8 @@ async function handleGenerateDeploymentDoc(validated) {
176
261
  step_count: required.steps.length,
177
262
  },
178
263
  validation: validationResult,
264
+ estimated_gas: gasEstimate,
265
+ persisted: docSetResult,
179
266
  can_proceed: errorCount === 0,
180
267
  next_action: errorCount === 0 ? "trace_substeps" : "fix_doc_errors",
181
268
  user_action_required: errorCount > 0
@@ -183,6 +270,7 @@ async function handleGenerateDeploymentDoc(validated) {
183
270
  : warningCount > 0
184
271
  ? `${warningCount} D-warning(s) found. You may proceed at your own risk.`
185
272
  : "Deployment document ready. You may proceed to stage 5.",
273
+ gate_validation: gate4,
186
274
  };
187
275
  }
188
276
  async function handleTraceSubsteps(validated) {
@@ -196,6 +284,23 @@ async function handleTraceSubsteps(validated) {
196
284
  });
197
285
  const hasFailedSubstep = substeps.some((s) => s.status === "FAILED");
198
286
  const canProceed = result.coherent && !hasFailedSubstep;
287
+ updateStageCache(prefix, version, {
288
+ stage: 5,
289
+ trace_coherent: result.coherent,
290
+ trace_can_proceed: canProceed,
291
+ });
292
+ const stage5GasBudget = {
293
+ network: validated.gas_budget?.network ?? network,
294
+ already_spent_gas: validated.gas_budget?.already_spent_gas ?? 0,
295
+ estimated_rerun_gas: validated.gas_budget?.estimated_rerun_gas ?? 0,
296
+ warning: validated.gas_budget?.warning,
297
+ };
298
+ const gate5 = validateStageGate({
299
+ stage: 5, prefix, version,
300
+ trace_coherent: result.coherent,
301
+ gas_budget: stage5GasBudget,
302
+ });
303
+ appendGateAudit(prefix, version, 5, gate5);
199
304
  const issueParts = [];
200
305
  if (result.dangling_inputs.length > 0) {
201
306
  issueParts.push(`${result.dangling_inputs.length} dangling inputs`);
@@ -230,6 +335,619 @@ async function handleTraceSubsteps(validated) {
230
335
  user_action_required: issueParts.length > 0
231
336
  ? `Fix: ${issueParts.join(", ")}`
232
337
  : "All substeps passed. Deployment complete.",
338
+ gate_validation: gate5,
339
+ };
340
+ }
341
+ async function handleLoadProject(validated) {
342
+ if (!validated.project || !validated.version) {
343
+ const localProjects = ProjectStore.listLocalProjects();
344
+ const chainProjects = await queryProjects();
345
+ const chainSet = new Set(chainProjects.map((p) => p.prefix));
346
+ const items = localProjects.map((lp) => ({
347
+ prefix: lp.prefix,
348
+ version: lp.version,
349
+ dir_name: lp.dir_name,
350
+ initialized: lp.initialized,
351
+ archived: lp.archived,
352
+ needs_migration: lp.needs_migration,
353
+ forked_from: lp.forked_from,
354
+ chain_exists: chainSet.has(lp.prefix),
355
+ sync_status: !lp.initialized
356
+ ? "uninitialized"
357
+ : lp.archived
358
+ ? "archived"
359
+ : chainSet.has(lp.prefix)
360
+ ? "synced"
361
+ : "local_only",
362
+ }));
363
+ return { action: "load_project", items, total: items.length };
364
+ }
365
+ const { prefix, version } = requireProject(validated);
366
+ const exists = ProjectStore.projectExists(prefix, version);
367
+ if (!exists) {
368
+ return {
369
+ action: "load_project",
370
+ project: prefix,
371
+ version,
372
+ local_exists: false,
373
+ message: "project not found locally; call analyze_intent to initialize",
374
+ };
375
+ }
376
+ let migrationResult;
377
+ try {
378
+ const manifest = ProjectStore.loadManifest(prefix, version);
379
+ if (manifest.schema_version !== ProjectStore.CURRENT_SCHEMA_VERSION) {
380
+ migrationResult = migrateProject(prefix, version);
381
+ }
382
+ }
383
+ catch {
384
+ }
385
+ const manifest = ProjectStore.loadManifest(prefix, version);
386
+ const stageState = ProjectStore.loadStageState(prefix, version);
387
+ const syncStatus = ProjectStore.getLocalSyncStatus(prefix, version);
388
+ return {
389
+ action: "load_project",
390
+ project: prefix,
391
+ version,
392
+ local_exists: true,
393
+ manifest,
394
+ stage_state: stageState,
395
+ sync_status: syncStatus,
396
+ migration: migrationResult,
397
+ };
398
+ }
399
+ async function handleForkProject(validated) {
400
+ const { prefix: srcPrefix, version: srcVersion } = requireProject(validated);
401
+ if (!validated.fork_to_version) {
402
+ throw new Error("'fork_to_version' is required for fork_project (e.g. 'v2')");
403
+ }
404
+ if (!ProjectStore.projectExists(srcPrefix, srcVersion)) {
405
+ throw new Error(`source project not found: ${srcPrefix}_${srcVersion}`);
406
+ }
407
+ const result = ProjectStore.forkProject(srcPrefix, srcVersion, {
408
+ newVersion: validated.fork_to_version,
409
+ newPrefix: validated.fork_to_prefix ?? srcPrefix,
410
+ });
411
+ return {
412
+ action: "fork_project",
413
+ new_prefix: result.new_prefix,
414
+ new_version: result.new_version,
415
+ new_path: result.new_path,
416
+ forked_from: result.forked_from,
417
+ copied_files: result.copied_files,
418
+ copied_file_count: result.copied_files.length,
419
+ warning: "forked project must re-create its own objects (project isolation §3.0); " +
420
+ "chain addresses in copied files are for audit reference only",
421
+ next_action: "analyze_intent",
422
+ };
423
+ }
424
+ async function handleExportProject(validated) {
425
+ const { prefix, version } = requireProject(validated);
426
+ if (!ProjectStore.projectExists(prefix, version)) {
427
+ throw new Error(`project not found: ${prefix}_${version}`);
428
+ }
429
+ const files = ProjectStore.listProjectFiles(prefix, version);
430
+ const exportedFiles = files.map((f) => ({
431
+ path: f.path,
432
+ size: f.size,
433
+ kind: f.kind,
434
+ content: ProjectStore.readProjectFile(prefix, version, f.path) ?? "",
435
+ }));
436
+ return {
437
+ action: "export_project",
438
+ project: prefix,
439
+ version,
440
+ files: exportedFiles,
441
+ total_files: exportedFiles.length,
442
+ };
443
+ }
444
+ async function handleGetProjectFiles(validated) {
445
+ const { prefix, version } = requireProject(validated);
446
+ if (!ProjectStore.projectExists(prefix, version)) {
447
+ throw new Error(`project not found: ${prefix}_${version}`);
448
+ }
449
+ const files = ProjectStore.listProjectFiles(prefix, version);
450
+ return {
451
+ action: "get_project_files",
452
+ project: prefix,
453
+ version,
454
+ files: files.map((f) => ({
455
+ path: f.path,
456
+ size: f.size,
457
+ kind: f.kind,
458
+ mtime: f.mtime,
459
+ })),
460
+ total_files: files.length,
461
+ };
462
+ }
463
+ const STAGE_DIR_NAMES = {
464
+ 1: "namespace",
465
+ 2: "puzzle",
466
+ 3: "risk",
467
+ 4: "steps",
468
+ 5: "substeps",
469
+ };
470
+ function requireTargetStage(v) {
471
+ if (v.target_stage === undefined || v.target_stage === null) {
472
+ throw new Error("'target_stage' (1-5) is required for this action");
473
+ }
474
+ const s = v.target_stage;
475
+ if (s < 1 || s > 5 || !Number.isInteger(s)) {
476
+ throw new Error("'target_stage' must be an integer 1-5");
477
+ }
478
+ return s;
479
+ }
480
+ function stageDirPath(stage) {
481
+ return `deployment/0${stage}-${STAGE_DIR_NAMES[stage]}`;
482
+ }
483
+ function requireDeploymentDocExists(prefix, version) {
484
+ if (!ProjectStore.projectExists(prefix, version)) {
485
+ throw new Error(`project not found: ${prefix}_${version}`);
486
+ }
487
+ const readme = ProjectStore.readProjectFile(prefix, version, "deployment/README.md");
488
+ if (readme === undefined) {
489
+ throw new Error(`deployment doc not found for ${prefix}_${version}. Call 'generate_deployment_doc' first.`);
490
+ }
491
+ }
492
+ async function handleValidateStageUnit(validated) {
493
+ const { prefix, version } = requireProject(validated);
494
+ const stage = requireTargetStage(validated);
495
+ requireDeploymentDocExists(prefix, version);
496
+ const dir = stageDirPath(stage);
497
+ const files = ["README.md", "assessment.json", "risk-policy.json", "verification.json", "content.md"];
498
+ const missing = [];
499
+ for (const f of files) {
500
+ const rel = `${dir}/${f}`;
501
+ if (ProjectStore.readProjectFile(prefix, version, rel) === undefined) {
502
+ missing.push(rel);
503
+ }
504
+ }
505
+ const checks = [];
506
+ const blocking = [];
507
+ if (missing.length === 0) {
508
+ checks.push({ check_id: "SU-01", status: "pass", message: `All 5 stage unit files present in ${dir}/` });
509
+ }
510
+ else {
511
+ checks.push({ check_id: "SU-01", status: "fail", message: `${missing.length} file(s) missing: ${missing.join(", ")}` });
512
+ blocking.push(`Missing files: ${missing.join(", ")}`);
513
+ }
514
+ const assessment = ProjectStore.loadProjectFile(prefix, version, `${dir}/assessment.json`);
515
+ const riskPolicy = ProjectStore.loadProjectFile(prefix, version, `${dir}/risk-policy.json`);
516
+ const verification = ProjectStore.loadProjectFile(prefix, version, `${dir}/verification.json`);
517
+ if (assessment) {
518
+ const ok = assessment.stage === stage;
519
+ checks.push({ check_id: "SU-02", status: ok ? "pass" : "fail", message: ok ? `assessment.json stage=${stage} matches` : `assessment.json stage=${assessment.stage} != target ${stage}` });
520
+ if (!ok)
521
+ blocking.push("assessment.json stage mismatch");
522
+ }
523
+ if (riskPolicy) {
524
+ const ok = riskPolicy.stage === stage;
525
+ checks.push({ check_id: "SU-03", status: ok ? "pass" : "fail", message: ok ? `risk-policy.json stage=${stage} matches` : `risk-policy.json stage=${riskPolicy.stage} != target ${stage}` });
526
+ if (!ok)
527
+ blocking.push("risk-policy.json stage mismatch");
528
+ }
529
+ if (verification) {
530
+ const ok = verification.stage === stage;
531
+ checks.push({ check_id: "SU-04", status: ok ? "pass" : "fail", message: ok ? `verification.json stage=${stage} matches` : `verification.json stage=${verification.stage} != target ${stage}` });
532
+ if (!ok)
533
+ blocking.push("verification.json stage mismatch");
534
+ if (ok) {
535
+ const passed = verification.stage_passed === true;
536
+ const hasBlocking = (verification.blocking_issues?.length ?? 0) > 0;
537
+ const consistent = passed !== hasBlocking;
538
+ checks.push({
539
+ check_id: "SU-05",
540
+ status: consistent ? "pass" : "warn",
541
+ message: consistent
542
+ ? `stage_passed=${passed} consistent with blocking_issues (count=${verification.blocking_issues?.length ?? 0})`
543
+ : `stage_passed=${passed} but blocking_issues count=${verification.blocking_issues?.length ?? 0} — possible inconsistency`,
544
+ });
545
+ }
546
+ }
547
+ return {
548
+ action: "validate_stage_unit",
549
+ project: prefix,
550
+ version,
551
+ stage,
552
+ valid: blocking.length === 0,
553
+ missing_files: missing,
554
+ checks,
555
+ blocking_issues: blocking,
556
+ stage_passed: verification?.stage_passed,
557
+ };
558
+ }
559
+ async function handleGetStageAssessment(validated) {
560
+ const { prefix, version } = requireProject(validated);
561
+ const stage = requireTargetStage(validated);
562
+ requireDeploymentDocExists(prefix, version);
563
+ const assessment = ProjectStore.loadProjectFile(prefix, version, `${stageDirPath(stage)}/assessment.json`);
564
+ return {
565
+ action: "get_stage_assessment",
566
+ project: prefix,
567
+ version,
568
+ stage,
569
+ found: assessment !== undefined,
570
+ assessment: assessment ?? undefined,
571
+ };
572
+ }
573
+ async function handleGetStageRiskPolicy(validated) {
574
+ const { prefix, version } = requireProject(validated);
575
+ const stage = requireTargetStage(validated);
576
+ requireDeploymentDocExists(prefix, version);
577
+ const riskPolicy = ProjectStore.loadProjectFile(prefix, version, `${stageDirPath(stage)}/risk-policy.json`);
578
+ return {
579
+ action: "get_stage_risk_policy",
580
+ project: prefix,
581
+ version,
582
+ stage,
583
+ found: riskPolicy !== undefined,
584
+ risk_policy: riskPolicy ?? undefined,
585
+ };
586
+ }
587
+ async function handleGetDocRelations(validated) {
588
+ const { prefix, version } = requireProject(validated);
589
+ requireDeploymentDocExists(prefix, version);
590
+ const relations = ProjectStore.loadProjectFile(prefix, version, "deployment/relations.json");
591
+ return {
592
+ action: "get_doc_relations",
593
+ project: prefix,
594
+ version,
595
+ found: relations !== undefined,
596
+ relations: relations ?? undefined,
597
+ };
598
+ }
599
+ async function handleUpdateDeploymentDoc(validated) {
600
+ const { prefix, version } = requireProject(validated);
601
+ const required = requireDeploymentInputs(validated);
602
+ requireDeploymentDocExists(prefix, version);
603
+ const docInput = {
604
+ project_prefix: prefix,
605
+ version: version,
606
+ business_intent: required.business_intent,
607
+ industry: validated.industry ?? "general",
608
+ author: validated.author,
609
+ objects: required.objects,
610
+ edges: required.edges,
611
+ steps: required.steps,
612
+ scenarios: validated.scenarios,
613
+ risk_status: validated.risk_status,
614
+ risk_critical_count: validated.risk_critical_count,
615
+ risk_high_count: validated.risk_high_count,
616
+ };
617
+ const persisted = generateDeploymentDocSet(prefix, version, docInput);
618
+ const stagesAffected = persisted.relations.stage_units.map((su) => su.stage);
619
+ return {
620
+ action: "update_deployment_doc",
621
+ project: prefix,
622
+ version,
623
+ updated: true,
624
+ updated_files: persisted.all_files,
625
+ updated_file_count: persisted.all_files.length,
626
+ all_stages_passed: persisted.all_stages_passed,
627
+ impact_summary: {
628
+ stages_affected: stagesAffected,
629
+ relations_rebuilt: true,
630
+ },
631
+ next_action: "validate_validation_chain",
632
+ };
633
+ }
634
+ async function handleValidateValidationChain(validated) {
635
+ const { prefix, version } = requireProject(validated);
636
+ requireDeploymentDocExists(prefix, version);
637
+ const relations = ProjectStore.loadProjectFile(prefix, version, "deployment/relations.json");
638
+ const derivationChecks = [];
639
+ const propagationChecks = [];
640
+ const crossStageChecks = [];
641
+ const impactMapChecks = [];
642
+ const blocking = [];
643
+ const warnings = [];
644
+ if (!relations) {
645
+ return {
646
+ action: "validate_validation_chain",
647
+ project: prefix, version,
648
+ valid: false,
649
+ derivation_checks: [{ check_id: "VC-00", status: "fail", message: "relations.json not found" }],
650
+ propagation_checks: [], cross_stage_checks: [], impact_map_checks: [],
651
+ blocking_issues: ["relations.json not found"], warnings: [],
652
+ };
653
+ }
654
+ const invariantIds = new Set((relations.project_invariants ?? []).map((i) => i.invariant_id));
655
+ const derivations = relations.derivations ?? [];
656
+ const stageUnits = relations.stage_units ?? [];
657
+ if (derivations.length === 0) {
658
+ derivationChecks.push({ check_id: "VC-D01", status: "warn", message: "No derivations defined in relations.json" });
659
+ warnings.push("No derivations defined");
660
+ }
661
+ else {
662
+ const orphanDerivations = derivations.filter((d) => d.source_type === "project_invariant" && !invariantIds.has(d.source_id));
663
+ if (orphanDerivations.length === 0) {
664
+ derivationChecks.push({ check_id: "VC-D01", status: "pass", message: `All ${derivations.length} derivation(s) reference valid project invariants` });
665
+ }
666
+ else {
667
+ derivationChecks.push({ check_id: "VC-D01", status: "fail", message: `${orphanDerivations.length} derivation(s) reference unknown invariant: ${orphanDerivations.map((d) => d.source_id).join(", ")}` });
668
+ blocking.push(`Orphan derivations: ${orphanDerivations.length}`);
669
+ }
670
+ }
671
+ const stagesWithDerivations = new Set(derivations.map((d) => d.target_stage));
672
+ const stagesWithoutDerivations = stageUnits.filter((su) => !stagesWithDerivations.has(su.stage));
673
+ if (stagesWithoutDerivations.length === 0) {
674
+ derivationChecks.push({ check_id: "VC-D02", status: "pass", message: "All stage units have derivations" });
675
+ }
676
+ else {
677
+ derivationChecks.push({ check_id: "VC-D02", status: "warn", message: `Stage(s) without derivations: ${stagesWithoutDerivations.map((su) => su.stage).join(", ")}` });
678
+ warnings.push(`Stages without derivations: ${stagesWithoutDerivations.map((su) => su.stage).join(", ")}`);
679
+ }
680
+ const validStages = new Set(stageUnits.map((su) => su.stage));
681
+ const rules = relations.propagation_rules ?? [];
682
+ const invalidRules = rules.filter((r) => !validStages.has(r.trigger.stage));
683
+ if (rules.length === 0) {
684
+ propagationChecks.push({ check_id: "VC-P01", status: "warn", message: "No propagation rules defined" });
685
+ warnings.push("No propagation rules defined");
686
+ }
687
+ else if (invalidRules.length === 0) {
688
+ propagationChecks.push({ check_id: "VC-P01", status: "pass", message: `All ${rules.length} propagation rule(s) reference valid stages` });
689
+ }
690
+ else {
691
+ propagationChecks.push({ check_id: "VC-P01", status: "fail", message: `${invalidRules.length} rule(s) reference invalid stage: ${invalidRules.map((r) => r.rule_id).join(", ")}` });
692
+ blocking.push(`Invalid propagation rules: ${invalidRules.length}`);
693
+ }
694
+ for (const su of stageUnits) {
695
+ const vPath = `${stageDirPath(su.stage)}/verification.json`;
696
+ const v = ProjectStore.loadProjectFile(prefix, version, vPath);
697
+ if (!v) {
698
+ crossStageChecks.push({ check_id: `VC-C${su.stage}`, status: "warn", message: `Stage ${su.stage} verification.json missing` });
699
+ warnings.push(`Stage ${su.stage} verification.json missing`);
700
+ }
701
+ else if (v.stage_passed === true) {
702
+ crossStageChecks.push({ check_id: `VC-C${su.stage}`, status: "pass", message: `Stage ${su.stage} verification passed` });
703
+ }
704
+ else {
705
+ crossStageChecks.push({ check_id: `VC-C${su.stage}`, status: "fail", message: `Stage ${su.stage} verification NOT passed (blocking_issues: ${v.blocking_issues?.length ?? 0})` });
706
+ blocking.push(`Stage ${su.stage} verification failed`);
707
+ }
708
+ }
709
+ const impactMap = relations.impact_map ?? {};
710
+ const impactValues = new Set(Object.values(impactMap).flat());
711
+ const stagesNotInImpactMap = stageUnits.filter((su) => !impactValues.has(`stage_${su.stage}`) && !impactValues.has(String(su.stage)));
712
+ if (stageUnits.length === 0) {
713
+ impactMapChecks.push({ check_id: "VC-I01", status: "warn", message: "No stage units defined" });
714
+ }
715
+ else if (stagesNotInImpactMap.length === 0) {
716
+ impactMapChecks.push({ check_id: "VC-I01", status: "pass", message: "All stage units appear in impact map" });
717
+ }
718
+ else {
719
+ impactMapChecks.push({ check_id: "VC-I01", status: "warn", message: `Stage(s) not in impact map: ${stagesNotInImpactMap.map((su) => su.stage).join(", ")}` });
720
+ warnings.push(`Stages not in impact map: ${stagesNotInImpactMap.map((su) => su.stage).join(", ")}`);
721
+ }
722
+ return {
723
+ action: "validate_validation_chain",
724
+ project: prefix,
725
+ version,
726
+ valid: blocking.length === 0,
727
+ derivation_checks: derivationChecks,
728
+ propagation_checks: propagationChecks,
729
+ cross_stage_checks: crossStageChecks,
730
+ impact_map_checks: impactMapChecks,
731
+ blocking_issues: blocking,
732
+ warnings,
733
+ };
734
+ }
735
+ async function handleApplyImprovement(validated) {
736
+ if (!validated.proposal_id) {
737
+ throw new Error("'proposal_id' is required for apply_improvement");
738
+ }
739
+ if (!validated.review_status) {
740
+ throw new Error("'review_status' (approved|rejected|applied) is required for apply_improvement");
741
+ }
742
+ const proposalId = validated.proposal_id;
743
+ const newStatus = validated.review_status;
744
+ const all = loadImprovementQueue();
745
+ const proposal = all.find((p) => p.proposal_id === proposalId);
746
+ if (!proposal) {
747
+ throw new Error(`Proposal not found in queue: ${proposalId}`);
748
+ }
749
+ const previousStatus = proposal.review_status;
750
+ if (newStatus === "rejected") {
751
+ updateProposalReviewStatus(proposalId, "rejected");
752
+ return {
753
+ action: "apply_improvement",
754
+ proposal_id: proposalId,
755
+ previous_status: previousStatus,
756
+ new_status: "rejected",
757
+ applied: false,
758
+ apply_mode: proposal.apply_mode,
759
+ message: `Proposal ${proposalId} rejected.`,
760
+ next_action: "get_improvement_queue",
761
+ };
762
+ }
763
+ if (newStatus === "approved") {
764
+ let overrideFile;
765
+ let patchFile;
766
+ let applied = false;
767
+ if (proposal.apply_mode === "config_override") {
768
+ try {
769
+ overrideFile = applyConfigOverride(proposal);
770
+ clearOverrideCache();
771
+ refreshKnowledgeOverrides();
772
+ applied = true;
773
+ }
774
+ catch (e) {
775
+ throw new Error(`Failed to apply config_override for ${proposalId}: ${e instanceof Error ? e.message : String(e)}`);
776
+ }
777
+ }
778
+ else {
779
+ try {
780
+ patchFile = produceSourcePatch(proposal);
781
+ applied = true;
782
+ }
783
+ catch (e) {
784
+ throw new Error(`Failed to produce source patch for ${proposalId}: ${e instanceof Error ? e.message : String(e)}`);
785
+ }
786
+ }
787
+ updateProposalReviewStatus(proposalId, "applied");
788
+ return {
789
+ action: "apply_improvement",
790
+ proposal_id: proposalId,
791
+ previous_status: previousStatus,
792
+ new_status: "applied",
793
+ applied,
794
+ apply_mode: proposal.apply_mode,
795
+ override_file: overrideFile,
796
+ patch_file: patchFile,
797
+ message: proposal.apply_mode === "config_override"
798
+ ? `Proposal applied as config_override. Override written to ${overrideFile}. Takes effect on next action call.`
799
+ : `Proposal applied as source_patch. Patch file written to ${patchFile}. Requires manual merge into MCP source + republish.`,
800
+ next_action: "get_improvement_queue",
801
+ };
802
+ }
803
+ updateProposalReviewStatus(proposalId, "applied");
804
+ return {
805
+ action: "apply_improvement",
806
+ proposal_id: proposalId,
807
+ previous_status: previousStatus,
808
+ new_status: "applied",
809
+ applied: false,
810
+ apply_mode: proposal.apply_mode,
811
+ message: `Proposal ${proposalId} marked as applied (external application).`,
812
+ next_action: "get_flywheel_config",
813
+ };
814
+ }
815
+ async function handleGetImprovementQueue(validated) {
816
+ const filter = {};
817
+ if (validated.queue_filter_status)
818
+ filter.status = validated.queue_filter_status;
819
+ if (validated.queue_filter_type)
820
+ filter.type = validated.queue_filter_type;
821
+ if (validated.queue_filter_priority)
822
+ filter.priority = validated.queue_filter_priority;
823
+ const all = loadImprovementQueue();
824
+ const filtered = filter.status || filter.type || filter.priority
825
+ ? loadImprovementQueue(filter)
826
+ : all;
827
+ const pendingCount = all.filter((p) => p.review_status === "pending").length;
828
+ const summary = `${all.length} total proposals (${pendingCount} pending). Showing ${filtered.length}.`;
829
+ const proposals = filtered.map((p) => ({
830
+ proposal_id: p.proposal_id,
831
+ source_diagnosis_id: p.source_diagnosis_id,
832
+ type: p.type,
833
+ priority: p.priority,
834
+ automation: p.automation,
835
+ apply_mode: p.apply_mode,
836
+ override_category: p.override_category,
837
+ title: p.title,
838
+ description: p.description,
839
+ target: p.target,
840
+ review_status: p.review_status,
841
+ ab_test_recommended: p.ab_test_recommended,
842
+ persisted_at: p.persisted_at,
843
+ reviewed_at: p.reviewed_at,
844
+ }));
845
+ return {
846
+ action: "get_improvement_queue",
847
+ total: all.length,
848
+ filtered_count: filtered.length,
849
+ proposals,
850
+ summary,
851
+ };
852
+ }
853
+ async function handleGetFlywheelConfig() {
854
+ const summary = getFlywheelConfigSummary();
855
+ let reflowStatus;
856
+ if (summary.pending_count > 0) {
857
+ reflowStatus = "active";
858
+ }
859
+ else if (summary.approved_count > 0) {
860
+ reflowStatus = "blocked";
861
+ }
862
+ else {
863
+ reflowStatus = "idle";
864
+ }
865
+ const recentProposals = summary.recent_proposals.map((p) => ({
866
+ proposal_id: p.proposal_id,
867
+ type: p.type,
868
+ priority: p.priority,
869
+ review_status: p.review_status,
870
+ title: p.title,
871
+ }));
872
+ return {
873
+ action: "get_flywheel_config",
874
+ queue_path: summary.queue_path,
875
+ overrides_dir: summary.overrides_dir,
876
+ patches_dir: summary.patches_dir,
877
+ total_proposals: summary.total_proposals,
878
+ pending_count: summary.pending_count,
879
+ approved_count: summary.approved_count,
880
+ applied_count: summary.applied_count,
881
+ rejected_count: summary.rejected_count,
882
+ override_files: summary.override_files,
883
+ recent_proposals: recentProposals,
884
+ reflow_status: reflowStatus,
885
+ };
886
+ }
887
+ async function handleRollbackStage(validated) {
888
+ const { prefix, version } = requireProject(validated);
889
+ if (!validated.target_stage) {
890
+ throw new Error("'target_stage' is required for rollback_stage (the stage to rollback to, 1-4)");
891
+ }
892
+ const targetStage = validated.target_stage;
893
+ const dryRun = validated.dry_run ?? false;
894
+ if (dryRun) {
895
+ const policy = evaluateRollbackPolicy(prefix, version, targetStage);
896
+ return {
897
+ action: "rollback_stage",
898
+ success: false,
899
+ dry_run: true,
900
+ target_stage: targetStage,
901
+ previous_stage: policy.current_stage,
902
+ allowed: policy.allowed,
903
+ block_reason: policy.block_reason,
904
+ files_to_clean: policy.files_to_clean,
905
+ files_cleaned: [],
906
+ warnings: policy.warnings,
907
+ iteration_strategy: policy.iteration_strategy,
908
+ message: policy.allowed
909
+ ? `Dry run: rollback to stage ${targetStage} is allowed. ${policy.files_to_clean.length} file(s) would be deleted.`
910
+ : `Dry run: rollback blocked — ${policy.block_reason}`,
911
+ };
912
+ }
913
+ const result = rollbackStageWithPolicy(prefix, version, targetStage);
914
+ return {
915
+ action: "rollback_stage",
916
+ success: result.success,
917
+ dry_run: false,
918
+ target_stage: result.target_stage,
919
+ previous_stage: result.previous_stage,
920
+ allowed: result.success,
921
+ block_reason: result.success ? undefined : result.message,
922
+ files_to_clean: result.files_to_clean,
923
+ files_cleaned: result.files_cleaned,
924
+ warnings: result.warnings,
925
+ iteration_strategy: result.iteration_strategy,
926
+ message: result.message,
927
+ };
928
+ }
929
+ async function handleGetReversibility(validated) {
930
+ const objectType = validated.query_object_type;
931
+ const lifecycleState = validated.query_lifecycle_state;
932
+ let entries;
933
+ if (objectType && lifecycleState) {
934
+ const entry = queryReversibility(objectType, lifecycleState);
935
+ entries = entry ? [entry] : [];
936
+ }
937
+ else if (objectType) {
938
+ entries = getReversibilityForType(objectType);
939
+ }
940
+ else {
941
+ entries = REVERSIBILITY_MATRIX;
942
+ }
943
+ return {
944
+ action: "get_reversibility",
945
+ query: {
946
+ object_type: objectType,
947
+ lifecycle_state: lifecycleState,
948
+ },
949
+ entries,
950
+ total: entries.length,
233
951
  };
234
952
  }
235
953
  export async function handleProjectOperation(args) {
@@ -287,6 +1005,74 @@ export async function handleProjectOperation(args) {
287
1005
  case "trace_substeps":
288
1006
  result = await handleTraceSubsteps(validated);
289
1007
  break;
1008
+ case "get_project_status": {
1009
+ const { prefix: gpPrefix, version: gpVersion } = requireProject(validated);
1010
+ const status = getProjectStatus(gpPrefix, gpVersion);
1011
+ result = {
1012
+ action: "get_project_status",
1013
+ project: gpPrefix,
1014
+ version: gpVersion,
1015
+ stage: status.stage,
1016
+ stage_name: status.stage_name,
1017
+ stage_description: status.stage_description,
1018
+ next_action: status.next_action,
1019
+ can_proceed: status.can_proceed,
1020
+ last_updated: status.details?.updated_at,
1021
+ risk_status: status.details?.risk_status,
1022
+ risk_can_proceed: status.details?.risk_can_proceed,
1023
+ doc_generated: status.details?.doc_generated,
1024
+ trace_coherent: status.details?.trace_coherent,
1025
+ };
1026
+ break;
1027
+ }
1028
+ case "load_project":
1029
+ result = await handleLoadProject(validated);
1030
+ break;
1031
+ case "fork_project":
1032
+ result = await handleForkProject(validated);
1033
+ break;
1034
+ case "export_project":
1035
+ result = await handleExportProject(validated);
1036
+ break;
1037
+ case "get_project_files":
1038
+ result = await handleGetProjectFiles(validated);
1039
+ break;
1040
+ case "validate_stage_unit":
1041
+ result = await handleValidateStageUnit(validated);
1042
+ break;
1043
+ case "get_stage_assessment":
1044
+ result = await handleGetStageAssessment(validated);
1045
+ break;
1046
+ case "get_stage_risk_policy":
1047
+ result = await handleGetStageRiskPolicy(validated);
1048
+ break;
1049
+ case "get_doc_relations":
1050
+ result = await handleGetDocRelations(validated);
1051
+ break;
1052
+ case "update_deployment_doc":
1053
+ result = await handleUpdateDeploymentDoc(validated);
1054
+ break;
1055
+ case "validate_validation_chain":
1056
+ result = await handleValidateValidationChain(validated);
1057
+ break;
1058
+ case "apply_improvement":
1059
+ result = await handleApplyImprovement(validated);
1060
+ break;
1061
+ case "get_improvement_queue":
1062
+ result = await handleGetImprovementQueue(validated);
1063
+ break;
1064
+ case "get_flywheel_config":
1065
+ result = await handleGetFlywheelConfig();
1066
+ break;
1067
+ case "rollback_stage":
1068
+ result = await handleRollbackStage(validated);
1069
+ break;
1070
+ case "get_reversibility":
1071
+ result = await handleGetReversibility(validated);
1072
+ break;
1073
+ case "assemble_context":
1074
+ result = await assembleContext(validated);
1075
+ break;
290
1076
  default:
291
1077
  throw new Error(`Unknown project_operation action: ${String(action)}`);
292
1078
  }