@wowok/agent-mcp 2.6.8 → 2.6.9

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 (53) hide show
  1. package/dist/customer/customer-advice.js +1 -0
  2. package/dist/customer/info-puzzle.js +1 -0
  3. package/dist/customer/reminder-system.d.ts +1 -0
  4. package/dist/customer/reminder-system.js +20 -0
  5. package/dist/customer/types.d.ts +1 -0
  6. package/dist/examples/{insurance-machine-create-publish.json → insurance-machine-create.json} +9 -9
  7. package/dist/examples/insurance-service-allocators.json +55 -0
  8. package/dist/examples/machine-publish.json +30 -0
  9. package/dist/examples/rental-ziroom-service-create.json +12 -64
  10. package/dist/examples/retail-myshop-service-create.json +14 -64
  11. package/dist/examples/retail-myshop-service-customer-required.json +31 -0
  12. package/dist/examples/threebody-machine-create.json +9 -10
  13. package/dist/examples/threebody-service-allocators.json +3 -4
  14. package/dist/examples/travel-machine-create.json +9 -10
  15. package/dist/examples/travel-service-create.json +11 -79
  16. package/dist/harness/index.d.ts +6 -1
  17. package/dist/harness/index.js +4 -1
  18. package/dist/harness/plan.d.ts +13 -0
  19. package/dist/harness/plan.js +24 -0
  20. package/dist/harness/recover.js +2 -2
  21. package/dist/index.js +10 -0
  22. package/dist/project/context-assembly.d.ts +9 -0
  23. package/dist/project/context-assembly.js +122 -6
  24. package/dist/project/graph-builder.d.ts +6 -1
  25. package/dist/project/graph-builder.js +1 -1
  26. package/dist/project/handlers.d.ts +1 -0
  27. package/dist/project/handlers.js +22 -9
  28. package/dist/schema/call/allocation.js +1 -1
  29. package/dist/schema/call/payment.d.ts +11 -11
  30. package/dist/schema/call/payment.js +5 -3
  31. package/dist/schema/call/semantic.js +10 -1
  32. package/dist/schema/call/service.d.ts +6 -6
  33. package/dist/schema/call/service.js +14 -3
  34. package/dist/schema/operations.d.ts +11 -11
  35. package/dist/schema/project/index.d.ts +105 -0
  36. package/dist/schema/project/index.js +53 -0
  37. package/dist/schema/query/index.d.ts +571 -0
  38. package/dist/schema/query/index.js +42 -1
  39. package/dist/schema/sync-layer4.js +25 -4
  40. package/dist/schemas/index.json +1 -1
  41. package/dist/schemas/onchain_operations.schema.json +7 -8
  42. package/dist/schemas/onchain_operations_allocation.schema.json +1 -1
  43. package/dist/schemas/onchain_operations_payment.schema.json +3 -4
  44. package/dist/schemas/onchain_operations_service.schema.json +3 -3
  45. package/dist/schemas/project_operation.output.json +79 -0
  46. package/dist/schemas/project_operation.schema.json +13 -0
  47. package/dist/schemas/query_toolkit.output.json +39 -1
  48. package/dist/schemas/wowok_buildin_info.output.json +132 -0
  49. package/dist/schemas/wowok_buildin_info.schema.json +14 -0
  50. package/dist/tools/handlers/onchain.js +94 -4
  51. package/dist/tools/index.js +3 -3
  52. package/package.json +2 -2
  53. package/dist/examples/insurance-service-allocators-publish.json +0 -56
@@ -1,10 +1,10 @@
1
1
  {
2
- "title": "Create and Publish Travel Service with Tiered Allocation Waterfall",
3
- "description": "Create the Iceland travel Service with Machine binding, one sales item, Arbitration binding, and a 3-tier order_allocators waterfall (first-Guard-wins): merchant victory 100% to Treasury, no-ice-scooting 80/20 Treasury/customer, no-SPA 5/95 Treasury/customer — then publish in the same transaction.",
4
- "tags": ["service", "travel", "order_allocators", "waterfall", "allocation", "publish", "arbitration"],
2
+ "title": "Create Travel Service DRAFT (Iceland)",
3
+ "description": "Step 3 of the 12-step deploy plan: create the Iceland travel Service object in DRAFT (unpublished) with only its identity — name, permission, and description. Machine binding, sales (WIP), Arbitration binding, order_allocators (tiered waterfall), and publish are each separate later steps and are intentionally NOT bundled here.",
4
+ "tags": ["service", "travel", "draft", "create", "12-step"],
5
5
  "industry": "travel",
6
6
  "operation_type": "service",
7
- "source": "docs/examples/Travel — schema-validated, not chain-verified",
7
+ "source": "docs/examples/Travel — adapted to the 12-step plan (DRAFT only, schema-validated)",
8
8
  "verified": false,
9
9
  "network": "testnet",
10
10
  "call": {
@@ -16,87 +16,19 @@
16
16
  "permission": "travel_permission",
17
17
  "replaceExistName": true
18
18
  },
19
- "description": "Iceland travel service: Blue Lagoon SPA + Glacier Ice Scooting.",
20
- "machine": "travel_machine",
21
- "sales": {
22
- "op": "add",
23
- "sales": [
24
- {
25
- "name": "Iceland Travel Package",
26
- "price": "500000000",
27
- "stock": "99",
28
- "suspension": false,
29
- "wip": "",
30
- "wip_hash": ""
31
- }
32
- ]
33
- },
34
- "arbitrations": {
35
- "op": "add",
36
- "objects": ["travel_arbitration"]
37
- },
38
- "order_allocators": {
39
- "description": "Travel order revenue allocation based on progress state",
40
- "threshold": 0,
41
- "allocators": [
42
- {
43
- "guard": "merchant_victory_guard",
44
- "sharing": [
45
- {
46
- "who": {"Entity": {"name_or_address": "travel_treasury"}},
47
- "sharing": 10000,
48
- "mode": "Rate"
49
- }
50
- ]
51
- },
52
- {
53
- "guard": "no_ice_scooting_guard",
54
- "sharing": [
55
- {
56
- "who": {"Entity": {"name_or_address": "travel_treasury"}},
57
- "sharing": 8000,
58
- "mode": "Rate"
59
- },
60
- {
61
- "who": {"GuardIdentifier": 0},
62
- "sharing": 2000,
63
- "mode": "Rate"
64
- }
65
- ]
66
- },
67
- {
68
- "guard": "no_spa_guard",
69
- "sharing": [
70
- {
71
- "who": {"Entity": {"name_or_address": "travel_treasury"}},
72
- "sharing": 500,
73
- "mode": "Rate"
74
- },
75
- {
76
- "who": {"GuardIdentifier": 0},
77
- "sharing": 9500,
78
- "mode": "Rate"
79
- }
80
- ]
81
- }
82
- ]
83
- },
84
- "pause": false,
85
- "publish": true
19
+ "description": "Iceland travel service: Blue Lagoon SPA + Glacier Ice Scooting."
86
20
  },
87
21
  "env": {
88
22
  "account": "travel_provider",
89
23
  "network": "testnet",
90
- "no_cache": true,
91
- "confirmed": true
24
+ "no_cache": true
92
25
  }
93
26
  },
94
27
  "notes": [
95
- "Tiered allocation waterfall pattern (query/index.ts AllocatorsSchema): allocators are evaluated IN ORDER and the FIRST allocator whose Guard passes wins (mutually exclusive paths). Each tier's Rate-mode sharing sums to exactly 10000 basis points (10000=100%; 8000+2000; 500+9500) — required by the contract when no Surplus item exists (ERATE_NOT_10000). The three Guards discriminate on progress.current ('Complete' / 'Cancel'|'Ice Scooting' / 'SPA') plus order.service ownership, so the tier that fires is determined by the terminal workflow state.",
96
- "Recipient forms (query/index.ts RecipientSchema): {Entity:{name_or_address:'travel_treasury'}} is a FIXED address resolved at build time — merchant revenue always flows to the Treasury object regardless of who calls alloc_by_guard (Treasury-first rule, R-C3-06 safe, no Signer binding needed). {GuardIdentifier:0} is DYNAMIC — resolved from the Guard table submission at allocation time; all three allocation Guards define identifier 0 as b_submission:true Address accepting the Order ID, so the customer share escrows to the Order object (claimable by the order owner via order receive).",
97
- "Schema check (call/service.ts CallService_DataSchema, strict): object uses the OBJECT form of TypedPermissionObjectSchema (type_parameter omitted -> WOW default '0x2::wow::WOW'); sales is an op discriminated union {op:'add', sales:[ServiceSaleSchema]} — each sale requires name/price/stock/suspension/wip/wip_hash (price '500000000' = 0.5 WOW smallest unit as string; empty wip/wip_hash are TESTING-ONLY, production must pin a real WIP URL + hash); arbitrations uses ObjectsSchema {op:'add', objects:[...]} — the bound Arbitration MUST use a Permission DIFFERENT from the Service's (E_ARBITRATION_PERMISSION_CONFLICT), hence travel_arbitration_permission in the doc.",
98
- "L1 immutability warning: machine and order_allocators are PERMANENTLY LOCKED once publish=true executes (service.move assert!(!bPublished)) — there is no pause+lock exception. Verify every guard name resolves and every sharing split is intended BEFORE publishing; after publish the only fix is a NEW Service object. Guards (merchant_victory_guard, no_ice_scooting_guard, no_spa_guard), the published Machine (travel_machine), the Arbitration (travel_arbitration), and the Treasury (travel_treasury) must all exist before this call.",
99
- "threshold:0 means no minimum balance is required for allocation to fire. Allocator 'fix' and 'max' fields are intentionally omitted — fix is output-only (contract-computed sum of Amount-mode items) and max is an optional cap.",
100
- "Desensitization: doc payload already uses generic local-mark names only (travel_provider, travel_service, travel_treasury, travel_arbitration, guard names); no real personal data or raw 0x object addresses present — nothing replaced."
28
+ "12-STEP PLAN alignment: this file is ONE step (Step 3 Service DRAFT). The full order is Account → Permission → Service DRAFT → Machine → Guard → Machine publish → Sales(WIP) → Treasury(optional) → order_allocators → Contact(um) → Arbitration → Service publish. Do NOT bundle machine/sales/arbitrations/order_allocators/publish into the create call.",
29
+ "object uses the OBJECT form of TypedPermissionObjectSchema (type_parameter omitted → WOW default '0x2::wow::WOW'); description is a top-level Service field. No publish:true here — the Service stays unpublished until Step 12.",
30
+ "machine and order_allocators are PERMANENTLY LOCKED once publish=true executes (service.move assert!(!bPublished)) — set them in their own pre-publish steps, not in this DRAFT.",
31
+ "arbitrations binding requires a Permission DIFFERENT from the Service's (E_ARBITRATION_PERMISSION_CONFLICT) — create a dedicated travel_arbitration Permission first, then bind the Arbitration in the Arbitration step (Step 11), not here.",
32
+ "Travel is a PHYSICAL/service scenario; if it declares customer_required, set it together with a Contact bound as um (hard linkage) in the Contact step."
101
33
  ]
102
34
  }
@@ -3,7 +3,7 @@ export * from "./plan.js";
3
3
  export * from "./verify.js";
4
4
  export * from "./recover.js";
5
5
  export * from "./checkpoint.js";
6
- import type { DecisionPoint } from "./plan.js";
6
+ import type { DecisionPoint, MigrationDecision } from "./plan.js";
7
7
  import type { VerifyInput } from "./verify.js";
8
8
  import type { ODG, ExpectedResult, VerifyReport, RecoveryAction, Checkpoint } from "./types.js";
9
9
  export declare class Harness {
@@ -11,6 +11,11 @@ export declare class Harness {
11
11
  plan(userInput: string, taskId?: string): ODG;
12
12
  classifyIntent(userInput: string): import("./plan.js").IntentClassification;
13
13
  getDecisions(odg: ODG): DecisionPoint[];
14
+ getMigrationDecisions(options?: {
15
+ from_network?: "testnet";
16
+ to_network?: "mainnet";
17
+ current_payment_token?: string;
18
+ }): MigrationDecision[];
14
19
  detectCycles(odg: ODG): string[] | null;
15
20
  getScenarioRegistry(): import("./types.js").ScenarioTemplate[];
16
21
  expect(operation: string, intent: string, operationType: string, data?: Record<string, unknown>): ExpectedResult;
@@ -3,7 +3,7 @@ export * from "./plan.js";
3
3
  export * from "./verify.js";
4
4
  export * from "./recover.js";
5
5
  export * from "./checkpoint.js";
6
- import { classifyIntent, generateODG, identifyDecisionPoints, detectCycles, SCENARIO_REGISTRY } from "./plan.js";
6
+ import { classifyIntent, generateODG, identifyDecisionPoints, detectCycles, SCENARIO_REGISTRY, identifyMigrationDecisions } from "./plan.js";
7
7
  import { verify, generateExpected } from "./verify.js";
8
8
  import { recover, resetAttempts, getBackoffDelay, RECOVERY_RULES } from "./recover.js";
9
9
  import { saveCheckpoint, loadLatestCheckpoint, listCheckpoints, listTasks, createCheckpoint } from "./checkpoint.js";
@@ -18,6 +18,9 @@ export class Harness {
18
18
  getDecisions(odg) {
19
19
  return identifyDecisionPoints(odg);
20
20
  }
21
+ getMigrationDecisions(options) {
22
+ return identifyMigrationDecisions(options);
23
+ }
21
24
  detectCycles(odg) {
22
25
  return detectCycles(odg);
23
26
  }
@@ -16,3 +16,16 @@ export interface DecisionPoint {
16
16
  }
17
17
  export declare function identifyDecisionPoints(odg: ODG): DecisionPoint[];
18
18
  export declare function detectCycles(odg: ODG): string[] | null;
19
+ export interface MigrationDecision {
20
+ round: string;
21
+ question: string;
22
+ options: string[];
23
+ default?: string;
24
+ note?: string;
25
+ }
26
+ export interface MigrationDecisionOptions {
27
+ from_network?: "testnet";
28
+ to_network?: "mainnet";
29
+ current_payment_token?: string;
30
+ }
31
+ export declare function identifyMigrationDecisions(options?: MigrationDecisionOptions): MigrationDecision[];
@@ -250,3 +250,27 @@ export function detectCycles(odg) {
250
250
  }
251
251
  return null;
252
252
  }
253
+ export function identifyMigrationDecisions(options) {
254
+ const current = options?.current_payment_token ?? "WOW";
255
+ const from = options?.from_network ?? "testnet";
256
+ const to = options?.to_network ?? "mainnet";
257
+ return [
258
+ {
259
+ round: "M1",
260
+ question: `Your project currently uses "${current}" as the payment token on ${from}. ` +
261
+ `When migrating to ${to}, do you want to keep "${current}" or switch to a stablecoin ` +
262
+ `(e.g. USDT, available via the ETH mainnet cross-chain bridge)?`,
263
+ options: [
264
+ `Keep ${current}`,
265
+ "Switch to USDT",
266
+ "Switch to USDC",
267
+ "Other stablecoin",
268
+ ],
269
+ default: `Keep ${current}`,
270
+ note: `Testnet recommendation: WOW for all merchant and order testing. ` +
271
+ `Mainnet: USDT and other stablecoins are available via the ETH mainnet cross-chain bridge ` +
272
+ `and are often preferred to avoid price volatility. If switching, the Service / Treasury / ` +
273
+ `Allocation type_parameter must be updated to the stablecoin's WOW type tag before publishing on mainnet.`,
274
+ },
275
+ ];
276
+ }
@@ -4,8 +4,8 @@ export const RECOVERY_RULES = {
4
4
  strategy: "claim_faucet",
5
5
  max_attempts: 3,
6
6
  automation: "semi",
7
- detail: "1. Claim faucet tokens (testnet) 2. Prompt user to top up (mainnet) 3. Retry original operation",
8
- user_prompt: "Insufficient balance for gas or operation. On testnet, claim faucet tokens. On mainnet, please top up your wallet and retry.",
7
+ detail: "1. Testnet: claim WOW from the faucet 2. Mainnet: transfer ETH/USDT/USDC/WBTC via the ETH mainnet cross-chain bridge (query active EVM account → top up from external wallet → confirm → cross-chain) 3. Mention the WOW airdrop (under construction) 4. Retry original operation",
8
+ user_prompt: "Insufficient balance for gas or operation. How to obtain WOW tokens: (1) Testnet — claim WOW from the faucet (https://faucet.testnet.wowok.net); all merchant and order testing can use WOW as the payment token. (2) Mainnet — transfer ETH / USDT / USDC / WBTC via the ETH mainnet cross-chain bridge: first query the active EVM account (bridge_operation query_active_evm_account, auto-generated on first use), then transfer from an external wallet (e.g. MetaMask) to that address, confirm the balance arrived, and cross-chain to WOW mainnet (bridge_operation cross_chain_evm_to_wow). (3) WOW mainnet airdrop: https://airdrop.wowok.net (under construction).",
9
9
  },
10
10
  network_error: {
11
11
  error_code: "network_error",
package/dist/index.js CHANGED
@@ -89,6 +89,16 @@ Read the schema, fix your params, and retry. CACHE the schema in your context fo
89
89
 
90
90
  When the current context does not contain a sub-tool's input/output schema, or when you are uncertain whether the schema you have is complete and up-to-date, you MUST query it first before calling the sub-tool. Use \`wowok({ tool: "schema_query", data: { action: "get", name: "<sub-tool>" } })` + "`" + ` for operational sub-tool schemas or \`wowok({ tool: "wowok_buildin_info", data: { info: "..." } })\` for protocol constants and reference data. Never guess schema parameters, query instruction IDs, or type codes — always retrieve them from the live server.
91
91
 
92
+ ## CRITICAL: Global Unread Messenger Check (every conversation)
93
+
94
+ At the START of EVERY conversation — before answering the user's request, regardless of what it is about — check for unread Messenger messages and IMMEDIATELY and PROMINENTLY remind the user to read them:
95
+
96
+ \`\`\`
97
+ wowok({ tool: "messenger_operation", data: { operation: "watch_conversations", filter: { unreadOnly: true, previewMessageCount: 0, skipAutoMarkViewed: true } } })
98
+ \`\`\`
99
+
100
+ If the result contains any conversation with \`unreadCount > 0\`, surface a prominent reminder at the TOP of your response (do not wait for the user to ask), listing each peer with unread messages and the count. Use \`skipAutoMarkViewed: true\` so merely checking does not mark them read. If there are none, do not mention the check.
101
+
92
102
  ## Token System Overview
93
103
 
94
104
  ### Default Platform Token: WOW
@@ -2,11 +2,20 @@ import type { z } from "zod";
2
2
  import type { ProjectOperationInputSchema } from "../schema/project/index.js";
3
3
  import { type ContextCollectionResult } from "../loop-engineering/context-collect.js";
4
4
  type ValidatedInput = z.infer<typeof ProjectOperationInputSchema>;
5
+ export interface DependencyEdge {
6
+ object: string;
7
+ depth: number;
8
+ via_field: string;
9
+ via_type: string;
10
+ parent: string;
11
+ }
5
12
  export interface AssembleContextResult {
6
13
  action: "assemble_context";
7
14
  objects: unknown[];
8
15
  events?: unknown[];
9
16
  embedded_history?: Record<string, unknown>;
17
+ dependencies?: DependencyEdge[];
18
+ dependency_objects?: unknown[];
10
19
  semantic_summary?: unknown;
11
20
  context_digest: string;
12
21
  next_action: string;
@@ -3,6 +3,7 @@ import { query_objects, query_events } from "@wowok/wowok";
3
3
  import { annotateEventsMonetaryFields } from "../knowledge/fund-layer.js";
4
4
  import { buildDataSemantic } from "../schema/call/semantic.js";
5
5
  import { collectContextExperience } from "../loop-engineering/context-collect.js";
6
+ import { extractAddressFields } from "./graph-builder.js";
6
7
  const STATE_TRANSITION_EVENTS = [
7
8
  "NewOrderEvent",
8
9
  "ProgressEvent",
@@ -11,6 +12,7 @@ const STATE_TRANSITION_EVENTS = [
11
12
  "DemandFeedbackEvent",
12
13
  "NewEntityEvent",
13
14
  ];
15
+ const MAX_OBJECTS_PER_QUERY = 50;
14
16
  export async function assembleContext(validated) {
15
17
  const contextObjects = validated.context_objects;
16
18
  if (!contextObjects || contextObjects.length === 0) {
@@ -18,13 +20,105 @@ export async function assembleContext(validated) {
18
20
  }
19
21
  const network = (validated.context_network ?? "testnet");
20
22
  const includeEvents = validated.include_events ?? false;
23
+ const depth = Math.max(0, Math.min(5, validated.context_depth ?? 0));
24
+ const includeFilter = validated.context_include?.length
25
+ ? new Set(validated.context_include)
26
+ : null;
21
27
  const objectsResult = await query_objects({
22
28
  objects: contextObjects,
23
29
  no_cache: false,
24
30
  network,
25
31
  });
26
32
  const objects = objectsResult?.objects ?? [];
27
- const embeddedHistory = extractEmbeddedHistory(objects);
33
+ const dependencies = [];
34
+ const dependencyObjects = [];
35
+ if (depth > 0) {
36
+ const visited = new Set();
37
+ for (const o of objects) {
38
+ const id = o?.object;
39
+ if (typeof id === "string")
40
+ visited.add(id);
41
+ }
42
+ let frontier = [];
43
+ for (const o of objects) {
44
+ const refs = safeExtractAddressFields(o);
45
+ for (const r of refs) {
46
+ if (includeFilter && !includeFilter.has(r.field))
47
+ continue;
48
+ if (visited.has(r.address))
49
+ continue;
50
+ frontier.push({
51
+ id: r.address,
52
+ parent: o?.object ?? "",
53
+ viaField: r.field,
54
+ viaType: r.type,
55
+ depth: 1,
56
+ });
57
+ }
58
+ }
59
+ for (let currentDepth = 1; currentDepth <= depth && frontier.length > 0; currentDepth++) {
60
+ const seenInLevel = new Set();
61
+ const uniqueFrontier = [];
62
+ for (const f of frontier) {
63
+ if (visited.has(f.id) || seenInLevel.has(f.id))
64
+ continue;
65
+ seenInLevel.add(f.id);
66
+ visited.add(f.id);
67
+ uniqueFrontier.push(f);
68
+ }
69
+ if (uniqueFrontier.length === 0)
70
+ break;
71
+ const nextFrontier = [];
72
+ for (let i = 0; i < uniqueFrontier.length; i += MAX_OBJECTS_PER_QUERY) {
73
+ const batch = uniqueFrontier.slice(i, i + MAX_OBJECTS_PER_QUERY);
74
+ let batchResult;
75
+ try {
76
+ batchResult = await query_objects({
77
+ objects: batch.map((b) => b.id),
78
+ no_cache: false,
79
+ network,
80
+ });
81
+ }
82
+ catch {
83
+ continue;
84
+ }
85
+ const batchObjs = batchResult?.objects ?? [];
86
+ for (let j = 0; j < batch.length; j++) {
87
+ const f = batch[j];
88
+ const obj = batchObjs[j];
89
+ if (!obj)
90
+ continue;
91
+ dependencies.push({
92
+ object: f.id,
93
+ depth: f.depth,
94
+ via_field: f.viaField,
95
+ via_type: f.viaType,
96
+ parent: f.parent,
97
+ });
98
+ dependencyObjects.push(obj);
99
+ if (currentDepth < depth) {
100
+ const refs = safeExtractAddressFields(obj);
101
+ for (const r of refs) {
102
+ if (includeFilter && !includeFilter.has(r.field))
103
+ continue;
104
+ if (visited.has(r.address))
105
+ continue;
106
+ nextFrontier.push({
107
+ id: r.address,
108
+ parent: f.id,
109
+ viaField: r.field,
110
+ viaType: r.type,
111
+ depth: currentDepth + 1,
112
+ });
113
+ }
114
+ }
115
+ }
116
+ }
117
+ frontier = nextFrontier;
118
+ }
119
+ }
120
+ const allObjectsForHistory = [...objects, ...dependencyObjects];
121
+ const embeddedHistory = extractEmbeddedHistory(allObjectsForHistory);
28
122
  const hasEmbeddedHistory = Object.keys(embeddedHistory).length > 0;
29
123
  let events;
30
124
  if (includeEvents) {
@@ -61,16 +155,26 @@ export async function assembleContext(validated) {
61
155
  };
62
156
  const semanticSummary = buildDataSemantic({ objects, embedded_history: embeddedHistory, events }, semanticCtx);
63
157
  const digestParts = objects.map((obj) => `${obj?.object ?? obj?.data?.object ?? "?"}:${obj?.version ?? obj?.data?.version ?? "?"}`);
158
+ if (dependencyObjects.length > 0) {
159
+ digestParts.push(`deps:${dependencyObjects
160
+ .map((o) => `${o?.object ?? "?"}:${o?.version ?? "?"}`)
161
+ .join(",")}`);
162
+ }
64
163
  digestParts.push(`ts:${Date.now()}`);
65
164
  const contextDigest = createHash("sha256")
66
165
  .update(digestParts.join("|"))
67
166
  .digest("hex")
68
167
  .substring(0, 16);
69
- const nextAction = hasEmbeddedHistory
70
- ? "Context assembled with embedded operation history. Use onchain_transaction with a specific digest to verify a past operation, or proceed with onchain_operations (consider dry_run=true first to validate)."
71
- : events && events.length > 0
72
- ? "Context assembled with recent events. Use onchain_transaction with a specific digest to verify any event's tx, or proceed with onchain_operations."
73
- : "Context assembled (current state only). Proceed with onchain_operations (consider dry_run=true first to validate).";
168
+ const hasDependencies = dependencies.length > 0;
169
+ const nextAction = hasDependencies
170
+ ? `Context assembled with ${dependencies.length} dependency object(s) across ${depth} level(s). ` +
171
+ "Use onchain_transaction with a specific digest to verify a past operation, " +
172
+ "or proceed with onchain_operations (consider dry_run=true first to validate)."
173
+ : hasEmbeddedHistory
174
+ ? "Context assembled with embedded operation history. Use onchain_transaction with a specific digest to verify a past operation, or proceed with onchain_operations (consider dry_run=true first to validate)."
175
+ : events && events.length > 0
176
+ ? "Context assembled with recent events. Use onchain_transaction with a specific digest to verify any event's tx, or proceed with onchain_operations."
177
+ : "Context assembled (current state only). Proceed with onchain_operations (consider dry_run=true first to validate).";
74
178
  let flywheelCollected;
75
179
  try {
76
180
  flywheelCollected = collectContextExperience({
@@ -90,12 +194,24 @@ export async function assembleContext(validated) {
90
194
  objects,
91
195
  events,
92
196
  embedded_history: hasEmbeddedHistory ? embeddedHistory : undefined,
197
+ dependencies: hasDependencies ? dependencies : undefined,
198
+ dependency_objects: hasDependencies ? dependencyObjects : undefined,
93
199
  semantic_summary: semanticSummary,
94
200
  context_digest: contextDigest,
95
201
  next_action: nextAction,
96
202
  flywheel_collected: flywheelCollected,
97
203
  };
98
204
  }
205
+ function safeExtractAddressFields(obj) {
206
+ if (!obj || typeof obj !== "object")
207
+ return [];
208
+ try {
209
+ return extractAddressFields(obj);
210
+ }
211
+ catch {
212
+ return [];
213
+ }
214
+ }
99
215
  function extractEmbeddedHistory(objects) {
100
216
  const history = {};
101
217
  for (const obj of objects) {
@@ -1,4 +1,4 @@
1
- import { type GraphData, type GraphNode } from "@wowok/wowok";
1
+ import { type ObjectBase, type GraphData, type GraphNode } from "@wowok/wowok";
2
2
  export type GraphNodeWithTemplate = GraphNode & {
3
3
  isTemplate?: boolean;
4
4
  };
@@ -29,6 +29,11 @@ export interface GraphBuildResult {
29
29
  graph: GraphData;
30
30
  reputation: Map<string, ReputationData>;
31
31
  }
32
+ export declare function extractAddressFields(obj: ObjectBase): Array<{
33
+ address: string;
34
+ field: string;
35
+ type: string;
36
+ }>;
32
37
  export declare class GraphBuilder {
33
38
  private localProject;
34
39
  private rateLimiter;
@@ -7,7 +7,7 @@ function shortTypeName(objectType) {
7
7
  const segments = base.split("::");
8
8
  return segments[segments.length - 1] || "unknown";
9
9
  }
10
- function extractAddressFields(obj) {
10
+ export function extractAddressFields(obj) {
11
11
  const refs = [];
12
12
  const rawType = obj.type;
13
13
  let objType = rawType;
@@ -320,6 +320,7 @@ export declare function handleMigrateToMainnet(v: ProjectInput): Promise<{
320
320
  cloned_objects_count: number;
321
321
  };
322
322
  key_principle: string;
323
+ payment_token_decision: import("../harness/plan.js").MigrationDecision;
323
324
  migration_plan: ({
324
325
  step: number;
325
326
  status: string;
@@ -8,6 +8,7 @@ import { renderGuardMermaid, renderGuardTreeIndented, renderGuardAscii, renderGu
8
8
  import { renderMachineMermaid, renderMachineTreeIndented, renderMachineAscii, renderMachineMarkmap, } from "../knowledge/machine-render.js";
9
9
  import { inferTraitsFromDescription, findSimilarIndustries, } from "../knowledge/industry-generalizer.js";
10
10
  import { isObjectOfType } from "../schema/utils/object-type-utils.js";
11
+ import { identifyMigrationDecisions } from "../harness/plan.js";
11
12
  const localProject = LocalProject.Instance();
12
13
  function requireField(value, name) {
13
14
  if (value === undefined || value === null) {
@@ -309,14 +310,18 @@ function getRecommendedCreationOrder(industry) {
309
310
  ? ` (industry="${industry}" — see IndustryMode.build_notes for overrides)`
310
311
  : "";
311
312
  return [
312
- { step: 1, object: "Permission", reason: "Base permission object, referenced by all other objects.", required: true },
313
- { step: 2, object: "Treasury", reason: "Standalone object, no dependencies. Optional but recommended for fund management.", required: false },
314
- { step: 3, object: "Machine", reason: `Requires Permission. publish:true locks nodes/pairs/forwards permanently.${industryNote}`, required: true },
315
- { step: 4, object: "Contact", reason: "Requires Permission. Used as Service.um (user manual / contact info).", required: true },
316
- { step: 5, object: "Arbitration", reason: "Requires Permission. Optional but recommended for dispute resolution.", required: false },
317
- { step: 6, object: "Service (unpublished)", reason: "Requires Permission + Machine + Contact + Arbitration. Create WITHOUT publish:true first.", required: true },
318
- { step: 7, object: "Guard x N", reason: "Can reference Service via LocalMark. Create all Guards (buy_guard, allocator_guard, etc.) before publishing Service.", required: true },
319
- { step: 8, object: "Service update + publish", reason: "Add order_allocators referencing Guards, then publish:true. After publish, machine/order_allocators are immutable.", required: true },
313
+ { step: 1, object: "Account", reason: "Base identity for on-chain operations; owns all subsequent objects and receives settlement.", required: true },
314
+ { step: 2, object: "Permission", reason: "Centralized access control; referenced by ALL objects (Service, Machine, Guard, Contact, Arbitration).", required: true },
315
+ { step: 3, object: "Service (draft)", reason: "Create the skeleton FIRST (unpublished) so Guards can reference it by LocalMark NAME — breaks the Guard↔Service circular dependency.", required: true },
316
+ { step: 4, object: "Machine (unpublished)", reason: `Business workflow nodes/forwards. Requires Permission.${industryNote}`, required: true },
317
+ { step: 5, object: "Guard x N", reason: "Acceptance logic referencing machine node names + service name via LocalMark. Bind to Machine forwards before publish.", required: true },
318
+ { step: 6, object: "Machine publish", reason: "Freeze workflow topology (nodes/pairs/forwards immutable). Export machineNode2file first for backup.", required: true },
319
+ { step: 7, object: "Sales (WIP)", reason: "Products with wip URL (must be a public endpoint) + wip_hash. Recommend generating WIP from web/doc material via AI sub-task.", required: true },
320
+ { step: 8, object: "Treasury (optional)", reason: "Fund pool for organizations; referenced by order_allocators as an Entity recipient. Skip for personal merchants.", required: false },
321
+ { step: 9, object: "order_allocators", reason: "Fund distribution (Amount/Rate/Surplus). Personal merchant → Permission owner; organization → Treasury.", required: true },
322
+ { step: 10, object: "Contact", reason: "Customer-service channel (Service.um → Contact → ims[]); enable local account as messenger + anti-spam.", required: true },
323
+ { step: 11, object: "Arbitration (optional)", reason: "Third-party dispute resolution (REUSE an existing Arbitration). MUST NOT reuse Service's Permission — E_ARBITRATION_PERMISSION_CONFLICT. Requires compensation_fund if configured.", required: false },
324
+ { step: 12, object: "Service publish", reason: "Add machine + order_allocators + buy_guard + sales + arbitrations, then publish:true. machine/order_allocators/arbitrations immutable after publish.", required: true },
320
325
  ];
321
326
  }
322
327
  function mapEdgeKindToRelationshipType(edgeKind) {
@@ -1155,6 +1160,11 @@ export async function handleMigrateToMainnet(v) {
1155
1160
  "but they correspond to DIFFERENT on-chain addresses. The testnet project is preserved unchanged. " +
1156
1161
  "LocalMark names are NETWORK-SCOPED: a name resolves to a testnet address when env.network=testnet, " +
1157
1162
  "and to a mainnet address when env.network=mainnet. Register the SAME name TWICE (once per network).",
1163
+ payment_token_decision: identifyMigrationDecisions({
1164
+ from_network: "testnet",
1165
+ to_network: "mainnet",
1166
+ current_payment_token: "WOW",
1167
+ })[0],
1158
1168
  migration_plan: [
1159
1169
  {
1160
1170
  step: 1,
@@ -1173,7 +1183,10 @@ export async function handleMigrateToMainnet(v) {
1173
1183
  deployment_plan: deploymentPlan,
1174
1184
  critical_note: "Re-deploy in dependency order: Permission → Machine → Contact → Guard(s) → Service. " +
1175
1185
  "For the Service↔Guard circular dependency, use the 3-step pattern " +
1176
- "(Service without order_allocators → Guards → Service with order_allocators + publish).",
1186
+ "(Service without order_allocators → Guards → Service with order_allocators + publish). " +
1187
+ "BEFORE deploying, decide the payment token (see payment_token_decision above): if switching " +
1188
+ "from WOW to a stablecoin (e.g. USDT), set the Service / Treasury / Allocation type_parameter " +
1189
+ "to the stablecoin's WOW type tag (query 'mainnet bridge tokens' via wowok_buildin_info).",
1177
1190
  },
1178
1191
  {
1179
1192
  step: 3,
@@ -18,7 +18,7 @@ export const CallAllocation_OperateSchema = z.object({
18
18
  "GuardIdentifier n recipients receive it at the ADDRESS SUBMITTED for identifier n in this call's submission " +
19
19
  "(resolved via passport::submission_get) — conventionally the Order OBJECT address (escrow pattern), " +
20
20
  "in which case the order owner claims it via operation_type='order' {object:'<order_id>', receive:'recently'}. " +
21
- "Claim paths by holder: EOA wallet → operation_type='payment' RECEIVE mode {object:'<coinwrapper_id>', receive:true, type_parameter:'0x2::wow::WOW'}; " +
21
+ "Claim paths by holder: EOA wallet → operation_type='payment' RECEIVE mode {object:'<coinwrapper_id>', receive:true} (type_parameter optional, auto-derived from the CoinWrapper type); " +
22
22
  "Order object → order receive; Treasury object → treasury receive. " +
23
23
  "Find pending CoinWrappers via query_toolkit query_type='onchain_received'. " +
24
24
  "Verify the distribution via the immutable Payment object created by this call (allocation.payment array).")
@@ -180,15 +180,15 @@ export declare const CallPayment_CreateSchema: z.ZodObject<{
180
180
  export declare const CallPayment_ReceiveSchema: z.ZodObject<{
181
181
  object: z.ZodEffects<z.ZodString, string, string>;
182
182
  receive: z.ZodLiteral<true>;
183
- type_parameter: z.ZodString;
183
+ type_parameter: z.ZodOptional<z.ZodString>;
184
184
  }, "strict", z.ZodTypeAny, {
185
185
  object: string;
186
- type_parameter: string;
187
186
  receive: true;
187
+ type_parameter?: string | undefined;
188
188
  }, {
189
189
  object: string;
190
- type_parameter: string;
191
190
  receive: true;
191
+ type_parameter?: string | undefined;
192
192
  }>;
193
193
  export declare const CallPayment_DataSchema: z.ZodUnion<[z.ZodObject<{
194
194
  object: z.ZodObject<{
@@ -325,15 +325,15 @@ export declare const CallPayment_DataSchema: z.ZodUnion<[z.ZodObject<{
325
325
  }>, z.ZodObject<{
326
326
  object: z.ZodEffects<z.ZodString, string, string>;
327
327
  receive: z.ZodLiteral<true>;
328
- type_parameter: z.ZodString;
328
+ type_parameter: z.ZodOptional<z.ZodString>;
329
329
  }, "strict", z.ZodTypeAny, {
330
330
  object: string;
331
- type_parameter: string;
332
331
  receive: true;
332
+ type_parameter?: string | undefined;
333
333
  }, {
334
334
  object: string;
335
- type_parameter: string;
336
335
  receive: true;
336
+ type_parameter?: string | undefined;
337
337
  }>]>;
338
338
  export declare const CallPayment_InputSchema: z.ZodObject<{
339
339
  data: z.ZodUnion<[z.ZodObject<{
@@ -471,15 +471,15 @@ export declare const CallPayment_InputSchema: z.ZodObject<{
471
471
  }>, z.ZodObject<{
472
472
  object: z.ZodEffects<z.ZodString, string, string>;
473
473
  receive: z.ZodLiteral<true>;
474
- type_parameter: z.ZodString;
474
+ type_parameter: z.ZodOptional<z.ZodString>;
475
475
  }, "strict", z.ZodTypeAny, {
476
476
  object: string;
477
- type_parameter: string;
478
477
  receive: true;
478
+ type_parameter?: string | undefined;
479
479
  }, {
480
480
  object: string;
481
- type_parameter: string;
482
481
  receive: true;
482
+ type_parameter?: string | undefined;
483
483
  }>]>;
484
484
  env: z.ZodOptional<z.ZodObject<{
485
485
  account: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>>;
@@ -546,8 +546,8 @@ export declare const CallPayment_InputSchema: z.ZodObject<{
546
546
  }[];
547
547
  } | {
548
548
  object: string;
549
- type_parameter: string;
550
549
  receive: true;
550
+ type_parameter?: string | undefined;
551
551
  };
552
552
  env?: {
553
553
  account: string;
@@ -590,8 +590,8 @@ export declare const CallPayment_InputSchema: z.ZodObject<{
590
590
  }[];
591
591
  } | {
592
592
  object: string;
593
- type_parameter: string;
594
593
  receive: true;
594
+ type_parameter?: string | undefined;
595
595
  };
596
596
  env?: {
597
597
  no_cache?: boolean | undefined;