@wowok/agent-mcp 2.6.1 → 2.6.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 (125) hide show
  1. package/dist/customer/info-puzzle.d.ts +1 -1
  2. package/dist/customer/info-puzzle.js +4 -2
  3. package/dist/customer/risk-assessment.js +26 -4
  4. package/dist/customer/types.d.ts +2 -0
  5. package/dist/examples/guard-template-balance-check.json +38 -0
  6. package/dist/examples/guard-template-time-lock.json +39 -0
  7. package/dist/examples/machine-template-7node-rental.json +114 -0
  8. package/dist/examples/rental-ziroom-machine-create.json +137 -0
  9. package/dist/examples/rental-ziroom-permission-create.json +35 -0
  10. package/dist/examples/rental-ziroom-service-create.json +80 -0
  11. package/dist/examples/retail-myshop-service-create.json +88 -0
  12. package/dist/extensions/capability-manifest.js +24 -24
  13. package/dist/extensions/constraint-registry.js +18 -18
  14. package/dist/extensions/metric-registry.js +14 -14
  15. package/dist/extensions/mode-evaluator.js +16 -16
  16. package/dist/extensions/modes.js +131 -45
  17. package/dist/extensions/registry.d.ts +2 -0
  18. package/dist/extensions/registry.js +63 -30
  19. package/dist/extensions/types.d.ts +1 -0
  20. package/dist/index.js +50 -0
  21. package/dist/knowledge/deployment-scanner.js +1 -1
  22. package/dist/knowledge/fund-layer.d.ts +72 -0
  23. package/dist/knowledge/fund-layer.js +420 -0
  24. package/dist/knowledge/guard-render.d.ts +57 -0
  25. package/dist/knowledge/guard-render.js +700 -0
  26. package/dist/knowledge/guard-submission-prompt.d.ts +31 -0
  27. package/dist/knowledge/guard-submission-prompt.js +171 -0
  28. package/dist/knowledge/machine-ledger.js +1 -1
  29. package/dist/knowledge/machine-render.d.ts +41 -0
  30. package/dist/knowledge/machine-render.js +565 -0
  31. package/dist/knowledge/machine-templates.js +4 -4
  32. package/dist/knowledge/reward-confirm.js +2 -2
  33. package/dist/knowledge/reward-puzzle.js +1 -1
  34. package/dist/knowledge/reward-risk.js +9 -9
  35. package/dist/knowledge/reward-templates.js +2 -2
  36. package/dist/knowledge/service-confirm.d.ts +1 -1
  37. package/dist/knowledge/service-confirm.js +3 -3
  38. package/dist/knowledge/service-context.js +1 -1
  39. package/dist/knowledge/service-ledger.js +1 -1
  40. package/dist/knowledge/service-risk.d.ts +1 -1
  41. package/dist/knowledge/service-risk.js +3 -3
  42. package/dist/knowledge/service-templates.js +2 -2
  43. package/dist/knowledge/service-translation.d.ts +1 -1
  44. package/dist/knowledge/service-translation.js +7 -7
  45. package/dist/project/deployment-bridge.js +6 -5
  46. package/dist/project/deployment-doc.js +5 -5
  47. package/dist/project/edit-planner.d.ts +123 -0
  48. package/dist/project/edit-planner.js +1371 -0
  49. package/dist/project/evaluation.js +314 -14
  50. package/dist/project/graph-builder.js +6 -1
  51. package/dist/project/handlers.d.ts +99 -2
  52. package/dist/project/handlers.js +358 -16
  53. package/dist/project/stage-gate.js +4 -4
  54. package/dist/schema/call/allocation.js +2 -2
  55. package/dist/schema/call/arbitration.js +19 -6
  56. package/dist/schema/call/contact.js +2 -2
  57. package/dist/schema/call/demand.js +2 -2
  58. package/dist/schema/call/guard.js +1 -1
  59. package/dist/schema/call/machine.d.ts +1975 -777
  60. package/dist/schema/call/machine.js +50 -4
  61. package/dist/schema/call/order.js +3 -6
  62. package/dist/schema/call/permission.js +2 -2
  63. package/dist/schema/call/repository.js +2 -2
  64. package/dist/schema/call/reward.js +3 -3
  65. package/dist/schema/call/semantic.js +7 -1
  66. package/dist/schema/call/service.d.ts +180 -8
  67. package/dist/schema/call/service.js +82 -27
  68. package/dist/schema/call/treasury.js +3 -3
  69. package/dist/schema/common/index.d.ts +2 -0
  70. package/dist/schema/common/index.js +46 -10
  71. package/dist/schema/local/index.js +5 -1
  72. package/dist/schema/operations.d.ts +755 -176
  73. package/dist/schema/operations.js +43 -7
  74. package/dist/schema/project/index.d.ts +969 -6
  75. package/dist/schema/project/index.js +268 -4
  76. package/dist/schema/query/index.d.ts +217 -0
  77. package/dist/schema/query/index.js +63 -33
  78. package/dist/schema/schema-query/index.d.ts +53 -3
  79. package/dist/schema/schema-query/index.js +17 -2
  80. package/dist/schema/utils/node-parser.js +13 -0
  81. package/dist/schema/utils/object-type-utils.d.ts +12 -0
  82. package/dist/schema/utils/object-type-utils.js +35 -0
  83. package/dist/schema/utils/permission-machine-check.d.ts +49 -0
  84. package/dist/schema/utils/permission-machine-check.js +121 -0
  85. package/dist/schema/utils/skills-recommendation.d.ts +2 -0
  86. package/dist/schema/utils/skills-recommendation.js +76 -0
  87. package/dist/schema-query/index.d.ts +14 -1
  88. package/dist/schema-query/index.js +104 -2
  89. package/dist/schemas/account_operation.schema.json +1 -1
  90. package/dist/schemas/index.json +1 -1
  91. package/dist/schemas/onchain_events.output.json +1 -1
  92. package/dist/schemas/onchain_operations.output.json +2820 -0
  93. package/dist/schemas/onchain_operations.schema.json +115 -53
  94. package/dist/schemas/onchain_operations_allocation.schema.json +5 -5
  95. package/dist/schemas/onchain_operations_arbitration.schema.json +9 -7
  96. package/dist/schemas/onchain_operations_contact.schema.json +3 -3
  97. package/dist/schemas/onchain_operations_demand.schema.json +3 -3
  98. package/dist/schemas/onchain_operations_gen_passport.schema.json +2 -2
  99. package/dist/schemas/onchain_operations_guard.schema.json +1 -1
  100. package/dist/schemas/onchain_operations_machine.schema.json +4 -4
  101. package/dist/schemas/onchain_operations_order.schema.json +3 -3
  102. package/dist/schemas/onchain_operations_payment.schema.json +1 -1
  103. package/dist/schemas/onchain_operations_permission.schema.json +2 -2
  104. package/dist/schemas/onchain_operations_progress.schema.json +1 -1
  105. package/dist/schemas/onchain_operations_proof.schema.json +1 -1
  106. package/dist/schemas/onchain_operations_repository.schema.json +3 -3
  107. package/dist/schemas/onchain_operations_reward.schema.json +6 -6
  108. package/dist/schemas/onchain_operations_service.schema.json +77 -17
  109. package/dist/schemas/onchain_operations_treasury.schema.json +4 -4
  110. package/dist/schemas/onchain_table_data.output.json +1 -1
  111. package/dist/schemas/onchain_table_data.schema.json +10 -9
  112. package/dist/schemas/project_operation.output.json +1026 -7
  113. package/dist/schemas/project_operation.schema.json +46 -4
  114. package/dist/schemas/query_toolkit.output.json +15 -15
  115. package/dist/schemas/query_toolkit.schema.json +3 -3
  116. package/dist/schemas/schema_query.output.json +64 -1
  117. package/dist/schemas/schema_query.schema.json +3 -2
  118. package/dist/schemas/wowok_buildin_info.output.json +81 -8
  119. package/dist/schemas/wowok_buildin_info.schema.json +46 -2
  120. package/dist/tools/handlers/onchain.js +571 -6
  121. package/dist/tools/handlers/project.js +25 -2
  122. package/dist/tools/handlers/schema-query.js +24 -1
  123. package/dist/tools/index.d.ts +8 -0
  124. package/dist/tools/index.js +177 -6
  125. package/package.json +2 -2
@@ -0,0 +1,565 @@
1
+ function sanitizeMermaidLabel(text) {
2
+ if (/[<>"\[\]{}()|&]/.test(text)) {
3
+ return `"${text.replace(/"/g, "'")}"`;
4
+ }
5
+ return text;
6
+ }
7
+ const MACHINE_NODE_COLORS = {
8
+ entry: { fill: "#10b981", stroke: "#065f46" },
9
+ terminal: { fill: "#ef4444", stroke: "#991b1b" },
10
+ revision: { fill: "#f59e0b", stroke: "#92400e" },
11
+ normal: { fill: "#3b82f6", stroke: "#1e40af" },
12
+ };
13
+ function classifyMachineNode(nodeName, edges, entryNodes) {
14
+ const outEdges = edges.filter(e => e.from === nodeName);
15
+ if (outEdges.length === 0)
16
+ return "terminal";
17
+ const hasOutgoingToNode = outEdges.some(e => e.to !== "");
18
+ if (!hasOutgoingToNode)
19
+ return "terminal";
20
+ const isRevisionTarget = edges.some(e => e.to === nodeName && e.from === nodeName);
21
+ if (isRevisionTarget)
22
+ return "revision";
23
+ if (entryNodes.has(nodeName))
24
+ return "entry";
25
+ return "normal";
26
+ }
27
+ export function sanitizeMermaidNodeId(name) {
28
+ if (/[^a-zA-Z0-9_]/.test(name)) {
29
+ return `"${name}"`;
30
+ }
31
+ return name;
32
+ }
33
+ export function renderMachineMermaid(nodes, edges, options) {
34
+ const colored = options?.colored !== false;
35
+ const lines = ["stateDiagram-v2"];
36
+ if (colored) {
37
+ lines.push(" %% Color Legend (BehaviorTree.CPP-inspired workflow roles):");
38
+ lines.push(" %% green #10b981 - entry (start state, targeted by [*])");
39
+ lines.push(" %% red #ef4444 - terminal (end state, no outgoing edges)");
40
+ lines.push(" %% amber #f59e0b - revision (self-loop / revision cycle)");
41
+ lines.push(" %% blue #3b82f6 - normal (regular intermediate state)");
42
+ lines.push(" %% Priority: terminal > revision > entry > normal");
43
+ }
44
+ const nodesWithIncoming = new Set(edges.filter(e => e.from !== "").map(e => e.to));
45
+ const entryNodes = new Set();
46
+ for (const node of nodes) {
47
+ if (!nodesWithIncoming.has(node.name)) {
48
+ entryNodes.add(node.name);
49
+ }
50
+ }
51
+ const entryNodesList = nodes.filter(n => entryNodes.has(n.name));
52
+ for (const entry of entryNodesList) {
53
+ const entryEdges = edges.filter(e => e.from === "" && e.to === entry.name);
54
+ if (entryEdges.length > 0) {
55
+ for (const edge of entryEdges) {
56
+ for (const fwd of edge.forwards) {
57
+ const label = buildForwardLabel(fwd, edge.threshold);
58
+ lines.push(` [*] --> ${sanitizeMermaidNodeId(entry.name)}: ${sanitizeMermaidLabel(label)}`);
59
+ }
60
+ }
61
+ }
62
+ else {
63
+ lines.push(` [*] --> ${sanitizeMermaidNodeId(entry.name)}`);
64
+ }
65
+ }
66
+ for (const edge of edges) {
67
+ if (edge.from === "")
68
+ continue;
69
+ const fromId = sanitizeMermaidNodeId(edge.from);
70
+ const toId = edge.to === "" ? "[*]" : sanitizeMermaidNodeId(edge.to);
71
+ for (const fwd of edge.forwards) {
72
+ const label = buildForwardLabel(fwd, edge.threshold);
73
+ lines.push(` ${fromId} --> ${toId}: ${sanitizeMermaidLabel(label)}`);
74
+ }
75
+ }
76
+ for (const node of nodes) {
77
+ if (node.description) {
78
+ lines.push(` ${sanitizeMermaidNodeId(node.name)}: ${sanitizeMermaidLabel(node.description)}`);
79
+ }
80
+ }
81
+ if (colored) {
82
+ lines.push("");
83
+ lines.push(" %% Node colors (BehaviorTree.CPP-inspired workflow roles)");
84
+ for (const node of nodes) {
85
+ const category = classifyMachineNode(node.name, edges, entryNodes);
86
+ const color = MACHINE_NODE_COLORS[category];
87
+ lines.push(` style ${sanitizeMermaidNodeId(node.name)} fill:${color.fill},stroke:${color.stroke},color:#fff`);
88
+ }
89
+ }
90
+ return lines.join("\n");
91
+ }
92
+ function buildForwardLabel(fwd, threshold) {
93
+ let label = fwd.name;
94
+ const annotations = [];
95
+ if (threshold > 1) {
96
+ annotations.push(`threshold=${threshold}`);
97
+ }
98
+ if (fwd.guard) {
99
+ const shortGuard = fwd.guard.length > 10
100
+ ? `${fwd.guard.slice(0, 6)}…${fwd.guard.slice(-4)}`
101
+ : fwd.guard;
102
+ annotations.push(`guard=${shortGuard}`);
103
+ }
104
+ if (annotations.length > 0) {
105
+ label += ` (${annotations.join(", ")})`;
106
+ }
107
+ return label;
108
+ }
109
+ export function renderMachineTreeIndented(input) {
110
+ const { nodes, edges, machineName, machineAddress, published, paused } = input;
111
+ const lines = [];
112
+ lines.push("# Machine Workflow Definition");
113
+ lines.push("");
114
+ if (machineName) {
115
+ lines.push(`**Machine:** ${machineName}`);
116
+ }
117
+ if (machineAddress) {
118
+ lines.push(`**Address:** ${machineAddress}`);
119
+ }
120
+ lines.push(`**Total Nodes:** ${nodes.length}`);
121
+ lines.push(`**Total Edges:** ${edges.length}`);
122
+ if (published !== null && published !== undefined) {
123
+ lines.push(`**Published:** ${published}`);
124
+ }
125
+ if (paused !== null && paused !== undefined) {
126
+ lines.push(`**Paused:** ${paused}`);
127
+ }
128
+ lines.push("");
129
+ lines.push("## Topology (directed graph outline)");
130
+ lines.push("");
131
+ const entryEdges = edges.filter(e => e.from === "");
132
+ const regularEdges = edges.filter(e => e.from !== "");
133
+ for (const edge of entryEdges) {
134
+ const header = `- [*] --> ${edge.to} (threshold=${edge.threshold})`;
135
+ lines.push(header);
136
+ for (const fwd of edge.forwards) {
137
+ lines.push(` - forward: ${formatForwardInline(fwd)}`);
138
+ }
139
+ }
140
+ for (const edge of regularEdges) {
141
+ const isSelfLoop = edge.from === edge.to;
142
+ const annotation = isSelfLoop ? " # self-loop (revision cycle)" : "";
143
+ const toLabel = edge.to === "" ? "[*]" : edge.to;
144
+ const header = `- ${edge.from} --> ${toLabel} (threshold=${edge.threshold})${annotation}`;
145
+ lines.push(header);
146
+ for (const fwd of edge.forwards) {
147
+ lines.push(` - forward: ${formatForwardInline(fwd)}`);
148
+ }
149
+ }
150
+ const nodesWithDesc = nodes.filter(n => n.description);
151
+ if (nodesWithDesc.length > 0) {
152
+ lines.push("");
153
+ lines.push("## Node Descriptions");
154
+ lines.push("");
155
+ for (const node of nodes) {
156
+ if (node.description) {
157
+ lines.push(`- ${node.name}: ${node.description}`);
158
+ }
159
+ }
160
+ }
161
+ const incomingMap = new Map();
162
+ for (const edge of edges) {
163
+ if (!incomingMap.has(edge.to))
164
+ incomingMap.set(edge.to, []);
165
+ incomingMap.get(edge.to).push({
166
+ from: edge.from === "" ? "[*]" : edge.from,
167
+ forwards: edge.forwards.map(f => f.name),
168
+ });
169
+ }
170
+ if (incomingMap.size > 0) {
171
+ lines.push("");
172
+ lines.push("## Backrefs (incoming edges per node)");
173
+ lines.push("");
174
+ for (const node of nodes) {
175
+ const incoming = incomingMap.get(node.name);
176
+ if (!incoming || incoming.length === 0)
177
+ continue;
178
+ const parts = incoming.map(inc => {
179
+ const fwdStr = inc.forwards.length > 0 ? ` (${inc.forwards.join(", ")})` : "";
180
+ const selfLoop = inc.from === node.name ? " # self-loop" : "";
181
+ return `<- ${inc.from}${fwdStr}${selfLoop}`;
182
+ });
183
+ lines.push(`- ${node.name}: ${parts.join(", ")}`);
184
+ }
185
+ }
186
+ lines.push("");
187
+ lines.push("## JSON Definition");
188
+ lines.push("");
189
+ lines.push("```json");
190
+ lines.push(JSON.stringify({ nodes, edges }, null, 2));
191
+ lines.push("```");
192
+ return lines.join("\n");
193
+ }
194
+ function formatForwardInline(fwd) {
195
+ const parts = [`weight=${fwd.weight}`];
196
+ if (fwd.named_operator !== null && fwd.named_operator !== undefined) {
197
+ parts.push(`namedOperator='${fwd.named_operator}'`);
198
+ }
199
+ if (fwd.permission_index !== null && fwd.permission_index !== undefined) {
200
+ parts.push(`permissionIndex=${fwd.permission_index}`);
201
+ }
202
+ if (fwd.guard) {
203
+ parts.push(`guard=${fwd.guard}`);
204
+ }
205
+ if (fwd.retained_submission) {
206
+ const rsStr = Array.isArray(fwd.retained_submission)
207
+ ? `[${fwd.retained_submission.join(",")}]`
208
+ : String(fwd.retained_submission);
209
+ parts.push(`retained_submission=${rsStr}`);
210
+ }
211
+ return `${fwd.name} (${parts.join(", ")})`;
212
+ }
213
+ export function parseMachineTreeIndented(text) {
214
+ const errors = [];
215
+ const jsonMatch = text.match(/```json\s*\n([\s\S]*?)```/);
216
+ if (jsonMatch) {
217
+ try {
218
+ const data = JSON.parse(jsonMatch[1].trim());
219
+ if (data && typeof data === "object" && Array.isArray(data.nodes) && Array.isArray(data.edges)) {
220
+ return { success: true, data, errors: [] };
221
+ }
222
+ if (Array.isArray(data)) {
223
+ const { nodes, edges } = convertNodeArrayToGraph(data);
224
+ return { success: true, data: { nodes, edges }, errors: [] };
225
+ }
226
+ }
227
+ catch (e) {
228
+ errors.push(`JSON code block parse error: ${e.message}`);
229
+ }
230
+ }
231
+ const topologyMatch = text.match(/##\s*Topology[^\n]*\n([\s\S]*?)(?=\n##\s|$)/i);
232
+ if (!topologyMatch) {
233
+ return {
234
+ success: false,
235
+ errors: [
236
+ "No '## Topology' section found. " +
237
+ "Use the format produced by renderMachineTreeIndented() or a JSON code block.",
238
+ ],
239
+ };
240
+ }
241
+ const topologySection = topologyMatch[1];
242
+ const nodeNames = new Set();
243
+ const edges = [];
244
+ const edgeLines = topologySection.split("\n").filter(l => l.trim().startsWith("- "));
245
+ const pendingForwards = [];
246
+ let currentEdge = null;
247
+ for (const line of edgeLines) {
248
+ const trimmed = line.trim();
249
+ const isIndented = line.startsWith(" -");
250
+ if (isIndented) {
251
+ const fwdMatch = trimmed.match(/^-\s*forward:\s*(.+)$/);
252
+ if (fwdMatch && currentEdge) {
253
+ const fwd = parseForwardInline(fwdMatch[1]);
254
+ if (fwd) {
255
+ currentEdge.forwards.push(fwd);
256
+ }
257
+ }
258
+ continue;
259
+ }
260
+ const edgeMatch = trimmed.match(/^-\s+(.+?)\s+-->\s+(\S+)(?:\s+\(threshold=(\d+)\))?(.*)$/);
261
+ if (edgeMatch) {
262
+ if (currentEdge) {
263
+ edges.push(currentEdge);
264
+ }
265
+ const fromRaw = edgeMatch[1].trim();
266
+ const to = edgeMatch[2].trim();
267
+ const threshold = edgeMatch[3] ? parseInt(edgeMatch[3], 10) : 1;
268
+ const from = fromRaw === "[*]" ? "" : fromRaw;
269
+ currentEdge = {
270
+ from,
271
+ to,
272
+ threshold,
273
+ forwards: [],
274
+ };
275
+ nodeNames.add(to);
276
+ if (from)
277
+ nodeNames.add(from);
278
+ }
279
+ }
280
+ if (currentEdge) {
281
+ edges.push(currentEdge);
282
+ }
283
+ if (edges.length === 0) {
284
+ return {
285
+ success: false,
286
+ errors: ["No edges found in '## Topology' section. Expected lines like '- A --> B (threshold=1)'."],
287
+ };
288
+ }
289
+ const descMatch = text.match(/##\s*Node Descriptions[^\n]*\n([\s\S]*?)(?=\n##\s|$)/i);
290
+ const nodeDescMap = new Map();
291
+ if (descMatch) {
292
+ const descLines = descMatch[1].split("\n");
293
+ for (const line of descLines) {
294
+ const m = line.match(/^-\s+(\S+):\s*(.+)$/);
295
+ if (m) {
296
+ nodeDescMap.set(m[1], m[2]);
297
+ }
298
+ }
299
+ }
300
+ const nodes = [];
301
+ for (const name of nodeNames) {
302
+ nodes.push({
303
+ name,
304
+ description: nodeDescMap.get(name) ?? null,
305
+ });
306
+ }
307
+ return { success: true, data: { nodes, edges }, errors };
308
+ }
309
+ function parseForwardInline(text) {
310
+ const match = text.match(/^(\S+)\s*\(([^)]*)\)$/);
311
+ if (!match) {
312
+ return {
313
+ name: text.trim(),
314
+ weight: 1,
315
+ named_operator: null,
316
+ permission_index: null,
317
+ guard: null,
318
+ retained_submission: null,
319
+ };
320
+ }
321
+ const name = match[1];
322
+ const annotationStr = match[2];
323
+ const fwd = {
324
+ name,
325
+ weight: 1,
326
+ named_operator: null,
327
+ permission_index: null,
328
+ guard: null,
329
+ retained_submission: null,
330
+ };
331
+ for (const part of annotationStr.split(",").map(s => s.trim())) {
332
+ if (!part)
333
+ continue;
334
+ const [key, ...valParts] = part.split("=");
335
+ const val = valParts.join("=").trim();
336
+ switch (key.trim()) {
337
+ case "weight":
338
+ fwd.weight = parseInt(val, 10) || 1;
339
+ break;
340
+ case "namedOperator":
341
+ fwd.named_operator = val.replace(/^'|'$/g, "");
342
+ break;
343
+ case "permissionIndex":
344
+ fwd.permission_index = parseInt(val, 10) || null;
345
+ break;
346
+ case "guard":
347
+ fwd.guard = val || null;
348
+ break;
349
+ case "retained_submission":
350
+ if (val.startsWith("[") && val.endsWith("]")) {
351
+ fwd.retained_submission = val
352
+ .slice(1, -1)
353
+ .split(",")
354
+ .map(s => parseInt(s.trim(), 10))
355
+ .filter(n => !isNaN(n));
356
+ }
357
+ else {
358
+ fwd.retained_submission = val;
359
+ }
360
+ break;
361
+ }
362
+ }
363
+ return fwd;
364
+ }
365
+ function convertNodeArrayToGraph(data) {
366
+ const nodes = [];
367
+ const edges = [];
368
+ for (const item of data) {
369
+ if (!item || typeof item !== "object")
370
+ continue;
371
+ const node = item;
372
+ const name = typeof node.name === "string" ? node.name : "";
373
+ if (!name)
374
+ continue;
375
+ nodes.push({
376
+ name,
377
+ description: typeof node.description === "string" ? node.description : null,
378
+ });
379
+ const pairs = Array.isArray(node.pairs) ? node.pairs : [];
380
+ for (const pairRaw of pairs) {
381
+ if (!pairRaw || typeof pairRaw !== "object")
382
+ continue;
383
+ const pair = pairRaw;
384
+ const prevNode = typeof pair.prev_node === "string" ? pair.prev_node : "";
385
+ const threshold = typeof pair.threshold === "number" ? pair.threshold : 1;
386
+ const forwardsRaw = Array.isArray(pair.forwards) ? pair.forwards : [];
387
+ const forwards = forwardsRaw.map((f) => {
388
+ const fwd = f;
389
+ return {
390
+ name: typeof fwd.name === "string" ? fwd.name : "",
391
+ weight: typeof fwd.weight === "number" ? fwd.weight : 1,
392
+ named_operator: typeof fwd.namedOperator === "string" ? fwd.namedOperator : null,
393
+ permission_index: typeof fwd.permissionIndex === "number" ? fwd.permissionIndex : null,
394
+ guard: typeof fwd.guard === "string"
395
+ ? fwd.guard
396
+ : (fwd.guard && typeof fwd.guard.guard === "string")
397
+ ? fwd.guard.guard
398
+ : null,
399
+ retained_submission: null,
400
+ };
401
+ });
402
+ edges.push({
403
+ from: prevNode,
404
+ to: name,
405
+ threshold,
406
+ forwards,
407
+ });
408
+ }
409
+ }
410
+ return { nodes, edges };
411
+ }
412
+ export function renderMachineAscii(input) {
413
+ const { nodes, edges, machineName, machineAddress, published, paused } = input;
414
+ const lines = [];
415
+ if (machineName) {
416
+ lines.push(`Machine: ${machineName}`);
417
+ }
418
+ if (machineAddress) {
419
+ lines.push(`Address: ${machineAddress}`);
420
+ }
421
+ if (published !== null && published !== undefined) {
422
+ lines.push(`Published: ${published}`);
423
+ }
424
+ if (paused !== null && paused !== undefined) {
425
+ lines.push(`Paused: ${paused}`);
426
+ }
427
+ if (machineName || machineAddress) {
428
+ lines.push("");
429
+ }
430
+ const outgoingMap = new Map();
431
+ for (const edge of edges) {
432
+ if (edge.from === "")
433
+ continue;
434
+ if (!outgoingMap.has(edge.from))
435
+ outgoingMap.set(edge.from, []);
436
+ outgoingMap.get(edge.from).push(edge);
437
+ }
438
+ const terminalNodes = new Set();
439
+ for (const node of nodes) {
440
+ const outEdges = outgoingMap.get(node.name) ?? [];
441
+ const hasOutgoingToNode = outEdges.some(e => e.to !== "");
442
+ if (!hasOutgoingToNode) {
443
+ const isTargeted = edges.some(e => e.to === node.name);
444
+ if (isTargeted) {
445
+ terminalNodes.add(node.name);
446
+ }
447
+ }
448
+ }
449
+ const entryNodes = new Set();
450
+ for (const edge of edges) {
451
+ if (edge.from === "") {
452
+ entryNodes.add(edge.to);
453
+ }
454
+ }
455
+ const revisionNodes = new Set();
456
+ for (const edge of edges) {
457
+ if (edge.from === edge.to && edge.from !== "") {
458
+ revisionNodes.add(edge.from);
459
+ }
460
+ }
461
+ for (const edge of edges) {
462
+ const fromLabel = edge.from === "" ? "[*]" : edge.from;
463
+ const toLabel = edge.to === "" ? "[*]" : edge.to;
464
+ const isCycle = edge.from === edge.to && edge.from !== "";
465
+ for (const fwd of edge.forwards) {
466
+ const annotations = [];
467
+ if (isCycle)
468
+ annotations.push("cycle");
469
+ if (fwd.guard)
470
+ annotations.push(`guard=${fwd.guard}`);
471
+ if (fwd.named_operator !== null && fwd.named_operator !== undefined && fwd.named_operator !== "") {
472
+ annotations.push(`op=${fwd.named_operator}`);
473
+ }
474
+ if (fwd.permission_index !== null && fwd.permission_index !== undefined) {
475
+ annotations.push(`perm=${fwd.permission_index}`);
476
+ }
477
+ if (edge.threshold > 1)
478
+ annotations.push(`threshold=${edge.threshold}`);
479
+ const annotationStr = annotations.length > 0 ? ` [${annotations.join(", ")}]` : "";
480
+ const cycleStr = isCycle ? " ⟲" : "";
481
+ lines.push(`${fromLabel} ─${fwd.name}→ ${toLabel}${cycleStr}${annotationStr}`);
482
+ }
483
+ }
484
+ const annotatedNodes = [];
485
+ for (const node of nodes) {
486
+ const annotations = [];
487
+ if (entryNodes.has(node.name))
488
+ annotations.push("entry");
489
+ if (terminalNodes.has(node.name))
490
+ annotations.push("terminal");
491
+ if (revisionNodes.has(node.name))
492
+ annotations.push("revision");
493
+ if (annotations.length > 0) {
494
+ annotatedNodes.push(` ${node.name}: ${annotations.join(", ")}`);
495
+ }
496
+ }
497
+ if (annotatedNodes.length > 0) {
498
+ lines.push("");
499
+ lines.push("Node roles:");
500
+ lines.push(...annotatedNodes);
501
+ }
502
+ return lines.join("\n");
503
+ }
504
+ export function renderMachineMarkmap(input) {
505
+ const { nodes, edges, machineName, machineAddress, published, paused } = input;
506
+ const lines = [];
507
+ const titleParts = ["Machine"];
508
+ if (machineName)
509
+ titleParts.push(machineName);
510
+ lines.push(`# ${titleParts.join(": ")}`);
511
+ if (machineAddress || published !== null || paused !== null) {
512
+ lines.push("");
513
+ if (machineAddress)
514
+ lines.push(`**Address:** ${machineAddress}`);
515
+ if (published !== null && published !== undefined)
516
+ lines.push(`**Published:** ${published}`);
517
+ if (paused !== null && paused !== undefined)
518
+ lines.push(`**Paused:** ${paused}`);
519
+ }
520
+ lines.push("");
521
+ const outgoingMap = new Map();
522
+ for (const edge of edges) {
523
+ if (edge.from === "")
524
+ continue;
525
+ if (!outgoingMap.has(edge.from))
526
+ outgoingMap.set(edge.from, []);
527
+ outgoingMap.get(edge.from).push(edge);
528
+ }
529
+ const terminalNodes = new Set();
530
+ for (const node of nodes) {
531
+ const outEdges = outgoingMap.get(node.name) ?? [];
532
+ const hasOutgoingToNode = outEdges.some(e => e.to !== "");
533
+ if (!hasOutgoingToNode) {
534
+ const isTargeted = edges.some(e => e.to === node.name);
535
+ if (isTargeted)
536
+ terminalNodes.add(node.name);
537
+ }
538
+ }
539
+ for (const edge of edges) {
540
+ const fromLabel = edge.from === "" ? "[*]" : edge.from;
541
+ const toLabel = edge.to === "" ? "[*]" : edge.to;
542
+ const isCycle = edge.from === edge.to && edge.from !== "";
543
+ const cycleStr = isCycle ? " (cycle)" : "";
544
+ const terminalStr = terminalNodes.has(edge.to) ? " (terminal)" : "";
545
+ lines.push(`## ${fromLabel} → ${toLabel}${cycleStr}${terminalStr}`);
546
+ for (const fwd of edge.forwards) {
547
+ const parts = [`weight=${fwd.weight}`];
548
+ if (fwd.named_operator !== null && fwd.named_operator !== undefined) {
549
+ parts.push(`namedOperator='${fwd.named_operator}'`);
550
+ }
551
+ if (fwd.permission_index !== null && fwd.permission_index !== undefined) {
552
+ parts.push(`permissionIndex=${fwd.permission_index}`);
553
+ }
554
+ if (fwd.guard) {
555
+ parts.push(`guard=${fwd.guard}`);
556
+ }
557
+ if (edge.threshold > 1) {
558
+ parts.push(`threshold=${edge.threshold}`);
559
+ }
560
+ lines.push(`### forward: ${fwd.name} (${parts.join(", ")})`);
561
+ }
562
+ lines.push("");
563
+ }
564
+ return lines.join("\n");
565
+ }
@@ -1016,7 +1016,7 @@ export const MACHINE_TEMPLATES = [
1016
1016
  type: "string",
1017
1017
  required: true,
1018
1018
  default: "wonder",
1019
- description: "Node name for positive feedback (好评) terminal",
1019
+ description: "Node name for positive feedback (praise) terminal",
1020
1020
  constraint: "Must match /^(wonder|praise|thumbs_up)$/i OR be a custom name; must NOT match dispute anti-pattern regex",
1021
1021
  },
1022
1022
  {
@@ -1024,7 +1024,7 @@ export const MACHINE_TEMPLATES = [
1024
1024
  type: "string",
1025
1025
  required: true,
1026
1026
  default: "no_wonder",
1027
- description: "Node name for negative feedback (差评) terminal",
1027
+ description: "Node name for negative feedback (complaint) terminal",
1028
1028
  constraint: "Must match /^(no_wonder|complain|thumbs_down)$/i OR be a custom name; must NOT match dispute anti-pattern regex",
1029
1029
  },
1030
1030
  {
@@ -1047,8 +1047,8 @@ export const MACHINE_TEMPLATES = [
1047
1047
  { name: "Shipped", description: "Merchant dispatched goods/service" },
1048
1048
  { name: "Received", description: "Customer confirmed receipt" },
1049
1049
  { name: "Completed", description: "Terminal business state — triggers merchant Allocation. Funds settled." },
1050
- { name: "${wonder_node_name}", description: "Positive feedback terminal (好评). OrderHolder-only. Reward-eligible." },
1051
- { name: "${no_wonder_node_name}", description: "Negative feedback terminal (差评). OrderHolder-only. Optional Repository write for analytics." },
1050
+ { name: "${wonder_node_name}", description: "Positive feedback terminal (praise). OrderHolder-only. Reward-eligible." },
1051
+ { name: "${no_wonder_node_name}", description: "Negative feedback terminal (complaint). OrderHolder-only. Optional Repository write for analytics." },
1052
1052
  ],
1053
1053
  example_pairs: [
1054
1054
  {
@@ -137,7 +137,7 @@ function runStaticChecklist(input) {
137
137
  const cr11 = items.find(i => i.id === "C-R-11");
138
138
  if (data.guard_expected_progress_state && input.user_intent_phrases && input.user_intent_phrases.length > 0) {
139
139
  const intentLower = input.user_intent_phrases.join(" ").toLowerCase();
140
- const praiseKeywords = ["好评", "praise", "wonder", "thumbs_up", "positive review", "satisfaction reward", "好评奖励"];
140
+ const praiseKeywords = ["praise", "wonder", "thumbs_up", "positive review", "satisfaction reward", "praise reward"];
141
141
  const isPraiseIntent = praiseKeywords.some(kw => intentLower.includes(kw.toLowerCase()));
142
142
  if (isPraiseIntent && input.machine_has_wonder_node !== false && data.guard_expected_progress_state !== "wonder") {
143
143
  cr11.passed = false;
@@ -224,7 +224,7 @@ export const REWARD_CONFIRMATION_QUESTIONS = [
224
224
  {
225
225
  id: "QRW7",
226
226
  question: "⚠️ For guard_add with progress.current check: does the Guard's expected progress node match the business intent? " +
227
- "If intent is '好评/praise', Guard must check 'wonder' (NOT 'completed'). " +
227
+ "If intent is 'praise/positive review', Guard must check 'wonder' (NOT 'completed'). " +
228
228
  "Premature claim at wrong node drains reward pool — Guard is immutable after creation.",
229
229
  requires_explicit_yes: true,
230
230
  related_risk_ids: ["R-R-6-01", "R-R-6-02"],
@@ -184,7 +184,7 @@ export function validateConstraints(puzzle) {
184
184
  constraint_id: "F-R-09",
185
185
  severity: "HIGH",
186
186
  message: "Guard's expected progress.current value does not match business intent — " +
187
- "praise reward (好评/wonder) must check 'wonder' node, not 'completed'. " +
187
+ "praise reward (praise/wonder) must check 'wonder' node, not 'completed'. " +
188
188
  "Guard is immutable after creation; mismatch requires full rebuild.",
189
189
  });
190
190
  }
@@ -472,7 +472,7 @@ const R_R_5_03 = {
472
472
  const R_R_6_01 = {
473
473
  id: "R-R-6-01",
474
474
  category: "business_semantic",
475
- trigger: "intent mentions praise/好评 but Guard checks non-wonder progress node",
475
+ trigger: "intent mentions praise/positive-review but Guard checks non-wonder progress node",
476
476
  check: (ctx) => {
477
477
  if (!ctx.user_intent_phrases || ctx.user_intent_phrases.length === 0)
478
478
  return null;
@@ -480,8 +480,8 @@ const R_R_6_01 = {
480
480
  return null;
481
481
  const intentLower = ctx.user_intent_phrases.join(" ").toLowerCase();
482
482
  const praiseKeywords = [
483
- "好评", "praise", "wonder", "thumbs_up",
484
- "positive review", "satisfaction reward", "好评奖励",
483
+ "praise", "wonder", "thumbs_up",
484
+ "positive review", "satisfaction reward", "praise reward",
485
485
  ];
486
486
  const isPraiseIntent = praiseKeywords.some(kw => intentLower.includes(kw.toLowerCase()));
487
487
  if (!isPraiseIntent)
@@ -495,10 +495,10 @@ const R_R_6_01 = {
495
495
  level: "HIGH",
496
496
  category: "business_semantic",
497
497
  title: `Guard checks progress=="${expected}" but intent indicates praise reward (wonder node)`,
498
- description: `User intent mentions praise/好评/wonder, which maps to the 'wonder' progress node ` +
498
+ description: `User intent mentions praise/positive-review/wonder, which maps to the 'wonder' progress node ` +
499
499
  `(customer gives positive review AFTER service completion). But the Guard's table bakes ` +
500
500
  `expected state="${expected}", allowing reward claim at the wrong lifecycle stage. ` +
501
- `This violates the business semantics: "好评奖励" should only be claimable AFTER the ` +
501
+ `This violates the business semantics: "praise reward" should only be claimable AFTER the ` +
502
502
  `customer advances to the 'wonder' node, not before. ` +
503
503
  `Guard is immutable — fixing this requires creating a new Guard + Reward pair.`,
504
504
  affected_stakeholders: ["owner", "service_provider", "claimer"],
@@ -526,8 +526,8 @@ const R_R_6_02 = {
526
526
  return null;
527
527
  const intentLower = ctx.user_intent_phrases.join(" ").toLowerCase();
528
528
  const praiseKeywords = [
529
- "好评", "praise", "wonder", "thumbs_up",
530
- "positive review", "satisfaction reward", "好评奖励",
529
+ "praise", "wonder", "thumbs_up",
530
+ "positive review", "satisfaction reward", "praise reward",
531
531
  ];
532
532
  const isPraiseIntent = praiseKeywords.some(kw => intentLower.includes(kw.toLowerCase()));
533
533
  if (isPraiseIntent)
@@ -538,12 +538,12 @@ const R_R_6_02 = {
538
538
  category: "business_semantic",
539
539
  title: "Guard checks wonder node but intent does not mention praise",
540
540
  description: `Guard's expected progress state is "wonder" (positive-review node), but the user intent ` +
541
- `does not mention any praise/好评 keyword. This may be a copy-paste from a wonder_praise ` +
541
+ `does not mention any praise/positive-review keyword. This may be a copy-paste from a wonder_praise ` +
542
542
  `template without adjusting the Guard for the actual business semantics. If this is a ` +
543
543
  `general feedback reward (wonder_feedback), this is fine. Otherwise, verify the node choice.`,
544
544
  affected_stakeholders: ["owner"],
545
545
  scenario: "Designer copies wonder_praise template but actually wants a completion-based reward",
546
- mitigation: "Verify: if intent is praise reward, add '好评/praise' to description. " +
546
+ mitigation: "Verify: if intent is praise reward, add 'praise/positive review' to description. " +
547
547
  "If intent is completion-based reward, change Guard to check 'completed' node.",
548
548
  evidence: `expected_state="wonder", intent="${intentLower}" (no praise keyword)`,
549
549
  auto_fixable: false,