@wowok/agent-mcp 2.6.0 → 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 (186) hide show
  1. package/README.md +5 -3
  2. package/dist/customer/info-puzzle.d.ts +1 -1
  3. package/dist/customer/info-puzzle.js +4 -2
  4. package/dist/customer/risk-assessment.js +26 -4
  5. package/dist/customer/types.d.ts +2 -0
  6. package/dist/examples/guard-template-balance-check.json +38 -0
  7. package/dist/examples/guard-template-time-lock.json +39 -0
  8. package/dist/examples/machine-template-7node-rental.json +114 -0
  9. package/dist/examples/rental-ziroom-machine-create.json +137 -0
  10. package/dist/examples/rental-ziroom-permission-create.json +35 -0
  11. package/dist/examples/rental-ziroom-service-create.json +80 -0
  12. package/dist/examples/retail-myshop-service-create.json +88 -0
  13. package/dist/extensions/capability-manifest.d.ts +125 -0
  14. package/dist/extensions/capability-manifest.js +594 -0
  15. package/dist/extensions/constraint-registry.d.ts +24 -0
  16. package/dist/extensions/constraint-registry.js +196 -0
  17. package/dist/extensions/index.d.ts +12 -0
  18. package/dist/extensions/index.js +6 -0
  19. package/dist/extensions/metric-registry.d.ts +26 -0
  20. package/dist/extensions/metric-registry.js +257 -0
  21. package/dist/extensions/mode-evaluator.d.ts +15 -0
  22. package/dist/extensions/mode-evaluator.js +170 -0
  23. package/dist/extensions/modes.d.ts +2 -0
  24. package/dist/extensions/modes.js +493 -0
  25. package/dist/extensions/registry.d.ts +50 -0
  26. package/dist/extensions/registry.js +662 -0
  27. package/dist/extensions/types.d.ts +219 -0
  28. package/dist/extensions/types.js +1 -0
  29. package/dist/index.js +50 -0
  30. package/dist/knowledge/deployment-scanner.d.ts +3 -0
  31. package/dist/knowledge/deployment-scanner.js +64 -3
  32. package/dist/knowledge/fund-layer.d.ts +72 -0
  33. package/dist/knowledge/fund-layer.js +420 -0
  34. package/dist/knowledge/guard-render.d.ts +57 -0
  35. package/dist/knowledge/guard-render.js +700 -0
  36. package/dist/knowledge/guard-risk.d.ts +13 -0
  37. package/dist/knowledge/guard-risk.js +57 -0
  38. package/dist/knowledge/guard-submission-prompt.d.ts +31 -0
  39. package/dist/knowledge/guard-submission-prompt.js +171 -0
  40. package/dist/knowledge/guard-templates.js +278 -0
  41. package/dist/knowledge/machine-ledger.js +1 -1
  42. package/dist/knowledge/machine-render.d.ts +41 -0
  43. package/dist/knowledge/machine-render.js +565 -0
  44. package/dist/knowledge/machine-templates.js +24 -5
  45. package/dist/knowledge/reward-confirm.js +2 -2
  46. package/dist/knowledge/reward-puzzle.js +1 -1
  47. package/dist/knowledge/reward-risk.js +9 -9
  48. package/dist/knowledge/reward-templates.js +2 -2
  49. package/dist/knowledge/service-confirm.d.ts +15 -6
  50. package/dist/knowledge/service-confirm.js +119 -11
  51. package/dist/knowledge/service-context.js +1 -1
  52. package/dist/knowledge/service-ledger.js +1 -1
  53. package/dist/knowledge/service-risk.d.ts +1 -1
  54. package/dist/knowledge/service-risk.js +3 -3
  55. package/dist/knowledge/service-templates.js +2 -2
  56. package/dist/knowledge/service-translation.d.ts +1 -1
  57. package/dist/knowledge/service-translation.js +7 -7
  58. package/dist/knowledge/tool-constraints.js +6 -2
  59. package/dist/project/deployment-bridge.d.ts +1 -1
  60. package/dist/project/deployment-bridge.js +31 -7
  61. package/dist/project/deployment-doc.d.ts +3 -0
  62. package/dist/project/deployment-doc.js +76 -14
  63. package/dist/project/edit-planner.d.ts +123 -0
  64. package/dist/project/edit-planner.js +1371 -0
  65. package/dist/project/evaluation.d.ts +2 -0
  66. package/dist/project/evaluation.js +873 -88
  67. package/dist/project/graph-builder.d.ts +4 -1
  68. package/dist/project/graph-builder.js +132 -62
  69. package/dist/project/graph.d.ts +1 -0
  70. package/dist/project/handlers.d.ts +317 -6
  71. package/dist/project/handlers.js +1171 -19
  72. package/dist/project/stage-gate.d.ts +4 -0
  73. package/dist/project/stage-gate.js +64 -5
  74. package/dist/project/task-tracker.d.ts +26 -0
  75. package/dist/project/task-tracker.js +78 -0
  76. package/dist/safety/preview.js +16 -0
  77. package/dist/schema/call/allocation.d.ts +16 -16
  78. package/dist/schema/call/allocation.js +2 -2
  79. package/dist/schema/call/arbitration.js +19 -6
  80. package/dist/schema/call/base.d.ts +21 -13
  81. package/dist/schema/call/base.js +27 -6
  82. package/dist/schema/call/bridge.d.ts +5 -5
  83. package/dist/schema/call/bridge.js +3 -1
  84. package/dist/schema/call/contact.js +2 -2
  85. package/dist/schema/call/demand.d.ts +23 -31
  86. package/dist/schema/call/demand.js +2 -2
  87. package/dist/schema/call/guard.js +2 -2
  88. package/dist/schema/call/machine.d.ts +1976 -752
  89. package/dist/schema/call/machine.js +50 -4
  90. package/dist/schema/call/order.d.ts +149 -228
  91. package/dist/schema/call/order.js +4 -3
  92. package/dist/schema/call/payment.d.ts +183 -3
  93. package/dist/schema/call/payment.js +21 -3
  94. package/dist/schema/call/permission.js +2 -2
  95. package/dist/schema/call/personal.d.ts +241 -52
  96. package/dist/schema/call/progress.d.ts +53 -61
  97. package/dist/schema/call/progress.js +18 -4
  98. package/dist/schema/call/repository.d.ts +23 -31
  99. package/dist/schema/call/repository.js +2 -2
  100. package/dist/schema/call/reward.js +3 -3
  101. package/dist/schema/call/semantic.d.ts +1 -1
  102. package/dist/schema/call/semantic.js +37 -2
  103. package/dist/schema/call/service.d.ts +275 -127
  104. package/dist/schema/call/service.js +89 -13
  105. package/dist/schema/call/treasury.js +3 -3
  106. package/dist/schema/common/index.d.ts +13 -2
  107. package/dist/schema/common/index.js +80 -15
  108. package/dist/schema/local/index.d.ts +32 -35
  109. package/dist/schema/local/index.js +28 -6
  110. package/dist/schema/messenger/index.d.ts +274 -46
  111. package/dist/schema/operations.d.ts +1264 -544
  112. package/dist/schema/operations.js +65 -7
  113. package/dist/schema/project/index.d.ts +2846 -167
  114. package/dist/schema/project/index.js +570 -16
  115. package/dist/schema/query/index.d.ts +922 -349
  116. package/dist/schema/query/index.js +205 -42
  117. package/dist/schema/schema-query/index.d.ts +65 -3
  118. package/dist/schema/schema-query/index.js +38 -5
  119. package/dist/schema/utils/node-parser.js +20 -4
  120. package/dist/schema/utils/object-type-utils.d.ts +12 -0
  121. package/dist/schema/utils/object-type-utils.js +35 -0
  122. package/dist/schema/utils/permission-machine-check.d.ts +49 -0
  123. package/dist/schema/utils/permission-machine-check.js +121 -0
  124. package/dist/schema/utils/skills-recommendation.d.ts +2 -0
  125. package/dist/schema/utils/skills-recommendation.js +76 -0
  126. package/dist/schema-query/index.d.ts +20 -1
  127. package/dist/schema-query/index.js +306 -4
  128. package/dist/schemas/account_operation.output.json +7 -1
  129. package/dist/schemas/account_operation.schema.json +3 -3
  130. package/dist/schemas/bridge_operation.output.json +6 -0
  131. package/dist/schemas/bridge_operation.schema.json +1 -1
  132. package/dist/schemas/guard-templates.json +379 -0
  133. package/dist/schemas/guard2file.schema.json +1 -1
  134. package/dist/schemas/index.json +1 -1
  135. package/dist/schemas/local_info_operation.output.json +6 -0
  136. package/dist/schemas/local_mark_operation.output.json +7 -1
  137. package/dist/schemas/local_mark_operation.schema.json +1 -1
  138. package/dist/schemas/machineNode2file.schema.json +1 -1
  139. package/dist/schemas/messenger_operation.schema.json +4 -4
  140. package/dist/schemas/onchain_events.output.json +1 -1
  141. package/dist/schemas/onchain_operations.output.json +2820 -0
  142. package/dist/schemas/onchain_operations.schema.json +444 -330
  143. package/dist/schemas/onchain_operations_allocation.schema.json +37 -28
  144. package/dist/schemas/onchain_operations_arbitration.schema.json +16 -14
  145. package/dist/schemas/onchain_operations_contact.schema.json +10 -10
  146. package/dist/schemas/onchain_operations_demand.schema.json +10 -10
  147. package/dist/schemas/onchain_operations_gen_passport.schema.json +16 -16
  148. package/dist/schemas/onchain_operations_gen_proof.schema.json +2 -2
  149. package/dist/schemas/onchain_operations_guard.schema.json +2 -2
  150. package/dist/schemas/onchain_operations_machine.schema.json +43 -35
  151. package/dist/schemas/onchain_operations_order.schema.json +72 -78
  152. package/dist/schemas/onchain_operations_payment.schema.json +141 -111
  153. package/dist/schemas/onchain_operations_permission.schema.json +3 -3
  154. package/dist/schemas/onchain_operations_personal.schema.json +7 -7
  155. package/dist/schemas/onchain_operations_progress.schema.json +9 -9
  156. package/dist/schemas/onchain_operations_proof.schema.json +8 -8
  157. package/dist/schemas/onchain_operations_repository.schema.json +10 -10
  158. package/dist/schemas/onchain_operations_reward.schema.json +14 -14
  159. package/dist/schemas/onchain_operations_service.schema.json +119 -48
  160. package/dist/schemas/onchain_operations_treasury.schema.json +11 -11
  161. package/dist/schemas/onchain_table_data.output.json +33 -25
  162. package/dist/schemas/onchain_table_data.schema.json +22 -21
  163. package/dist/schemas/project_operation.output.json +2194 -23
  164. package/dist/schemas/project_operation.schema.json +84 -6
  165. package/dist/schemas/query_toolkit.output.json +108 -80
  166. package/dist/schemas/query_toolkit.schema.json +12 -12
  167. package/dist/schemas/schema_query.output.json +70 -3
  168. package/dist/schemas/schema_query.schema.json +18 -3
  169. package/dist/schemas/wowok_buildin_info.output.json +81 -8
  170. package/dist/schemas/wowok_buildin_info.schema.json +46 -2
  171. package/dist/tools/handlers/local.js +20 -5
  172. package/dist/tools/handlers/onchain.js +594 -6
  173. package/dist/tools/handlers/project.js +76 -4
  174. package/dist/tools/handlers/query.js +27 -0
  175. package/dist/tools/handlers/schema-query.js +43 -1
  176. package/dist/tools/handlers/task-status.d.ts +170 -0
  177. package/dist/tools/handlers/task-status.js +55 -0
  178. package/dist/tools/handlers/wip.js +47 -1
  179. package/dist/tools/index.d.ts +8 -0
  180. package/dist/tools/index.js +387 -12
  181. package/dist/tools/retry.d.ts +8 -0
  182. package/dist/tools/retry.js +85 -0
  183. package/dist/tools/wip-deploy-assist.d.ts +28 -0
  184. package/dist/tools/wip-deploy-assist.js +278 -0
  185. package/package.json +2 -2
  186. package/dist/schemas/guard-node-examples.md +0 -199
@@ -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
  }
@@ -81,19 +325,144 @@ export async function handleOnchainOperations(args) {
81
325
  validated.data = pn.data;
82
326
  projectWarnings = pn.warnings ?? [];
83
327
  }
328
+ if (!env.account && projectEnvPrefix) {
329
+ try {
330
+ const project = await LocalProject.Instance().getProjectByPrefix(projectEnvPrefix);
331
+ if (project?.defaultAccount) {
332
+ env.account = project.defaultAccount;
333
+ }
334
+ }
335
+ catch { }
336
+ }
84
337
  delete env.confirmed;
85
338
  delete env.user_intent_phrases;
86
339
  delete env.project;
87
340
  delete env.client_schema_version;
88
341
  delete env.schema_strict_mode;
342
+ const skillsHint = getSkillsHintForOnchain(validated.operation_type, validated.data);
343
+ if (skillsHint) {
344
+ constraintWarnings.push(skillsHint);
345
+ }
89
346
  switch (validated.operation_type) {
90
347
  case "service": {
91
- const callService = new CallService(validated.data);
92
- const result = validated.submission
93
- ? await callService.call_with_submission(env, await transformSubmission(validated.submission))
94
- : await callService.call(env);
95
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
+ }
96
432
  const intent = data?.publish ? "publish service" : data?.bPublished !== undefined ? "modify service" : "create service";
433
+ const isCreatingService = data?.object != null && typeof data.object === "object";
434
+ const hasCompensationFundAdd = data?.compensation_fund_add != null;
435
+ if (isCreatingService && !hasCompensationFundAdd) {
436
+ constraintWarnings.push("Service.compensation_fund balance is 0 — no refund protection for buyers. " +
437
+ "If buyers need refund protection, call service.compensation_fund_add with a Coin<T> " +
438
+ "to deposit. Without deposit, arbitration rulings cannot withdraw compensation " +
439
+ "from this Service. (Note: some industries like freelance do not require this; " +
440
+ "the evaluation engine will check industry-specific requirements.)");
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
+ }
97
466
  const output = handleCallResult(result, withHarness(buildCtx(data), "service", intent));
98
467
  autoAddToProject(projectEnvPrefix, validated.operation_type, result).catch(() => { });
99
468
  return output;
@@ -123,6 +492,33 @@ export async function handleOnchainOperations(args) {
123
492
  bReplace: true
124
493
  };
125
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
+ }
126
522
  const callMachine = new CallMachine(validated.data);
127
523
  const result = validated.submission
128
524
  ? await callMachine.call_with_submission(env, await transformSubmission(validated.submission))
@@ -143,6 +539,65 @@ export async function handleOnchainOperations(args) {
143
539
  const result = validated.submission
144
540
  ? await callProgress.call_with_submission(env, await transformSubmission(validated.submission))
145
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
+ }
146
601
  const output = handleCallResult(result, buildCtx(validated.data));
147
602
  autoAddToProject(projectEnvPrefix, validated.operation_type, result).catch(() => { });
148
603
  return output;
@@ -157,6 +612,14 @@ export async function handleOnchainOperations(args) {
157
612
  return output;
158
613
  }
159
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
+ }
160
623
  const callArbitration = new CallArbitration(validated.data);
161
624
  const result = validated.submission
162
625
  ? await callArbitration.call_with_submission(env, await transformSubmission(validated.submission))
@@ -175,6 +638,14 @@ export async function handleOnchainOperations(args) {
175
638
  return output;
176
639
  }
177
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
+ }
178
649
  const callTreasury = new CallTreasury(validated.data);
179
650
  const result = validated.submission
180
651
  ? await callTreasury.call_with_submission(env, await transformSubmission(validated.submission))
@@ -184,6 +655,14 @@ export async function handleOnchainOperations(args) {
184
655
  return output;
185
656
  }
186
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
+ }
187
666
  const transformedData = transformRewardInput(validated.data);
188
667
  const callReward = new CallReward(transformedData);
189
668
  const result = validated.submission
@@ -198,6 +677,51 @@ export async function handleOnchainOperations(args) {
198
677
  const result = validated.submission
199
678
  ? await callAllocation.call_with_submission(env, await transformSubmission(validated.submission))
200
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
+ }
201
725
  const output = handleCallResult(result, buildCtx(validated.data));
202
726
  autoAddToProject(projectEnvPrefix, validated.operation_type, result).catch(() => { });
203
727
  return output;
@@ -259,6 +783,34 @@ export async function handleOnchainOperations(args) {
259
783
  }
260
784
  const callGuard = new CallGuard(validatedData);
261
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
+ }
262
814
  const output = handleCallResult(result, buildCtx(validated.data));
263
815
  autoAddToProject(projectEnvPrefix, validated.operation_type, result).catch(() => { });
264
816
  return output;
@@ -272,6 +824,37 @@ export async function handleOnchainOperations(args) {
272
824
  return output;
273
825
  }
274
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
+ }
275
858
  const callPayment = new CallPayment(validated.data);
276
859
  const result = await callPayment.call(env);
277
860
  const output = handleCallResult(result, buildCtx(validated.data));
@@ -293,6 +876,11 @@ export async function handleOnchainOperations(args) {
293
876
  "namedOperator=\"\" (OrderHolder). If the target Forward uses a " +
294
877
  "non-empty namedOperator or permissionIndex-only, use progress.operate " +
295
878
  "on the Progress object directly instead.");
879
+ constraintWarnings.push("Allocation hint: if this operation advances the order to a terminal " +
880
+ "state (e.g. Completed/Cancelled/Refunded), funds remain in the " +
881
+ "Allocation object and are NOT auto-distributed. To release funds, " +
882
+ "trigger the corresponding Guard verification via allocation operation " +
883
+ "(the Guard bound to the matching Allocator will verify and distribute).");
296
884
  }
297
885
  const callOrder = new CallOrder(validated.data);
298
886
  const result = validated.submission