@wowok/agent-mcp 2.5.4 → 2.6.0

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 (76) hide show
  1. package/README.md +33 -26
  2. package/dist/config/runtime.js +3 -6
  3. package/dist/harness/checkpoint.js +2 -2
  4. package/dist/knowledge/flywheel-loop.js +2 -5
  5. package/dist/knowledge/overrides-loader.js +2 -4
  6. package/dist/knowledge/progress-ledger.js +3 -0
  7. package/dist/knowledge/progress-translation.js +5 -1
  8. package/dist/knowledge/reward-confirm.d.ts +3 -0
  9. package/dist/knowledge/reward-confirm.js +30 -0
  10. package/dist/knowledge/reward-puzzle.d.ts +1 -0
  11. package/dist/knowledge/reward-puzzle.js +12 -0
  12. package/dist/knowledge/reward-risk.d.ts +4 -1
  13. package/dist/knowledge/reward-risk.js +85 -3
  14. package/dist/knowledge/tools-reference.js +5 -4
  15. package/dist/loop-engineering/improve.js +2 -4
  16. package/dist/project/deployment-bridge.d.ts +5 -0
  17. package/dist/project/deployment-bridge.js +96 -0
  18. package/dist/project/evaluation.d.ts +53 -0
  19. package/dist/project/evaluation.js +860 -0
  20. package/dist/project/graph-builder.d.ts +43 -0
  21. package/dist/project/graph-builder.js +585 -0
  22. package/dist/project/handlers.d.ts +154 -0
  23. package/dist/project/handlers.js +567 -0
  24. package/dist/project/index.d.ts +1 -0
  25. package/dist/project/index.js +26 -7
  26. package/dist/project/project-store.js +2 -5
  27. package/dist/project/query.d.ts +1 -0
  28. package/dist/project/query.js +2 -0
  29. package/dist/project/semantic-assembler.d.ts +93 -0
  30. package/dist/project/semantic-assembler.js +345 -0
  31. package/dist/schema/call/base.js +1 -1
  32. package/dist/schema/config/index.d.ts +12 -12
  33. package/dist/schema/local/index.d.ts +108 -108
  34. package/dist/schema/local/index.js +21 -18
  35. package/dist/schema/messenger/index.d.ts +16 -16
  36. package/dist/schema/messenger/index.js +2 -2
  37. package/dist/schema/operations.d.ts +0 -6
  38. package/dist/schema/project/index.d.ts +1840 -3903
  39. package/dist/schema/project/index.js +403 -955
  40. package/dist/schema/query/index.d.ts +10 -5
  41. package/dist/schema/trust/index.d.ts +6 -6
  42. package/dist/schemas/account_operation.output.json +7 -21
  43. package/dist/schemas/account_operation.schema.json +9 -23
  44. package/dist/schemas/bridge_operation.schema.json +1 -1
  45. package/dist/schemas/guard2file.schema.json +1 -1
  46. package/dist/schemas/index.json +2 -2
  47. package/dist/schemas/machineNode2file.schema.json +1 -1
  48. package/dist/schemas/messenger_operation.schema.json +6 -6
  49. package/dist/schemas/onchain_operations.schema.json +5 -5
  50. package/dist/schemas/onchain_operations_allocation.schema.json +1 -1
  51. package/dist/schemas/onchain_operations_arbitration.schema.json +1 -1
  52. package/dist/schemas/onchain_operations_contact.schema.json +1 -1
  53. package/dist/schemas/onchain_operations_demand.schema.json +1 -1
  54. package/dist/schemas/onchain_operations_gen_passport.schema.json +2 -2
  55. package/dist/schemas/onchain_operations_gen_proof.schema.json +2 -2
  56. package/dist/schemas/onchain_operations_guard.schema.json +1 -1
  57. package/dist/schemas/onchain_operations_machine.schema.json +1 -1
  58. package/dist/schemas/onchain_operations_order.schema.json +1 -1
  59. package/dist/schemas/onchain_operations_payment.schema.json +1 -1
  60. package/dist/schemas/onchain_operations_permission.schema.json +1 -1
  61. package/dist/schemas/onchain_operations_personal.schema.json +1 -1
  62. package/dist/schemas/onchain_operations_progress.schema.json +1 -1
  63. package/dist/schemas/onchain_operations_proof.schema.json +1 -1
  64. package/dist/schemas/onchain_operations_repository.schema.json +1 -1
  65. package/dist/schemas/onchain_operations_reward.schema.json +1 -1
  66. package/dist/schemas/onchain_operations_service.schema.json +1 -1
  67. package/dist/schemas/onchain_operations_treasury.schema.json +1 -1
  68. package/dist/schemas/project_operation.output.json +1178 -2494
  69. package/dist/schemas/project_operation.schema.json +216 -530
  70. package/dist/schemas/query_toolkit.output.json +7 -6
  71. package/dist/schemas/query_toolkit.schema.json +0 -4
  72. package/dist/telemetry/storage.js +2 -2
  73. package/dist/tools/handlers/onchain.js +110 -19
  74. package/dist/tools/handlers/project.js +56 -1046
  75. package/dist/tools/index.js +85 -56
  76. package/package.json +2 -2
@@ -1,1078 +1,88 @@
1
- import { queryProjects, queryProjectObjects, queryShareableObjects, queryDependencies, queryReferencedBy, queryPrePublishCheck, queryCrossProjectReferences, queryGraphStats, saveGraph, loadGraph, updateStageCache, getProjectStatus, } from "../../project/index.js";
2
- import { analyzeBusinessIntent } from "../../project/business-puzzle.js";
3
- import { aggregateProjectRisks } from "../../project/risk-aggregator.js";
4
- import { generateDeploymentDoc, generateDeploymentDocSet, validateDeploymentDoc, estimateDeploymentGas, } from "../../project/deployment-doc.js";
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
1
  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";
2
+ import { generateDeploymentDocFromProject } from "../../project/deployment-bridge.js";
3
+ import { LocalProject } from "@wowok/wowok";
4
+ import { handleListProjects, handleCreateProject, handleCreateProjectFromOnchain, handleUpdateProject, handleGetProjectDetail, handleAddObject, handleRemoveObject, handleUpdateObject, handleCreateVersion, handleBuildGraph, handleGetGraph, handleEvaluateProject, handleSaveEvaluation, handleCompareProjects, handleRefreshObjects, handleGetObjectDiff, handleDeleteProject, } from "../../project/handlers.js";
14
5
  import { strictParse } from "../../schema/index.js";
15
6
  import { ProjectOperationInputSchema } from "../../schema/project/index.js";
16
- import { injectEvolutionContext } from "../../knowledge/flywheel-loop.js";
17
- import { getExperienceFeedback } from "../../experience/index.js";
18
- function requireProject(v) {
19
- if (!v.project) {
20
- throw new Error("'project' (prefix) is required for this action");
21
- }
22
- if (!v.version) {
23
- throw new Error("'version' is required for this action (e.g. 'v1')");
24
- }
25
- return { prefix: v.project, version: v.version };
26
- }
27
- function requireUserIntent(v) {
28
- if (!v.user_intent) {
29
- throw new Error("'user_intent' is required for analyze_intent");
30
- }
31
- return v.user_intent;
32
- }
33
- function requirePuzzles(v) {
34
- if (!v.puzzles || Object.keys(v.puzzles).length === 0) {
35
- throw new Error("'puzzles' is required for this action (obtain from analyze_intent)");
36
- }
37
- return v.puzzles;
38
- }
39
- function requireDeploymentInputs(v) {
40
- if (!v.business_intent) {
41
- throw new Error("'business_intent' is required for generate_deployment_doc");
42
- }
43
- if (!v.objects || v.objects.length === 0) {
44
- throw new Error("'objects' is required for generate_deployment_doc");
45
- }
46
- if (!v.edges) {
47
- throw new Error("'edges' is required for generate_deployment_doc");
48
- }
49
- if (!v.steps) {
50
- throw new Error("'steps' is required for generate_deployment_doc");
51
- }
52
- return {
53
- business_intent: v.business_intent,
54
- objects: v.objects,
55
- edges: v.edges,
56
- steps: v.steps,
57
- };
58
- }
59
- function requireSubsteps(v) {
60
- if (!v.network) {
61
- throw new Error("'network' is required for trace_substeps");
62
- }
63
- if (v.network !== "testnet" && v.network !== "mainnet") {
64
- throw new Error("'network' must be 'testnet' or 'mainnet'");
65
- }
66
- if (!v.substeps || v.substeps.length === 0) {
67
- throw new Error("'substeps' is required for trace_substeps");
68
- }
69
- return {
70
- network: v.network,
71
- substeps: v.substeps,
72
- };
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
- }
90
- async function handleAnalyzeIntent(validated) {
91
- const { prefix, version } = requireProject(validated);
92
- const userIntent = requireUserIntent(validated);
93
- const result = analyzeBusinessIntent({
94
- user_intent: userIntent,
95
- project_name: `${prefix}_${version}`,
96
- industry: validated.industry,
97
- target_objects: validated.target_objects,
98
- });
99
- const industry = validated.industry ?? "general";
100
- let evolutionContext;
101
- let experienceFeedback;
102
- try {
103
- evolutionContext = injectEvolutionContext(undefined, industry);
104
- }
105
- catch {
106
- evolutionContext = undefined;
107
- }
108
- try {
109
- experienceFeedback = getExperienceFeedback("analyze_intent", { user_intent: userIntent, industry, target_objects: validated.target_objects }, `project:analyze_intent`);
110
- }
111
- catch {
112
- experienceFeedback = undefined;
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);
126
- return {
127
- action: "analyze_intent",
128
- intent_parsed: result.intent_parsed,
129
- puzzles: result.puzzles,
130
- overall_completeness: result.overall_completeness,
131
- next_step: result.next_step,
132
- recommended_creation_order: result.recommended_creation_order,
133
- next_action: result.overall_completeness === "complete" ? "aggregate_risks" : "none",
134
- warnings: result.warnings,
135
- evolution_context: evolutionContext,
136
- experience_feedback: experienceFeedback,
137
- gate_validation: gate2,
138
- };
139
- }
140
- async function handleAggregateRisks(validated) {
141
- const { prefix, version } = requireProject(validated);
142
- const puzzles = requirePuzzles(validated);
143
- const result = aggregateProjectRisks({
144
- project_prefix: prefix,
145
- version: version,
146
- industry: validated.industry,
147
- puzzles,
148
- severity_threshold: validated.severity_threshold,
149
- user_confirmed_high_risks: validated.user_confirmed_high_risks,
150
- });
151
- const hasCritical = result.severity_summary.CRITICAL > 0;
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);
164
- return {
165
- action: "aggregate_risks",
166
- namespace: result.namespace,
167
- findings: result.findings,
168
- severity_summary: result.severity_summary,
169
- status: result.status,
170
- pending_confirmations: result.pending_confirmations,
171
- fix_suggestions_grouped: result.fix_suggestions_grouped,
172
- calibrated_at: result.calibrated_at,
173
- warnings: result.warnings,
174
- can_proceed: !hasCritical,
175
- next_action: hasCritical ? "fix_risks" : "generate_deployment_doc",
176
- user_action_required: hasCritical
177
- ? `Fix ${result.severity_summary.CRITICAL} CRITICAL risk(s) before proceeding`
178
- : unconfirmedHigh > 0
179
- ? `Review ${unconfirmedHigh} HIGH risk(s). You may proceed at your own risk.`
180
- : "All risks reviewed. You may proceed.",
181
- gate_validation: gate3,
182
- };
183
- }
184
- async function handleGenerateDeploymentDoc(validated) {
185
- const { prefix, version } = requireProject(validated);
186
- const required = requireDeploymentInputs(validated);
187
- const docInput = {
188
- project_prefix: prefix,
189
- version: version,
190
- business_intent: required.business_intent,
191
- industry: validated.industry ?? "general",
192
- author: validated.author,
193
- objects: required.objects,
194
- edges: required.edges,
195
- steps: required.steps,
196
- scenarios: validated.scenarios,
197
- risk_status: validated.risk_status,
198
- risk_critical_count: validated.risk_critical_count,
199
- risk_high_count: validated.risk_high_count,
200
- };
201
- const markdown = generateDeploymentDoc(docInput);
202
- const generatedAt = new Date().toISOString();
203
- const shouldRunScanner = validated.run_scanner !== false;
204
- let validationResult;
205
- if (shouldRunScanner) {
206
- const validation = validateDeploymentDoc(docInput);
207
- validationResult = {
208
- valid: validation.valid,
209
- checks: validation.checks,
210
- errors: validation.errors,
211
- };
212
- }
213
- const errorCount = validationResult
214
- ? validationResult.checks.filter((c) => c.status === "FAIL").length
215
- : 0;
216
- const warningCount = validationResult
217
- ? validationResult.checks.filter((c) => c.status === "WARN").length
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);
253
- return {
254
- action: "generate_deployment_doc",
255
- markdown,
256
- meta: {
257
- project_prefix: prefix,
258
- version: version,
259
- generated_at: generatedAt,
260
- object_count: required.objects.length,
261
- step_count: required.steps.length,
262
- },
263
- validation: validationResult,
264
- estimated_gas: gasEstimate,
265
- persisted: docSetResult,
266
- can_proceed: errorCount === 0,
267
- next_action: errorCount === 0 ? "trace_substeps" : "fix_doc_errors",
268
- user_action_required: errorCount > 0
269
- ? `Fix ${errorCount} D-error(s) before deploying`
270
- : warningCount > 0
271
- ? `${warningCount} D-warning(s) found. You may proceed at your own risk.`
272
- : "Deployment document ready. You may proceed to stage 5.",
273
- gate_validation: gate4,
274
- };
275
- }
276
- async function handleTraceSubsteps(validated) {
277
- const { prefix, version } = requireProject(validated);
278
- const { network, substeps } = requireSubsteps(validated);
279
- const result = traceSubsteps({
280
- project_prefix: prefix,
281
- version: version,
282
- network: network,
283
- substeps,
284
- });
285
- const hasFailedSubstep = substeps.some((s) => s.status === "FAILED");
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);
304
- const issueParts = [];
305
- if (result.dangling_inputs.length > 0) {
306
- issueParts.push(`${result.dangling_inputs.length} dangling inputs`);
307
- }
308
- if (result.circular_refs.length > 0) {
309
- issueParts.push(`${result.circular_refs.length} circular refs`);
310
- }
311
- if (result.missing_outputs.length > 0) {
312
- issueParts.push(`${result.missing_outputs.length} missing outputs`);
313
- }
314
- if (result.cross_step_breaks.length > 0) {
315
- issueParts.push(`${result.cross_step_breaks.length} cross-step breaks`);
316
- }
317
- if (hasFailedSubstep) {
318
- const failedCount = substeps.filter((s) => s.status === "FAILED").length;
319
- issueParts.push(`${failedCount} failed substep(s)`);
320
- }
321
- return {
322
- action: "trace_substeps",
323
- namespace: result.namespace,
324
- network: result.network,
325
- coherent: result.coherent,
326
- dangling_inputs: result.dangling_inputs,
327
- circular_refs: result.circular_refs,
328
- missing_outputs: result.missing_outputs,
329
- cross_step_breaks: result.cross_step_breaks,
330
- step_details: result.step_details,
331
- topological_order: result.topological_order,
332
- d10_check: result.d10_check,
333
- can_proceed: canProceed,
334
- next_action: canProceed ? "deploy" : "fix_substeps",
335
- user_action_required: issueParts.length > 0
336
- ? `Fix: ${issueParts.join(", ")}`
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,
951
- };
952
- }
953
7
  export async function handleProjectOperation(args) {
954
8
  const validated = strictParse(ProjectOperationInputSchema, args, "project_operation input");
955
9
  const { action } = validated;
956
10
  let result;
957
11
  switch (action) {
958
12
  case "list_projects":
959
- result = { action: "list_projects", items: await queryProjects() };
960
- break;
961
- case "list_objects":
962
- if (!validated.project)
963
- throw new Error("'project' param is required for list_objects");
964
- result = { action: "list_objects", items: await queryProjectObjects(validated.project) };
13
+ result = await handleListProjects(validated);
965
14
  break;
966
- case "shareable":
967
- result = { action: "shareable", items: await queryShareableObjects() };
15
+ case "create_project":
16
+ result = await handleCreateProject(validated);
968
17
  break;
969
- case "dependencies":
970
- if (!validated.object)
971
- throw new Error("'object' param is required for dependencies");
972
- result = { action: "dependencies", items: queryDependencies(validated.object) };
18
+ case "create_project_from_onchain":
19
+ result = await handleCreateProjectFromOnchain(validated);
973
20
  break;
974
- case "referenced_by":
975
- if (!validated.object)
976
- throw new Error("'object' param is required for referenced_by");
977
- result = { action: "referenced_by", items: queryReferencedBy(validated.object) };
21
+ case "update_project":
22
+ result = await handleUpdateProject(validated);
978
23
  break;
979
- case "pre_publish_check":
980
- if (!validated.object)
981
- throw new Error("'object' param is required for pre_publish_check");
982
- result = { action: "pre_publish_check", warnings: queryPrePublishCheck(validated.object) };
24
+ case "get_project_detail":
25
+ result = await handleGetProjectDetail(validated);
983
26
  break;
984
- case "cross_project_refs":
985
- result = { action: "cross_project_refs", items: queryCrossProjectReferences() };
27
+ case "add_object":
28
+ result = await handleAddObject(validated);
986
29
  break;
987
- case "graph_stats":
988
- result = { action: "graph_stats", stats: queryGraphStats() };
30
+ case "remove_object":
31
+ result = await handleRemoveObject(validated);
989
32
  break;
990
- case "save_graph":
991
- result = { action: "save_graph", saved: true, path: saveGraph() };
33
+ case "update_object":
34
+ result = await handleUpdateObject(validated);
992
35
  break;
993
- case "load_graph":
994
- result = { action: "load_graph", loaded: loadGraph() };
36
+ case "create_version":
37
+ result = await handleCreateVersion(validated);
995
38
  break;
996
- case "analyze_intent":
997
- result = await handleAnalyzeIntent(validated);
39
+ case "build_graph":
40
+ result = await handleBuildGraph(validated);
998
41
  break;
999
- case "aggregate_risks":
1000
- result = await handleAggregateRisks(validated);
42
+ case "get_graph":
43
+ result = await handleGetGraph(validated);
1001
44
  break;
1002
- case "generate_deployment_doc":
1003
- result = await handleGenerateDeploymentDoc(validated);
45
+ case "evaluate_project":
46
+ result = await handleEvaluateProject(validated);
1004
47
  break;
1005
- case "trace_substeps":
1006
- result = await handleTraceSubsteps(validated);
48
+ case "save_evaluation":
49
+ result = await handleSaveEvaluation(validated);
1007
50
  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);
51
+ case "compare_projects":
52
+ result = await handleCompareProjects(validated);
1051
53
  break;
1052
- case "update_deployment_doc":
1053
- result = await handleUpdateDeploymentDoc(validated);
54
+ case "refresh_objects":
55
+ result = await handleRefreshObjects(validated);
1054
56
  break;
1055
- case "validate_validation_chain":
1056
- result = await handleValidateValidationChain(validated);
57
+ case "get_object_diff":
58
+ result = await handleGetObjectDiff(validated);
1057
59
  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);
60
+ case "delete_project":
61
+ result = await handleDeleteProject(validated);
1072
62
  break;
1073
63
  case "assemble_context":
1074
64
  result = await assembleContext(validated);
1075
65
  break;
66
+ case "generate_deployment_doc": {
67
+ const { project_id, network, save = true } = validated;
68
+ if (!project_id) {
69
+ throw new Error("'project_id' is required for generate_deployment_doc");
70
+ }
71
+ if (!network) {
72
+ throw new Error("'network' is required for generate_deployment_doc");
73
+ }
74
+ const genResult = await generateDeploymentDocFromProject(project_id, network);
75
+ if (save) {
76
+ await LocalProject.Instance().saveDocument(project_id, network, genResult.markdown);
77
+ }
78
+ result = {
79
+ action: "generate_deployment_doc",
80
+ markdown: genResult.markdown,
81
+ validation: genResult.validation,
82
+ saved: save,
83
+ };
84
+ break;
85
+ }
1076
86
  default:
1077
87
  throw new Error(`Unknown project_operation action: ${String(action)}`);
1078
88
  }