@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
@@ -1,10 +1,247 @@
1
1
  import { readFileSync } from "fs";
2
2
  import { resolve } from "path";
3
- import { CallService, CallMachine, CallProgress, CallGuard, CallArbitration, CallRepository, CallContact, CallTreasury, CallReward, CallAllocation, CallPersonal, CallPayment, CallDemand, CallOrder, gen_passport, CallProof, gen_proof, ResponseData, LocalProject, parseGuardFile, formatGuardParseErrors, transformRewardInput, transformPersonalInput, } from "@wowok/wowok";
3
+ import { CallService, CallMachine, CallProgress, CallGuard, CallArbitration, CallRepository, CallContact, CallTreasury, CallReward, CallAllocation, CallPersonal, CallPayment, CallDemand, CallOrder, gen_passport, CallProof, gen_proof, ResponseData, LocalProject, LocalMark, query_objects, parseGuardFile, formatGuardParseErrors, transformRewardInput, transformPersonalInput, } from "@wowok/wowok";
4
4
  import { OnchainOperationsSchema, strictParse, getEnvConfig, handleCallResult, checkClientSchemaCompatibility, parseMachineNodesFromText, formatNodeErrors as formatMachineNodeErrors, transformSubmission, } from "../../schema/index.js";
5
5
  import { handlePermissionOperations } from "../../schema/call/permission-handler.js";
6
+ import { collectPermissionIndexes, checkPermissionAuthorization, formatPermissionWarning, } from "../../schema/utils/permission-machine-check.js";
6
7
  import { isProjectServiceEnabled, normalize as projectNormalize, } from "../../project/index.js";
8
+ import { getSkillsHintForOnchain } from "../../schema/utils/skills-recommendation.js";
9
+ import { processFundOperation, generateSkillsHint as generateFundSkillsHint } from "../../knowledge/fund-layer.js";
10
+ import { generateGuardSubmissionPrompt, formatSubmissionPrompt } from "../../knowledge/guard-submission-prompt.js";
7
11
  import { withHarness } from "../shared.js";
12
+ function formatRecipientLabel(recipient) {
13
+ if (!recipient)
14
+ return "unknown";
15
+ if (typeof recipient === "string")
16
+ return recipient;
17
+ if ("GuardIdentifier" in recipient) {
18
+ return `GuardIdentifier(${recipient.GuardIdentifier})`;
19
+ }
20
+ if ("Entity" in recipient) {
21
+ const addr = recipient.Entity;
22
+ if (typeof addr === "string" && addr.length > 16) {
23
+ return `Entity(${addr.slice(0, 8)}...${addr.slice(-4)})`;
24
+ }
25
+ return `Entity(${addr})`;
26
+ }
27
+ if ("Signer" in recipient) {
28
+ return "Signer (transaction signer)";
29
+ }
30
+ return JSON.stringify(recipient);
31
+ }
32
+ function formatMistAmount(amount) {
33
+ const wowEquivalent = Number(amount) / 1_000_000_000;
34
+ if (wowEquivalent === 0)
35
+ return "0 WOW";
36
+ const wowStr = wowEquivalent.toFixed(9).replace(/\.?0+$/, "");
37
+ return `${wowStr} WOW (${amount.toString()} MIST)`;
38
+ }
39
+ function extractNodesForCheck(data) {
40
+ if (!data?.node)
41
+ return [];
42
+ if (data.node.nodes && Array.isArray(data.node.nodes)) {
43
+ return data.node.nodes;
44
+ }
45
+ return [];
46
+ }
47
+ function resolvePermissionRef(data) {
48
+ if (!data?.object)
49
+ return null;
50
+ if (typeof data.object === "string")
51
+ return null;
52
+ const obj = data.object;
53
+ if (obj.permission) {
54
+ if (typeof obj.permission === "string")
55
+ return obj.permission;
56
+ return null;
57
+ }
58
+ return null;
59
+ }
60
+ async function checkMachinePermissionBeforePublish(data, env) {
61
+ if (data?.publish !== true)
62
+ return "";
63
+ const nodes = extractNodesForCheck(data);
64
+ if (nodes.length === 0)
65
+ return "";
66
+ const collection = collectPermissionIndexes(nodes);
67
+ if (collection.requiredIndexes.length === 0) {
68
+ return "";
69
+ }
70
+ let warning = "";
71
+ if (collection.missingRefs.length > 0) {
72
+ warning += "WARNING: Some forwards have NEITHER permissionIndex nor namedOperator. " +
73
+ "These forwards cannot be executed. Add one or the other:\n";
74
+ for (const ref of collection.missingRefs) {
75
+ warning += ` - Node "${ref.nodeName}", pair prev_node="${ref.prevNode}", forward "${ref.forwardName}"\n`;
76
+ }
77
+ warning += "\n";
78
+ }
79
+ const permRef = resolvePermissionRef(data);
80
+ if (!permRef) {
81
+ if (collection.requiredIndexes.length > 0) {
82
+ warning += "PRE-PUBLISH REMINDER: This Machine uses " + collection.requiredIndexes.length +
83
+ " custom permission index(es): [" + collection.requiredIndexes.join(", ") + "]. " +
84
+ "After creating the Permission object, grant entities for each index via " +
85
+ 'permission.op="add perm by index" BEFORE publishing the Machine. ' +
86
+ "Otherwise, forwards using these indexes will be un-executable.\n";
87
+ }
88
+ return warning;
89
+ }
90
+ let permAddress = permRef;
91
+ if (!permRef.startsWith("0x")) {
92
+ try {
93
+ const mark = await LocalMark.Instance().get(permRef);
94
+ if (mark?.address) {
95
+ permAddress = mark.address;
96
+ }
97
+ else {
98
+ return warning + "PRE-PUBLISH: Could not resolve Permission name '" + permRef +
99
+ "' to an address. Ensure the Permission object exists and is marked. " +
100
+ "Required indexes: [" + collection.requiredIndexes.join(", ") + "]\n";
101
+ }
102
+ }
103
+ catch {
104
+ return warning + "PRE-PUBLISH: Failed to lookup Permission name '" + permRef +
105
+ "'. Required indexes: [" + collection.requiredIndexes.join(", ") + "]\n";
106
+ }
107
+ }
108
+ const network = env?.network ?? "testnet";
109
+ let permData = null;
110
+ try {
111
+ const queryResult = await query_objects({
112
+ objects: [permAddress],
113
+ network: network,
114
+ });
115
+ const permObj = queryResult?.objects?.[0];
116
+ if (permObj) {
117
+ permData = {
118
+ address: permAddress,
119
+ entity_count: permObj.entity_count,
120
+ perm_remark: permObj.perm_remark,
121
+ owner: permObj.owner ?? permObj.builder,
122
+ admin: permObj.admin,
123
+ };
124
+ }
125
+ }
126
+ catch {
127
+ return warning + "PRE-PUBLISH: Failed to query Permission object " + permAddress +
128
+ ". Required indexes: [" + collection.requiredIndexes.join(", ") + "]\n";
129
+ }
130
+ if (!permData) {
131
+ return warning + "PRE-PUBLISH: Permission object " + permAddress +
132
+ " not found on-chain. Required indexes: [" + collection.requiredIndexes.join(", ") + "]\n";
133
+ }
134
+ const report = checkPermissionAuthorization(collection.requiredIndexes, permData);
135
+ if (!report.allAuthorized) {
136
+ warning += formatPermissionWarning(report) + "\n";
137
+ }
138
+ return warning;
139
+ }
140
+ async function detectServiceGuardCircularDependency(data) {
141
+ if (!data || typeof data.object !== "object" || data.object === null)
142
+ return null;
143
+ const orderAllocators = data.order_allocators;
144
+ if (!orderAllocators || typeof orderAllocators !== "object")
145
+ return null;
146
+ const allocators = Array.isArray(orderAllocators.allocators)
147
+ ? orderAllocators.allocators
148
+ : [];
149
+ if (allocators.length === 0)
150
+ return null;
151
+ const unresolvedGuards = [];
152
+ const seen = new Set();
153
+ for (const alloc of allocators) {
154
+ const guardRef = alloc?.guard;
155
+ if (typeof guardRef === "string" && !guardRef.startsWith("0x")) {
156
+ if (seen.has(guardRef))
157
+ continue;
158
+ seen.add(guardRef);
159
+ try {
160
+ const addr = await LocalMark.Instance().get_address(guardRef);
161
+ if (!addr) {
162
+ unresolvedGuards.push(guardRef);
163
+ }
164
+ }
165
+ catch {
166
+ unresolvedGuards.push(guardRef);
167
+ }
168
+ }
169
+ }
170
+ if (unresolvedGuards.length === 0)
171
+ return null;
172
+ const guardList = unresolvedGuards.map(g => `'${g}'`).join(", ");
173
+ const serviceObj = data.object;
174
+ const serviceName = serviceObj.name ?? "<service_name>";
175
+ const recommended_steps = [
176
+ {
177
+ step: 1,
178
+ action: "onchain_operations",
179
+ operation_type: "service",
180
+ params: {
181
+ ...data,
182
+ order_allocators: null,
183
+ publish: false,
184
+ },
185
+ purpose: `Create Service '${serviceName}' WITHOUT order_allocators to establish ` +
186
+ `its LocalMark entry. After this step, the name '${serviceName}' resolves ` +
187
+ `to an on-chain address.`,
188
+ },
189
+ {
190
+ step: 2,
191
+ action: "onchain_operations",
192
+ operation_type: "guard",
193
+ params: unresolvedGuards.map(name => ({
194
+ object: { name, type: "Guard" },
195
+ _hint: `Table items may reference Service '${serviceName}' by name`,
196
+ })),
197
+ purpose: `Create Guard(s) ${guardList}. Their table items can now resolve ` +
198
+ `Service '${serviceName}' by name (LocalMark entry from step 1).`,
199
+ },
200
+ {
201
+ step: 3,
202
+ action: "onchain_operations",
203
+ operation_type: "service",
204
+ params: {
205
+ object: serviceName,
206
+ order_allocators: orderAllocators,
207
+ publish: data.publish ?? true,
208
+ },
209
+ purpose: "Update Service with order_allocators (referencing Guards created in " +
210
+ "step 2) and publish. After publish, order_allocators becomes SDK-LOCKED.",
211
+ },
212
+ ];
213
+ const guideText = `⚠️ Circular dependency detected: Service ↔ Guard\n\n` +
214
+ `Cannot create Service with order_allocators referencing non-existent Guard(s): ${guardList}.\n\n` +
215
+ `Explanation: Guard table items may reference the Service by name, creating a circular ` +
216
+ `dependency: the Service must exist as a LocalMark before the Guard can resolve it, ` +
217
+ `but the Guard must exist before the Service can reference it in order_allocators. ` +
218
+ `The SDK would fail with a BCS serialization error: "Expected valid Address for ` +
219
+ `ValueType.Address, but failed to resolve string: <name>".\n\n` +
220
+ `Recommended steps:\n` +
221
+ recommended_steps
222
+ .map(s => ` Step ${s.step} (${s.operation_type}): ${s.purpose}`)
223
+ .join("\n") +
224
+ `\n\nHint: This is the canonical Service↔Guard circular dependency. The 3-step ` +
225
+ `pattern above is the documented solution (see SCHEMA-03 / P0-01 fix in ` +
226
+ `schema/call/service.ts publish field description).`;
227
+ return {
228
+ content: [{
229
+ type: "text",
230
+ text: guideText,
231
+ }],
232
+ structuredContent: {
233
+ result: {
234
+ type: "error",
235
+ error: `Cannot create Service with order_allocators referencing non-existent Guard(s): ${guardList}. Circular dependency: Service↔Guard.`,
236
+ error_code: "circular_dependency_detected",
237
+ retryable: true,
238
+ recovery_hint: JSON.stringify(recommended_steps),
239
+ related_object: serviceName,
240
+ },
241
+ message: "Circular dependency detected: Service ↔ Guard. See recovery_hint for the 3-step creation pattern.",
242
+ },
243
+ };
244
+ }
8
245
  export async function handleOnchainOperations(args) {
9
246
  let validated;
10
247
  let constraintWarnings = [];
@@ -34,12 +271,19 @@ export async function handleOnchainOperations(args) {
34
271
  const rData = ResponseData(result);
35
272
  const created = rData.filter((r) => r.change === "created" && r.object);
36
273
  for (const obj of created) {
274
+ const isService = !!(obj.type_raw && obj.type_raw.includes("service::Service"));
37
275
  await lp.addObject(project.id, {
38
276
  objectAddress: obj.object,
39
277
  objectType: obj.type_raw,
40
- role: "reference",
278
+ role: isService ? "core" : "reference",
41
279
  });
42
280
  }
281
+ if (operationType === "service") {
282
+ const svc = created.find((o) => o.type_raw && o.type_raw.includes("service::Service"));
283
+ if (svc && svc.object) {
284
+ await lp.updateProject(project.id, { serviceAddress: svc.object }).catch(() => { });
285
+ }
286
+ }
43
287
  }
44
288
  catch {
45
289
  }
@@ -95,13 +339,96 @@ export async function handleOnchainOperations(args) {
95
339
  delete env.project;
96
340
  delete env.client_schema_version;
97
341
  delete env.schema_strict_mode;
342
+ const skillsHint = getSkillsHintForOnchain(validated.operation_type, validated.data);
343
+ if (skillsHint) {
344
+ constraintWarnings.push(skillsHint);
345
+ }
98
346
  switch (validated.operation_type) {
99
347
  case "service": {
100
- const callService = new CallService(validated.data);
101
- const result = validated.submission
102
- ? await callService.call_with_submission(env, await transformSubmission(validated.submission))
103
- : await callService.call(env);
104
348
  const data = validated.data;
349
+ const circularDepGuide = await detectServiceGuardCircularDependency(data);
350
+ if (circularDepGuide) {
351
+ return circularDepGuide;
352
+ }
353
+ const fundResult = await processFundOperation(data, "service", env?.network);
354
+ constraintWarnings.push(...fundResult.warnings);
355
+ if (fundResult.confirmation) {
356
+ constraintWarnings.push(fundResult.confirmation.message);
357
+ const fundHint = generateFundSkillsHint(fundResult.confirmation);
358
+ if (fundHint)
359
+ constraintWarnings.push(fundHint);
360
+ }
361
+ const orderAllocators = data?.order_allocators;
362
+ if (orderAllocators && typeof orderAllocators === "object") {
363
+ const allocators = Array.isArray(orderAllocators.allocators)
364
+ ? orderAllocators.allocators : [];
365
+ for (let i = 0; i < allocators.length; i++) {
366
+ const alloc = allocators[i];
367
+ const sharing = Array.isArray(alloc?.sharing) ? alloc.sharing : [];
368
+ if (sharing.length <= 1)
369
+ continue;
370
+ const seen = new Map();
371
+ for (let j = 0; j < sharing.length; j++) {
372
+ const who = sharing[j]?.who;
373
+ let key = "";
374
+ if (typeof who === "string") {
375
+ key = who;
376
+ }
377
+ else if (who && typeof who === "object") {
378
+ if (who.Entity && typeof who.Entity === "object") {
379
+ key = "Entity:" + (who.Entity.name_or_address ?? "");
380
+ }
381
+ else if (who.Signer) {
382
+ key = "Signer";
383
+ }
384
+ else if (who.GuardIdentifier !== undefined) {
385
+ key = "Guard:" + who.GuardIdentifier;
386
+ }
387
+ else {
388
+ key = JSON.stringify(who);
389
+ }
390
+ }
391
+ if (!key)
392
+ continue;
393
+ const count = seen.get(key) ?? 0;
394
+ seen.set(key, count + 1);
395
+ }
396
+ for (const [key, count] of seen) {
397
+ if (count > 1) {
398
+ constraintWarnings.push(`DUPLICATE SHARING ENTITY: Allocator[${i}] has entity "${key}" appearing ${count} times ` +
399
+ `in the sharing array. This is likely a configuration error — each entity should appear ` +
400
+ `at most once per allocator. Total sharing: ${count * 100}% to the same entity. ` +
401
+ `If intentional, ignore this warning.`);
402
+ }
403
+ }
404
+ }
405
+ }
406
+ const callService = new CallService(validated.data);
407
+ let result;
408
+ try {
409
+ result = validated.submission
410
+ ? await callService.call_with_submission(env, await transformSubmission(validated.submission))
411
+ : await callService.call(env);
412
+ }
413
+ catch (e) {
414
+ const errMsg = e.message ?? String(e);
415
+ if (/not found|GetObjectExisted|resolve|LocalMark|failed to resolve/i.test(errMsg)) {
416
+ const permRef = (typeof data?.object === 'object' && data?.object !== null)
417
+ ? data.object.permission
418
+ : undefined;
419
+ throw new Error(`DEPENDENCY RESOLUTION FAILED: One or more referenced objects could not be resolved.\n` +
420
+ `Original error: ${errMsg}\n` +
421
+ `Common causes:\n` +
422
+ ` 1. Object name typo — check spelling in LocalMark\n` +
423
+ ` 2. Object not yet created — create dependencies first\n` +
424
+ ` 3. Object on different network — check env.network\n` +
425
+ `Referenced objects in this call: machine=${data?.machine ?? "<none>"}, ` +
426
+ `buy_guard=${data?.buy_guard ?? "<none>"}, ` +
427
+ `permission=${permRef ?? "<inline/new>"}, ` +
428
+ `arbitrations=${Array.isArray(data?.arbitrations) ? data.arbitrations.length + " item(s)" : "<none>"}`);
429
+ }
430
+ throw e;
431
+ }
105
432
  const intent = data?.publish ? "publish service" : data?.bPublished !== undefined ? "modify service" : "create service";
106
433
  const isCreatingService = data?.object != null && typeof data.object === "object";
107
434
  const hasCompensationFundAdd = data?.compensation_fund_add != null;
@@ -112,6 +439,30 @@ export async function handleOnchainOperations(args) {
112
439
  "from this Service. (Note: some industries like freelance do not require this; " +
113
440
  "the evaluation engine will check industry-specific requirements.)");
114
441
  }
442
+ const isPublishing = data?.publish === true;
443
+ const hasArbitrations = Array.isArray(data?.arbitrations) && data.arbitrations.length > 0;
444
+ if (isPublishing && !hasArbitrations && hasCompensationFundAdd) {
445
+ throw new Error("HARD PRE-CHECK FAILED: Cannot publish Service with compensation_fund > 0 but no Arbitration bound.\n" +
446
+ "Contract (service.move:494): assert!(arbitration_count > 0, E_ARBITRATION_NOT_SET_WITH_COMPENSATION_FUND).\n" +
447
+ "The transaction WILL ABORT on-chain if you proceed.\n" +
448
+ "Fix: (1) Create an Arbitration object first (onchain_operations with operation_type='arbitration').\n" +
449
+ " (2) Set data.arbitrations=[<arbitration_name_or_id>] in this same call.\n" +
450
+ " (3) Then call publish=true.\n" +
451
+ "Note: After publish, arbitrations can still be ADDED (but not removed without pause+lock).");
452
+ }
453
+ if (isPublishing && !hasArbitrations && !hasCompensationFundAdd) {
454
+ constraintWarnings.push("WARNING: Publishing Service without arbitrations. If compensation_fund was " +
455
+ "deposited in a prior call, the contract (service.move:494) WILL ABORT with " +
456
+ "E_ARBITRATION_NOT_SET_WITH_COMPENSATION_FUND. If compensation_fund is 0, " +
457
+ "publish will succeed but buyers have no dispute resolution path. " +
458
+ "Recommended: bind arbitrations before publish.");
459
+ }
460
+ if (!isPublishing && hasCompensationFundAdd && !hasArbitrations) {
461
+ constraintWarnings.push("WARNING: Depositing compensation_fund on a Service without arbitrations bound. " +
462
+ "If this Service is already published, arbitration rulings will not be able to " +
463
+ "withdraw compensation from this Service. Recommended: bind arbitrations first, " +
464
+ "then deposit compensation_fund.");
465
+ }
115
466
  const output = handleCallResult(result, withHarness(buildCtx(data), "service", intent));
116
467
  autoAddToProject(projectEnvPrefix, validated.operation_type, result).catch(() => { });
117
468
  return output;
@@ -141,6 +492,33 @@ export async function handleOnchainOperations(args) {
141
492
  bReplace: true
142
493
  };
143
494
  }
495
+ const machineData = validated.data;
496
+ const permWarning = await checkMachinePermissionBeforePublish(machineData, env);
497
+ if (permWarning) {
498
+ constraintWarnings.push(permWarning);
499
+ }
500
+ const machineNodes = machineData?.node?.nodes ?? machineData?.node;
501
+ if (Array.isArray(machineNodes)) {
502
+ const arbPatterns = /^(dispute|disputed|arbitration|arb_|arb\.|resolve_dispute|start_arbitration|open_dispute)/i;
503
+ for (const node of machineNodes) {
504
+ const nodeName = typeof node === 'object' ? node?.name : '';
505
+ if (typeof nodeName === 'string' && arbPatterns.test(nodeName)) {
506
+ constraintWarnings.push(`ARBITRATION SEPARATION WARNING: Machine node "${nodeName}" appears to be an arbitration-related node.\n` +
507
+ `CORE PRINCIPLE: A merchant cannot handle disputes fairly — they would be 'both player and referee'.\n` +
508
+ `The WoWok smart contract design makes Arbitration a completely separate object:\n` +
509
+ ` - Arbitration has its own Permission, voting_guard, usage_guard, and balance\n` +
510
+ ` - Arb instances have a 7-state lifecycle managed by Arbitration, not by Machine\n` +
511
+ ` - The Order object is the bridge: it has 'progress' (Machine) and 'dispute' (Arb list) fields\n` +
512
+ ` - When Arb rules, it calls order::compensate() — the ONLY connection to the business flow\n\n` +
513
+ `CORRECT PATTERN:\n` +
514
+ ` - Machine: business states only (ordered -> shipped -> delivered -> refunded -> completed)\n` +
515
+ ` - Arbitration: separate object with its own Permission (NOT shared with Service)\n` +
516
+ ` - Arb: 7-state lifecycle (Principal_confirming -> Arbitrator_confirming -> Voting -> Arbitrated -> Objectionable -> Finished -> Withdrawn)\n` +
517
+ ` - Use 'refunded'/'cancelled' nodes for the BUSINESS OUTCOME of a dispute, not 'disputed'\n\n` +
518
+ `If this node name is a legitimate business state (not arbitration), ignore this warning.`);
519
+ }
520
+ }
521
+ }
144
522
  const callMachine = new CallMachine(validated.data);
145
523
  const result = validated.submission
146
524
  ? await callMachine.call_with_submission(env, await transformSubmission(validated.submission))
@@ -161,6 +539,65 @@ export async function handleOnchainOperations(args) {
161
539
  const result = validated.submission
162
540
  ? await callProgress.call_with_submission(env, await transformSubmission(validated.submission))
163
541
  : await callProgress.call(env);
542
+ if (!validated.submission && result && typeof result === 'object' && 'submission' in result) {
543
+ const submissionData = result.submission;
544
+ if (Array.isArray(submissionData) && submissionData.length > 0) {
545
+ const guardRef = submissionData[0]?.guard;
546
+ if (guardRef) {
547
+ const submissionCtx = {
548
+ operation: "progress_next",
549
+ network: env?.network,
550
+ signer: env?.account,
551
+ progress_address: validated.data?.object,
552
+ order_address: validated.data?.task,
553
+ };
554
+ const prompt = await generateGuardSubmissionPrompt(guardRef, submissionCtx);
555
+ if (prompt) {
556
+ constraintWarnings.push(formatSubmissionPrompt(prompt));
557
+ }
558
+ }
559
+ }
560
+ }
561
+ if (result && typeof result === 'object' && 'digest' in result
562
+ && result?.effects?.status?.status === 'success') {
563
+ try {
564
+ const progressRef = validated.data?.object;
565
+ let progressAddr;
566
+ if (typeof progressRef === 'string') {
567
+ if (progressRef.startsWith('0x')) {
568
+ progressAddr = progressRef;
569
+ }
570
+ else {
571
+ progressAddr = await LocalMark.Instance().get_address(progressRef) ?? undefined;
572
+ }
573
+ }
574
+ if (progressAddr) {
575
+ const progressQuery = await query_objects({
576
+ objects: [progressAddr],
577
+ no_cache: true,
578
+ network: env?.network,
579
+ });
580
+ const progressObj = progressQuery?.objects?.[0];
581
+ if (progressObj?.type === "Progress") {
582
+ const currentNode = progressObj.current ?? "<unknown>";
583
+ const historyCount = Array.isArray(progressObj.session)
584
+ ? progressObj.session.length : 0;
585
+ const machineAddr = progressObj.machine;
586
+ const previewLines = [
587
+ `PROGRESS PREVIEW:`,
588
+ ` • current node: "${currentNode}"`,
589
+ ` • history count: ${historyCount} session(s)`,
590
+ ];
591
+ if (machineAddr) {
592
+ previewLines.push(` • machine: ${machineAddr}`);
593
+ }
594
+ constraintWarnings.push(previewLines.join("\n"));
595
+ }
596
+ }
597
+ }
598
+ catch {
599
+ }
600
+ }
164
601
  const output = handleCallResult(result, buildCtx(validated.data));
165
602
  autoAddToProject(projectEnvPrefix, validated.operation_type, result).catch(() => { });
166
603
  return output;
@@ -175,6 +612,14 @@ export async function handleOnchainOperations(args) {
175
612
  return output;
176
613
  }
177
614
  case "arbitration": {
615
+ const arbFundResult = await processFundOperation(validated.data, "arbitration", env?.network);
616
+ constraintWarnings.push(...arbFundResult.warnings);
617
+ if (arbFundResult.confirmation) {
618
+ constraintWarnings.push(arbFundResult.confirmation.message);
619
+ const fundHint = generateFundSkillsHint(arbFundResult.confirmation);
620
+ if (fundHint)
621
+ constraintWarnings.push(fundHint);
622
+ }
178
623
  const callArbitration = new CallArbitration(validated.data);
179
624
  const result = validated.submission
180
625
  ? await callArbitration.call_with_submission(env, await transformSubmission(validated.submission))
@@ -193,6 +638,14 @@ export async function handleOnchainOperations(args) {
193
638
  return output;
194
639
  }
195
640
  case "treasury": {
641
+ const trFundResult = await processFundOperation(validated.data, "treasury", env?.network);
642
+ constraintWarnings.push(...trFundResult.warnings);
643
+ if (trFundResult.confirmation) {
644
+ constraintWarnings.push(trFundResult.confirmation.message);
645
+ const fundHint = generateFundSkillsHint(trFundResult.confirmation);
646
+ if (fundHint)
647
+ constraintWarnings.push(fundHint);
648
+ }
196
649
  const callTreasury = new CallTreasury(validated.data);
197
650
  const result = validated.submission
198
651
  ? await callTreasury.call_with_submission(env, await transformSubmission(validated.submission))
@@ -202,6 +655,14 @@ export async function handleOnchainOperations(args) {
202
655
  return output;
203
656
  }
204
657
  case "reward": {
658
+ const rwFundResult = await processFundOperation(validated.data, "reward", env?.network);
659
+ constraintWarnings.push(...rwFundResult.warnings);
660
+ if (rwFundResult.confirmation) {
661
+ constraintWarnings.push(rwFundResult.confirmation.message);
662
+ const fundHint = generateFundSkillsHint(rwFundResult.confirmation);
663
+ if (fundHint)
664
+ constraintWarnings.push(fundHint);
665
+ }
205
666
  const transformedData = transformRewardInput(validated.data);
206
667
  const callReward = new CallReward(transformedData);
207
668
  const result = validated.submission
@@ -216,6 +677,51 @@ export async function handleOnchainOperations(args) {
216
677
  const result = validated.submission
217
678
  ? await callAllocation.call_with_submission(env, await transformSubmission(validated.submission))
218
679
  : await callAllocation.call(env);
680
+ const allocData = validated.data;
681
+ if (allocData?.alloc_by_guard) {
682
+ const createdPayments = ResponseData(result).filter((e) => e?.type === "Payment" && e?.change === "created");
683
+ if (createdPayments.length > 0) {
684
+ const paymentAddrs = createdPayments.map((p) => p.object).join(", ");
685
+ try {
686
+ const paymentResult = await query_objects({
687
+ objects: createdPayments.map((p) => p.object),
688
+ no_cache: true,
689
+ network: env?.network,
690
+ });
691
+ const distributionLines = [];
692
+ let totalDistributed = BigInt(0);
693
+ for (const obj of paymentResult?.objects || []) {
694
+ if (obj?.type === "Payment" && obj?.record) {
695
+ for (const entry of obj.record) {
696
+ const recipientLabel = formatRecipientLabel(entry.recipient);
697
+ const amountStr = typeof entry.amount === 'string' ? entry.amount : String(entry.amount);
698
+ const amountBig = BigInt(amountStr);
699
+ totalDistributed += amountBig;
700
+ distributionLines.push(` • ${recipientLabel}: ${formatMistAmount(amountBig)}`);
701
+ }
702
+ if (obj.object) {
703
+ distributionLines.push(` • Payment object: ${obj.object}`);
704
+ }
705
+ }
706
+ }
707
+ if (distributionLines.length > 0) {
708
+ distributionLines.unshift(`DISTRIBUTION DETAILS (alloc_by_guard):`);
709
+ distributionLines.push(` ─────────────────`, ` • Total distributed: ${formatMistAmount(totalDistributed)}`);
710
+ const isEscrow = paymentResult?.objects?.some((obj) => obj?.type === "Payment" && obj?.info?.for_object);
711
+ if (isEscrow) {
712
+ distributionLines.push(``, `ESCROW MODE: Funds are held in escrow (Payment.for_object points to an Order). ` +
713
+ `The Order owner must call order_claim (or service_order_claim) to actually receive the funds. ` +
714
+ `This happens when the Guard's sharing config uses { GuardIdentifier: 0 }.`);
715
+ }
716
+ constraintWarnings.push(distributionLines.join("\n"));
717
+ }
718
+ }
719
+ catch {
720
+ constraintWarnings.push(`alloc_by_guard created Payment object(s) [${paymentAddrs}]. ` +
721
+ `Query these Payment objects to see the distribution details and check for_object for escrow mode.`);
722
+ }
723
+ }
724
+ }
219
725
  const output = handleCallResult(result, buildCtx(validated.data));
220
726
  autoAddToProject(projectEnvPrefix, validated.operation_type, result).catch(() => { });
221
727
  return output;
@@ -277,6 +783,34 @@ export async function handleOnchainOperations(args) {
277
783
  }
278
784
  const callGuard = new CallGuard(validatedData);
279
785
  const result = await callGuard.call(env);
786
+ if (result && typeof result === 'object' && 'digest' in result
787
+ && result?.effects?.status?.status === 'success') {
788
+ try {
789
+ const rootType = validatedData.root?.type ?? "<unknown>";
790
+ const tableArr = Array.isArray(validatedData.table) ? validatedData.table : [];
791
+ const tableEntries = tableArr.length;
792
+ const submissionEntries = tableArr.filter((t) => t?.b_submission === true).length;
793
+ const relyGuards = validatedData.rely?.guards;
794
+ const relyCount = Array.isArray(relyGuards) ? relyGuards.length : 0;
795
+ const relyMode = validatedData.rely?.logic_or === true
796
+ ? "OR" : validatedData.rely?.logic_or === false ? "AND" : "none";
797
+ const summaryLines = [
798
+ `GUARD LOGIC SUMMARY:`,
799
+ ` • root type: ${rootType}`,
800
+ ` • table entries: ${tableEntries} (${submissionEntries} require runtime submission)`,
801
+ ];
802
+ if (relyCount > 0) {
803
+ summaryLines.push(` • relies on: ${relyCount} guard(s) (mode: ${relyMode})`);
804
+ }
805
+ if (validatedData.description) {
806
+ const desc = String(validatedData.description).slice(0, 80);
807
+ summaryLines.push(` • description: "${desc}"`);
808
+ }
809
+ constraintWarnings.push(summaryLines.join("\n"));
810
+ }
811
+ catch {
812
+ }
813
+ }
280
814
  const output = handleCallResult(result, buildCtx(validated.data));
281
815
  autoAddToProject(projectEnvPrefix, validated.operation_type, result).catch(() => { });
282
816
  return output;
@@ -290,6 +824,37 @@ export async function handleOnchainOperations(args) {
290
824
  return output;
291
825
  }
292
826
  case "payment": {
827
+ const payFundResult = await processFundOperation(validated.data, "payment", env?.network);
828
+ constraintWarnings.push(...payFundResult.warnings);
829
+ if (payFundResult.confirmation) {
830
+ constraintWarnings.push(payFundResult.confirmation.message);
831
+ const fundHint = generateFundSkillsHint(payFundResult.confirmation);
832
+ if (fundHint)
833
+ constraintWarnings.push(fundHint);
834
+ }
835
+ const paymentData = validated.data;
836
+ if (paymentData?.receive === true) {
837
+ constraintWarnings.push("RECEIVE MODE (order_claim): You are unwrapping a CoinWrapper to your wallet. " +
838
+ "This is the final step of the escrow flow:\n" +
839
+ " 1. Allocation's alloc_by_guard created a Payment object with your address as a recipient\n" +
840
+ " 2. The Payment's revenue split transferred a CoinWrapper to your wallet (owned but not spendable)\n" +
841
+ " 3. THIS operation unwraps the CoinWrapper via payment::unwrap_to_myself, deleting the " +
842
+ "CoinWrapper and transferring the underlying coin to tx_context::sender\n" +
843
+ "Requirements:\n" +
844
+ " - You MUST be the CoinWrapper's owner (the recipient specified in the Allocation)\n" +
845
+ " - type_parameter MUST match the coin type used when the Allocation created the Payment " +
846
+ "(e.g. '0x2::wow::WOW')\n" +
847
+ " - object can be a CoinWrapper ID (0x...) or a local mark name\n" +
848
+ "To find received CoinWrappers: call query_toolkit with query_type='onchain_received' " +
849
+ "and type='CoinWrapper' for your account.\n" +
850
+ "After success: verify your balance increased via account_balance query.");
851
+ }
852
+ else if (paymentData?.revenue) {
853
+ constraintWarnings.push("CREATE MODE: Creating a new Payment object. Payments are IMMUTABLE after creation — " +
854
+ "they cannot be modified. The 'revenue' array defines the recipients and amounts; " +
855
+ "ensure correctness before submitting. The 'info.for_guard' field (if set) binds this " +
856
+ "Payment to a Guard for conditional release (common in escrow workflows).");
857
+ }
293
858
  const callPayment = new CallPayment(validated.data);
294
859
  const result = await callPayment.call(env);
295
860
  const output = handleCallResult(result, buildCtx(validated.data));