@wowok/agent-mcp 2.3.14 → 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 (156) 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/index.js +570 -186
  36. package/dist/knowledge/acquisition-flywheel.d.ts +50 -0
  37. package/dist/knowledge/acquisition-flywheel.js +183 -0
  38. package/dist/knowledge/arbitration-trust.d.ts +24 -0
  39. package/dist/knowledge/arbitration-trust.js +117 -0
  40. package/dist/knowledge/audit-rules.d.ts +28 -0
  41. package/dist/knowledge/audit-rules.js +141 -0
  42. package/dist/knowledge/demand-matching.d.ts +29 -0
  43. package/dist/knowledge/demand-matching.js +132 -0
  44. package/dist/knowledge/dynamic-pricing.d.ts +31 -0
  45. package/dist/knowledge/dynamic-pricing.js +87 -0
  46. package/dist/knowledge/flywheel-loop.d.ts +87 -0
  47. package/dist/knowledge/flywheel-loop.js +378 -0
  48. package/dist/knowledge/glossary.d.ts +18 -0
  49. package/dist/knowledge/glossary.js +209 -0
  50. package/dist/knowledge/index.d.ts +64 -0
  51. package/dist/knowledge/index.js +66 -0
  52. package/dist/knowledge/industry-evolution.d.ts +82 -0
  53. package/dist/knowledge/industry-evolution.js +323 -0
  54. package/dist/knowledge/industry-generalizer.d.ts +17 -0
  55. package/dist/knowledge/industry-generalizer.js +381 -0
  56. package/dist/knowledge/industry-registry.d.ts +49 -0
  57. package/dist/knowledge/industry-registry.js +167 -0
  58. package/dist/knowledge/intent-metrics.d.ts +42 -0
  59. package/dist/knowledge/intent-metrics.js +566 -0
  60. package/dist/knowledge/process-model.d.ts +24 -0
  61. package/dist/knowledge/process-model.js +160 -0
  62. package/dist/knowledge/reputation-rules.d.ts +42 -0
  63. package/dist/knowledge/reputation-rules.js +99 -0
  64. package/dist/knowledge/reward-templates.d.ts +25 -0
  65. package/dist/knowledge/reward-templates.js +125 -0
  66. package/dist/knowledge/safety-rules.d.ts +36 -0
  67. package/dist/knowledge/safety-rules.js +171 -0
  68. package/dist/knowledge/tool-constraints.d.ts +30 -0
  69. package/dist/knowledge/tool-constraints.js +185 -0
  70. package/dist/knowledge/trust-metrics.d.ts +37 -0
  71. package/dist/knowledge/trust-metrics.js +138 -0
  72. package/dist/loop-engineering/diagnose.d.ts +3 -2
  73. package/dist/loop-engineering/diagnose.js +94 -0
  74. package/dist/loop-engineering/improve.d.ts +1 -1
  75. package/dist/loop-engineering/improve.js +52 -1
  76. package/dist/project/graph.d.ts +71 -0
  77. package/dist/project/graph.js +314 -0
  78. package/dist/project/index.d.ts +62 -0
  79. package/dist/project/index.js +167 -0
  80. package/dist/project/namespace.d.ts +62 -0
  81. package/dist/project/namespace.js +181 -0
  82. package/dist/project/query.d.ts +40 -0
  83. package/dist/project/query.js +110 -0
  84. package/dist/safety/confirm-gate.d.ts +15 -0
  85. package/dist/safety/confirm-gate.js +44 -0
  86. package/dist/safety/index.d.ts +3 -0
  87. package/dist/safety/index.js +3 -0
  88. package/dist/safety/preview.d.ts +2 -0
  89. package/dist/safety/preview.js +36 -0
  90. package/dist/schema/call/allocation.d.ts +15 -0
  91. package/dist/schema/call/arbitration.d.ts +111 -96
  92. package/dist/schema/call/base.d.ts +1070 -44
  93. package/dist/schema/call/base.js +69 -1
  94. package/dist/schema/call/bridge.d.ts +709 -52
  95. package/dist/schema/call/bridge.js +13 -2
  96. package/dist/schema/call/contact.d.ts +15 -0
  97. package/dist/schema/call/demand.d.ts +69 -54
  98. package/dist/schema/call/guard.d.ts +125 -80
  99. package/dist/schema/call/handler.d.ts +3 -0
  100. package/dist/schema/call/handler.js +14 -0
  101. package/dist/schema/call/machine.d.ts +830 -800
  102. package/dist/schema/call/order.d.ts +15 -0
  103. package/dist/schema/call/payment.d.ts +15 -0
  104. package/dist/schema/call/permission.d.ts +15 -0
  105. package/dist/schema/call/personal.d.ts +15 -0
  106. package/dist/schema/call/progress.d.ts +15 -0
  107. package/dist/schema/call/proof.d.ts +42 -12
  108. package/dist/schema/call/proof.js +3 -3
  109. package/dist/schema/call/repository.d.ts +91 -76
  110. package/dist/schema/call/reward.d.ts +45 -30
  111. package/dist/schema/call/semantic.d.ts +1 -0
  112. package/dist/schema/call/semantic.js +217 -0
  113. package/dist/schema/call/service.d.ts +407 -392
  114. package/dist/schema/call/treasury.d.ts +15 -0
  115. package/dist/schema/common/index.js +3 -3
  116. package/dist/schema/local/index.d.ts +228 -72
  117. package/dist/schema/local/index.js +33 -6
  118. package/dist/schema/messenger/index.d.ts +668 -50
  119. package/dist/schema/messenger/index.js +9 -0
  120. package/dist/schema/operations.d.ts +1693 -1369
  121. package/dist/schema/operations.js +2 -2
  122. package/dist/schema/query/index.d.ts +1614 -1614
  123. package/dist/schema/query/index.js +30 -27
  124. package/dist/schemas/account_operation.output.json +25 -16
  125. package/dist/schemas/account_operation.schema.json +1 -1
  126. package/dist/schemas/bridge_operation.output.json +520 -0
  127. package/dist/schemas/bridge_operation.schema.json +15 -0
  128. package/dist/schemas/guard2file.schema.json +15 -0
  129. package/dist/schemas/index.json +1 -1
  130. package/dist/schemas/local_info_operation.output.json +23 -0
  131. package/dist/schemas/local_info_operation.schema.json +1 -1
  132. package/dist/schemas/local_mark_operation.output.json +24 -1
  133. package/dist/schemas/local_mark_operation.schema.json +4 -4
  134. package/dist/schemas/machineNode2file.schema.json +15 -0
  135. package/dist/schemas/messenger_operation.output.json +528 -0
  136. package/dist/schemas/onchain_operations.output.json +350 -16
  137. package/dist/schemas/onchain_operations.schema.json +96 -23
  138. package/dist/schemas/onchain_operations_allocation.schema.json +15 -0
  139. package/dist/schemas/onchain_operations_arbitration.schema.json +15 -0
  140. package/dist/schemas/onchain_operations_contact.schema.json +15 -0
  141. package/dist/schemas/onchain_operations_demand.schema.json +15 -0
  142. package/dist/schemas/onchain_operations_gen_passport.schema.json +30 -0
  143. package/dist/schemas/onchain_operations_guard.schema.json +15 -0
  144. package/dist/schemas/onchain_operations_machine.schema.json +81 -23
  145. package/dist/schemas/onchain_operations_order.schema.json +15 -0
  146. package/dist/schemas/onchain_operations_payment.schema.json +15 -0
  147. package/dist/schemas/onchain_operations_permission.schema.json +15 -0
  148. package/dist/schemas/onchain_operations_personal.schema.json +15 -0
  149. package/dist/schemas/onchain_operations_progress.schema.json +15 -0
  150. package/dist/schemas/onchain_operations_repository.schema.json +15 -0
  151. package/dist/schemas/onchain_operations_reward.schema.json +15 -0
  152. package/dist/schemas/onchain_operations_service.schema.json +15 -0
  153. package/dist/schemas/onchain_operations_treasury.schema.json +15 -0
  154. package/dist/schemas/onchain_table_data.output.json +221 -69
  155. package/dist/schemas/onchain_table_data.schema.json +2 -2
  156. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -5,13 +5,18 @@ 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
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, } from "./knowledge/index.js";
17
+ const HARNESS_ENABLED = () => isRuntimeEnabled("harness");
13
18
  function withHarness(base, operation, intent) {
14
- if (!HARNESS_ENABLED)
19
+ if (!HARNESS_ENABLED())
15
20
  return base;
16
21
  try {
17
22
  const harness = getHarness();
@@ -27,6 +32,58 @@ function withHarness(base, operation, intent) {
27
32
  return base;
28
33
  }
29
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
+ }
30
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";
31
88
  import { areSchemasAvailable, getSchemaIndex, processSchemaQuery, } from "./schema-query/index.js";
32
89
  const SERVER_DESCRIPTION = `WoWok MCP Server - Making It Easy for AI Agents to Communicate, Collaborate, Trade, and Trust.
@@ -141,8 +198,73 @@ import { withTelemetry, setTelemetryEnabled } from "./telemetry/index.js";
141
198
  if (process.env.WOWOK_TELEMETRY === "false" || process.env.WOWOK_TELEMETRY === "0") {
142
199
  setTelemetryEnabled(false);
143
200
  }
144
- function reg(name, config, handler) {
145
- server.registerTool(name, config, withTelemetry(name, handler));
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
+ };
146
268
  }
147
269
  function convertAmountType(type) {
148
270
  if (typeof type === "number")
@@ -261,6 +383,7 @@ async function handleOnchainTableData(args) {
261
383
  }
262
384
  async function handleOnchainOperations(args) {
263
385
  let validated;
386
+ let constraintWarnings = [];
264
387
  try {
265
388
  if (typeof args === 'object' && args !== null && args.description && !args.operation_type) {
266
389
  const hasWrappedParams = typeof args.description === 'string' &&
@@ -273,6 +396,29 @@ async function handleOnchainOperations(args) {
273
396
  }
274
397
  validated = strictParse(OnchainOperationsSchema, args, "onchain_operations input");
275
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
+ }
276
422
  switch (validated.operation_type) {
277
423
  case "service": {
278
424
  const callService = new CallService(validated.data);
@@ -281,7 +427,7 @@ async function handleOnchainOperations(args) {
281
427
  : await callService.call(env);
282
428
  const data = validated.data;
283
429
  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));
430
+ return handleCallResult(result, withHarness({ operation_type: validated.operation_type, data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined }, "service", intent));
285
431
  }
286
432
  case "machine": {
287
433
  if (validated.data.node && typeof validated.data.node === 'object' && 'json_or_markdown_file' in validated.data.node) {
@@ -312,42 +458,42 @@ async function handleOnchainOperations(args) {
312
458
  const result = validated.submission
313
459
  ? await callMachine.call_with_submission(env, await transformSubmission(validated.submission))
314
460
  : await callMachine.call(env);
315
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
461
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
316
462
  }
317
463
  case "progress": {
318
464
  const callProgress = new CallProgress(validated.data);
319
465
  const result = validated.submission
320
466
  ? await callProgress.call_with_submission(env, await transformSubmission(validated.submission))
321
467
  : await callProgress.call(env);
322
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
468
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
323
469
  }
324
470
  case "repository": {
325
471
  const callRepository = new CallRepository(validated.data);
326
472
  const result = validated.submission
327
473
  ? await callRepository.call_with_submission(env, await transformSubmission(validated.submission))
328
474
  : await callRepository.call(env);
329
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
475
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
330
476
  }
331
477
  case "arbitration": {
332
478
  const callArbitration = new CallArbitration(validated.data);
333
479
  const result = validated.submission
334
480
  ? await callArbitration.call_with_submission(env, await transformSubmission(validated.submission))
335
481
  : await callArbitration.call(env);
336
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
482
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
337
483
  }
338
484
  case "contact": {
339
485
  const callContact = new CallContact(validated.data);
340
486
  const result = validated.submission
341
487
  ? await callContact.call_with_submission(env, await transformSubmission(validated.submission))
342
488
  : await callContact.call(env);
343
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
489
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
344
490
  }
345
491
  case "treasury": {
346
492
  const callTreasury = new CallTreasury(validated.data);
347
493
  const result = validated.submission
348
494
  ? await callTreasury.call_with_submission(env, await transformSubmission(validated.submission))
349
495
  : await callTreasury.call(env);
350
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
496
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
351
497
  }
352
498
  case "reward": {
353
499
  const transformedData = transformRewardData(validated.data);
@@ -355,19 +501,19 @@ async function handleOnchainOperations(args) {
355
501
  const result = validated.submission
356
502
  ? await callReward.call_with_submission(env, await transformSubmission(validated.submission))
357
503
  : await callReward.call(env);
358
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
504
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
359
505
  }
360
506
  case "allocation": {
361
507
  const callAllocation = new CallAllocation(validated.data);
362
508
  const result = validated.submission
363
509
  ? await callAllocation.call_with_submission(env, await transformSubmission(validated.submission))
364
510
  : await callAllocation.call(env);
365
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
511
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
366
512
  }
367
513
  case "permission": {
368
514
  const callPermission = new CallPermission(validated.data);
369
515
  const result = await callPermission.call(env);
370
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
516
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
371
517
  }
372
518
  case "guard": {
373
519
  const validatedData = validated.data;
@@ -414,7 +560,7 @@ async function handleOnchainOperations(args) {
414
560
  }
415
561
  const callGuard = new CallGuard(validatedData);
416
562
  const result = await callGuard.call(env);
417
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
563
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
418
564
  }
419
565
  case "personal": {
420
566
  const transformPersonalData = (data) => {
@@ -467,48 +613,48 @@ async function handleOnchainOperations(args) {
467
613
  const transformedData = transformPersonalData(validated.data);
468
614
  const callPersonal = new CallPersonal(transformedData);
469
615
  const result = await callPersonal.call(env);
470
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
616
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
471
617
  }
472
618
  case "payment": {
473
619
  const callPayment = new CallPayment(validated.data);
474
620
  const result = await callPayment.call(env);
475
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
621
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
476
622
  }
477
623
  case "demand": {
478
624
  const callDemand = new CallDemand(validated.data);
479
625
  const result = validated.submission
480
626
  ? await callDemand.call_with_submission(env, await transformSubmission(validated.submission))
481
627
  : await callDemand.call(env);
482
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
628
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
483
629
  }
484
630
  case "order": {
485
631
  const callOrder = new CallOrder(validated.data);
486
632
  const result = validated.submission
487
633
  ? await callOrder.call_with_submission(env, await transformSubmission(validated.submission))
488
634
  : await callOrder.call(env);
489
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
635
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
490
636
  }
491
637
  case "gen_passport": {
492
638
  const result = await gen_passport(env, validated.guard, validated.info);
493
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
639
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
494
640
  }
495
641
  case "proof": {
496
642
  const callProof = new CallProof(validated.data);
497
643
  const result = validated.submission
498
644
  ? await callProof.call_with_submission(env, await transformSubmission(validated.submission))
499
645
  : await callProof.call(env);
500
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
646
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
501
647
  }
502
648
  case "gen_proof": {
503
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);
504
- return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data });
650
+ return handleCallResult(result, { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined });
505
651
  }
506
652
  }
507
653
  throw new Error(`Unknown on-chain operation type: ${validated.operation_type}`);
508
654
  }
509
655
  catch (error) {
510
656
  const errorMessage = error instanceof Error ? error.message : String(error);
511
- return handleCallResult({ error: errorMessage }, validated ? { operation_type: validated.operation_type, data: validated.data } : undefined);
657
+ return handleCallResult({ error: errorMessage }, validated ? { operation_type: validated.operation_type, data: validated.data, pre_warnings: constraintWarnings.length ? constraintWarnings : undefined } : undefined);
512
658
  }
513
659
  }
514
660
  async function handleAccountOperation(args) {
@@ -532,16 +678,20 @@ async function handleAccountOperation(args) {
532
678
  const errorMessage = error instanceof Error ? error.message : String(error);
533
679
  const ctx = validated ? { operation_type: "account_" + validated.operation_type, data: validated } : undefined;
534
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;
535
691
  return {
536
692
  content: [{ type: "text", text: `Error: ${errorMessage}` }],
537
693
  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
- },
694
+ result: errorResult,
545
695
  semantic: buildDataSemantic(undefined, ctx, true, errorMessage),
546
696
  },
547
697
  };
@@ -568,16 +718,17 @@ async function handleMarkOperation(args) {
568
718
  const errorMessage = error instanceof Error ? error.message : String(error);
569
719
  const ctx = validated ? { operation_type: "mark_" + validated.operation_type, data: validated } : undefined;
570
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;
571
728
  return {
572
729
  content: [{ type: "text", text: `Error: ${errorMessage}` }],
573
730
  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
- },
731
+ result: errorResult,
581
732
  semantic: buildDataSemantic(undefined, ctx, true, errorMessage),
582
733
  },
583
734
  };
@@ -604,16 +755,17 @@ async function handleInfoOperation(args) {
604
755
  const errorMessage = error instanceof Error ? error.message : String(error);
605
756
  const ctx = validated ? { operation_type: "local_info", data: validated } : undefined;
606
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;
607
765
  return {
608
766
  content: [{ type: "text", text: `Error: ${errorMessage}` }],
609
767
  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,
616
- },
768
+ result: errorResult,
617
769
  semantic: buildDataSemantic(undefined, ctx, true, errorMessage),
618
770
  },
619
771
  };
@@ -780,168 +932,304 @@ async function handleOnchainEvents(args) {
780
932
  },
781
933
  };
782
934
  }
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");
935
+ async function handleProjectOperation(args) {
936
+ const action = args.action;
937
+ const project = args.project;
938
+ const object = args.object;
800
939
  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 };
940
+ switch (action) {
941
+ case "list_projects":
942
+ result = await queryProjects();
805
943
  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 };
944
+ case "list_objects":
945
+ if (!project)
946
+ throw new Error("'project' param is required for list_objects");
947
+ result = await queryProjectObjects(project);
821
948
  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 };
949
+ case "shareable":
950
+ result = await queryShareableObjects();
837
951
  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 };
952
+ case "dependencies":
953
+ if (!object)
954
+ throw new Error("'object' param is required for dependencies");
955
+ result = queryDependencies(object);
846
956
  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 };
957
+ case "referenced_by":
958
+ if (!object)
959
+ throw new Error("'object' param is required for referenced_by");
960
+ result = queryReferencedBy(object);
851
961
  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 };
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) };
860
966
  break;
861
- }
862
- case "verify_wts": {
863
- const verifyResult = await verify_wts(validated.wtsFilePath);
864
- result = { operation: "verify_wts", result: verifyResult };
967
+ case "cross_project_refs":
968
+ result = queryCrossProjectReferences();
865
969
  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 };
970
+ case "graph_stats":
971
+ result = queryGraphStats();
870
972
  break;
871
- }
872
- case "wts2html": {
873
- const htmlResult = await wts2html(validated.wtsPath, validated.options);
874
- result = { operation: "wts2html", result: htmlResult };
973
+ case "save_graph":
974
+ result = { saved: true, path: saveGraph() };
875
975
  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 };
976
+ case "load_graph":
977
+ result = { loaded: loadGraph() };
880
978
  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 };
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() };
892
993
  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);
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(", ")}`);
901
1001
  }
902
- const friendslistResult = await friendslist(friendslistParams);
903
- 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 };
904
1005
  break;
905
1006
  }
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 };
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 };
912
1014
  break;
913
1015
  }
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 };
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 };
920
1023
  break;
921
1024
  }
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 };
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 };
925
1032
  break;
926
1033
  }
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 };
930
- break;
931
- }
932
- case "pull_messages": {
933
- const messages = await pull_messages(validated.account, validated.limit);
934
- result = { operation: "pull_messages", result: messages };
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);
935
1039
  break;
936
1040
  }
937
1041
  default:
938
- throw new Error(`Unknown messenger operation: ${validated.operation}`);
1042
+ throw new Error(`Unknown config_operation action: ${action}`);
939
1043
  }
940
1044
  return {
941
- content: [{ type: "text", text: JSON.stringify(result) }],
1045
+ content: [{ type: "text", text: JSON.stringify({ result }) }],
942
1046
  structuredContent: { result },
943
1047
  };
944
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
+ }
945
1233
  async function handleGuard2File(args) {
946
1234
  const validated = strictParse(Guard2File_InputSchema, args, "guard2file input");
947
1235
  const env = getEnvConfig(validated.env);
@@ -980,6 +1268,24 @@ async function handleMachineNode2File(args) {
980
1268
  const env = getEnvConfig(validated.env);
981
1269
  try {
982
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
+ }
983
1289
  const result = {
984
1290
  result: {
985
1291
  status: "success",
@@ -987,10 +1293,12 @@ async function handleMachineNode2File(args) {
987
1293
  file_path: resolve(validated.file_path),
988
1294
  format: validated.format || "json",
989
1295
  machine_object: validated.machine,
990
- node_count: 0,
991
1296
  },
992
1297
  },
993
1298
  };
1299
+ if (node_count !== undefined) {
1300
+ result.result.data.node_count = node_count;
1301
+ }
994
1302
  return {
995
1303
  content: [{ type: "text", text: JSON.stringify(result) }],
996
1304
  structuredContent: result,
@@ -1020,6 +1328,16 @@ async function main() {
1020
1328
  else {
1021
1329
  console.error("Schema files not available. Run 'npm run generate:schemas' to generate them.");
1022
1330
  }
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"}`);
1023
1341
  reg("onchain_operations", {
1024
1342
  title: "⛓️ On-chain Operations",
1025
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).",
@@ -1035,7 +1353,7 @@ async function main() {
1035
1353
  outputSchema: AccountOperationOutputWrappedSchema,
1036
1354
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
1037
1355
  _meta: createToolMeta("operation", ["account", "local", "private", "wallet", "off-chain"]),
1038
- }, handleAccountOperation);
1356
+ }, handleAccountOperation, statusErrorShape);
1039
1357
  reg("local_mark_operation", {
1040
1358
  title: "🔒 LOCAL ONLY: LocalMark - Address Book Management",
1041
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.",
@@ -1043,7 +1361,7 @@ async function main() {
1043
1361
  outputSchema: LocalMarkOperationOutputWrappedSchema,
1044
1362
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
1045
1363
  _meta: createToolMeta("operation", ["mark", "local", "private", "address-book", "off-chain"]),
1046
- }, handleMarkOperation);
1364
+ }, handleMarkOperation, statusErrorShape);
1047
1365
  reg("local_info_operation", {
1048
1366
  title: "🔒 LOCAL ONLY: LocalInfo - Private Data Management",
1049
1367
  description: "100% LOCAL, NEVER ON-CHAIN 🔒 Manage sensitive personal information stored ONLY on your device: delivery addresses, phone numbers, contacts.",
@@ -1051,7 +1369,7 @@ async function main() {
1051
1369
  outputSchema: LocalInfoOperationOutputWrappedSchema,
1052
1370
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
1053
1371
  _meta: createToolMeta("operation", ["info", "local", "private", "data-management", "off-chain"]),
1054
- }, handleInfoOperation);
1372
+ }, handleInfoOperation, statusErrorShape);
1055
1373
  reg("wip_file", {
1056
1374
  title: "🤝 Witness Immutable Promise File Operations",
1057
1375
  description: "generate (create WIP files from markdown and images), verify (integrity check), sign (add signatures), or wip2html (convert to HTML).",
@@ -1069,7 +1387,7 @@ async function main() {
1069
1387
  outputSchema: MessengerOperationOutputSchema,
1070
1388
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
1071
1389
  _meta: createToolMeta("operation", ["messenger", "message", "file", "wts", "blacklist", "friendslist", "guardlist", "settings", "proof", "communication"]),
1072
- }, handleMessengerOperation);
1390
+ }, handleMessengerOperation, operationErrorShape, 30000);
1073
1391
  reg("guard2file", {
1074
1392
  title: "📄 Guard to File - Export Guard Definition",
1075
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.",
@@ -1077,7 +1395,7 @@ async function main() {
1077
1395
  outputSchema: Guard2File_OutputWrappedSchema,
1078
1396
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
1079
1397
  _meta: createToolMeta("generate file", ["guard", "export", "file", "json", "markdown", "on-chain"]),
1080
- }, handleGuard2File);
1398
+ }, handleGuard2File, strictStatusErrorShape);
1081
1399
  reg("machineNode2file", {
1082
1400
  title: "⚙️ Machine Node to File - Export Machine Node Definition",
1083
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.",
@@ -1085,7 +1403,7 @@ async function main() {
1085
1403
  outputSchema: MachineNode2File_OutputWrappedSchema,
1086
1404
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
1087
1405
  _meta: createToolMeta("generate file", ["machine", "export", "file", "json", "markdown", "on-chain", "workflow"]),
1088
- }, handleMachineNode2File);
1406
+ }, handleMachineNode2File, strictStatusErrorShape);
1089
1407
  reg("query_toolkit", {
1090
1408
  title: "🔍 Data Query Toolkit",
1091
1409
  description: "WOWOK data query toolkit — 9 query types covering local device data and on-chain blockchain data:\n\n"
@@ -1103,7 +1421,8 @@ async function main() {
1103
1421
  + "For dynamic table data queries (pagination, table items), use the 'onchain_table_data' tool.",
1104
1422
  inputSchema: WatchQueryOperationsSchema,
1105
1423
  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[].")
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"),
1107
1426
  }),
1108
1427
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
1109
1428
  _meta: createToolMeta("query", ["watch", "query", "on-chain", "local", "events", "objects", "tokens", "balance", "profile"]),
@@ -1285,6 +1604,71 @@ async function main() {
1285
1604
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
1286
1605
  _meta: createToolMeta("operation", ["bridge", "cross-chain", "evm", "ethereum", "wow", "transfer", "rpc"]),
1287
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);
1288
1672
  const transport = new StdioServerTransport();
1289
1673
  await server.connect(transport);
1290
1674
  process.on("SIGINT", async () => {