@wowok/agent-mcp 2.3.14 → 2.3.18

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 (189) hide show
  1. package/dist/config/index.d.ts +1 -0
  2. package/dist/config/index.js +1 -0
  3. package/dist/config/runtime.d.ts +26 -0
  4. package/dist/config/runtime.js +217 -0
  5. package/dist/customer/index.d.ts +9 -0
  6. package/dist/customer/index.js +9 -0
  7. package/dist/customer/industry-risks.d.ts +40 -0
  8. package/dist/customer/industry-risks.js +438 -0
  9. package/dist/customer/info-puzzle.d.ts +102 -0
  10. package/dist/customer/info-puzzle.js +312 -0
  11. package/dist/customer/order-monitor.d.ts +75 -0
  12. package/dist/customer/order-monitor.js +327 -0
  13. package/dist/customer/order-strategy.d.ts +36 -0
  14. package/dist/customer/order-strategy.js +373 -0
  15. package/dist/customer/post-purchase.d.ts +42 -0
  16. package/dist/customer/post-purchase.js +350 -0
  17. package/dist/customer/reminder-system.d.ts +42 -0
  18. package/dist/customer/reminder-system.js +295 -0
  19. package/dist/customer/risk-assessment.d.ts +8 -0
  20. package/dist/customer/risk-assessment.js +337 -0
  21. package/dist/customer/types.d.ts +193 -0
  22. package/dist/customer/types.js +13 -0
  23. package/dist/customer/user-preferences.d.ts +70 -0
  24. package/dist/customer/user-preferences.js +460 -0
  25. package/dist/experience/experience-reuse.d.ts +10 -0
  26. package/dist/experience/experience-reuse.js +103 -0
  27. package/dist/experience/index.d.ts +6 -0
  28. package/dist/experience/index.js +5 -0
  29. package/dist/experience/intent-distill.d.ts +3 -0
  30. package/dist/experience/intent-distill.js +83 -0
  31. package/dist/experience/realtime-feedback.d.ts +5 -0
  32. package/dist/experience/realtime-feedback.js +94 -0
  33. package/dist/experience/types.d.ts +50 -0
  34. package/dist/experience/types.js +1 -0
  35. package/dist/experience/user-profile.d.ts +25 -0
  36. package/dist/experience/user-profile.js +171 -0
  37. package/dist/index.js +842 -371
  38. package/dist/knowledge/acquisition-flywheel.d.ts +53 -0
  39. package/dist/knowledge/acquisition-flywheel.js +192 -0
  40. package/dist/knowledge/arbitration-trust.d.ts +24 -0
  41. package/dist/knowledge/arbitration-trust.js +117 -0
  42. package/dist/knowledge/audit-rules.d.ts +28 -0
  43. package/dist/knowledge/audit-rules.js +141 -0
  44. package/dist/knowledge/demand-matching.d.ts +29 -0
  45. package/dist/knowledge/demand-matching.js +132 -0
  46. package/dist/knowledge/dynamic-pricing.d.ts +31 -0
  47. package/dist/knowledge/dynamic-pricing.js +87 -0
  48. package/dist/knowledge/flywheel-loop.d.ts +87 -0
  49. package/dist/knowledge/flywheel-loop.js +378 -0
  50. package/dist/knowledge/glossary.d.ts +18 -0
  51. package/dist/knowledge/glossary.js +209 -0
  52. package/dist/knowledge/guard-ledger.d.ts +19 -0
  53. package/dist/knowledge/guard-ledger.js +219 -0
  54. package/dist/knowledge/guard-puzzle.d.ts +93 -0
  55. package/dist/knowledge/guard-puzzle.js +278 -0
  56. package/dist/knowledge/guard-risk.d.ts +60 -0
  57. package/dist/knowledge/guard-risk.js +474 -0
  58. package/dist/knowledge/guard-translation.d.ts +46 -0
  59. package/dist/knowledge/guard-translation.js +487 -0
  60. package/dist/knowledge/index.d.ts +77 -0
  61. package/dist/knowledge/index.js +79 -0
  62. package/dist/knowledge/industry-evolution.d.ts +82 -0
  63. package/dist/knowledge/industry-evolution.js +323 -0
  64. package/dist/knowledge/industry-generalizer.d.ts +17 -0
  65. package/dist/knowledge/industry-generalizer.js +381 -0
  66. package/dist/knowledge/industry-registry.d.ts +48 -0
  67. package/dist/knowledge/industry-registry.js +187 -0
  68. package/dist/knowledge/intent-metrics.d.ts +42 -0
  69. package/dist/knowledge/intent-metrics.js +566 -0
  70. package/dist/knowledge/process-model.d.ts +24 -0
  71. package/dist/knowledge/process-model.js +160 -0
  72. package/dist/knowledge/reputation-rules.d.ts +42 -0
  73. package/dist/knowledge/reputation-rules.js +99 -0
  74. package/dist/knowledge/reward-templates.d.ts +25 -0
  75. package/dist/knowledge/reward-templates.js +125 -0
  76. package/dist/knowledge/safety-rules.d.ts +36 -0
  77. package/dist/knowledge/safety-rules.js +232 -0
  78. package/dist/knowledge/tool-constraints.d.ts +30 -0
  79. package/dist/knowledge/tool-constraints.js +175 -0
  80. package/dist/knowledge/trust-metrics.d.ts +37 -0
  81. package/dist/knowledge/trust-metrics.js +138 -0
  82. package/dist/loop-engineering/diagnose.d.ts +3 -2
  83. package/dist/loop-engineering/diagnose.js +94 -0
  84. package/dist/loop-engineering/improve.d.ts +1 -1
  85. package/dist/loop-engineering/improve.js +52 -1
  86. package/dist/project/graph.d.ts +71 -0
  87. package/dist/project/graph.js +314 -0
  88. package/dist/project/index.d.ts +62 -0
  89. package/dist/project/index.js +167 -0
  90. package/dist/project/namespace.d.ts +62 -0
  91. package/dist/project/namespace.js +181 -0
  92. package/dist/project/query.d.ts +40 -0
  93. package/dist/project/query.js +110 -0
  94. package/dist/safety/confirm-gate.d.ts +17 -0
  95. package/dist/safety/confirm-gate.js +88 -0
  96. package/dist/safety/index.d.ts +3 -0
  97. package/dist/safety/index.js +3 -0
  98. package/dist/safety/preview.d.ts +2 -0
  99. package/dist/safety/preview.js +36 -0
  100. package/dist/schema/call/allocation.d.ts +39 -14
  101. package/dist/schema/call/arbitration.d.ts +187 -162
  102. package/dist/schema/call/base.d.ts +1971 -87
  103. package/dist/schema/call/base.js +135 -3
  104. package/dist/schema/call/bridge-handler.js +15 -2
  105. package/dist/schema/call/bridge.d.ts +1478 -53
  106. package/dist/schema/call/bridge.js +50 -2
  107. package/dist/schema/call/contact.d.ts +25 -0
  108. package/dist/schema/call/demand.d.ts +79 -54
  109. package/dist/schema/call/guard.d.ts +125 -50
  110. package/dist/schema/call/handler.d.ts +3 -0
  111. package/dist/schema/call/handler.js +60 -14
  112. package/dist/schema/call/machine.d.ts +988 -938
  113. package/dist/schema/call/order.d.ts +25 -0
  114. package/dist/schema/call/payment.d.ts +25 -0
  115. package/dist/schema/call/permission.d.ts +244 -219
  116. package/dist/schema/call/personal.d.ts +25 -0
  117. package/dist/schema/call/progress.d.ts +25 -0
  118. package/dist/schema/call/proof.d.ts +62 -12
  119. package/dist/schema/call/proof.js +3 -3
  120. package/dist/schema/call/repository.d.ts +101 -76
  121. package/dist/schema/call/reward.d.ts +55 -30
  122. package/dist/schema/call/semantic.d.ts +10 -2
  123. package/dist/schema/call/semantic.js +616 -11
  124. package/dist/schema/call/service.d.ts +442 -417
  125. package/dist/schema/call/treasury.d.ts +25 -0
  126. package/dist/schema/common/index.js +3 -3
  127. package/dist/schema/config/index.d.ts +18 -0
  128. package/dist/schema/config/index.js +17 -0
  129. package/dist/schema/index.d.ts +6 -0
  130. package/dist/schema/index.js +5 -0
  131. package/dist/schema/local/index.d.ts +237 -81
  132. package/dist/schema/local/index.js +42 -6
  133. package/dist/schema/messenger/index.d.ts +1018 -79
  134. package/dist/schema/messenger/index.js +26 -17
  135. package/dist/schema/operations.d.ts +3192 -1746
  136. package/dist/schema/operations.js +93 -98
  137. package/dist/schema/project/index.d.ts +21 -0
  138. package/dist/schema/project/index.js +32 -0
  139. package/dist/schema/query/index.d.ts +2762 -1856
  140. package/dist/schema/query/index.js +38 -35
  141. package/dist/schema/schema-query/index.d.ts +33 -0
  142. package/dist/schema/schema-query/index.js +36 -0
  143. package/dist/schema/schema-version.d.ts +25 -0
  144. package/dist/schema/schema-version.js +76 -0
  145. package/dist/schema/trust/index.d.ts +407 -0
  146. package/dist/schema/trust/index.js +113 -0
  147. package/dist/schemas/account_operation.output.json +25 -16
  148. package/dist/schemas/account_operation.schema.json +1 -1
  149. package/dist/schemas/bridge_operation.output.json +744 -0
  150. package/dist/schemas/bridge_operation.schema.json +82 -8
  151. package/dist/schemas/config_operation.output.json +18 -0
  152. package/dist/schemas/config_operation.schema.json +34 -0
  153. package/dist/schemas/guard-node-schema.json +82 -0
  154. package/dist/schemas/guard2file.schema.json +23 -0
  155. package/dist/schemas/index.json +19 -1
  156. package/dist/schemas/local_info_operation.output.json +23 -0
  157. package/dist/schemas/local_info_operation.schema.json +1 -1
  158. package/dist/schemas/local_mark_operation.output.json +24 -1
  159. package/dist/schemas/local_mark_operation.schema.json +4 -4
  160. package/dist/schemas/machineNode2file.schema.json +23 -0
  161. package/dist/schemas/messenger_operation.output.json +752 -0
  162. package/dist/schemas/onchain_events.output.json +718 -0
  163. package/dist/schemas/onchain_operations.output.json +627 -18
  164. package/dist/schemas/onchain_operations.schema.json +115 -39
  165. package/dist/schemas/onchain_operations_allocation.schema.json +23 -0
  166. package/dist/schemas/onchain_operations_arbitration.schema.json +23 -0
  167. package/dist/schemas/onchain_operations_contact.schema.json +23 -0
  168. package/dist/schemas/onchain_operations_demand.schema.json +23 -0
  169. package/dist/schemas/onchain_operations_gen_passport.schema.json +46 -0
  170. package/dist/schemas/onchain_operations_guard.schema.json +26 -16
  171. package/dist/schemas/onchain_operations_machine.schema.json +89 -23
  172. package/dist/schemas/onchain_operations_order.schema.json +23 -0
  173. package/dist/schemas/onchain_operations_payment.schema.json +23 -0
  174. package/dist/schemas/onchain_operations_permission.schema.json +23 -0
  175. package/dist/schemas/onchain_operations_personal.schema.json +23 -0
  176. package/dist/schemas/onchain_operations_progress.schema.json +23 -0
  177. package/dist/schemas/onchain_operations_repository.schema.json +23 -0
  178. package/dist/schemas/onchain_operations_reward.schema.json +23 -0
  179. package/dist/schemas/onchain_operations_service.schema.json +23 -0
  180. package/dist/schemas/onchain_operations_treasury.schema.json +23 -0
  181. package/dist/schemas/onchain_table_data.output.json +939 -69
  182. package/dist/schemas/onchain_table_data.schema.json +2 -2
  183. package/dist/schemas/project_operation.output.json +18 -0
  184. package/dist/schemas/project_operation.schema.json +42 -0
  185. package/dist/schemas/query_toolkit.schema.json +360 -368
  186. package/dist/schemas/schema_query.schema.json +6 -3
  187. package/dist/schemas/trust_score.output.json +327 -0
  188. package/dist/schemas/trust_score.schema.json +46 -0
  189. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -5,13 +5,19 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
5
5
  import { readFileSync } from "fs";
6
6
  import { resolve } from "path";
7
7
  const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
8
- import { MachineNode2File_InputSchema, MachineNode2File_OutputWrappedSchema, Guard2File_InputSchema, Guard2File_OutputWrappedSchema, strictParse, CallOutputSchema, handleCallResult, createServerConfig, createCapabilitiesConfig, createToolMeta, transformSubmission, getEnvConfig, OnchainEventsInputSchema, OnchainEventsResultSchema, ProtocolInfoQuerySchema, ProtocolInfoResultSchema, AccountOperationOutputWrappedSchema, LocalMarkOperationOutputWrappedSchema, LocalInfoOperationOutputWrappedSchema, WipOperationOutputSchema, MessengerOperationOutputSchema, AccountOperationSchema, LocalMarkOperationSchema, LocalInfoOperationSchema, parseMachineNodesFromText, formatNodeErrors as formatMachineNodeErrors, MessengerOperationInputSchema, BridgeOperationsSchema, BridgeCallOutputSchema, OnchainOperationsSchema, WipOperationsSchema, OnchainTableDataSchema, OnchainTableDataResultSchema, WatchQueryOperationsSchema, } from "./schema/index.js";
8
+ import { MachineNode2File_InputSchema, MachineNode2File_OutputWrappedSchema, Guard2File_InputSchema, Guard2File_OutputWrappedSchema, strictParse, CallOutputSchema, handleCallResult, createServerConfig, createCapabilitiesConfig, createToolMeta, transformSubmission, getEnvConfig, OnchainEventsInputSchema, OnchainEventsResultSchema, ProtocolInfoQuerySchema, ProtocolInfoResultSchema, AccountOperationOutputWrappedSchema, LocalMarkOperationOutputWrappedSchema, LocalInfoOperationOutputWrappedSchema, WipOperationOutputSchema, MessengerOperationOutputSchema, AccountOperationSchema, LocalMarkOperationSchema, LocalInfoOperationSchema, parseMachineNodesFromText, formatNodeErrors as formatMachineNodeErrors, MessengerOperationInputSchema, BridgeOperationsSchema, BridgeCallOutputSchema, OnchainOperationsSchema, WipOperationsSchema, OnchainTableDataSchema, OnchainTableDataResultSchema, WatchQueryOperationsSchema, registerSuccessHook, SchemaQueryInputSchema, SchemaQueryOutputSchema, ProjectOperationInputSchema, ProjectOperationOutputSchema, ConfigOperationInputSchema, ConfigOperationOutputSchema, TrustScoreInputSchema, TrustScoreOutputSchema, checkClientSchemaCompatibility, } from "./schema/index.js";
9
9
  import { handleBridgeOperations } from "./schema/call/bridge-handler.js";
10
10
  import { buildDataSemantic, classifyError } from "./schema/call/semantic.js";
11
11
  import { getHarness } from "./harness/index.js";
12
- const HARNESS_ENABLED = process.env.WOWOK_HARNESS_ENABLED === "1" || process.env.WOWOK_HARNESS_ENABLED === "true";
12
+ import { confirmGate } from "./safety/confirm-gate.js";
13
+ import { renderPreview } from "./safety/preview.js";
14
+ import { isProjectServiceEnabled, normalize as projectNormalize, observe as projectObserve, queryProjects, queryProjectObjects, queryShareableObjects, queryDependencies, queryReferencedBy, queryPrePublishCheck, queryCrossProjectReferences, queryGraphStats, saveGraph, loadGraph, } from "./project/index.js";
15
+ import { isEnabled as isRuntimeEnabled, listServices, getServiceInfo, toggle as toggleService, setEnabled as setServiceEnabled, reset as resetService, } from "./config/index.js";
16
+ import { validateOperation, hasBlockingViolations, getWarningViolations, computeServiceTrustScore, } from "./knowledge/index.js";
17
+ import { assembleInfoPuzzle, assessRisk, } from "./customer/index.js";
18
+ const HARNESS_ENABLED = () => isRuntimeEnabled("harness");
13
19
  function withHarness(base, operation, intent) {
14
- if (!HARNESS_ENABLED)
20
+ if (!HARNESS_ENABLED())
15
21
  return base;
16
22
  try {
17
23
  const harness = getHarness();
@@ -27,7 +33,59 @@ function withHarness(base, operation, intent) {
27
33
  return base;
28
34
  }
29
35
  }
30
- import { CallService, CallMachine, CallProgress, CallPermission, CallGuard, CallArbitration, CallRepository, CallContact, CallTreasury, CallReward, CallAllocation, CallPersonal, CallPayment, CallDemand, CallOrder, gen_passport, CallProof, gen_proof, guard2file, parseGuardFile, formatGuardParseErrors, machineNode2file, generateNodeComments, generate_wip, verify_wip, sign_wip, wip2html, account_operation, local_mark_operation, local_info_operation, watch_conversations, send_message, send_file, watch_messages, extract_zip_messages, pull_messages, generate_wts, verify_wts, sign_wts, wts2html, proof_message, mark_messages_as_viewed, mark_conversation_as_viewed, query_local_mark_list, query_account_list, query_local_info_list, query_local_token_list, query_account, GetLocalNamesByAddresses, query_personal, query_objects, query_table, query_tableItem, queryProtocolInfo, query_received, queryTableItem_RepositoryData, queryTableItem_PermissionPerm, queryTableItem_RewardRecord, queryTableItem_DemandPresenter, queryTableItem_TreasuryHistory, queryTableItem_MachineNode, queryTableItem_ProgressHistory, queryTableItem_AddressMark, queryTableItem_EntityRegistrar, queryTableItem_EntityLinker, query_events, blacklist, friendslist, guardlist, settings, AmountType, } from "@wowok/wowok";
36
+ function buildPendingConfirmation(operation_type, data, env) {
37
+ const gate = confirmGate(operation_type, data, env, env?.user_intent_phrases);
38
+ if (gate.pass)
39
+ return { content: [], structuredContent: null };
40
+ const preview = gate.preview;
41
+ const rendered = renderPreview(preview);
42
+ const output = {
43
+ message: rendered,
44
+ result: {
45
+ type: "pending_confirmation",
46
+ preview,
47
+ rule_id: gate.rule_id,
48
+ },
49
+ semantic: {
50
+ intent: `${operation_type}_awaiting_confirmation`,
51
+ status: "pending_input",
52
+ summary: `Operation blocked by ConfirmGate (${gate.level}). Review the preview and re-call with env.confirmed=true to proceed.`,
53
+ next_actions: [
54
+ {
55
+ action: "confirm: re-call the SAME operation with env.confirmed=true",
56
+ reason: `ConfirmGate rule '${gate.rule_id}' matched. The operation was NOT executed.`,
57
+ tool: "onchain_operations",
58
+ priority: "required",
59
+ },
60
+ ],
61
+ warnings: preview.warnings ?? [],
62
+ },
63
+ };
64
+ return {
65
+ content: [{ type: "text", text: rendered }],
66
+ structuredContent: output,
67
+ };
68
+ }
69
+ function buildConstraintError(operation_type, violations) {
70
+ const errors = violations.filter((v) => v.severity === "error");
71
+ const errorList = errors.map((v) => ` • [${v.field}] ${v.message}`).join("\n");
72
+ const message = `Pre-call constraint violations for '${operation_type}':\n${errorList}\n\nFix the listed field(s) and retry.`;
73
+ const output = {
74
+ message,
75
+ result: {
76
+ type: "error",
77
+ error: message,
78
+ error_code: "invalid_parameter",
79
+ retryable: false,
80
+ recovery_hint: "Review the constraint violations above and correct the corresponding fields.",
81
+ },
82
+ };
83
+ return {
84
+ content: [{ type: "text", text: message }],
85
+ structuredContent: output,
86
+ };
87
+ }
88
+ import { CallService, CallMachine, CallProgress, CallPermission, CallGuard, CallArbitration, CallRepository, CallContact, CallTreasury, CallReward, CallAllocation, CallPersonal, CallPayment, CallDemand, CallOrder, gen_passport, CallProof, gen_proof, guard2file, parseGuardFile, formatGuardParseErrors, machineNode2file, generateNodeComments, generate_wip, verify_wip, sign_wip, wip2html, account_operation, local_mark_operation, local_info_operation, watch_conversations, send_message, send_file, watch_messages, extract_zip_messages, pull_messages, generate_wts, verify_wts, sign_wts, wts2html, proof_message, mark_messages_as_viewed, mark_conversation_as_viewed, query_local_mark_list, query_account_list, query_local_info_list, query_local_token_list, query_account, GetLocalNamesByAddresses, query_personal, query_objects, query_table, query_tableItem, queryProtocolInfo, query_received, queryTableItem_RepositoryData, queryTableItem_PermissionPerm, queryTableItem_RewardRecord, queryTableItem_DemandPresenter, queryTableItem_TreasuryHistory, queryTableItem_MachineNode, queryTableItem_ProgressHistory, queryTableItem_AddressMark, queryTableItem_EntityRegistrar, queryTableItem_EntityLinker, query_events, blacklist, friendslist, guardlist, settings, transformRewardInput, transformPersonalInput, } from "@wowok/wowok";
31
89
  import { areSchemasAvailable, getSchemaIndex, processSchemaQuery, } from "./schema-query/index.js";
32
90
  const SERVER_DESCRIPTION = `WoWok MCP Server - Making It Easy for AI Agents to Communicate, Collaborate, Trade, and Trust.
33
91
 
@@ -141,40 +199,73 @@ import { withTelemetry, setTelemetryEnabled } from "./telemetry/index.js";
141
199
  if (process.env.WOWOK_TELEMETRY === "false" || process.env.WOWOK_TELEMETRY === "0") {
142
200
  setTelemetryEnabled(false);
143
201
  }
144
- function reg(name, config, handler) {
145
- server.registerTool(name, config, withTelemetry(name, handler));
202
+ function buildClassifiedErrorResult(base, error, classified) {
203
+ const result = { ...base, error };
204
+ if (classified.error_code !== undefined)
205
+ result.error_code = classified.error_code;
206
+ if (classified.retryable !== undefined)
207
+ result.retryable = classified.retryable;
208
+ if (classified.recovery_hint !== undefined)
209
+ result.recovery_hint = classified.recovery_hint;
210
+ return result;
146
211
  }
147
- function convertAmountType(type) {
148
- if (typeof type === "number")
149
- return type;
150
- const upperType = type.toUpperCase();
151
- if (upperType === "GUARDU64IDENTIFIER" || upperType === "GUARD_U64_IDENTIFIER") {
152
- return AmountType.GuardU64Identifier;
153
- }
154
- if (upperType === "FIXED") {
155
- return AmountType.Fixed;
156
- }
157
- return AmountType.Fixed;
212
+ const statusErrorShape = (error, classified, ctx) => ({
213
+ result: buildClassifiedErrorResult({ status: "error" }, error, classified),
214
+ semantic: buildDataSemantic(undefined, ctx, true, error),
215
+ });
216
+ const operationErrorShape = (error, classified, ctx) => ({
217
+ result: buildClassifiedErrorResult({ operation: "error" }, error, classified),
218
+ semantic: buildDataSemantic(undefined, ctx, true, error),
219
+ });
220
+ const strictStatusErrorShape = (error, _classified, _ctx) => ({
221
+ result: { status: "error", error },
222
+ });
223
+ function reg(name, config, handler, errorShapeBuilder, customTimeoutMs) {
224
+ const timeoutMs = customTimeoutMs ?? 60000;
225
+ const wrappedHandler = wrapHandlerWithErrorShape(handler, timeoutMs, name, errorShapeBuilder);
226
+ server.registerTool(name, config, withTelemetry(name, wrappedHandler));
227
+ }
228
+ function withTimeout(promise, timeoutMs = 30000, operationName = "operation") {
229
+ let timer;
230
+ return Promise.race([
231
+ promise.finally(() => {
232
+ if (timer)
233
+ clearTimeout(timer);
234
+ }),
235
+ new Promise((_, reject) => {
236
+ timer = setTimeout(() => {
237
+ let hint = "";
238
+ if (operationName.includes("messenger")) {
239
+ hint = " This is a messenger network operation. Possible causes: " +
240
+ "(1) messenger server (https://messenger.wowok.net) unreachable, " +
241
+ "(2) no messenger-enabled account configured (use account_operation to set messenger name), " +
242
+ "(3) network connectivity issue. " +
243
+ "Ensure you have a messenger-enabled account and the server is reachable.";
244
+ }
245
+ reject(new Error(`Operation '${operationName}' timed out after ${timeoutMs}ms.${hint}`));
246
+ }, timeoutMs);
247
+ }),
248
+ ]);
158
249
  }
159
- function transformRewardData(data) {
160
- if (!data)
161
- return data;
162
- const transformed = { ...data };
163
- if (transformed.guard_add && Array.isArray(transformed.guard_add)) {
164
- transformed.guard_add = transformed.guard_add.map((guard) => {
165
- if (guard.amount && typeof guard.amount.type === "string") {
250
+ function wrapHandlerWithErrorShape(handler, timeoutMs, toolName, errorShapeBuilder) {
251
+ return async (args) => {
252
+ try {
253
+ return await withTimeout(handler(args), timeoutMs, toolName);
254
+ }
255
+ catch (error) {
256
+ if (errorShapeBuilder) {
257
+ const errorMessage = error instanceof Error ? error.message : String(error);
258
+ const classified = classifyError(errorMessage);
259
+ const ctx = { operation_type: toolName, data: args };
260
+ const structuredContent = errorShapeBuilder(errorMessage, classified, ctx);
166
261
  return {
167
- ...guard,
168
- amount: {
169
- ...guard.amount,
170
- type: convertAmountType(guard.amount.type)
171
- }
262
+ content: [{ type: "text", text: `Error: ${errorMessage}` }],
263
+ structuredContent,
172
264
  };
173
265
  }
174
- return guard;
175
- });
176
- }
177
- return transformed;
266
+ throw error;
267
+ }
268
+ };
178
269
  }
179
270
  async function handleOnchainTableData(args) {
180
271
  const validated = strictParse(OnchainTableDataSchema, args, "onchain_table_data input");
@@ -261,6 +352,7 @@ async function handleOnchainTableData(args) {
261
352
  }
262
353
  async function handleOnchainOperations(args) {
263
354
  let validated;
355
+ let constraintWarnings = [];
264
356
  try {
265
357
  if (typeof args === 'object' && args !== null && args.description && !args.operation_type) {
266
358
  const hasWrappedParams = typeof args.description === 'string' &&
@@ -273,6 +365,42 @@ async function handleOnchainOperations(args) {
273
365
  }
274
366
  validated = strictParse(OnchainOperationsSchema, args, "onchain_operations input");
275
367
  const env = getEnvConfig(validated.env);
368
+ const gateResult = buildPendingConfirmation(validated.operation_type, validated.data, env);
369
+ if (gateResult.structuredContent) {
370
+ return gateResult;
371
+ }
372
+ const constraintViolations = validateOperation(validated.operation_type, validated.data);
373
+ if (hasBlockingViolations(constraintViolations)) {
374
+ return buildConstraintError(validated.operation_type, constraintViolations);
375
+ }
376
+ constraintWarnings = getWarningViolations(constraintViolations).map((v) => `[PRE-CHECK] ${v.message}`);
377
+ const clientSchemaVersion = env?.client_schema_version;
378
+ const schemaStrictMode = env?.schema_strict_mode;
379
+ const schemaCheck = clientSchemaVersion
380
+ ? checkClientSchemaCompatibility(clientSchemaVersion, { mode: schemaStrictMode ? "strict" : "warn" })
381
+ : undefined;
382
+ const buildCtx = (data) => ({
383
+ operation_type: validated.operation_type,
384
+ data,
385
+ pre_warnings: constraintWarnings.length ? constraintWarnings : undefined,
386
+ schema_check: schemaCheck,
387
+ });
388
+ const projectEnvPrefix = env?.project;
389
+ if (isProjectServiceEnabled()) {
390
+ const pn = projectNormalize({
391
+ operation_type: validated.operation_type,
392
+ data: validated.data,
393
+ projectPrefix: projectEnvPrefix,
394
+ });
395
+ validated.data = pn.data;
396
+ }
397
+ if (env && typeof env === "object") {
398
+ delete env.confirmed;
399
+ delete env.user_intent_phrases;
400
+ delete env.project;
401
+ delete env.client_schema_version;
402
+ delete env.schema_strict_mode;
403
+ }
276
404
  switch (validated.operation_type) {
277
405
  case "service": {
278
406
  const callService = new CallService(validated.data);
@@ -281,7 +409,7 @@ async function handleOnchainOperations(args) {
281
409
  : await callService.call(env);
282
410
  const data = validated.data;
283
411
  const intent = data?.publish ? "publish service" : data?.bPublished !== undefined ? "modify service" : "create service";
284
- return handleCallResult(result, withHarness({ operation_type: validated.operation_type, data }, "service", intent));
412
+ return handleCallResult(result, withHarness(buildCtx(data), "service", intent));
285
413
  }
286
414
  case "machine": {
287
415
  if (validated.data.node && typeof validated.data.node === 'object' && 'json_or_markdown_file' in validated.data.node) {
@@ -312,62 +440,62 @@ async function handleOnchainOperations(args) {
312
440
  const result = validated.submission
313
441
  ? await callMachine.call_with_submission(env, await transformSubmission(validated.submission))
314
442
  : await callMachine.call(env);
315
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
443
+ return handleCallResult(result, buildCtx(validated.data));
316
444
  }
317
445
  case "progress": {
318
446
  const callProgress = new CallProgress(validated.data);
319
447
  const result = validated.submission
320
448
  ? await callProgress.call_with_submission(env, await transformSubmission(validated.submission))
321
449
  : await callProgress.call(env);
322
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
450
+ return handleCallResult(result, buildCtx(validated.data));
323
451
  }
324
452
  case "repository": {
325
453
  const callRepository = new CallRepository(validated.data);
326
454
  const result = validated.submission
327
455
  ? await callRepository.call_with_submission(env, await transformSubmission(validated.submission))
328
456
  : await callRepository.call(env);
329
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
457
+ return handleCallResult(result, buildCtx(validated.data));
330
458
  }
331
459
  case "arbitration": {
332
460
  const callArbitration = new CallArbitration(validated.data);
333
461
  const result = validated.submission
334
462
  ? await callArbitration.call_with_submission(env, await transformSubmission(validated.submission))
335
463
  : await callArbitration.call(env);
336
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
464
+ return handleCallResult(result, buildCtx(validated.data));
337
465
  }
338
466
  case "contact": {
339
467
  const callContact = new CallContact(validated.data);
340
468
  const result = validated.submission
341
469
  ? await callContact.call_with_submission(env, await transformSubmission(validated.submission))
342
470
  : await callContact.call(env);
343
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
471
+ return handleCallResult(result, buildCtx(validated.data));
344
472
  }
345
473
  case "treasury": {
346
474
  const callTreasury = new CallTreasury(validated.data);
347
475
  const result = validated.submission
348
476
  ? await callTreasury.call_with_submission(env, await transformSubmission(validated.submission))
349
477
  : await callTreasury.call(env);
350
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
478
+ return handleCallResult(result, buildCtx(validated.data));
351
479
  }
352
480
  case "reward": {
353
- const transformedData = transformRewardData(validated.data);
481
+ const transformedData = transformRewardInput(validated.data);
354
482
  const callReward = new CallReward(transformedData);
355
483
  const result = validated.submission
356
484
  ? await callReward.call_with_submission(env, await transformSubmission(validated.submission))
357
485
  : await callReward.call(env);
358
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
486
+ return handleCallResult(result, buildCtx(validated.data));
359
487
  }
360
488
  case "allocation": {
361
489
  const callAllocation = new CallAllocation(validated.data);
362
490
  const result = validated.submission
363
491
  ? await callAllocation.call_with_submission(env, await transformSubmission(validated.submission))
364
492
  : await callAllocation.call(env);
365
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
493
+ return handleCallResult(result, buildCtx(validated.data));
366
494
  }
367
495
  case "permission": {
368
496
  const callPermission = new CallPermission(validated.data);
369
497
  const result = await callPermission.call(env);
370
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
498
+ return handleCallResult(result, buildCtx(validated.data));
371
499
  }
372
500
  case "guard": {
373
501
  const validatedData = validated.data;
@@ -414,211 +542,120 @@ async function handleOnchainOperations(args) {
414
542
  }
415
543
  const callGuard = new CallGuard(validatedData);
416
544
  const result = await callGuard.call(env);
417
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
545
+ return handleCallResult(result, buildCtx(validated.data));
418
546
  }
419
547
  case "personal": {
420
- const transformPersonalData = (data) => {
421
- const result = { ...data };
422
- if (data.mark) {
423
- const transformAddress = (addr) => {
424
- if (typeof addr === 'string') {
425
- return { name_or_address: addr, local_mark_first: true };
426
- }
427
- return addr;
428
- };
429
- if (data.mark.op === 'add' && data.mark.data) {
430
- result.mark = {
431
- ...data.mark,
432
- data: data.mark.data.map((item) => ({
433
- ...item,
434
- address: transformAddress(item.address)
435
- }))
436
- };
437
- }
438
- else if (data.mark.op === 'remove' && data.mark.data) {
439
- result.mark = {
440
- ...data.mark,
441
- data: data.mark.data.map((item) => ({
442
- ...item,
443
- address: transformAddress(item.address)
444
- }))
445
- };
446
- }
447
- else if (data.mark.op === 'clear' && data.mark.address) {
448
- const addr = data.mark.address;
449
- if (Array.isArray(addr) && addr.every((a) => typeof a === 'string')) {
450
- result.mark = {
451
- ...data.mark,
452
- address: {
453
- entities: addr.map((a) => ({ name_or_address: a, local_mark_first: true }))
454
- }
455
- };
456
- }
457
- }
458
- else if (data.mark.op === 'transfer' && data.mark.to) {
459
- result.mark = {
460
- ...data.mark,
461
- to: transformAddress(data.mark.to)
462
- };
463
- }
464
- }
465
- return result;
466
- };
467
- const transformedData = transformPersonalData(validated.data);
548
+ const transformedData = transformPersonalInput(validated.data);
468
549
  const callPersonal = new CallPersonal(transformedData);
469
550
  const result = await callPersonal.call(env);
470
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
551
+ return handleCallResult(result, buildCtx(validated.data));
471
552
  }
472
553
  case "payment": {
473
554
  const callPayment = new CallPayment(validated.data);
474
555
  const result = await callPayment.call(env);
475
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
556
+ return handleCallResult(result, buildCtx(validated.data));
476
557
  }
477
558
  case "demand": {
478
559
  const callDemand = new CallDemand(validated.data);
479
560
  const result = validated.submission
480
561
  ? await callDemand.call_with_submission(env, await transformSubmission(validated.submission))
481
562
  : await callDemand.call(env);
482
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
563
+ return handleCallResult(result, buildCtx(validated.data));
483
564
  }
484
565
  case "order": {
485
566
  const callOrder = new CallOrder(validated.data);
486
567
  const result = validated.submission
487
568
  ? await callOrder.call_with_submission(env, await transformSubmission(validated.submission))
488
569
  : await callOrder.call(env);
489
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
570
+ return handleCallResult(result, buildCtx(validated.data));
490
571
  }
491
572
  case "gen_passport": {
492
573
  const result = await gen_passport(env, validated.guard, validated.info);
493
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
574
+ return handleCallResult(result, buildCtx(validated.data));
494
575
  }
495
576
  case "proof": {
496
577
  const callProof = new CallProof(validated.data);
497
578
  const result = validated.submission
498
579
  ? await callProof.call_with_submission(env, await transformSubmission(validated.submission))
499
580
  : await callProof.call(env);
500
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
581
+ return handleCallResult(result, buildCtx(validated.data));
501
582
  }
502
583
  case "gen_proof": {
503
584
  const result = await gen_proof(env, validated.proof, validated.server_pubkey, validated.server_signature, validated.proof_type, validated.description, validated.item_count, validated.about_address);
504
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
585
+ return handleCallResult(result, buildCtx(validated.data));
505
586
  }
506
587
  }
507
588
  throw new Error(`Unknown on-chain operation type: ${validated.operation_type}`);
508
589
  }
509
590
  catch (error) {
510
591
  const errorMessage = error instanceof Error ? error.message : String(error);
511
- return handleCallResult({ error: errorMessage }, validated ? { operation_type: validated.operation_type, data: validated.data } : undefined);
512
- }
513
- }
514
- async function handleAccountOperation(args) {
515
- let validated;
516
- try {
517
- validated = strictParse(AccountOperationSchema, args, "account_operation input");
518
- const result = await account_operation(validated);
519
- const ctx = { operation_type: "account_" + validated.operation_type, data: validated };
520
- return {
521
- content: [{ type: "text", text: JSON.stringify(result) }],
522
- structuredContent: {
523
- result: {
524
- status: "success",
525
- data: result,
526
- },
527
- semantic: buildDataSemantic(result, ctx),
528
- },
529
- };
530
- }
531
- catch (error) {
532
- const errorMessage = error instanceof Error ? error.message : String(error);
533
- const ctx = validated ? { operation_type: "account_" + validated.operation_type, data: validated } : undefined;
534
- const classified = classifyError(errorMessage);
535
- return {
536
- content: [{ type: "text", text: `Error: ${errorMessage}` }],
537
- structuredContent: {
538
- result: {
539
- status: "error",
540
- error: errorMessage,
541
- error_code: classified.error_code,
542
- retryable: classified.retryable,
543
- recovery_hint: classified.recovery_hint,
544
- },
545
- semantic: buildDataSemantic(undefined, ctx, true, errorMessage),
546
- },
547
- };
548
- }
549
- }
550
- async function handleMarkOperation(args) {
551
- let validated;
552
- try {
553
- validated = strictParse(LocalMarkOperationSchema, args, "local_mark_operation input");
554
- const result = await local_mark_operation(validated);
555
- const ctx = { operation_type: "mark_" + validated.operation_type, data: validated };
556
- return {
557
- content: [{ type: "text", text: JSON.stringify(result) }],
558
- structuredContent: {
559
- result: {
560
- status: "success",
561
- data: result,
562
- },
563
- semantic: buildDataSemantic(result, ctx),
564
- },
565
- };
566
- }
567
- catch (error) {
568
- const errorMessage = error instanceof Error ? error.message : String(error);
569
- const ctx = validated ? { operation_type: "mark_" + validated.operation_type, data: validated } : undefined;
570
- const classified = classifyError(errorMessage);
571
- return {
572
- content: [{ type: "text", text: `Error: ${errorMessage}` }],
573
- structuredContent: {
574
- result: {
575
- status: "error",
576
- error: errorMessage,
577
- error_code: classified.error_code,
578
- retryable: classified.retryable,
579
- recovery_hint: classified.recovery_hint,
580
- },
581
- semantic: buildDataSemantic(undefined, ctx, true, errorMessage),
582
- },
583
- };
592
+ return handleCallResult({ error: errorMessage }, validated ? {
593
+ operation_type: validated.operation_type,
594
+ data: validated.data,
595
+ } : undefined);
584
596
  }
585
597
  }
586
- async function handleInfoOperation(args) {
587
- let validated;
588
- try {
589
- validated = strictParse(LocalInfoOperationSchema, args, "local_info_operation input");
590
- const result = await local_info_operation(validated);
591
- const ctx = { operation_type: "local_info", data: validated };
592
- return {
593
- content: [{ type: "text", text: JSON.stringify(result) }],
594
- structuredContent: {
595
- result: {
596
- status: "success",
597
- data: result,
598
+ function wrapLocalHandler(config) {
599
+ const { schema, operationFn, parseLabel, buildContext } = config;
600
+ return async (args) => {
601
+ let validated;
602
+ try {
603
+ validated = strictParse(schema, args, parseLabel);
604
+ const result = await operationFn(validated);
605
+ const ctx = buildContext(validated);
606
+ return {
607
+ content: [{ type: "text", text: JSON.stringify(result) }],
608
+ structuredContent: {
609
+ result: {
610
+ status: "success",
611
+ data: result,
612
+ },
613
+ semantic: buildDataSemantic(result, ctx),
598
614
  },
599
- semantic: buildDataSemantic(result, ctx),
600
- },
601
- };
602
- }
603
- catch (error) {
604
- const errorMessage = error instanceof Error ? error.message : String(error);
605
- const ctx = validated ? { operation_type: "local_info", data: validated } : undefined;
606
- const classified = classifyError(errorMessage);
607
- return {
608
- content: [{ type: "text", text: `Error: ${errorMessage}` }],
609
- structuredContent: {
610
- result: {
611
- status: "error",
612
- error: errorMessage,
613
- error_code: classified.error_code,
614
- retryable: classified.retryable,
615
- recovery_hint: classified.recovery_hint,
615
+ };
616
+ }
617
+ catch (error) {
618
+ const errorMessage = error instanceof Error ? error.message : String(error);
619
+ const ctx = validated ? buildContext(validated) : undefined;
620
+ const classified = classifyError(errorMessage);
621
+ const errorResult = {
622
+ status: "error",
623
+ error: errorMessage,
624
+ };
625
+ if (classified.error_code !== undefined)
626
+ errorResult.error_code = classified.error_code;
627
+ if (classified.retryable !== undefined)
628
+ errorResult.retryable = classified.retryable;
629
+ if (classified.recovery_hint !== undefined)
630
+ errorResult.recovery_hint = classified.recovery_hint;
631
+ return {
632
+ content: [{ type: "text", text: `Error: ${errorMessage}` }],
633
+ structuredContent: {
634
+ result: errorResult,
635
+ semantic: buildDataSemantic(undefined, ctx, true, errorMessage),
616
636
  },
617
- semantic: buildDataSemantic(undefined, ctx, true, errorMessage),
618
- },
619
- };
620
- }
637
+ };
638
+ }
639
+ };
621
640
  }
641
+ const handleAccountOperation = wrapLocalHandler({
642
+ schema: AccountOperationSchema,
643
+ operationFn: account_operation,
644
+ parseLabel: "account_operation input",
645
+ buildContext: (validated) => ({ operation_type: "account_" + validated.operation_type, data: validated }),
646
+ });
647
+ const handleMarkOperation = wrapLocalHandler({
648
+ schema: LocalMarkOperationSchema,
649
+ operationFn: local_mark_operation,
650
+ parseLabel: "local_mark_operation input",
651
+ buildContext: (validated) => ({ operation_type: "mark_" + validated.operation_type, data: validated }),
652
+ });
653
+ const handleInfoOperation = wrapLocalHandler({
654
+ schema: LocalInfoOperationSchema,
655
+ operationFn: local_info_operation,
656
+ parseLabel: "local_info_operation input",
657
+ buildContext: (validated) => ({ operation_type: "local_info", data: validated }),
658
+ });
622
659
  async function handleWipOperations(args) {
623
660
  const validated = strictParse(WipOperationsSchema, args, "wip_file input");
624
661
  let structuredContent;
@@ -780,168 +817,501 @@ async function handleOnchainEvents(args) {
780
817
  },
781
818
  };
782
819
  }
783
- function normalizeAccountOrMark(input) {
784
- if (typeof input === 'string') {
785
- return { name_or_address: input, local_mark_first: true };
786
- }
787
- return input;
788
- }
789
- function normalizeManyAccountOrMark(input) {
790
- if (Array.isArray(input)) {
791
- return {
792
- entities: input.map(item => typeof item === 'string' ? { name_or_address: item, local_mark_first: true } : item),
793
- check_all_founded: true
794
- };
795
- }
796
- return input;
797
- }
798
- async function handleMessengerOperation(args) {
799
- const validated = strictParse(MessengerOperationInputSchema, args, "messenger_operation input");
820
+ async function handleProjectOperation(args) {
821
+ const action = args.action;
822
+ const project = args.project;
823
+ const object = args.object;
800
824
  let result;
801
- switch (validated.operation) {
802
- case "watch_conversations": {
803
- const conversations = await watch_conversations(validated.filter);
804
- result = { operation: "watch_conversations", result: conversations };
825
+ switch (action) {
826
+ case "list_projects":
827
+ result = await queryProjects();
805
828
  break;
806
- }
807
- case "send_message": {
808
- const sendResult = await send_message(validated.from, normalizeAccountOrMark(validated.to), validated.content, validated.options);
809
- const filteredResult = {
810
- ...sendResult,
811
- merkleData: sendResult.merkleData ? {
812
- leafIndex: sendResult.merkleData.leafIndex,
813
- prevRoot: sendResult.merkleData.prevRoot,
814
- newRoot: sendResult.merkleData.newRoot,
815
- serverSignature: sendResult.merkleData.serverSignature,
816
- serverTimestamp: sendResult.merkleData.serverTimestamp,
817
- serverPublicKey: sendResult.merkleData.serverPublicKey,
818
- } : undefined,
819
- };
820
- result = { operation: "send_message", result: filteredResult };
829
+ case "list_objects":
830
+ if (!project)
831
+ throw new Error("'project' param is required for list_objects");
832
+ result = await queryProjectObjects(project);
821
833
  break;
822
- }
823
- case "send_file": {
824
- const sendResult = await send_file(validated.from, normalizeAccountOrMark(validated.to), validated.filePath, validated.options);
825
- const filteredResult = {
826
- ...sendResult,
827
- merkleData: sendResult.merkleData ? {
828
- leafIndex: sendResult.merkleData.leafIndex,
829
- prevRoot: sendResult.merkleData.prevRoot,
830
- newRoot: sendResult.merkleData.newRoot,
831
- serverSignature: sendResult.merkleData.serverSignature,
832
- serverTimestamp: sendResult.merkleData.serverTimestamp,
833
- serverPublicKey: sendResult.merkleData.serverPublicKey,
834
- } : undefined,
835
- };
836
- result = { operation: "send_file", result: filteredResult };
834
+ case "shareable":
835
+ result = await queryShareableObjects();
837
836
  break;
838
- }
839
- case "watch_messages": {
840
- const filter = validated.filter ? {
841
- ...validated.filter,
842
- peerAddress: validated.filter.peerAddress ? normalizeAccountOrMark(validated.filter.peerAddress) : undefined
843
- } : undefined;
844
- const messages = await watch_messages(filter);
845
- result = { operation: "watch_messages", result: messages };
837
+ case "dependencies":
838
+ if (!object)
839
+ throw new Error("'object' param is required for dependencies");
840
+ result = queryDependencies(object);
846
841
  break;
847
- }
848
- case "extract_zip_messages": {
849
- const extractedPaths = await extract_zip_messages(validated.account, validated.messages, validated.outputDir);
850
- result = { operation: "extract_zip_messages", result: extractedPaths };
842
+ case "referenced_by":
843
+ if (!object)
844
+ throw new Error("'object' param is required for referenced_by");
845
+ result = queryReferencedBy(object);
851
846
  break;
852
- }
853
- case "generate_wts": {
854
- const params = validated.params ? {
855
- ...validated.params,
856
- peerAccount: normalizeAccountOrMark(validated.params.peerAccount)
857
- } : undefined;
858
- const wtsResult = await generate_wts(params);
859
- result = { operation: "generate_wts", result: wtsResult };
847
+ case "pre_publish_check":
848
+ if (!object)
849
+ throw new Error("'object' param is required for pre_publish_check");
850
+ result = { warnings: queryPrePublishCheck(object) };
860
851
  break;
861
- }
862
- case "verify_wts": {
863
- const verifyResult = await verify_wts(validated.wtsFilePath);
864
- result = { operation: "verify_wts", result: verifyResult };
852
+ case "cross_project_refs":
853
+ result = queryCrossProjectReferences();
865
854
  break;
866
- }
867
- case "sign_wts": {
868
- const signedPath = await sign_wts(validated.wtsFilePath, validated.account, validated.outputPath);
869
- result = { operation: "sign_wts", result: signedPath };
855
+ case "graph_stats":
856
+ result = queryGraphStats();
870
857
  break;
871
- }
872
- case "wts2html": {
873
- const htmlResult = await wts2html(validated.wtsPath, validated.options);
874
- result = { operation: "wts2html", result: htmlResult };
858
+ case "save_graph":
859
+ result = { saved: true, path: saveGraph() };
875
860
  break;
876
- }
877
- case "proof_message": {
878
- const proofResult = await proof_message(validated.account, validated.messageId, validated.network);
879
- result = { operation: "proof_message", result: proofResult };
861
+ case "load_graph":
862
+ result = { loaded: loadGraph() };
880
863
  break;
881
- }
882
- case "blacklist": {
883
- const blacklistParams = {
884
- account: validated.account,
885
- op: validated.blacklist.op
886
- };
887
- if ('users' in validated.blacklist) {
888
- blacklistParams.users = normalizeManyAccountOrMark(validated.blacklist.users);
889
- }
890
- const blacklistResult = await blacklist(blacklistParams);
891
- result = { operation: "blacklist", op: validated.blacklist.op, result: blacklistResult.result };
864
+ default:
865
+ throw new Error(`Unknown project_operation action: ${action}`);
866
+ }
867
+ return {
868
+ content: [{ type: "text", text: JSON.stringify({ result }) }],
869
+ structuredContent: { result },
870
+ };
871
+ }
872
+ async function handleConfigOperation(args) {
873
+ const action = args.action;
874
+ let result;
875
+ switch (action) {
876
+ case "list":
877
+ result = { services: listServices() };
892
878
  break;
893
- }
894
- case "friendslist": {
895
- const friendslistParams = {
896
- account: validated.account,
897
- op: validated.friendslist.op
898
- };
899
- if ('users' in validated.friendslist) {
900
- friendslistParams.users = normalizeManyAccountOrMark(validated.friendslist.users);
879
+ case "toggle": {
880
+ const service = args.service;
881
+ if (!service)
882
+ throw new Error("'service' param is required for toggle");
883
+ const existing = getServiceInfo(service);
884
+ if (!existing) {
885
+ throw new Error(`Unknown service: ${service}. Use action='list' to see all valid services.`);
901
886
  }
902
- const friendslistResult = await friendslist(friendslistParams);
903
- result = { operation: "friendslist", op: validated.friendslist.op, result: friendslistResult.result };
904
- break;
905
- }
906
- case "guardlist": {
907
- const guardlistResult = await guardlist({
908
- account: validated.account,
909
- ...validated.guardlist
910
- });
911
- result = { operation: "guardlist", op: validated.guardlist.op, result: guardlistResult.result };
887
+ const newState = toggleService(service);
888
+ result = { service, enabled: newState, reminder: existing.reminder };
912
889
  break;
913
890
  }
914
- case "settings": {
915
- const settingsResult = await settings({
916
- account: validated.account,
917
- ...validated.settings
918
- });
919
- result = { operation: "settings", op: validated.settings.op, result: settingsResult.result };
891
+ case "enable": {
892
+ const service = args.service;
893
+ if (!service)
894
+ throw new Error("'service' param is required for enable");
895
+ const existing = getServiceInfo(service);
896
+ if (!existing)
897
+ throw new Error(`Unknown service: ${service}. Use action='list' to see all valid services.`);
898
+ setServiceEnabled(service, true);
899
+ result = { service, enabled: true, reminder: existing.reminder };
920
900
  break;
921
901
  }
922
- case "mark_messages_as_viewed": {
923
- const markedCount = await mark_messages_as_viewed(validated.messageIds, validated.account);
924
- result = { operation: "mark_messages_as_viewed", result: markedCount };
902
+ case "disable": {
903
+ const service = args.service;
904
+ if (!service)
905
+ throw new Error("'service' param is required for disable");
906
+ const existing = getServiceInfo(service);
907
+ if (!existing)
908
+ throw new Error(`Unknown service: ${service}. Use action='list' to see all valid services.`);
909
+ setServiceEnabled(service, false);
910
+ result = { service, enabled: false, reminder: existing.reminder };
925
911
  break;
926
912
  }
927
- case "mark_conversation_as_viewed": {
928
- const markedCount = await mark_conversation_as_viewed(normalizeAccountOrMark(validated.peerAddress), validated.account);
929
- result = { operation: "mark_conversation_as_viewed", result: markedCount };
913
+ case "reset": {
914
+ const service = args.service;
915
+ if (!service)
916
+ throw new Error("'service' param is required for reset");
917
+ const existing = getServiceInfo(service);
918
+ if (!existing)
919
+ throw new Error(`Unknown service: ${service}. Use action='list' to see all valid services.`);
920
+ resetService(service);
921
+ result = { service, enabled: getServiceInfo(service)?.enabled, reminder: existing.reminder, reset: true };
930
922
  break;
931
923
  }
932
- case "pull_messages": {
933
- const messages = await pull_messages(validated.account, validated.limit);
934
- result = { operation: "pull_messages", result: messages };
924
+ case "info": {
925
+ const service = args.service;
926
+ if (!service)
927
+ throw new Error("'service' param is required for info");
928
+ const info = getServiceInfo(service);
929
+ if (!info)
930
+ throw new Error(`Unknown service: ${service}. Use action='list' to see all valid services.`);
931
+ result = info;
935
932
  break;
936
933
  }
937
934
  default:
938
- throw new Error(`Unknown messenger operation: ${validated.operation}`);
935
+ throw new Error(`Unknown config_operation action: ${action}`);
939
936
  }
940
937
  return {
941
- content: [{ type: "text", text: JSON.stringify(result) }],
938
+ content: [{ type: "text", text: JSON.stringify({ result }) }],
942
939
  structuredContent: { result },
943
940
  };
944
941
  }
942
+ function extractTrustMetrics(serviceObj) {
943
+ const data = serviceObj?.data ?? serviceObj ?? {};
944
+ const sales = Array.isArray(data.sales) ? data.sales : [];
945
+ const activeSales = sales.filter((s) => s && !s.suspension);
946
+ const compensationFund = data.compensation_fund;
947
+ const compBalance = (() => {
948
+ if (compensationFund === null || compensationFund === undefined)
949
+ return undefined;
950
+ if (typeof compensationFund === "bigint")
951
+ return compensationFund;
952
+ if (typeof compensationFund === "number")
953
+ return BigInt(compensationFund);
954
+ if (typeof compensationFund === "string") {
955
+ try {
956
+ return BigInt(compensationFund);
957
+ }
958
+ catch {
959
+ return undefined;
960
+ }
961
+ }
962
+ if (typeof compensationFund === "object") {
963
+ const bal = compensationFund.balance;
964
+ if (bal === null || bal === undefined)
965
+ return undefined;
966
+ try {
967
+ return BigInt(bal);
968
+ }
969
+ catch {
970
+ return undefined;
971
+ }
972
+ }
973
+ return undefined;
974
+ })();
975
+ return {
976
+ arbitrationCases: Array.isArray(data.arbitrations) ? data.arbitrations.length : undefined,
977
+ compensationFundBalance: compBalance,
978
+ hasMachineBound: typeof data.machine === "string" && data.machine.length > 0,
979
+ hasBuyGuard: typeof data.buy_guard === "string" && data.buy_guard.length > 0,
980
+ };
981
+ }
982
+ function buildPuzzleRawData(serviceObj, orderAmount, trustScore, serviceOwner) {
983
+ const data = serviceObj?.data ?? serviceObj ?? {};
984
+ const sales = Array.isArray(data.sales) ? data.sales : [];
985
+ const order_allocators = data.order_allocators
986
+ ? Array.isArray(data.order_allocators.allocators)
987
+ ? data.order_allocators
988
+ : { allocators: data.order_allocators }
989
+ : undefined;
990
+ const serviceRaw = {
991
+ name: data.name ?? serviceObj?.id,
992
+ bPublished: data.bPublished,
993
+ bPaused: data.bPaused,
994
+ price: sales[0]?.price != null ? String(sales[0].price) : "0",
995
+ priceRaw: sales[0]?.price != null ? BigInt(sales[0].price) : 0n,
996
+ token_type: sales[0]?.price_type ?? (compensation_fund_token(data) ?? "0x2::wow::WOW"),
997
+ sales,
998
+ machine: data.machine ?? undefined,
999
+ buy_guard: data.buy_guard ?? undefined,
1000
+ customer_required: data.customer_required,
1001
+ arbitrations: data.arbitrations,
1002
+ compensation_fund: data.compensation_fund
1003
+ ? { balance: extractBalance(data.compensation_fund) }
1004
+ : undefined,
1005
+ compensation_lock_duration: typeof data.setting_lock_duration === "number"
1006
+ ? data.setting_lock_duration
1007
+ : undefined,
1008
+ um: data.um ?? undefined,
1009
+ order_allocators: order_allocators ? [order_allocators] : undefined,
1010
+ };
1011
+ return {
1012
+ service: serviceRaw,
1013
+ order_amount: orderAmount,
1014
+ trust_score: trustScore,
1015
+ service_owner: serviceOwner,
1016
+ };
1017
+ }
1018
+ function compensation_fund_token(data) {
1019
+ if (data?.compensation_fund && typeof data.compensation_fund === "object") {
1020
+ return data.compensation_fund.token_type;
1021
+ }
1022
+ return undefined;
1023
+ }
1024
+ function extractBalance(b) {
1025
+ if (b === null || b === undefined)
1026
+ return 0n;
1027
+ if (typeof b === "bigint")
1028
+ return b;
1029
+ if (typeof b === "number")
1030
+ return BigInt(b);
1031
+ if (typeof b === "string") {
1032
+ try {
1033
+ return BigInt(b);
1034
+ }
1035
+ catch {
1036
+ return 0n;
1037
+ }
1038
+ }
1039
+ if (typeof b === "object") {
1040
+ const bal = b.balance;
1041
+ if (bal === null || bal === undefined)
1042
+ return 0n;
1043
+ try {
1044
+ return BigInt(bal);
1045
+ }
1046
+ catch {
1047
+ return 0n;
1048
+ }
1049
+ }
1050
+ return 0n;
1051
+ }
1052
+ async function handleTrustScore(args) {
1053
+ const validated = strictParse(TrustScoreInputSchema, args, "trust_score input");
1054
+ const depth = (validated.depth ?? "evaluate");
1055
+ const queryResult = await query_objects({
1056
+ objects: [validated.service],
1057
+ no_cache: validated.no_cache,
1058
+ network: validated.network,
1059
+ });
1060
+ const objects = queryResult?.objects;
1061
+ if (!objects || !Array.isArray(objects) || objects.length === 0) {
1062
+ throw new Error(`Service object not found for '${validated.service}'. ` +
1063
+ `Verify the ID/name and network, or use query_toolkit with query_type='onchain_objects' to debug.`);
1064
+ }
1065
+ const serviceObj = objects[0];
1066
+ const objType = serviceObj?.data?.object_type ?? serviceObj?.object_type ?? serviceObj?.type;
1067
+ if (objType && typeof objType === "string" && !objType.includes("Service")) {
1068
+ throw new Error(`Object '${validated.service}' is not a Service (type: ${objType}). ` +
1069
+ `trust_score only evaluates Service objects.`);
1070
+ }
1071
+ const metrics = extractTrustMetrics(serviceObj);
1072
+ const trustScore = computeServiceTrustScore(metrics);
1073
+ const sales = Array.isArray(serviceObj?.data?.sales) ? serviceObj.data.sales : [];
1074
+ const activeSale = sales.find((s) => s && !s.suspension) ?? sales[0];
1075
+ const salePriceRaw = activeSale?.price != null ? BigInt(activeSale.price) : 0n;
1076
+ const orderAmount = validated.order_amount != null
1077
+ ? BigInt(validated.order_amount)
1078
+ : salePriceRaw;
1079
+ let riskScore = undefined;
1080
+ let infoPuzzle = undefined;
1081
+ if (depth === "evaluate" || depth === "preorder") {
1082
+ const puzzleRaw = buildPuzzleRawData(serviceObj, orderAmount, { score: trustScore.score, level: trustScore.level }, undefined);
1083
+ infoPuzzle = assembleInfoPuzzle(validated.service, puzzleRaw, depth);
1084
+ riskScore = assessRisk(infoPuzzle);
1085
+ }
1086
+ const result = {
1087
+ service_id: validated.service,
1088
+ service_name: serviceObj?.data?.name ?? serviceObj?.name ?? validated.service,
1089
+ service_basics: {
1090
+ bPublished: serviceObj?.data?.bPublished ?? false,
1091
+ bPaused: serviceObj?.data?.bPaused ?? false,
1092
+ sales_count: sales.filter((s) => s && !s.suspension).length,
1093
+ has_machine: !!serviceObj?.data?.machine,
1094
+ has_buy_guard: !!serviceObj?.data?.buy_guard,
1095
+ has_um_contact: !!serviceObj?.data?.um,
1096
+ arbitrations_count: Array.isArray(serviceObj?.data?.arbitrations)
1097
+ ? serviceObj.data.arbitrations.length
1098
+ : 0,
1099
+ },
1100
+ trust_score: {
1101
+ score: trustScore.score,
1102
+ level: trustScore.level,
1103
+ summary: trustScore.summary,
1104
+ warnings: trustScore.warnings,
1105
+ breakdown: trustScore.breakdown,
1106
+ },
1107
+ order_amount: orderAmount.toString(),
1108
+ depth,
1109
+ ...(riskScore ? {
1110
+ risk_score: {
1111
+ total: riskScore.total,
1112
+ level: riskScore.level,
1113
+ red_flags: riskScore.red_flags,
1114
+ advice: riskScore.advice,
1115
+ dimensions: riskScore.dimensions,
1116
+ },
1117
+ } : {}),
1118
+ ...(infoPuzzle ? {
1119
+ info_puzzle: {
1120
+ completeness: infoPuzzle.completeness,
1121
+ gaps: infoPuzzle.gaps,
1122
+ assembled_at: infoPuzzle.assembled_at,
1123
+ },
1124
+ } : {}),
1125
+ };
1126
+ return {
1127
+ content: [{ type: "text", text: JSON.stringify({ result }) }],
1128
+ structuredContent: { result },
1129
+ };
1130
+ }
1131
+ function normalizeAccountOrMark(input) {
1132
+ if (typeof input === 'string') {
1133
+ return { name_or_address: input, local_mark_first: true };
1134
+ }
1135
+ return input;
1136
+ }
1137
+ function normalizeManyAccountOrMark(input) {
1138
+ if (Array.isArray(input)) {
1139
+ return {
1140
+ entities: input.map(item => typeof item === 'string' ? { name_or_address: item, local_mark_first: true } : item),
1141
+ check_all_founded: true
1142
+ };
1143
+ }
1144
+ return input;
1145
+ }
1146
+ async function handleMessengerOperation(args) {
1147
+ let validated;
1148
+ try {
1149
+ validated = strictParse(MessengerOperationInputSchema, args, "messenger_operation input");
1150
+ let result;
1151
+ switch (validated.operation) {
1152
+ case "watch_conversations": {
1153
+ const conversations = await watch_conversations(validated.filter);
1154
+ result = { operation: "watch_conversations", result: conversations };
1155
+ break;
1156
+ }
1157
+ case "send_message": {
1158
+ const sendResult = await send_message(validated.from, normalizeAccountOrMark(validated.to), validated.content, validated.options);
1159
+ const filteredResult = {
1160
+ ...sendResult,
1161
+ merkleData: sendResult.merkleData ? {
1162
+ leafIndex: sendResult.merkleData.leafIndex,
1163
+ prevRoot: sendResult.merkleData.prevRoot,
1164
+ newRoot: sendResult.merkleData.newRoot,
1165
+ serverSignature: sendResult.merkleData.serverSignature,
1166
+ serverTimestamp: sendResult.merkleData.serverTimestamp,
1167
+ serverPublicKey: sendResult.merkleData.serverPublicKey,
1168
+ } : undefined,
1169
+ };
1170
+ result = { operation: "send_message", result: filteredResult };
1171
+ break;
1172
+ }
1173
+ case "send_file": {
1174
+ const sendResult = await send_file(validated.from, normalizeAccountOrMark(validated.to), validated.filePath, validated.options);
1175
+ const filteredResult = {
1176
+ ...sendResult,
1177
+ merkleData: sendResult.merkleData ? {
1178
+ leafIndex: sendResult.merkleData.leafIndex,
1179
+ prevRoot: sendResult.merkleData.prevRoot,
1180
+ newRoot: sendResult.merkleData.newRoot,
1181
+ serverSignature: sendResult.merkleData.serverSignature,
1182
+ serverTimestamp: sendResult.merkleData.serverTimestamp,
1183
+ serverPublicKey: sendResult.merkleData.serverPublicKey,
1184
+ } : undefined,
1185
+ };
1186
+ result = { operation: "send_file", result: filteredResult };
1187
+ break;
1188
+ }
1189
+ case "watch_messages": {
1190
+ const filter = validated.filter ? {
1191
+ ...validated.filter,
1192
+ peerAddress: validated.filter.peerAddress ? normalizeAccountOrMark(validated.filter.peerAddress) : undefined
1193
+ } : undefined;
1194
+ const messages = await watch_messages(filter);
1195
+ result = { operation: "watch_messages", result: messages };
1196
+ break;
1197
+ }
1198
+ case "extract_zip_messages": {
1199
+ const extractedPaths = await extract_zip_messages(validated.account, validated.messages, validated.outputDir);
1200
+ result = { operation: "extract_zip_messages", result: extractedPaths };
1201
+ break;
1202
+ }
1203
+ case "generate_wts": {
1204
+ const params = validated.params ? {
1205
+ ...validated.params,
1206
+ peerAccount: normalizeAccountOrMark(validated.params.peerAccount)
1207
+ } : undefined;
1208
+ const wtsResult = await generate_wts(params);
1209
+ result = { operation: "generate_wts", result: wtsResult };
1210
+ break;
1211
+ }
1212
+ case "verify_wts": {
1213
+ const verifyResult = await verify_wts(validated.wtsFilePath);
1214
+ result = { operation: "verify_wts", result: verifyResult };
1215
+ break;
1216
+ }
1217
+ case "sign_wts": {
1218
+ const signedPath = await sign_wts(validated.wtsFilePath, validated.account, validated.outputPath);
1219
+ result = { operation: "sign_wts", result: signedPath };
1220
+ break;
1221
+ }
1222
+ case "wts2html": {
1223
+ const htmlResult = await wts2html(validated.wtsPath, validated.options);
1224
+ result = { operation: "wts2html", result: htmlResult };
1225
+ break;
1226
+ }
1227
+ case "proof_message": {
1228
+ const proofResult = await proof_message(validated.account, validated.messageId, validated.network);
1229
+ result = { operation: "proof_message", result: proofResult };
1230
+ break;
1231
+ }
1232
+ case "blacklist": {
1233
+ const blacklistParams = {
1234
+ account: validated.account,
1235
+ op: validated.blacklist.op
1236
+ };
1237
+ if ('users' in validated.blacklist) {
1238
+ blacklistParams.users = normalizeManyAccountOrMark(validated.blacklist.users);
1239
+ }
1240
+ const blacklistResult = await blacklist(blacklistParams);
1241
+ result = { operation: "blacklist", op: validated.blacklist.op, result: blacklistResult.result };
1242
+ break;
1243
+ }
1244
+ case "friendslist": {
1245
+ const friendslistParams = {
1246
+ account: validated.account,
1247
+ op: validated.friendslist.op
1248
+ };
1249
+ if ('users' in validated.friendslist) {
1250
+ friendslistParams.users = normalizeManyAccountOrMark(validated.friendslist.users);
1251
+ }
1252
+ const friendslistResult = await friendslist(friendslistParams);
1253
+ result = { operation: "friendslist", op: validated.friendslist.op, result: friendslistResult.result };
1254
+ break;
1255
+ }
1256
+ case "guardlist": {
1257
+ const guardlistResult = await guardlist({
1258
+ account: validated.account,
1259
+ ...validated.guardlist
1260
+ });
1261
+ result = { operation: "guardlist", op: validated.guardlist.op, result: guardlistResult.result };
1262
+ break;
1263
+ }
1264
+ case "settings": {
1265
+ const settingsResult = await settings({
1266
+ account: validated.account,
1267
+ ...validated.settings
1268
+ });
1269
+ result = { operation: "settings", op: validated.settings.op, result: settingsResult.result };
1270
+ break;
1271
+ }
1272
+ case "mark_messages_as_viewed": {
1273
+ const markedCount = await mark_messages_as_viewed(validated.messageIds, validated.account);
1274
+ result = { operation: "mark_messages_as_viewed", result: markedCount };
1275
+ break;
1276
+ }
1277
+ case "mark_conversation_as_viewed": {
1278
+ const markedCount = await mark_conversation_as_viewed(normalizeAccountOrMark(validated.peerAddress), validated.account);
1279
+ result = { operation: "mark_conversation_as_viewed", result: markedCount };
1280
+ break;
1281
+ }
1282
+ case "pull_messages": {
1283
+ const messages = await pull_messages(validated.account, validated.limit);
1284
+ result = { operation: "pull_messages", result: messages };
1285
+ break;
1286
+ }
1287
+ default:
1288
+ throw new Error(`Unknown messenger operation: ${validated.operation}`);
1289
+ }
1290
+ return {
1291
+ content: [{ type: "text", text: JSON.stringify(result) }],
1292
+ structuredContent: { result },
1293
+ };
1294
+ }
1295
+ catch (error) {
1296
+ const errorMessage = error instanceof Error ? error.message : String(error);
1297
+ const ctx = validated ? { operation_type: "messenger_" + validated.operation, data: validated } : undefined;
1298
+ const classified = classifyError(errorMessage);
1299
+ const errorResult = { operation: "error", error: errorMessage };
1300
+ if (classified.error_code !== undefined)
1301
+ errorResult.error_code = classified.error_code;
1302
+ if (classified.retryable !== undefined)
1303
+ errorResult.retryable = classified.retryable;
1304
+ if (classified.recovery_hint !== undefined)
1305
+ errorResult.recovery_hint = classified.recovery_hint;
1306
+ return {
1307
+ content: [{ type: "text", text: `Error: ${errorMessage}` }],
1308
+ structuredContent: {
1309
+ result: errorResult,
1310
+ semantic: buildDataSemantic(undefined, ctx, true, errorMessage),
1311
+ },
1312
+ };
1313
+ }
1314
+ }
945
1315
  async function handleGuard2File(args) {
946
1316
  const validated = strictParse(Guard2File_InputSchema, args, "guard2file input");
947
1317
  const env = getEnvConfig(validated.env);
@@ -980,6 +1350,24 @@ async function handleMachineNode2File(args) {
980
1350
  const env = getEnvConfig(validated.env);
981
1351
  try {
982
1352
  await machineNode2file(validated.machine, validated.file_path, validated.format || "json", env.network);
1353
+ let node_count = undefined;
1354
+ try {
1355
+ const filePath = resolve(validated.file_path);
1356
+ const fileContent = await import('fs/promises').then(fs => fs.readFile(filePath, 'utf-8'));
1357
+ if ((validated.format || "json") === "json") {
1358
+ const parsed = JSON.parse(fileContent);
1359
+ if (Array.isArray(parsed)) {
1360
+ node_count = parsed.length;
1361
+ }
1362
+ }
1363
+ else {
1364
+ const nodeMatches = fileContent.match(/^##\s+Node:/gm);
1365
+ node_count = nodeMatches ? nodeMatches.length : 0;
1366
+ }
1367
+ }
1368
+ catch {
1369
+ node_count = undefined;
1370
+ }
983
1371
  const result = {
984
1372
  result: {
985
1373
  status: "success",
@@ -987,10 +1375,12 @@ async function handleMachineNode2File(args) {
987
1375
  file_path: resolve(validated.file_path),
988
1376
  format: validated.format || "json",
989
1377
  machine_object: validated.machine,
990
- node_count: 0,
991
1378
  },
992
1379
  },
993
1380
  };
1381
+ if (node_count !== undefined) {
1382
+ result.result.data.node_count = node_count;
1383
+ }
994
1384
  return {
995
1385
  content: [{ type: "text", text: JSON.stringify(result) }],
996
1386
  structuredContent: result,
@@ -1020,9 +1410,19 @@ async function main() {
1020
1410
  else {
1021
1411
  console.error("Schema files not available. Run 'npm run generate:schemas' to generate them.");
1022
1412
  }
1413
+ if (isProjectServiceEnabled()) {
1414
+ registerSuccessHook((result, context) => {
1415
+ if (context?.operation_type && context?.data) {
1416
+ projectObserve(context.operation_type, context.data, result);
1417
+ }
1418
+ });
1419
+ console.error("ProjectService enabled — object graph observe active");
1420
+ }
1421
+ const activeServices = listServices().filter((s) => s.enabled).map((s) => s.name);
1422
+ console.error(`Phase 2 active services: ${activeServices.join(", ") || "none"}`);
1023
1423
  reg("onchain_operations", {
1024
1424
  title: "⛓️ On-chain Operations",
1025
- description: "On-chain operations for WoWok object: service (marketplace listings), machine (workflow templates), progress (order tracking), repository (on-chain database), arbitration (dispute resolution), contact (IM management), treasury (team funds), reward (incentive pools), allocation (auto-distribution), permission (access control), guard (programmable trust rules), personal (public profile), payment (direct coin transfers), demand (service requests), order (order management), gen_passport (verified credentials), proof (on-chain proof objects), gen_proof (generate proof shortcut).",
1425
+ description: "On-chain operations for WoWok object: service (marketplace listings), machine (workflow templates), progress (order tracking), repository (on-chain database), arbitration (dispute resolution), contact (IM management), treasury (team funds), reward (incentive pools), allocation (auto-distribution), permission (access control), guard (programmable trust rules), personal (public profile), payment (direct coin transfers), demand (service requests), order (order management), gen_passport (verified credentials), proof (on-chain proof objects), gen_proof (generate proof shortcut).\n\n💡 Schema hint: Use schema_query with action='get' and name='onchain_operations' to retrieve the complete parameter schema. For individual operation schemas (e.g., 'onchain_operations_permission'), use schema_query with action='list_operations' to see all available operation schemas.",
1026
1426
  inputSchema: OnchainOperationsSchema,
1027
1427
  outputSchema: CallOutputSchema,
1028
1428
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
@@ -1030,31 +1430,31 @@ async function main() {
1030
1430
  }, handleOnchainOperations);
1031
1431
  reg("account_operation", {
1032
1432
  title: "🔒 LOCAL ONLY: Account - Wallet Management",
1033
- description: "🔒 100% LOCAL, NEVER ON-CHAIN 🔒 Manage WoWok accounts locally on device: generate, suspend, resume, faucet-test, operate assets, sign data, etc.",
1433
+ description: "🔒 100% LOCAL, NEVER ON-CHAIN 🔒 Manage WoWok accounts locally on device: generate, suspend, resume, faucet-test, operate assets, sign data, etc.\n\n💡 Schema hint: Use schema_query with action='get' and name='account_operation' to retrieve the exact parameter schema before calling.",
1034
1434
  inputSchema: AccountOperationSchema,
1035
1435
  outputSchema: AccountOperationOutputWrappedSchema,
1036
1436
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
1037
1437
  _meta: createToolMeta("operation", ["account", "local", "private", "wallet", "off-chain"]),
1038
- }, handleAccountOperation);
1438
+ }, handleAccountOperation, statusErrorShape);
1039
1439
  reg("local_mark_operation", {
1040
1440
  title: "🔒 LOCAL ONLY: LocalMark - Address Book Management",
1041
- description: "100% LOCAL, NEVER ON-CHAIN 🔒 Manage ID names and tags stored ONLY on your local device for easy identification of user address or object IDs by name.",
1441
+ description: "100% LOCAL, NEVER ON-CHAIN 🔒 Manage ID names and tags stored ONLY on your local device for easy identification of user address or object IDs by name.\n\n💡 Schema hint: Use schema_query with action='get' and name='local_mark_operation' to retrieve the exact parameter schema before calling.",
1042
1442
  inputSchema: LocalMarkOperationSchema,
1043
1443
  outputSchema: LocalMarkOperationOutputWrappedSchema,
1044
1444
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
1045
1445
  _meta: createToolMeta("operation", ["mark", "local", "private", "address-book", "off-chain"]),
1046
- }, handleMarkOperation);
1446
+ }, handleMarkOperation, statusErrorShape);
1047
1447
  reg("local_info_operation", {
1048
1448
  title: "🔒 LOCAL ONLY: LocalInfo - Private Data Management",
1049
- description: "100% LOCAL, NEVER ON-CHAIN 🔒 Manage sensitive personal information stored ONLY on your device: delivery addresses, phone numbers, contacts.",
1449
+ description: "100% LOCAL, NEVER ON-CHAIN 🔒 Manage sensitive personal information stored ONLY on your device: delivery addresses, phone numbers, contacts.\n\n💡 Schema hint: Use schema_query with action='get' and name='local_info_operation' to retrieve the exact parameter schema before calling.",
1050
1450
  inputSchema: LocalInfoOperationSchema,
1051
1451
  outputSchema: LocalInfoOperationOutputWrappedSchema,
1052
1452
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
1053
1453
  _meta: createToolMeta("operation", ["info", "local", "private", "data-management", "off-chain"]),
1054
- }, handleInfoOperation);
1454
+ }, handleInfoOperation, statusErrorShape);
1055
1455
  reg("wip_file", {
1056
1456
  title: "🤝 Witness Immutable Promise File Operations",
1057
- description: "generate (create WIP files from markdown and images), verify (integrity check), sign (add signatures), or wip2html (convert to HTML).",
1457
+ description: "generate (create WIP files from markdown and images), verify (integrity check), sign (add signatures), or wip2html (convert to HTML).\n\n💡 Schema hint: Use schema_query with action='get' and name='wip_file' to retrieve the exact parameter schema before calling.",
1058
1458
  inputSchema: WipOperationsSchema,
1059
1459
  outputSchema: z.object({
1060
1460
  result: WipOperationOutputSchema,
@@ -1064,28 +1464,28 @@ async function main() {
1064
1464
  }, handleWipOperations);
1065
1465
  reg("messenger_operation", {
1066
1466
  title: "💬 Messenger Operations",
1067
- description: "WoWok encrypted messenger operations: watch conversations (with unread filtering, preview messages), send message, send file, watch messages (with viewed status filtering), extract zip messages, generate WTS, verify WTS, sign WTS, WTS to HTML, proof message on-chain, manage blacklist, friendslist, guardlist, settings, mark messages as viewed, mark conversation as viewed, and pull messages from server.",
1467
+ description: "WoWok encrypted messenger operations: watch conversations (with unread filtering, preview messages), send message, send file, watch messages (with viewed status filtering), extract zip messages, generate WTS, verify WTS, sign WTS, WTS to HTML, proof message on-chain, manage blacklist, friendslist, guardlist, settings, mark messages as viewed, mark conversation as viewed, and pull messages from server.\n\n💡 Schema hint: Use schema_query with action='get' and name='messenger_operation' to retrieve the exact parameter schema before calling.",
1068
1468
  inputSchema: MessengerOperationInputSchema,
1069
1469
  outputSchema: MessengerOperationOutputSchema,
1070
1470
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
1071
1471
  _meta: createToolMeta("operation", ["messenger", "message", "file", "wts", "blacklist", "friendslist", "guardlist", "settings", "proof", "communication"]),
1072
- }, handleMessengerOperation);
1472
+ }, handleMessengerOperation, operationErrorShape, 30000);
1073
1473
  reg("guard2file", {
1074
1474
  title: "📄 Guard to File - Export Guard Definition",
1075
- description: "Export a Guard object's definition from the blockchain to a local JSON or Markdown file for editing and creating new Guard objects. Note: To query on-chain object information, use the 'query_toolkit' tool instead.",
1475
+ description: "Export a Guard object's definition from the blockchain to a local JSON or Markdown file for editing and creating new Guard objects. Note: To query on-chain object information, use the 'query_toolkit' tool instead.\n\n💡 Schema hint: Use schema_query with action='get' and name='guard2file' to retrieve the exact parameter schema before calling.",
1076
1476
  inputSchema: Guard2File_InputSchema,
1077
1477
  outputSchema: Guard2File_OutputWrappedSchema,
1078
1478
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
1079
1479
  _meta: createToolMeta("generate file", ["guard", "export", "file", "json", "markdown", "on-chain"]),
1080
- }, handleGuard2File);
1480
+ }, handleGuard2File, strictStatusErrorShape);
1081
1481
  reg("machineNode2file", {
1082
1482
  title: "⚙️ Machine Node to File - Export Machine Node Definition",
1083
- description: "Export a Machine object's node definition from the blockchain to a local JSON or Markdown file for editing and creating new Machine objects. Note: To query on-chain object information, use the 'query_toolkit' tool instead.",
1483
+ description: "Export a Machine object's node definition from the blockchain to a local JSON or Markdown file for editing and creating new Machine objects. Note: To query on-chain object information, use the 'query_toolkit' tool instead.\n\n💡 Schema hint: Use schema_query with action='get' and name='machineNode2file' to retrieve the exact parameter schema before calling.",
1084
1484
  inputSchema: MachineNode2File_InputSchema,
1085
1485
  outputSchema: MachineNode2File_OutputWrappedSchema,
1086
1486
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
1087
1487
  _meta: createToolMeta("generate file", ["machine", "export", "file", "json", "markdown", "on-chain", "workflow"]),
1088
- }, handleMachineNode2File);
1488
+ }, handleMachineNode2File, strictStatusErrorShape);
1089
1489
  reg("query_toolkit", {
1090
1490
  title: "🔍 Data Query Toolkit",
1091
1491
  description: "WOWOK data query toolkit — 9 query types covering local device data and on-chain blockchain data:\n\n"
@@ -1100,10 +1500,12 @@ async function main() {
1100
1500
  + "7. onchain_personal_profile — Query any user's PUBLIC on-chain profile: social links, reputation (likes/dislikes), personal info records, voting history, referrer.\n"
1101
1501
  + "8. onchain_objects — Batch query on-chain WOWOK objects by ID or name: supports Service, Machine, Order, Treasury, Reward, Arb, Personal, Contact, and more.\n"
1102
1502
  + "9. onchain_received — Query objects (Payments, Tokens, NFTs) received by a specific object. Supports pagination and type filter.\n\n"
1103
- + "For dynamic table data queries (pagination, table items), use the 'onchain_table_data' tool.",
1503
+ + "For dynamic table data queries (pagination, table items), use the 'onchain_table_data' tool.\n\n"
1504
+ + "💡 Schema hint: Use schema_query with action='get' and name='query_toolkit' to retrieve the exact parameter schema with all query types and field definitions.",
1104
1505
  inputSchema: WatchQueryOperationsSchema,
1105
1506
  outputSchema: z.object({
1106
- result: z.any().describe("Query result — type depends on query_type. Local queries return arrays (MarkData[], AccountData[], InfoData[], TokenTypeInfo[]). account_balance returns { address, balance? | coin? }. Onchain queries return typed objects or undefined. onchain_received returns ReceivedBalance | ReceivedNormal[].")
1507
+ result: z.unknown().describe("Query result — type depends on query_type. Local queries return arrays (MarkData[], AccountData[], InfoData[], TokenTypeInfo[]). account_balance returns { address, balance? | coin? }. Onchain queries return typed objects or undefined. onchain_received returns ReceivedBalance | ReceivedNormal[]."),
1508
+ semantic: z.unknown().optional().describe("Business semantic summary for the query operation"),
1107
1509
  }),
1108
1510
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
1109
1511
  _meta: createToolMeta("query", ["watch", "query", "on-chain", "local", "events", "objects", "tokens", "balance", "profile"]),
@@ -1122,7 +1524,8 @@ async function main() {
1122
1524
  + "9. onchain_table_item_machine_node — Query a workflow node definition from a Machine object's node table (Parent: Machine). Key: node name (string). Returns node configuration: pairs, forwards, guards, thresholds.\n"
1123
1525
  + "10. onchain_table_item_progress_history — Query a progress step record from a Progress object's history table (Parent: Progress). Key: sequence number (u64). Returns step details: node, next_node, session state, time.\n"
1124
1526
  + "11. onchain_table_item_address_mark — Query a PUBLIC on-chain name/tag mark from an AddressMark object's table (Parent: AddressMark). Key: address. Returns public labels: entity, name, tags[]. Unlike local marks, these are published on-chain.\n"
1125
- + "12. onchain_table_item_generic — Query a generic table item from ANY object's dynamic fields (Parent: any object). Supports arbitrary key types (address, u64, string, object ID, etc.). Use for custom objects and general-purpose table lookups. Returns: ObjectBase | undefined.",
1527
+ + "12. onchain_table_item_generic — Query a generic table item from ANY object's dynamic fields (Parent: any object). Supports arbitrary key types (address, u64, string, object ID, etc.). Use for custom objects and general-purpose table lookups. Returns: ObjectBase | undefined.\n\n"
1528
+ + "💡 Schema hint: Use schema_query with action='get' and name='onchain_table_data' to retrieve the exact parameter schema with all table item types and field definitions.",
1126
1529
  inputSchema: OnchainTableDataSchema,
1127
1530
  outputSchema: OnchainTableDataResultSchema,
1128
1531
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
@@ -1130,7 +1533,7 @@ async function main() {
1130
1533
  }, handleOnchainTableData);
1131
1534
  reg("onchain_events", {
1132
1535
  title: "📅 Watch WoWok On-chain Events",
1133
- description: "Watch on-chain WoWok events by type. Supports arbitration events, new order events, progress events, demand presentation events, demand feedback events, and new entity registration events. Use pagination cursor for fetching large result sets.",
1536
+ description: "Watch on-chain WoWok events by type. Supports arbitration events, new order events, progress events, demand presentation events, demand feedback events, and new entity registration events. Use pagination cursor for fetching large result sets.\n\n💡 Schema hint: Use schema_query with action='get' and name='onchain_events' to retrieve the exact parameter schema with all event types and field definitions.",
1134
1537
  inputSchema: OnchainEventsInputSchema,
1135
1538
  outputSchema: OnchainEventsResultSchema,
1136
1539
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
@@ -1155,19 +1558,8 @@ async function main() {
1155
1558
  " 'get_output' - Fetch the output JSON Schema of a tool by name (e.g. 'onchain_operations'). Use with the 'name' param. Use this to understand a tool's return value structure.\n" +
1156
1559
  " 'search' - Find schemas by keyword, matching name/title/description. Use with the 'query' param.\n" +
1157
1560
  " 'list_operations' - Show only on-chain operation schemas (prefixed 'onchain_operations_'). Narrower than 'list'.",
1158
- inputSchema: z.object({
1159
- action: z.enum(["list", "get", "get_output", "search", "list_operations"])
1160
- .describe("Action to perform: 'list' to see all available schemas, 'get' to retrieve a specific input schema, 'get_output' to retrieve a tool's output schema, 'search' to find schemas by keyword, 'list_operations' to list all on-chain operations"),
1161
- name: z.string().optional().describe("Schema/tool name for 'get'/'get_output' action (e.g., 'onchain_operations', 'account_operation', 'onchain_operations_permission')"),
1162
- query: z.string().optional().describe("Search query for 'search' action"),
1163
- }),
1164
- outputSchema: z.object({
1165
- success: z.boolean().describe("Whether the request was successful"),
1166
- action: z.string().describe("The action that was performed"),
1167
- data: z.any().describe("Response data - JSON Schema object for 'get'/'get_output', array of schema info for 'list'/'search'/'list_operations'"),
1168
- message: z.string().describe("Human-readable message describing the result"),
1169
- suggestions: z.array(z.string()).optional().describe("Suggested next steps or alternatives"),
1170
- }),
1561
+ inputSchema: SchemaQueryInputSchema,
1562
+ outputSchema: SchemaQueryOutputSchema,
1171
1563
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
1172
1564
  _meta: createToolMeta("schema", ["schema", "json-schema", "types", "structure", "validation", "reference"]),
1173
1565
  }, async (args) => {
@@ -1285,6 +1677,85 @@ async function main() {
1285
1677
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
1286
1678
  _meta: createToolMeta("operation", ["bridge", "cross-chain", "evm", "ethereum", "wow", "transfer", "rpc"]),
1287
1679
  }, handleBridgeOperations);
1680
+ reg("project_operation", {
1681
+ title: "🗂️ Project - Namespace & Object Graph",
1682
+ description: "Phase 2 project namespace service — manage and query the local object dependency graph (DAG) " +
1683
+ "built on top of local_mark tags. No on-chain writes; all data comes from local marks tagged " +
1684
+ "`project:<prefix>` (auto-injected by the ProjectService when enabled, default ON).\n\n" +
1685
+ "Actions:\n" +
1686
+ " • list_projects — List all discovered projects (grouped by `project:<prefix>` tag) with object counts.\n" +
1687
+ " • list_objects — List objects in a project (requires `project` param).\n" +
1688
+ " • shareable — List objects tagged `shareable:true` (cross-project reusable: common Permission, 3rd-party Arb).\n" +
1689
+ " • dependencies — Trace forward dependencies of an object (BFS transitive closure + dangling refs).\n" +
1690
+ " • referenced_by — Reverse query: who references this object?\n" +
1691
+ " • pre_publish_check — Pre-publish sanity check for a service (dangling deps + cycles).\n" +
1692
+ " • cross_project_refs — Find edges that cross project boundaries.\n" +
1693
+ " • graph_stats — Graph statistics (node/edge counts, cycles, dangling deps).\n" +
1694
+ " • save_graph — Save the in-memory graph to ~/.wowok/project-graph.json (persist across sessions).\n" +
1695
+ " • load_graph — Load the graph from file (restore after restart).\n\n" +
1696
+ "NOTE: The graph is in-memory by default. Use save_graph/load_graph for cross-session persistence " +
1697
+ "(or toggle graph_persist via config_operation for auto-save). " +
1698
+ "list_projects/shareable always query local_mark (persistent).\n\n" +
1699
+ "💡 Schema hint: Use schema_query with action='get' and name='project_operation' to retrieve the exact parameter schema with all actions and field definitions.",
1700
+ inputSchema: ProjectOperationInputSchema,
1701
+ outputSchema: ProjectOperationOutputSchema,
1702
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
1703
+ _meta: createToolMeta("project", ["project", "namespace", "graph", "dag", "dependency", "reference", "organization"]),
1704
+ }, handleProjectOperation);
1705
+ reg("config_operation", {
1706
+ title: "⚙️ Config - Runtime Service Toggles",
1707
+ description: "Phase 2 runtime configuration — toggle Phase 2 services on/off at runtime WITHOUT restarting the MCP server. " +
1708
+ "This is the session-level switch mechanism: AI can toggle based on user conversation context, or users can " +
1709
+ "directly control which Phase 2 features are active.\n\n" +
1710
+ "Actions:\n" +
1711
+ " • list — List all services with current state + reminders.\n" +
1712
+ " • toggle — Toggle a service on/off (requires `service` param). Returns reminder text.\n" +
1713
+ " • enable — Enable a service (requires `service` param).\n" +
1714
+ " • disable — Disable a service (requires `service` param).\n" +
1715
+ " • reset — Reset a service to its default (requires `service` param).\n" +
1716
+ " • info — Get detailed info about a service (requires `service` param).\n\n" +
1717
+ "Services:\n" +
1718
+ " • confirm_gate — Safety Confirmation Gate (default ON)\n" +
1719
+ " • project_service — Project Namespace + Dependency Graph (default ON)\n" +
1720
+ " • harness — L4 Verify/Recover Loop (default OFF)\n" +
1721
+ " • graph_persist — Graph Persistence to File (default OFF)\n" +
1722
+ " • semantic_rich — Semantic Layer Enrichment Reminder (default ON)\n" +
1723
+ " • experience_layer — Real-time Experience Layer (Phase 2 Topic 2, default ON)\n" +
1724
+ " • customer_intelligence — Buyer Intelligence / Risk & Preference Alerts (Phase 3 C-3, default ON)\n" +
1725
+ " • order_monitor — In-progress Order Monitoring (Phase 3 C-3.2, default OFF)\n" +
1726
+ " • industry_evolution — Industry Specialization Evolution Flywheel (Phase 4, default ON)\n\n" +
1727
+ "NOTE: Toggles persist for the MCP process lifetime. Set WOWOK_RUNTIME_CONFIG_PERSIST=1 " +
1728
+ "to persist across sessions to ~/.wowok/runtime-config.json.\n\n" +
1729
+ "💡 Schema hint: Use schema_query with action='get' and name='config_operation' to retrieve the exact parameter schema with all actions and field definitions.",
1730
+ inputSchema: ConfigOperationInputSchema,
1731
+ outputSchema: ConfigOperationOutputSchema,
1732
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
1733
+ _meta: createToolMeta("config", ["config", "toggle", "service", "runtime", "switch", "enable", "disable"]),
1734
+ }, handleConfigOperation);
1735
+ reg("trust_score", {
1736
+ title: "🛡️ Trust Score - Service Risk & Trust Assessment",
1737
+ description: "Proactively query the trust score and risk assessment of a Service object. " +
1738
+ "This is the standalone query form of the trust_score field that is otherwise only " +
1739
+ "passively injected into onchain_operations semantic output.\n\n" +
1740
+ "Returns:\n" +
1741
+ " • trust_score (0-100, 5 dimensions: arbitration/reviews/fulfillment/fund_safety/transparency)\n" +
1742
+ " • risk_score (4 dimensions: workflow/fund/trust/behavior, 100-point) when depth >= 'evaluate'\n" +
1743
+ " • info_puzzle completeness + gaps summary\n" +
1744
+ " • service_basics snapshot (published/paused/sales/guards/arbitrations)\n\n" +
1745
+ "Use this tool when the user asks 'is this service trustworthy?', 'should I buy from this merchant?', " +
1746
+ "'what's the risk of ordering this service?', or any explicit trust/risk inquiry about a Service.\n\n" +
1747
+ "Parameters:\n" +
1748
+ " • service (required) — Service object ID or local_mark name.\n" +
1749
+ " • order_amount (optional) — Order amount in smallest token unit (e.g. 2000000000 for 2 WOW). " +
1750
+ "Defaults to the service's first active sale price.\n" +
1751
+ " • depth (optional, default 'evaluate') — 'browse' (trust score only), 'evaluate' (+ risk assessment), " +
1752
+ "'preorder' (most thorough, includes market context dimension).\n\n" +
1753
+ "💡 Schema hint: Use schema_query with action='get' and name='trust_score' to retrieve the exact parameter schema.",
1754
+ inputSchema: TrustScoreInputSchema,
1755
+ outputSchema: TrustScoreOutputSchema,
1756
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
1757
+ _meta: createToolMeta("trust", ["trust", "score", "risk", "service", "merchant", "reputation", "safety", "evaluate"]),
1758
+ }, handleTrustScore);
1288
1759
  const transport = new StdioServerTransport();
1289
1760
  await server.connect(transport);
1290
1761
  process.on("SIGINT", async () => {