@wowok/agent-mcp 2.3.13 → 2.3.16

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 (194) 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/industry-risks.d.ts +36 -0
  6. package/dist/customer/industry-risks.js +424 -0
  7. package/dist/customer/info-puzzle.d.ts +102 -0
  8. package/dist/customer/info-puzzle.js +312 -0
  9. package/dist/customer/order-monitor.d.ts +75 -0
  10. package/dist/customer/order-monitor.js +327 -0
  11. package/dist/customer/order-strategy.d.ts +36 -0
  12. package/dist/customer/order-strategy.js +373 -0
  13. package/dist/customer/post-purchase.d.ts +42 -0
  14. package/dist/customer/post-purchase.js +350 -0
  15. package/dist/customer/reminder-system.d.ts +42 -0
  16. package/dist/customer/reminder-system.js +295 -0
  17. package/dist/customer/risk-assessment.d.ts +8 -0
  18. package/dist/customer/risk-assessment.js +337 -0
  19. package/dist/customer/types.d.ts +193 -0
  20. package/dist/customer/types.js +13 -0
  21. package/dist/customer/user-preferences.d.ts +67 -0
  22. package/dist/customer/user-preferences.js +451 -0
  23. package/dist/experience/experience-reuse.d.ts +10 -0
  24. package/dist/experience/experience-reuse.js +103 -0
  25. package/dist/experience/index.d.ts +6 -0
  26. package/dist/experience/index.js +5 -0
  27. package/dist/experience/intent-distill.d.ts +3 -0
  28. package/dist/experience/intent-distill.js +83 -0
  29. package/dist/experience/realtime-feedback.d.ts +5 -0
  30. package/dist/experience/realtime-feedback.js +77 -0
  31. package/dist/experience/types.d.ts +50 -0
  32. package/dist/experience/types.js +1 -0
  33. package/dist/experience/user-profile.d.ts +25 -0
  34. package/dist/experience/user-profile.js +171 -0
  35. package/dist/harness/checkpoint.d.ts +8 -0
  36. package/dist/harness/checkpoint.js +129 -0
  37. package/dist/harness/index.d.ts +33 -0
  38. package/dist/harness/index.js +75 -0
  39. package/dist/harness/plan.d.ts +18 -0
  40. package/dist/harness/plan.js +252 -0
  41. package/dist/harness/recover.d.ts +17 -0
  42. package/dist/harness/recover.js +139 -0
  43. package/dist/harness/types.d.ts +137 -0
  44. package/dist/harness/types.js +1 -0
  45. package/dist/harness/verify.d.ts +42 -0
  46. package/dist/harness/verify.js +237 -0
  47. package/dist/index.js +667 -201
  48. package/dist/knowledge/acquisition-flywheel.d.ts +50 -0
  49. package/dist/knowledge/acquisition-flywheel.js +183 -0
  50. package/dist/knowledge/arbitration-trust.d.ts +24 -0
  51. package/dist/knowledge/arbitration-trust.js +117 -0
  52. package/dist/knowledge/audit-rules.d.ts +28 -0
  53. package/dist/knowledge/audit-rules.js +141 -0
  54. package/dist/knowledge/demand-matching.d.ts +29 -0
  55. package/dist/knowledge/demand-matching.js +132 -0
  56. package/dist/knowledge/dynamic-pricing.d.ts +31 -0
  57. package/dist/knowledge/dynamic-pricing.js +87 -0
  58. package/dist/knowledge/flywheel-loop.d.ts +87 -0
  59. package/dist/knowledge/flywheel-loop.js +378 -0
  60. package/dist/knowledge/glossary.d.ts +18 -0
  61. package/dist/knowledge/glossary.js +209 -0
  62. package/dist/knowledge/index.d.ts +64 -0
  63. package/dist/knowledge/index.js +66 -0
  64. package/dist/knowledge/industry-evolution.d.ts +82 -0
  65. package/dist/knowledge/industry-evolution.js +323 -0
  66. package/dist/knowledge/industry-generalizer.d.ts +17 -0
  67. package/dist/knowledge/industry-generalizer.js +381 -0
  68. package/dist/knowledge/industry-registry.d.ts +49 -0
  69. package/dist/knowledge/industry-registry.js +167 -0
  70. package/dist/knowledge/intent-metrics.d.ts +42 -0
  71. package/dist/knowledge/intent-metrics.js +566 -0
  72. package/dist/knowledge/process-model.d.ts +24 -0
  73. package/dist/knowledge/process-model.js +160 -0
  74. package/dist/knowledge/reputation-rules.d.ts +42 -0
  75. package/dist/knowledge/reputation-rules.js +99 -0
  76. package/dist/knowledge/reward-templates.d.ts +25 -0
  77. package/dist/knowledge/reward-templates.js +125 -0
  78. package/dist/knowledge/safety-rules.d.ts +36 -0
  79. package/dist/knowledge/safety-rules.js +171 -0
  80. package/dist/knowledge/tool-constraints.d.ts +30 -0
  81. package/dist/knowledge/tool-constraints.js +185 -0
  82. package/dist/knowledge/trust-metrics.d.ts +37 -0
  83. package/dist/knowledge/trust-metrics.js +138 -0
  84. package/dist/loop-engineering/aggregate.d.ts +50 -0
  85. package/dist/loop-engineering/aggregate.js +132 -0
  86. package/dist/loop-engineering/diagnose.d.ts +22 -0
  87. package/dist/loop-engineering/diagnose.js +273 -0
  88. package/dist/loop-engineering/improve.d.ts +26 -0
  89. package/dist/loop-engineering/improve.js +229 -0
  90. package/dist/loop-engineering/index.d.ts +4 -0
  91. package/dist/loop-engineering/index.js +4 -0
  92. package/dist/loop-engineering/pipeline.d.ts +17 -0
  93. package/dist/loop-engineering/pipeline.js +56 -0
  94. package/dist/mode-market/index.d.ts +3 -0
  95. package/dist/mode-market/index.js +3 -0
  96. package/dist/mode-market/registry.d.ts +53 -0
  97. package/dist/mode-market/registry.js +124 -0
  98. package/dist/mode-market/review.d.ts +27 -0
  99. package/dist/mode-market/review.js +214 -0
  100. package/dist/mode-market/submission.d.ts +25 -0
  101. package/dist/mode-market/submission.js +85 -0
  102. package/dist/project/graph.d.ts +71 -0
  103. package/dist/project/graph.js +314 -0
  104. package/dist/project/index.d.ts +62 -0
  105. package/dist/project/index.js +167 -0
  106. package/dist/project/namespace.d.ts +62 -0
  107. package/dist/project/namespace.js +181 -0
  108. package/dist/project/query.d.ts +40 -0
  109. package/dist/project/query.js +110 -0
  110. package/dist/safety/confirm-gate.d.ts +15 -0
  111. package/dist/safety/confirm-gate.js +44 -0
  112. package/dist/safety/index.d.ts +3 -0
  113. package/dist/safety/index.js +3 -0
  114. package/dist/safety/preview.d.ts +2 -0
  115. package/dist/safety/preview.js +36 -0
  116. package/dist/schema/call/allocation.d.ts +55 -40
  117. package/dist/schema/call/arbitration.d.ts +201 -186
  118. package/dist/schema/call/base.d.ts +2104 -24
  119. package/dist/schema/call/base.js +168 -22
  120. package/dist/schema/call/bridge-handler.js +36 -18
  121. package/dist/schema/call/bridge.d.ts +777 -120
  122. package/dist/schema/call/bridge.js +13 -2
  123. package/dist/schema/call/contact.d.ts +15 -0
  124. package/dist/schema/call/demand.d.ts +69 -54
  125. package/dist/schema/call/guard.d.ts +125 -80
  126. package/dist/schema/call/handler.d.ts +5 -1
  127. package/dist/schema/call/handler.js +108 -3
  128. package/dist/schema/call/index.d.ts +1 -0
  129. package/dist/schema/call/index.js +1 -0
  130. package/dist/schema/call/machine.d.ts +830 -800
  131. package/dist/schema/call/order.d.ts +27 -12
  132. package/dist/schema/call/payment.d.ts +15 -0
  133. package/dist/schema/call/permission.d.ts +15 -0
  134. package/dist/schema/call/personal.d.ts +15 -0
  135. package/dist/schema/call/progress.d.ts +21 -6
  136. package/dist/schema/call/proof.d.ts +42 -12
  137. package/dist/schema/call/proof.js +3 -3
  138. package/dist/schema/call/repository.d.ts +91 -76
  139. package/dist/schema/call/reward.d.ts +51 -36
  140. package/dist/schema/call/semantic.d.ts +24 -0
  141. package/dist/schema/call/semantic.js +981 -0
  142. package/dist/schema/call/service.d.ts +444 -429
  143. package/dist/schema/call/treasury.d.ts +219 -204
  144. package/dist/schema/common/index.js +3 -3
  145. package/dist/schema/local/index.d.ts +341 -74
  146. package/dist/schema/local/index.js +44 -7
  147. package/dist/schema/messenger/index.d.ts +1034 -92
  148. package/dist/schema/messenger/index.js +18 -0
  149. package/dist/schema/operations.d.ts +2634 -1817
  150. package/dist/schema/operations.js +16 -5
  151. package/dist/schema/query/index.d.ts +2293 -2289
  152. package/dist/schema/query/index.js +34 -28
  153. package/dist/schemas/account_operation.output.json +28 -16
  154. package/dist/schemas/account_operation.schema.json +2 -2
  155. package/dist/schemas/bridge_operation.output.json +520 -0
  156. package/dist/schemas/bridge_operation.schema.json +15 -0
  157. package/dist/schemas/guard2file.schema.json +15 -0
  158. package/dist/schemas/index.json +1 -1
  159. package/dist/schemas/local_info_operation.output.json +26 -0
  160. package/dist/schemas/local_info_operation.schema.json +1 -1
  161. package/dist/schemas/local_mark_operation.output.json +27 -1
  162. package/dist/schemas/local_mark_operation.schema.json +4 -4
  163. package/dist/schemas/machineNode2file.schema.json +15 -0
  164. package/dist/schemas/messenger_operation.output.json +549 -0
  165. package/dist/schemas/messenger_operation.schema.json +21 -0
  166. package/dist/schemas/onchain_events.output.json +3 -0
  167. package/dist/schemas/onchain_operations.output.json +814 -37
  168. package/dist/schemas/onchain_operations.schema.json +117 -40
  169. package/dist/schemas/onchain_operations_allocation.schema.json +26 -9
  170. package/dist/schemas/onchain_operations_arbitration.schema.json +26 -9
  171. package/dist/schemas/onchain_operations_contact.schema.json +26 -9
  172. package/dist/schemas/onchain_operations_demand.schema.json +26 -9
  173. package/dist/schemas/onchain_operations_gen_passport.schema.json +51 -17
  174. package/dist/schemas/onchain_operations_guard.schema.json +26 -9
  175. package/dist/schemas/onchain_operations_machine.schema.json +92 -32
  176. package/dist/schemas/onchain_operations_order.schema.json +26 -9
  177. package/dist/schemas/onchain_operations_payment.schema.json +26 -9
  178. package/dist/schemas/onchain_operations_permission.schema.json +26 -9
  179. package/dist/schemas/onchain_operations_personal.schema.json +26 -9
  180. package/dist/schemas/onchain_operations_progress.schema.json +26 -9
  181. package/dist/schemas/onchain_operations_repository.schema.json +26 -9
  182. package/dist/schemas/onchain_operations_reward.schema.json +26 -9
  183. package/dist/schemas/onchain_operations_service.schema.json +26 -9
  184. package/dist/schemas/onchain_operations_treasury.schema.json +26 -9
  185. package/dist/schemas/onchain_table_data.output.json +224 -69
  186. package/dist/schemas/onchain_table_data.schema.json +2 -2
  187. package/dist/schemas/query_toolkit.schema.json +5 -1
  188. package/dist/telemetry/index.d.ts +19 -0
  189. package/dist/telemetry/index.js +112 -0
  190. package/dist/telemetry/redact.d.ts +2 -0
  191. package/dist/telemetry/redact.js +23 -0
  192. package/dist/telemetry/storage.d.ts +8 -0
  193. package/dist/telemetry/storage.js +80 -0
  194. package/package.json +6 -3
package/dist/index.js CHANGED
@@ -5,9 +5,86 @@ 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, } from "./schema/index.js";
9
9
  import { handleBridgeOperations } from "./schema/call/bridge-handler.js";
10
- import { CallService, CallMachine, CallProgress, CallPermission, CallGuard, CallArbitration, CallRepository, CallContact, CallTreasury, CallReward, CallAllocation, CallPersonal, CallPayment, CallDemand, CallOrder, gen_passport, 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, 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";
10
+ import { buildDataSemantic, classifyError } from "./schema/call/semantic.js";
11
+ import { getHarness } from "./harness/index.js";
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, } from "./knowledge/index.js";
17
+ const HARNESS_ENABLED = () => isRuntimeEnabled("harness");
18
+ function withHarness(base, operation, intent) {
19
+ if (!HARNESS_ENABLED())
20
+ return base;
21
+ try {
22
+ const harness = getHarness();
23
+ const expected = harness.expect(operation, intent, base.operation_type, base.data);
24
+ return {
25
+ ...base,
26
+ harness,
27
+ expected,
28
+ operation_id: `${base.operation_type}_${Date.now()}`,
29
+ };
30
+ }
31
+ catch {
32
+ return base;
33
+ }
34
+ }
35
+ function buildPendingConfirmation(operation_type, data, env) {
36
+ const gate = confirmGate(operation_type, data, env, env?.user_intent_phrases);
37
+ if (gate.pass)
38
+ return { content: [], structuredContent: null };
39
+ const preview = gate.preview;
40
+ const rendered = renderPreview(preview);
41
+ const output = {
42
+ message: rendered,
43
+ result: {
44
+ type: "pending_confirmation",
45
+ preview,
46
+ rule_id: gate.rule_id,
47
+ },
48
+ semantic: {
49
+ intent: `${operation_type}_awaiting_confirmation`,
50
+ status: "pending_input",
51
+ summary: `Operation blocked by ConfirmGate (${gate.level}). Review the preview and re-call with env.confirmed=true to proceed.`,
52
+ next_actions: [
53
+ {
54
+ action: "confirm: re-call the SAME operation with env.confirmed=true",
55
+ reason: `ConfirmGate rule '${gate.rule_id}' matched. The operation was NOT executed.`,
56
+ tool: "onchain_operations",
57
+ priority: "required",
58
+ },
59
+ ],
60
+ warnings: preview.warnings ?? [],
61
+ },
62
+ };
63
+ return {
64
+ content: [{ type: "text", text: rendered }],
65
+ structuredContent: output,
66
+ };
67
+ }
68
+ function buildConstraintError(operation_type, violations) {
69
+ const errors = violations.filter((v) => v.severity === "error");
70
+ const errorList = errors.map((v) => ` • [${v.field}] ${v.message}`).join("\n");
71
+ const message = `Pre-call constraint violations for '${operation_type}':\n${errorList}\n\nFix the listed field(s) and retry.`;
72
+ const output = {
73
+ message,
74
+ result: {
75
+ type: "error",
76
+ error: message,
77
+ error_code: "invalid_parameter",
78
+ retryable: false,
79
+ recovery_hint: "Review the constraint violations above and correct the corresponding fields.",
80
+ },
81
+ };
82
+ return {
83
+ content: [{ type: "text", text: message }],
84
+ structuredContent: output,
85
+ };
86
+ }
87
+ 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";
11
88
  import { areSchemasAvailable, getSchemaIndex, processSchemaQuery, } from "./schema-query/index.js";
12
89
  const SERVER_DESCRIPTION = `WoWok MCP Server - Making It Easy for AI Agents to Communicate, Collaborate, Trade, and Trust.
13
90
 
@@ -117,6 +194,78 @@ Token amounts are HIGHLY SENSITIVE. Always:
117
194
  - machineNode2file
118
195
  `;
119
196
  const server = new McpServer(createServerConfig(packageJson, SERVER_DESCRIPTION), createCapabilitiesConfig());
197
+ import { withTelemetry, setTelemetryEnabled } from "./telemetry/index.js";
198
+ if (process.env.WOWOK_TELEMETRY === "false" || process.env.WOWOK_TELEMETRY === "0") {
199
+ setTelemetryEnabled(false);
200
+ }
201
+ function buildClassifiedErrorResult(base, error, classified) {
202
+ const result = { ...base, error };
203
+ if (classified.error_code !== undefined)
204
+ result.error_code = classified.error_code;
205
+ if (classified.retryable !== undefined)
206
+ result.retryable = classified.retryable;
207
+ if (classified.recovery_hint !== undefined)
208
+ result.recovery_hint = classified.recovery_hint;
209
+ return result;
210
+ }
211
+ const statusErrorShape = (error, classified, ctx) => ({
212
+ result: buildClassifiedErrorResult({ status: "error" }, error, classified),
213
+ semantic: buildDataSemantic(undefined, ctx, true, error),
214
+ });
215
+ const operationErrorShape = (error, classified, ctx) => ({
216
+ result: buildClassifiedErrorResult({ operation: "error" }, error, classified),
217
+ semantic: buildDataSemantic(undefined, ctx, true, error),
218
+ });
219
+ const strictStatusErrorShape = (error, _classified, _ctx) => ({
220
+ result: { status: "error", error },
221
+ });
222
+ function reg(name, config, handler, errorShapeBuilder, customTimeoutMs) {
223
+ const timeoutMs = customTimeoutMs ?? 60000;
224
+ const wrappedHandler = wrapHandlerWithErrorShape(handler, timeoutMs, name, errorShapeBuilder);
225
+ server.registerTool(name, config, withTelemetry(name, wrappedHandler));
226
+ }
227
+ function withTimeout(promise, timeoutMs = 30000, operationName = "operation") {
228
+ let timer;
229
+ return Promise.race([
230
+ promise.finally(() => {
231
+ if (timer)
232
+ clearTimeout(timer);
233
+ }),
234
+ new Promise((_, reject) => {
235
+ timer = setTimeout(() => {
236
+ let hint = "";
237
+ if (operationName.includes("messenger")) {
238
+ hint = " This is a messenger network operation. Possible causes: " +
239
+ "(1) messenger server (https://messenger.wowok.net) unreachable, " +
240
+ "(2) no messenger-enabled account configured (use account_operation to set messenger name), " +
241
+ "(3) network connectivity issue. " +
242
+ "Ensure you have a messenger-enabled account and the server is reachable.";
243
+ }
244
+ reject(new Error(`Operation '${operationName}' timed out after ${timeoutMs}ms.${hint}`));
245
+ }, timeoutMs);
246
+ }),
247
+ ]);
248
+ }
249
+ function wrapHandlerWithErrorShape(handler, timeoutMs, toolName, errorShapeBuilder) {
250
+ return async (args) => {
251
+ try {
252
+ return await withTimeout(handler(args), timeoutMs, toolName);
253
+ }
254
+ catch (error) {
255
+ if (errorShapeBuilder) {
256
+ const errorMessage = error instanceof Error ? error.message : String(error);
257
+ const classified = classifyError(errorMessage);
258
+ const ctx = { operation_type: toolName, data: args };
259
+ const structuredContent = errorShapeBuilder(errorMessage, classified, ctx);
260
+ return {
261
+ content: [{ type: "text", text: `Error: ${errorMessage}` }],
262
+ structuredContent,
263
+ };
264
+ }
265
+ throw error;
266
+ }
267
+ };
268
+ }
120
269
  function convertAmountType(type) {
121
270
  if (typeof type === "number")
122
271
  return type;
@@ -223,10 +372,18 @@ async function handleOnchainTableData(args) {
223
372
  }
224
373
  return {
225
374
  content: [{ type: "text", text: JSON.stringify({ result }) }],
226
- structuredContent: { result },
375
+ structuredContent: {
376
+ result,
377
+ semantic: buildDataSemantic(result, {
378
+ operation_type: "onchain_table_data",
379
+ data: validated,
380
+ }),
381
+ },
227
382
  };
228
383
  }
229
384
  async function handleOnchainOperations(args) {
385
+ let validated;
386
+ let constraintWarnings = [];
230
387
  try {
231
388
  if (typeof args === 'object' && args !== null && args.description && !args.operation_type) {
232
389
  const hasWrappedParams = typeof args.description === 'string' &&
@@ -237,15 +394,40 @@ async function handleOnchainOperations(args) {
237
394
  "Incorrect format: { description: '{ operation_type: ... }' }");
238
395
  }
239
396
  }
240
- const validated = strictParse(OnchainOperationsSchema, args, "onchain_operations input");
397
+ validated = strictParse(OnchainOperationsSchema, args, "onchain_operations input");
241
398
  const env = getEnvConfig(validated.env);
399
+ const gateResult = buildPendingConfirmation(validated.operation_type, validated.data, env);
400
+ if (gateResult.structuredContent) {
401
+ return gateResult;
402
+ }
403
+ const constraintViolations = validateOperation(validated.operation_type, validated.data);
404
+ if (hasBlockingViolations(constraintViolations)) {
405
+ return buildConstraintError(validated.operation_type, constraintViolations);
406
+ }
407
+ constraintWarnings = getWarningViolations(constraintViolations).map((v) => `[PRE-CHECK] ${v.message}`);
408
+ const projectEnvPrefix = env?.project;
409
+ if (isProjectServiceEnabled()) {
410
+ const pn = projectNormalize({
411
+ operation_type: validated.operation_type,
412
+ data: validated.data,
413
+ projectPrefix: projectEnvPrefix,
414
+ });
415
+ validated.data = pn.data;
416
+ }
417
+ if (env && typeof env === "object") {
418
+ delete env.confirmed;
419
+ delete env.user_intent_phrases;
420
+ delete env.project;
421
+ }
242
422
  switch (validated.operation_type) {
243
423
  case "service": {
244
424
  const callService = new CallService(validated.data);
245
425
  const result = validated.submission
246
426
  ? await callService.call_with_submission(env, await transformSubmission(validated.submission))
247
427
  : await callService.call(env);
248
- return handleCallResult(result);
428
+ const data = validated.data;
429
+ const intent = data?.publish ? "publish service" : data?.bPublished !== undefined ? "modify service" : "create service";
430
+ return handleCallResult(result, withHarness({ operation_type: validated.operation_type, data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined }, "service", intent));
249
431
  }
250
432
  case "machine": {
251
433
  if (validated.data.node && typeof validated.data.node === 'object' && 'json_or_markdown_file' in validated.data.node) {
@@ -276,42 +458,42 @@ async function handleOnchainOperations(args) {
276
458
  const result = validated.submission
277
459
  ? await callMachine.call_with_submission(env, await transformSubmission(validated.submission))
278
460
  : await callMachine.call(env);
279
- return handleCallResult(result);
461
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
280
462
  }
281
463
  case "progress": {
282
464
  const callProgress = new CallProgress(validated.data);
283
465
  const result = validated.submission
284
466
  ? await callProgress.call_with_submission(env, await transformSubmission(validated.submission))
285
467
  : await callProgress.call(env);
286
- return handleCallResult(result);
468
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
287
469
  }
288
470
  case "repository": {
289
471
  const callRepository = new CallRepository(validated.data);
290
472
  const result = validated.submission
291
473
  ? await callRepository.call_with_submission(env, await transformSubmission(validated.submission))
292
474
  : await callRepository.call(env);
293
- return handleCallResult(result);
475
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
294
476
  }
295
477
  case "arbitration": {
296
478
  const callArbitration = new CallArbitration(validated.data);
297
479
  const result = validated.submission
298
480
  ? await callArbitration.call_with_submission(env, await transformSubmission(validated.submission))
299
481
  : await callArbitration.call(env);
300
- return handleCallResult(result);
482
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
301
483
  }
302
484
  case "contact": {
303
485
  const callContact = new CallContact(validated.data);
304
486
  const result = validated.submission
305
487
  ? await callContact.call_with_submission(env, await transformSubmission(validated.submission))
306
488
  : await callContact.call(env);
307
- return handleCallResult(result);
489
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
308
490
  }
309
491
  case "treasury": {
310
492
  const callTreasury = new CallTreasury(validated.data);
311
493
  const result = validated.submission
312
494
  ? await callTreasury.call_with_submission(env, await transformSubmission(validated.submission))
313
495
  : await callTreasury.call(env);
314
- return handleCallResult(result);
496
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
315
497
  }
316
498
  case "reward": {
317
499
  const transformedData = transformRewardData(validated.data);
@@ -319,19 +501,19 @@ async function handleOnchainOperations(args) {
319
501
  const result = validated.submission
320
502
  ? await callReward.call_with_submission(env, await transformSubmission(validated.submission))
321
503
  : await callReward.call(env);
322
- return handleCallResult(result);
504
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
323
505
  }
324
506
  case "allocation": {
325
507
  const callAllocation = new CallAllocation(validated.data);
326
508
  const result = validated.submission
327
509
  ? await callAllocation.call_with_submission(env, await transformSubmission(validated.submission))
328
510
  : await callAllocation.call(env);
329
- return handleCallResult(result);
511
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
330
512
  }
331
513
  case "permission": {
332
514
  const callPermission = new CallPermission(validated.data);
333
515
  const result = await callPermission.call(env);
334
- return handleCallResult(result);
516
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
335
517
  }
336
518
  case "guard": {
337
519
  const validatedData = validated.data;
@@ -378,7 +560,7 @@ async function handleOnchainOperations(args) {
378
560
  }
379
561
  const callGuard = new CallGuard(validatedData);
380
562
  const result = await callGuard.call(env);
381
- return handleCallResult(result);
563
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
382
564
  }
383
565
  case "personal": {
384
566
  const transformPersonalData = (data) => {
@@ -431,52 +613,56 @@ async function handleOnchainOperations(args) {
431
613
  const transformedData = transformPersonalData(validated.data);
432
614
  const callPersonal = new CallPersonal(transformedData);
433
615
  const result = await callPersonal.call(env);
434
- return handleCallResult(result);
616
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
435
617
  }
436
618
  case "payment": {
437
619
  const callPayment = new CallPayment(validated.data);
438
620
  const result = await callPayment.call(env);
439
- return handleCallResult(result);
621
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
440
622
  }
441
623
  case "demand": {
442
624
  const callDemand = new CallDemand(validated.data);
443
625
  const result = validated.submission
444
626
  ? await callDemand.call_with_submission(env, await transformSubmission(validated.submission))
445
627
  : await callDemand.call(env);
446
- return handleCallResult(result);
628
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
447
629
  }
448
630
  case "order": {
449
631
  const callOrder = new CallOrder(validated.data);
450
632
  const result = validated.submission
451
633
  ? await callOrder.call_with_submission(env, await transformSubmission(validated.submission))
452
634
  : await callOrder.call(env);
453
- return handleCallResult(result);
635
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
454
636
  }
455
637
  case "gen_passport": {
456
638
  const result = await gen_passport(env, validated.guard, validated.info);
457
- return handleCallResult(result);
639
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
640
+ }
641
+ case "proof": {
642
+ const callProof = new CallProof(validated.data);
643
+ const result = validated.submission
644
+ ? await callProof.call_with_submission(env, await transformSubmission(validated.submission))
645
+ : await callProof.call(env);
646
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
647
+ }
648
+ case "gen_proof": {
649
+ 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);
650
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
458
651
  }
459
652
  }
460
653
  throw new Error(`Unknown on-chain operation type: ${validated.operation_type}`);
461
654
  }
462
655
  catch (error) {
463
656
  const errorMessage = error instanceof Error ? error.message : String(error);
464
- return {
465
- content: [{ type: "text", text: `Error: ${errorMessage}` }],
466
- structuredContent: {
467
- message: `Error: ${errorMessage}`,
468
- result: {
469
- type: "error",
470
- error: errorMessage,
471
- },
472
- },
473
- };
657
+ return handleCallResult({ error: errorMessage }, validated ? { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined } : undefined);
474
658
  }
475
659
  }
476
660
  async function handleAccountOperation(args) {
661
+ let validated;
477
662
  try {
478
- const validated = strictParse(AccountOperationSchema, args, "account_operation input");
663
+ validated = strictParse(AccountOperationSchema, args, "account_operation input");
479
664
  const result = await account_operation(validated);
665
+ const ctx = { operation_type: "account_" + validated.operation_type, data: validated };
480
666
  return {
481
667
  content: [{ type: "text", text: JSON.stringify(result) }],
482
668
  structuredContent: {
@@ -484,26 +670,39 @@ async function handleAccountOperation(args) {
484
670
  status: "success",
485
671
  data: result,
486
672
  },
673
+ semantic: buildDataSemantic(result, ctx),
487
674
  },
488
675
  };
489
676
  }
490
677
  catch (error) {
491
678
  const errorMessage = error instanceof Error ? error.message : String(error);
679
+ const ctx = validated ? { operation_type: "account_" + validated.operation_type, data: validated } : undefined;
680
+ const classified = classifyError(errorMessage);
681
+ const errorResult = {
682
+ status: "error",
683
+ error: errorMessage,
684
+ };
685
+ if (classified.error_code !== undefined)
686
+ errorResult.error_code = classified.error_code;
687
+ if (classified.retryable !== undefined)
688
+ errorResult.retryable = classified.retryable;
689
+ if (classified.recovery_hint !== undefined)
690
+ errorResult.recovery_hint = classified.recovery_hint;
492
691
  return {
493
692
  content: [{ type: "text", text: `Error: ${errorMessage}` }],
494
693
  structuredContent: {
495
- result: {
496
- status: "error",
497
- error: errorMessage,
498
- },
694
+ result: errorResult,
695
+ semantic: buildDataSemantic(undefined, ctx, true, errorMessage),
499
696
  },
500
697
  };
501
698
  }
502
699
  }
503
700
  async function handleMarkOperation(args) {
701
+ let validated;
504
702
  try {
505
- const validated = strictParse(LocalMarkOperationSchema, args, "local_mark_operation input");
703
+ validated = strictParse(LocalMarkOperationSchema, args, "local_mark_operation input");
506
704
  const result = await local_mark_operation(validated);
705
+ const ctx = { operation_type: "mark_" + validated.operation_type, data: validated };
507
706
  return {
508
707
  content: [{ type: "text", text: JSON.stringify(result) }],
509
708
  structuredContent: {
@@ -511,26 +710,36 @@ async function handleMarkOperation(args) {
511
710
  status: "success",
512
711
  data: result,
513
712
  },
713
+ semantic: buildDataSemantic(result, ctx),
514
714
  },
515
715
  };
516
716
  }
517
717
  catch (error) {
518
718
  const errorMessage = error instanceof Error ? error.message : String(error);
719
+ const ctx = validated ? { operation_type: "mark_" + validated.operation_type, data: validated } : undefined;
720
+ const classified = classifyError(errorMessage);
721
+ const errorResult = { status: "error", error: errorMessage };
722
+ if (classified.error_code !== undefined)
723
+ errorResult.error_code = classified.error_code;
724
+ if (classified.retryable !== undefined)
725
+ errorResult.retryable = classified.retryable;
726
+ if (classified.recovery_hint !== undefined)
727
+ errorResult.recovery_hint = classified.recovery_hint;
519
728
  return {
520
729
  content: [{ type: "text", text: `Error: ${errorMessage}` }],
521
730
  structuredContent: {
522
- result: {
523
- status: "error",
524
- error: errorMessage,
525
- },
731
+ result: errorResult,
732
+ semantic: buildDataSemantic(undefined, ctx, true, errorMessage),
526
733
  },
527
734
  };
528
735
  }
529
736
  }
530
737
  async function handleInfoOperation(args) {
738
+ let validated;
531
739
  try {
532
- const validated = strictParse(LocalInfoOperationSchema, args, "local_info_operation input");
740
+ validated = strictParse(LocalInfoOperationSchema, args, "local_info_operation input");
533
741
  const result = await local_info_operation(validated);
742
+ const ctx = { operation_type: "local_info", data: validated };
534
743
  return {
535
744
  content: [{ type: "text", text: JSON.stringify(result) }],
536
745
  structuredContent: {
@@ -538,18 +747,26 @@ async function handleInfoOperation(args) {
538
747
  status: "success",
539
748
  data: result,
540
749
  },
750
+ semantic: buildDataSemantic(result, ctx),
541
751
  },
542
752
  };
543
753
  }
544
754
  catch (error) {
545
755
  const errorMessage = error instanceof Error ? error.message : String(error);
756
+ const ctx = validated ? { operation_type: "local_info", data: validated } : undefined;
757
+ const classified = classifyError(errorMessage);
758
+ const errorResult = { status: "error", error: errorMessage };
759
+ if (classified.error_code !== undefined)
760
+ errorResult.error_code = classified.error_code;
761
+ if (classified.retryable !== undefined)
762
+ errorResult.retryable = classified.retryable;
763
+ if (classified.recovery_hint !== undefined)
764
+ errorResult.recovery_hint = classified.recovery_hint;
546
765
  return {
547
766
  content: [{ type: "text", text: `Error: ${errorMessage}` }],
548
767
  structuredContent: {
549
- result: {
550
- status: "error",
551
- error: errorMessage,
552
- },
768
+ result: errorResult,
769
+ semantic: buildDataSemantic(undefined, ctx, true, errorMessage),
553
770
  },
554
771
  };
555
772
  }
@@ -674,7 +891,13 @@ async function handleWatchQueryOperations(args) {
674
891
  }
675
892
  return {
676
893
  content: [{ type: "text", text: JSON.stringify({ result }) }],
677
- structuredContent: { result },
894
+ structuredContent: {
895
+ result,
896
+ semantic: buildDataSemantic(result, {
897
+ operation_type: "query_toolkit",
898
+ data: validated,
899
+ }),
900
+ },
678
901
  };
679
902
  }
680
903
  async function handleWowokInfo(args) {
@@ -700,166 +923,313 @@ async function handleOnchainEvents(args) {
700
923
  });
701
924
  return {
702
925
  content: [{ type: "text", text: JSON.stringify({ result: queryResult }) }],
703
- structuredContent: { result: queryResult },
926
+ structuredContent: {
927
+ result: queryResult,
928
+ semantic: buildDataSemantic(queryResult, {
929
+ operation_type: "onchain_events",
930
+ data: validated,
931
+ }),
932
+ },
704
933
  };
705
934
  }
706
- function normalizeAccountOrMark(input) {
707
- if (typeof input === 'string') {
708
- return { name_or_address: input, local_mark_first: true };
709
- }
710
- return input;
711
- }
712
- function normalizeManyAccountOrMark(input) {
713
- if (Array.isArray(input)) {
714
- return {
715
- entities: input.map(item => typeof item === 'string' ? { name_or_address: item, local_mark_first: true } : item),
716
- check_all_founded: true
717
- };
718
- }
719
- return input;
720
- }
721
- async function handleMessengerOperation(args) {
722
- const validated = strictParse(MessengerOperationInputSchema, args, "messenger_operation input");
935
+ async function handleProjectOperation(args) {
936
+ const action = args.action;
937
+ const project = args.project;
938
+ const object = args.object;
723
939
  let result;
724
- switch (validated.operation) {
725
- case "watch_conversations": {
726
- const conversations = await watch_conversations(validated.filter);
727
- result = { operation: "watch_conversations", result: conversations };
940
+ switch (action) {
941
+ case "list_projects":
942
+ result = await queryProjects();
728
943
  break;
729
- }
730
- case "send_message": {
731
- const sendResult = await send_message(validated.from, normalizeAccountOrMark(validated.to), validated.content, validated.options);
732
- const filteredResult = {
733
- ...sendResult,
734
- merkleData: sendResult.merkleData ? {
735
- leafIndex: sendResult.merkleData.leafIndex,
736
- prevRoot: sendResult.merkleData.prevRoot,
737
- newRoot: sendResult.merkleData.newRoot,
738
- serverSignature: sendResult.merkleData.serverSignature,
739
- serverTimestamp: sendResult.merkleData.serverTimestamp,
740
- serverPublicKey: sendResult.merkleData.serverPublicKey,
741
- } : undefined,
742
- };
743
- result = { operation: "send_message", result: filteredResult };
944
+ case "list_objects":
945
+ if (!project)
946
+ throw new Error("'project' param is required for list_objects");
947
+ result = await queryProjectObjects(project);
744
948
  break;
745
- }
746
- case "send_file": {
747
- const sendResult = await send_file(validated.from, normalizeAccountOrMark(validated.to), validated.filePath, validated.options);
748
- const filteredResult = {
749
- ...sendResult,
750
- merkleData: sendResult.merkleData ? {
751
- leafIndex: sendResult.merkleData.leafIndex,
752
- prevRoot: sendResult.merkleData.prevRoot,
753
- newRoot: sendResult.merkleData.newRoot,
754
- serverSignature: sendResult.merkleData.serverSignature,
755
- serverTimestamp: sendResult.merkleData.serverTimestamp,
756
- serverPublicKey: sendResult.merkleData.serverPublicKey,
757
- } : undefined,
758
- };
759
- result = { operation: "send_file", result: filteredResult };
949
+ case "shareable":
950
+ result = await queryShareableObjects();
760
951
  break;
761
- }
762
- case "watch_messages": {
763
- const filter = validated.filter ? {
764
- ...validated.filter,
765
- peerAddress: validated.filter.peerAddress ? normalizeAccountOrMark(validated.filter.peerAddress) : undefined
766
- } : undefined;
767
- const messages = await watch_messages(filter);
768
- result = { operation: "watch_messages", result: messages };
952
+ case "dependencies":
953
+ if (!object)
954
+ throw new Error("'object' param is required for dependencies");
955
+ result = queryDependencies(object);
769
956
  break;
770
- }
771
- case "extract_zip_messages": {
772
- const extractedPaths = await extract_zip_messages(validated.account, validated.messages, validated.outputDir);
773
- result = { operation: "extract_zip_messages", result: extractedPaths };
957
+ case "referenced_by":
958
+ if (!object)
959
+ throw new Error("'object' param is required for referenced_by");
960
+ result = queryReferencedBy(object);
774
961
  break;
775
- }
776
- case "generate_wts": {
777
- const params = validated.params ? {
778
- ...validated.params,
779
- peerAccount: normalizeAccountOrMark(validated.params.peerAccount)
780
- } : undefined;
781
- const wtsResult = await generate_wts(params);
782
- result = { operation: "generate_wts", result: wtsResult };
962
+ case "pre_publish_check":
963
+ if (!object)
964
+ throw new Error("'object' param is required for pre_publish_check");
965
+ result = { warnings: queryPrePublishCheck(object) };
783
966
  break;
784
- }
785
- case "verify_wts": {
786
- const verifyResult = await verify_wts(validated.wtsFilePath);
787
- result = { operation: "verify_wts", result: verifyResult };
967
+ case "cross_project_refs":
968
+ result = queryCrossProjectReferences();
788
969
  break;
789
- }
790
- case "sign_wts": {
791
- const signedPath = await sign_wts(validated.wtsFilePath, validated.account, validated.outputPath);
792
- result = { operation: "sign_wts", result: signedPath };
970
+ case "graph_stats":
971
+ result = queryGraphStats();
793
972
  break;
794
- }
795
- case "wts2html": {
796
- const htmlResult = await wts2html(validated.wtsPath, validated.options);
797
- result = { operation: "wts2html", result: htmlResult };
973
+ case "save_graph":
974
+ result = { saved: true, path: saveGraph() };
798
975
  break;
799
- }
800
- case "proof_message": {
801
- const proofResult = await proof_message(validated.account, validated.messageId, validated.network);
802
- result = { operation: "proof_message", result: proofResult };
976
+ case "load_graph":
977
+ result = { loaded: loadGraph() };
803
978
  break;
804
- }
805
- case "blacklist": {
806
- const blacklistParams = {
807
- account: validated.account,
808
- op: validated.blacklist.op
809
- };
810
- if ('users' in validated.blacklist) {
811
- blacklistParams.users = normalizeManyAccountOrMark(validated.blacklist.users);
812
- }
813
- const blacklistResult = await blacklist(blacklistParams);
814
- result = { operation: "blacklist", op: validated.blacklist.op, result: blacklistResult.result };
979
+ default:
980
+ throw new Error(`Unknown project_operation action: ${action}`);
981
+ }
982
+ return {
983
+ content: [{ type: "text", text: JSON.stringify({ result }) }],
984
+ structuredContent: { result },
985
+ };
986
+ }
987
+ async function handleConfigOperation(args) {
988
+ const action = args.action;
989
+ let result;
990
+ switch (action) {
991
+ case "list":
992
+ result = { services: listServices() };
815
993
  break;
816
- }
817
- case "friendslist": {
818
- const friendslistParams = {
819
- account: validated.account,
820
- op: validated.friendslist.op
821
- };
822
- if ('users' in validated.friendslist) {
823
- friendslistParams.users = normalizeManyAccountOrMark(validated.friendslist.users);
994
+ case "toggle": {
995
+ const service = args.service;
996
+ if (!service)
997
+ throw new Error("'service' param is required for toggle");
998
+ const validServices = ["confirm_gate", "project_service", "harness", "graph_persist", "semantic_rich"];
999
+ if (!validServices.includes(service)) {
1000
+ throw new Error(`Unknown service: ${service}. Valid: ${validServices.join(", ")}`);
824
1001
  }
825
- const friendslistResult = await friendslist(friendslistParams);
826
- result = { operation: "friendslist", op: validated.friendslist.op, result: friendslistResult.result };
1002
+ const newState = toggleService(service);
1003
+ const info = getServiceInfo(service);
1004
+ result = { service, enabled: newState, reminder: info?.reminder };
827
1005
  break;
828
1006
  }
829
- case "guardlist": {
830
- const guardlistResult = await guardlist({
831
- account: validated.account,
832
- ...validated.guardlist
833
- });
834
- result = { operation: "guardlist", op: validated.guardlist.op, result: guardlistResult.result };
1007
+ case "enable": {
1008
+ const service = args.service;
1009
+ if (!service)
1010
+ throw new Error("'service' param is required for enable");
1011
+ setServiceEnabled(service, true);
1012
+ const info = getServiceInfo(service);
1013
+ result = { service, enabled: true, reminder: info?.reminder };
835
1014
  break;
836
1015
  }
837
- case "settings": {
838
- const settingsResult = await settings({
839
- account: validated.account,
840
- ...validated.settings
841
- });
842
- result = { operation: "settings", op: validated.settings.op, result: settingsResult.result };
1016
+ case "disable": {
1017
+ const service = args.service;
1018
+ if (!service)
1019
+ throw new Error("'service' param is required for disable");
1020
+ setServiceEnabled(service, false);
1021
+ const info = getServiceInfo(service);
1022
+ result = { service, enabled: false, reminder: info?.reminder };
843
1023
  break;
844
1024
  }
845
- case "mark_messages_as_viewed": {
846
- const markedCount = await mark_messages_as_viewed(validated.messageIds, validated.account);
847
- result = { operation: "mark_messages_as_viewed", result: markedCount };
1025
+ case "reset": {
1026
+ const service = args.service;
1027
+ if (!service)
1028
+ throw new Error("'service' param is required for reset");
1029
+ resetService(service);
1030
+ const info = getServiceInfo(service);
1031
+ result = { service, enabled: info?.enabled, reminder: info?.reminder, reset: true };
848
1032
  break;
849
1033
  }
850
- case "mark_conversation_as_viewed": {
851
- const markedCount = await mark_conversation_as_viewed(normalizeAccountOrMark(validated.peerAddress), validated.account);
852
- result = { operation: "mark_conversation_as_viewed", result: markedCount };
1034
+ case "info": {
1035
+ const service = args.service;
1036
+ if (!service)
1037
+ throw new Error("'service' param is required for info");
1038
+ result = getServiceInfo(service);
853
1039
  break;
854
1040
  }
855
1041
  default:
856
- throw new Error(`Unknown messenger operation: ${validated.operation}`);
1042
+ throw new Error(`Unknown config_operation action: ${action}`);
857
1043
  }
858
1044
  return {
859
- content: [{ type: "text", text: JSON.stringify(result) }],
1045
+ content: [{ type: "text", text: JSON.stringify({ result }) }],
860
1046
  structuredContent: { result },
861
1047
  };
862
1048
  }
1049
+ function normalizeAccountOrMark(input) {
1050
+ if (typeof input === 'string') {
1051
+ return { name_or_address: input, local_mark_first: true };
1052
+ }
1053
+ return input;
1054
+ }
1055
+ function normalizeManyAccountOrMark(input) {
1056
+ if (Array.isArray(input)) {
1057
+ return {
1058
+ entities: input.map(item => typeof item === 'string' ? { name_or_address: item, local_mark_first: true } : item),
1059
+ check_all_founded: true
1060
+ };
1061
+ }
1062
+ return input;
1063
+ }
1064
+ async function handleMessengerOperation(args) {
1065
+ let validated;
1066
+ try {
1067
+ validated = strictParse(MessengerOperationInputSchema, args, "messenger_operation input");
1068
+ let result;
1069
+ switch (validated.operation) {
1070
+ case "watch_conversations": {
1071
+ const conversations = await watch_conversations(validated.filter);
1072
+ result = { operation: "watch_conversations", result: conversations };
1073
+ break;
1074
+ }
1075
+ case "send_message": {
1076
+ const sendResult = await send_message(validated.from, normalizeAccountOrMark(validated.to), validated.content, validated.options);
1077
+ const filteredResult = {
1078
+ ...sendResult,
1079
+ merkleData: sendResult.merkleData ? {
1080
+ leafIndex: sendResult.merkleData.leafIndex,
1081
+ prevRoot: sendResult.merkleData.prevRoot,
1082
+ newRoot: sendResult.merkleData.newRoot,
1083
+ serverSignature: sendResult.merkleData.serverSignature,
1084
+ serverTimestamp: sendResult.merkleData.serverTimestamp,
1085
+ serverPublicKey: sendResult.merkleData.serverPublicKey,
1086
+ } : undefined,
1087
+ };
1088
+ result = { operation: "send_message", result: filteredResult };
1089
+ break;
1090
+ }
1091
+ case "send_file": {
1092
+ const sendResult = await send_file(validated.from, normalizeAccountOrMark(validated.to), validated.filePath, validated.options);
1093
+ const filteredResult = {
1094
+ ...sendResult,
1095
+ merkleData: sendResult.merkleData ? {
1096
+ leafIndex: sendResult.merkleData.leafIndex,
1097
+ prevRoot: sendResult.merkleData.prevRoot,
1098
+ newRoot: sendResult.merkleData.newRoot,
1099
+ serverSignature: sendResult.merkleData.serverSignature,
1100
+ serverTimestamp: sendResult.merkleData.serverTimestamp,
1101
+ serverPublicKey: sendResult.merkleData.serverPublicKey,
1102
+ } : undefined,
1103
+ };
1104
+ result = { operation: "send_file", result: filteredResult };
1105
+ break;
1106
+ }
1107
+ case "watch_messages": {
1108
+ const filter = validated.filter ? {
1109
+ ...validated.filter,
1110
+ peerAddress: validated.filter.peerAddress ? normalizeAccountOrMark(validated.filter.peerAddress) : undefined
1111
+ } : undefined;
1112
+ const messages = await watch_messages(filter);
1113
+ result = { operation: "watch_messages", result: messages };
1114
+ break;
1115
+ }
1116
+ case "extract_zip_messages": {
1117
+ const extractedPaths = await extract_zip_messages(validated.account, validated.messages, validated.outputDir);
1118
+ result = { operation: "extract_zip_messages", result: extractedPaths };
1119
+ break;
1120
+ }
1121
+ case "generate_wts": {
1122
+ const params = validated.params ? {
1123
+ ...validated.params,
1124
+ peerAccount: normalizeAccountOrMark(validated.params.peerAccount)
1125
+ } : undefined;
1126
+ const wtsResult = await generate_wts(params);
1127
+ result = { operation: "generate_wts", result: wtsResult };
1128
+ break;
1129
+ }
1130
+ case "verify_wts": {
1131
+ const verifyResult = await verify_wts(validated.wtsFilePath);
1132
+ result = { operation: "verify_wts", result: verifyResult };
1133
+ break;
1134
+ }
1135
+ case "sign_wts": {
1136
+ const signedPath = await sign_wts(validated.wtsFilePath, validated.account, validated.outputPath);
1137
+ result = { operation: "sign_wts", result: signedPath };
1138
+ break;
1139
+ }
1140
+ case "wts2html": {
1141
+ const htmlResult = await wts2html(validated.wtsPath, validated.options);
1142
+ result = { operation: "wts2html", result: htmlResult };
1143
+ break;
1144
+ }
1145
+ case "proof_message": {
1146
+ const proofResult = await proof_message(validated.account, validated.messageId, validated.network);
1147
+ result = { operation: "proof_message", result: proofResult };
1148
+ break;
1149
+ }
1150
+ case "blacklist": {
1151
+ const blacklistParams = {
1152
+ account: validated.account,
1153
+ op: validated.blacklist.op
1154
+ };
1155
+ if ('users' in validated.blacklist) {
1156
+ blacklistParams.users = normalizeManyAccountOrMark(validated.blacklist.users);
1157
+ }
1158
+ const blacklistResult = await blacklist(blacklistParams);
1159
+ result = { operation: "blacklist", op: validated.blacklist.op, result: blacklistResult.result };
1160
+ break;
1161
+ }
1162
+ case "friendslist": {
1163
+ const friendslistParams = {
1164
+ account: validated.account,
1165
+ op: validated.friendslist.op
1166
+ };
1167
+ if ('users' in validated.friendslist) {
1168
+ friendslistParams.users = normalizeManyAccountOrMark(validated.friendslist.users);
1169
+ }
1170
+ const friendslistResult = await friendslist(friendslistParams);
1171
+ result = { operation: "friendslist", op: validated.friendslist.op, result: friendslistResult.result };
1172
+ break;
1173
+ }
1174
+ case "guardlist": {
1175
+ const guardlistResult = await guardlist({
1176
+ account: validated.account,
1177
+ ...validated.guardlist
1178
+ });
1179
+ result = { operation: "guardlist", op: validated.guardlist.op, result: guardlistResult.result };
1180
+ break;
1181
+ }
1182
+ case "settings": {
1183
+ const settingsResult = await settings({
1184
+ account: validated.account,
1185
+ ...validated.settings
1186
+ });
1187
+ result = { operation: "settings", op: validated.settings.op, result: settingsResult.result };
1188
+ break;
1189
+ }
1190
+ case "mark_messages_as_viewed": {
1191
+ const markedCount = await mark_messages_as_viewed(validated.messageIds, validated.account);
1192
+ result = { operation: "mark_messages_as_viewed", result: markedCount };
1193
+ break;
1194
+ }
1195
+ case "mark_conversation_as_viewed": {
1196
+ const markedCount = await mark_conversation_as_viewed(normalizeAccountOrMark(validated.peerAddress), validated.account);
1197
+ result = { operation: "mark_conversation_as_viewed", result: markedCount };
1198
+ break;
1199
+ }
1200
+ case "pull_messages": {
1201
+ const messages = await pull_messages(validated.account, validated.limit);
1202
+ result = { operation: "pull_messages", result: messages };
1203
+ break;
1204
+ }
1205
+ default:
1206
+ throw new Error(`Unknown messenger operation: ${validated.operation}`);
1207
+ }
1208
+ return {
1209
+ content: [{ type: "text", text: JSON.stringify(result) }],
1210
+ structuredContent: { result },
1211
+ };
1212
+ }
1213
+ catch (error) {
1214
+ const errorMessage = error instanceof Error ? error.message : String(error);
1215
+ const ctx = validated ? { operation_type: "messenger_" + validated.operation, data: validated } : undefined;
1216
+ const classified = classifyError(errorMessage);
1217
+ const errorResult = { operation: "error", error: errorMessage };
1218
+ if (classified.error_code !== undefined)
1219
+ errorResult.error_code = classified.error_code;
1220
+ if (classified.retryable !== undefined)
1221
+ errorResult.retryable = classified.retryable;
1222
+ if (classified.recovery_hint !== undefined)
1223
+ errorResult.recovery_hint = classified.recovery_hint;
1224
+ return {
1225
+ content: [{ type: "text", text: `Error: ${errorMessage}` }],
1226
+ structuredContent: {
1227
+ result: errorResult,
1228
+ semantic: buildDataSemantic(undefined, ctx, true, errorMessage),
1229
+ },
1230
+ };
1231
+ }
1232
+ }
863
1233
  async function handleGuard2File(args) {
864
1234
  const validated = strictParse(Guard2File_InputSchema, args, "guard2file input");
865
1235
  const env = getEnvConfig(validated.env);
@@ -898,6 +1268,24 @@ async function handleMachineNode2File(args) {
898
1268
  const env = getEnvConfig(validated.env);
899
1269
  try {
900
1270
  await machineNode2file(validated.machine, validated.file_path, validated.format || "json", env.network);
1271
+ let node_count = undefined;
1272
+ try {
1273
+ const filePath = resolve(validated.file_path);
1274
+ const fileContent = await import('fs/promises').then(fs => fs.readFile(filePath, 'utf-8'));
1275
+ if ((validated.format || "json") === "json") {
1276
+ const parsed = JSON.parse(fileContent);
1277
+ if (Array.isArray(parsed)) {
1278
+ node_count = parsed.length;
1279
+ }
1280
+ }
1281
+ else {
1282
+ const nodeMatches = fileContent.match(/^##\s+Node:/gm);
1283
+ node_count = nodeMatches ? nodeMatches.length : 0;
1284
+ }
1285
+ }
1286
+ catch {
1287
+ node_count = undefined;
1288
+ }
901
1289
  const result = {
902
1290
  result: {
903
1291
  status: "success",
@@ -905,10 +1293,12 @@ async function handleMachineNode2File(args) {
905
1293
  file_path: resolve(validated.file_path),
906
1294
  format: validated.format || "json",
907
1295
  machine_object: validated.machine,
908
- node_count: 0,
909
1296
  },
910
1297
  },
911
1298
  };
1299
+ if (node_count !== undefined) {
1300
+ result.result.data.node_count = node_count;
1301
+ }
912
1302
  return {
913
1303
  content: [{ type: "text", text: JSON.stringify(result) }],
914
1304
  structuredContent: result,
@@ -938,39 +1328,49 @@ async function main() {
938
1328
  else {
939
1329
  console.error("Schema files not available. Run 'npm run generate:schemas' to generate them.");
940
1330
  }
941
- server.registerTool("onchain_operations", {
1331
+ if (isProjectServiceEnabled()) {
1332
+ registerSuccessHook((result, context) => {
1333
+ if (context?.operation_type && context?.data) {
1334
+ projectObserve(context.operation_type, context.data, result);
1335
+ }
1336
+ });
1337
+ console.error("ProjectService enabled — object graph observe active");
1338
+ }
1339
+ const activeServices = listServices().filter((s) => s.enabled).map((s) => s.name);
1340
+ console.error(`Phase 2 active services: ${activeServices.join(", ") || "none"}`);
1341
+ reg("onchain_operations", {
942
1342
  title: "⛓️ On-chain Operations",
943
- 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).",
1343
+ 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).",
944
1344
  inputSchema: OnchainOperationsSchema,
945
1345
  outputSchema: CallOutputSchema,
946
1346
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
947
- _meta: createToolMeta("operation", ["service", "machine", "progress", "repository", "arbitration", "contact", "treasury", "reward", "allocation", "permission", "guard", "personal", "payment", "demand", "order", "gen_passport", "on-chain", "blockchain"]),
1347
+ _meta: createToolMeta("operation", ["service", "machine", "progress", "repository", "arbitration", "contact", "treasury", "reward", "allocation", "permission", "guard", "personal", "payment", "demand", "order", "gen_passport", "proof", "gen_proof", "on-chain", "blockchain"]),
948
1348
  }, handleOnchainOperations);
949
- server.registerTool("account_operation", {
1349
+ reg("account_operation", {
950
1350
  title: "🔒 LOCAL ONLY: Account - Wallet Management",
951
1351
  description: "🔒 100% LOCAL, NEVER ON-CHAIN 🔒 Manage WoWok accounts locally on device: generate, suspend, resume, faucet-test, operate assets, sign data, etc.",
952
1352
  inputSchema: AccountOperationSchema,
953
1353
  outputSchema: AccountOperationOutputWrappedSchema,
954
1354
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
955
1355
  _meta: createToolMeta("operation", ["account", "local", "private", "wallet", "off-chain"]),
956
- }, handleAccountOperation);
957
- server.registerTool("local_mark_operation", {
1356
+ }, handleAccountOperation, statusErrorShape);
1357
+ reg("local_mark_operation", {
958
1358
  title: "🔒 LOCAL ONLY: LocalMark - Address Book Management",
959
1359
  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.",
960
1360
  inputSchema: LocalMarkOperationSchema,
961
1361
  outputSchema: LocalMarkOperationOutputWrappedSchema,
962
1362
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
963
1363
  _meta: createToolMeta("operation", ["mark", "local", "private", "address-book", "off-chain"]),
964
- }, handleMarkOperation);
965
- server.registerTool("local_info_operation", {
1364
+ }, handleMarkOperation, statusErrorShape);
1365
+ reg("local_info_operation", {
966
1366
  title: "🔒 LOCAL ONLY: LocalInfo - Private Data Management",
967
1367
  description: "100% LOCAL, NEVER ON-CHAIN 🔒 Manage sensitive personal information stored ONLY on your device: delivery addresses, phone numbers, contacts.",
968
1368
  inputSchema: LocalInfoOperationSchema,
969
1369
  outputSchema: LocalInfoOperationOutputWrappedSchema,
970
1370
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
971
1371
  _meta: createToolMeta("operation", ["info", "local", "private", "data-management", "off-chain"]),
972
- }, handleInfoOperation);
973
- server.registerTool("wip_file", {
1372
+ }, handleInfoOperation, statusErrorShape);
1373
+ reg("wip_file", {
974
1374
  title: "🤝 Witness Immutable Promise File Operations",
975
1375
  description: "generate (create WIP files from markdown and images), verify (integrity check), sign (add signatures), or wip2html (convert to HTML).",
976
1376
  inputSchema: WipOperationsSchema,
@@ -980,36 +1380,36 @@ async function main() {
980
1380
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
981
1381
  _meta: createToolMeta("operation", ["wip", "promise", "file-generation", "verification", "signature", "local"]),
982
1382
  }, handleWipOperations);
983
- server.registerTool("messenger_operation", {
1383
+ reg("messenger_operation", {
984
1384
  title: "💬 Messenger Operations",
985
- 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, and mark conversation as viewed.",
1385
+ 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.",
986
1386
  inputSchema: MessengerOperationInputSchema,
987
1387
  outputSchema: MessengerOperationOutputSchema,
988
1388
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
989
1389
  _meta: createToolMeta("operation", ["messenger", "message", "file", "wts", "blacklist", "friendslist", "guardlist", "settings", "proof", "communication"]),
990
- }, handleMessengerOperation);
991
- server.registerTool("guard2file", {
1390
+ }, handleMessengerOperation, operationErrorShape, 30000);
1391
+ reg("guard2file", {
992
1392
  title: "📄 Guard to File - Export Guard Definition",
993
1393
  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.",
994
1394
  inputSchema: Guard2File_InputSchema,
995
1395
  outputSchema: Guard2File_OutputWrappedSchema,
996
1396
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
997
1397
  _meta: createToolMeta("generate file", ["guard", "export", "file", "json", "markdown", "on-chain"]),
998
- }, handleGuard2File);
999
- server.registerTool("machineNode2file", {
1398
+ }, handleGuard2File, strictStatusErrorShape);
1399
+ reg("machineNode2file", {
1000
1400
  title: "⚙️ Machine Node to File - Export Machine Node Definition",
1001
1401
  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.",
1002
1402
  inputSchema: MachineNode2File_InputSchema,
1003
1403
  outputSchema: MachineNode2File_OutputWrappedSchema,
1004
1404
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
1005
1405
  _meta: createToolMeta("generate file", ["machine", "export", "file", "json", "markdown", "on-chain", "workflow"]),
1006
- }, handleMachineNode2File);
1007
- server.registerTool("query_toolkit", {
1406
+ }, handleMachineNode2File, strictStatusErrorShape);
1407
+ reg("query_toolkit", {
1008
1408
  title: "🔍 Data Query Toolkit",
1009
1409
  description: "WOWOK data query toolkit — 9 query types covering local device data and on-chain blockchain data:\n\n"
1010
1410
  + "LOCAL (device-only, never on-chain):\n"
1011
1411
  + "1. local_mark_list — Query your LOCAL address book: maps human-readable names to blockchain addresses with optional tags. Use to resolve names→addresses or find addresses by tag.\n"
1012
- + "2. account_list — Query your LOCAL accounts: view all accounts stored on this device (addresses, public keys, messenger status, suspension state). Use to discover available accounts before operations.\n"
1412
+ + "2. account_list — Query your LOCAL accounts (addresses, messenger status, suspension state). Use filter.includePubkey=true to also include public keys. Use to discover available accounts before operations.\n"
1013
1413
  + "3. local_info_list — Query your LOCAL private info: sensitive data like delivery addresses, phone numbers, contacts stored ONLY on this device.\n"
1014
1414
  + "4. token_list — Query cached token metadata: symbol, decimals, icon URL, description for tokens previously fetched from chain. Use to look up token precision/decimals before performing token operations. Returns: TokenTypeInfo[] (type, alias, name, symbol, decimals, iconUrl).\n"
1015
1415
  + "5. account_balance — Query an account's coin balance OR paginated coin objects. Use balance=true for total amount, or coin={cursor,limit} to list individual coin objects. Supports multi-token via token_type parameter.\n"
@@ -1021,12 +1421,13 @@ async function main() {
1021
1421
  + "For dynamic table data queries (pagination, table items), use the 'onchain_table_data' tool.",
1022
1422
  inputSchema: WatchQueryOperationsSchema,
1023
1423
  outputSchema: z.object({
1024
- 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[].")
1424
+ 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[]."),
1425
+ semantic: z.unknown().optional().describe("Business semantic summary for the query operation"),
1025
1426
  }),
1026
1427
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
1027
1428
  _meta: createToolMeta("query", ["watch", "query", "on-chain", "local", "events", "objects", "tokens", "balance", "profile"]),
1028
1429
  }, handleWatchQueryOperations);
1029
- server.registerTool("onchain_table_data", {
1430
+ reg("onchain_table_data", {
1030
1431
  title: "📊 Watch WoWok On-chain Table Data Query",
1031
1432
  description: "Query dynamic table data of on-chain objects — supports paginated table queries and specific table item lookups. Each table item belongs to a parent object type and has a specific meaning:\n\n"
1032
1433
  + "1. onchain_table — Paginated query of ANY object's dynamic fields table (Parent: any object). Returns all entries with keys, types, and object IDs. Use to explore all sub-items of an object.\n"
@@ -1046,7 +1447,7 @@ async function main() {
1046
1447
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
1047
1448
  _meta: createToolMeta("table query", ["on-chain", "table", "dynamic fields", "pagination", "repository", "permission", "reward", "demand", "treasury", "machine", "progress"]),
1048
1449
  }, handleOnchainTableData);
1049
- server.registerTool("onchain_events", {
1450
+ reg("onchain_events", {
1050
1451
  title: "📅 Watch WoWok On-chain Events",
1051
1452
  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.",
1052
1453
  inputSchema: OnchainEventsInputSchema,
@@ -1054,7 +1455,7 @@ async function main() {
1054
1455
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
1055
1456
  _meta: createToolMeta("watch wowook events", ["events", "on-chain", "arbitration", "order", "progress", "demand", "entity"]),
1056
1457
  }, handleOnchainEvents);
1057
- server.registerTool("wowok_buildin_info", {
1458
+ reg("wowok_buildin_info", {
1058
1459
  title: "ℹ️ WoWok Build-in Information",
1059
1460
  description: "Query WoWok protocol information: 'constants', 'built-in permissions', 'guard instructions', 'current network', 'value types', or 'mainnet bridge tokens'. For 'mainnet bridge tokens': returns cross-chain bridge tokens (ETH, WETH, WBTC, USDC, USDT) with each token's symbol, WOW-side type tag (wowTypeTag), EVM address, decimals, and description. The wowTypeTag (format {address}::{module}::{struct}) can be used directly as the `type_parameter` of Service / Treasury / Reward / Allocation objects to set their payment token — e.g. use USDT's wowTypeTag to create a Service that accepts USDT payments.",
1060
1461
  inputSchema: ProtocolInfoQuerySchema,
@@ -1062,7 +1463,7 @@ async function main() {
1062
1463
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
1063
1464
  _meta: createToolMeta("WoWok info", ["build-in", "constants", "permissions", "guard", "network", "value-types", "bridge-tokens"]),
1064
1465
  }, handleWowokInfo);
1065
- server.registerTool("schema_query", {
1466
+ reg("schema_query", {
1066
1467
  title: "📋 Schema Query",
1067
1468
  description: "Look up JSON Schemas for WoWok MCP tools and on-chain operations. " +
1068
1469
  "This is the authoritative reference for exact parameter structures, types, and required fields. " +
@@ -1179,7 +1580,7 @@ async function main() {
1179
1580
  structuredContent: response,
1180
1581
  };
1181
1582
  });
1182
- server.registerTool("bridge_operation", {
1583
+ reg("bridge_operation", {
1183
1584
  title: "🌉 Bridge - Cross-Chain Operations",
1184
1585
  description: "🌉 Simplified cross-chain bridge between WOW and EVM (Ethereum mainnet). Only WOW mainnet provides cross-chain functionality.\n\n" +
1185
1586
  "Key concepts (transparent to user):\n" +
@@ -1203,6 +1604,71 @@ async function main() {
1203
1604
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
1204
1605
  _meta: createToolMeta("operation", ["bridge", "cross-chain", "evm", "ethereum", "wow", "transfer", "rpc"]),
1205
1606
  }, handleBridgeOperations);
1607
+ reg("project_operation", {
1608
+ title: "🗂️ Project - Namespace & Object Graph",
1609
+ description: "Phase 2 project namespace service — manage and query the local object dependency graph (DAG) " +
1610
+ "built on top of local_mark tags. No on-chain writes; all data comes from local marks tagged " +
1611
+ "`project:<prefix>` (auto-injected by the ProjectService when enabled, default ON).\n\n" +
1612
+ "Actions:\n" +
1613
+ " • list_projects — List all discovered projects (grouped by `project:<prefix>` tag) with object counts.\n" +
1614
+ " • list_objects — List objects in a project (requires `project` param).\n" +
1615
+ " • shareable — List objects tagged `shareable:true` (cross-project reusable: common Permission, 3rd-party Arb).\n" +
1616
+ " • dependencies — Trace forward dependencies of an object (BFS transitive closure + dangling refs).\n" +
1617
+ " • referenced_by — Reverse query: who references this object?\n" +
1618
+ " • pre_publish_check — Pre-publish sanity check for a service (dangling deps + cycles).\n" +
1619
+ " • cross_project_refs — Find edges that cross project boundaries.\n" +
1620
+ " • graph_stats — Graph statistics (node/edge counts, cycles, dangling deps).\n" +
1621
+ " • save_graph — Save the in-memory graph to ~/.wowok/project-graph.json (persist across sessions).\n" +
1622
+ " • load_graph — Load the graph from file (restore after restart).\n\n" +
1623
+ "NOTE: The graph is in-memory by default. Use save_graph/load_graph for cross-session persistence " +
1624
+ "(or toggle graph_persist via config_operation for auto-save). " +
1625
+ "list_projects/shareable always query local_mark (persistent).",
1626
+ inputSchema: z.object({
1627
+ action: z.enum([
1628
+ "list_projects", "list_objects", "shareable",
1629
+ "dependencies", "referenced_by", "pre_publish_check",
1630
+ "cross_project_refs", "graph_stats",
1631
+ "save_graph", "load_graph",
1632
+ ]).describe("Query/action to perform"),
1633
+ project: z.string().optional().describe("Project prefix (for list_objects)"),
1634
+ object: z.string().optional().describe("Object name or address (for dependencies / referenced_by / pre_publish_check)"),
1635
+ }),
1636
+ outputSchema: z.object({
1637
+ result: z.any().describe("Query result — shape depends on action"),
1638
+ }),
1639
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
1640
+ _meta: createToolMeta("project", ["project", "namespace", "graph", "dag", "dependency", "reference", "organization"]),
1641
+ }, handleProjectOperation);
1642
+ reg("config_operation", {
1643
+ title: "⚙️ Config - Runtime Service Toggles",
1644
+ description: "Phase 2 runtime configuration — toggle Phase 2 services on/off at runtime WITHOUT restarting the MCP server. " +
1645
+ "This is the session-level switch mechanism: AI can toggle based on user conversation context, or users can " +
1646
+ "directly control which Phase 2 features are active.\n\n" +
1647
+ "Actions:\n" +
1648
+ " • list — List all services with current state + reminders.\n" +
1649
+ " • toggle — Toggle a service on/off (requires `service` param). Returns reminder text.\n" +
1650
+ " • enable — Enable a service (requires `service` param).\n" +
1651
+ " • disable — Disable a service (requires `service` param).\n" +
1652
+ " • reset — Reset a service to its default (requires `service` param).\n" +
1653
+ " • info — Get detailed info about a service (requires `service` param).\n\n" +
1654
+ "Services:\n" +
1655
+ " • confirm_gate — Safety Confirmation Gate (default ON)\n" +
1656
+ " • project_service — Project Namespace + Dependency Graph (default ON)\n" +
1657
+ " • harness — L4 Verify/Recover Loop (default OFF)\n" +
1658
+ " • graph_persist — Graph Persistence to File (default OFF)\n" +
1659
+ " • semantic_rich — Semantic Layer Enrichment Reminder (default ON)\n\n" +
1660
+ "NOTE: Toggles persist for the MCP process lifetime. Set WOWOK_RUNTIME_CONFIG_PERSIST=1 " +
1661
+ "to persist across sessions to ~/.wowok/runtime-config.json.",
1662
+ inputSchema: z.object({
1663
+ action: z.enum(["list", "toggle", "enable", "disable", "reset", "info"]).describe("Config action to perform"),
1664
+ service: z.string().optional().describe("Service name (required for toggle/enable/disable/reset/info)"),
1665
+ }),
1666
+ outputSchema: z.object({
1667
+ result: z.any().describe("Config result — shape depends on action"),
1668
+ }),
1669
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
1670
+ _meta: createToolMeta("config", ["config", "toggle", "service", "runtime", "switch", "enable", "disable"]),
1671
+ }, handleConfigOperation);
1206
1672
  const transport = new StdioServerTransport();
1207
1673
  await server.connect(transport);
1208
1674
  process.on("SIGINT", async () => {