@wowok/agent-mcp 2.6.1 → 2.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/dist/customer/info-puzzle.d.ts +1 -1
  2. package/dist/customer/info-puzzle.js +4 -2
  3. package/dist/customer/risk-assessment.js +26 -4
  4. package/dist/customer/types.d.ts +2 -0
  5. package/dist/examples/guard-template-balance-check.json +38 -0
  6. package/dist/examples/guard-template-time-lock.json +39 -0
  7. package/dist/examples/machine-template-7node-rental.json +114 -0
  8. package/dist/examples/rental-ziroom-machine-create.json +137 -0
  9. package/dist/examples/rental-ziroom-permission-create.json +35 -0
  10. package/dist/examples/rental-ziroom-service-create.json +80 -0
  11. package/dist/examples/retail-myshop-service-create.json +88 -0
  12. package/dist/extensions/capability-manifest.js +24 -24
  13. package/dist/extensions/constraint-registry.js +18 -18
  14. package/dist/extensions/metric-registry.js +14 -14
  15. package/dist/extensions/mode-evaluator.js +16 -16
  16. package/dist/extensions/modes.js +131 -45
  17. package/dist/extensions/registry.d.ts +2 -0
  18. package/dist/extensions/registry.js +63 -30
  19. package/dist/extensions/types.d.ts +1 -0
  20. package/dist/index.js +50 -0
  21. package/dist/knowledge/deployment-scanner.js +1 -1
  22. package/dist/knowledge/fund-layer.d.ts +72 -0
  23. package/dist/knowledge/fund-layer.js +420 -0
  24. package/dist/knowledge/guard-render.d.ts +57 -0
  25. package/dist/knowledge/guard-render.js +700 -0
  26. package/dist/knowledge/guard-submission-prompt.d.ts +31 -0
  27. package/dist/knowledge/guard-submission-prompt.js +171 -0
  28. package/dist/knowledge/machine-ledger.js +1 -1
  29. package/dist/knowledge/machine-render.d.ts +41 -0
  30. package/dist/knowledge/machine-render.js +565 -0
  31. package/dist/knowledge/machine-templates.js +4 -4
  32. package/dist/knowledge/reward-confirm.js +2 -2
  33. package/dist/knowledge/reward-puzzle.js +1 -1
  34. package/dist/knowledge/reward-risk.js +9 -9
  35. package/dist/knowledge/reward-templates.js +2 -2
  36. package/dist/knowledge/service-confirm.d.ts +1 -1
  37. package/dist/knowledge/service-confirm.js +3 -3
  38. package/dist/knowledge/service-context.js +1 -1
  39. package/dist/knowledge/service-ledger.js +1 -1
  40. package/dist/knowledge/service-risk.d.ts +1 -1
  41. package/dist/knowledge/service-risk.js +3 -3
  42. package/dist/knowledge/service-templates.js +2 -2
  43. package/dist/knowledge/service-translation.d.ts +1 -1
  44. package/dist/knowledge/service-translation.js +7 -7
  45. package/dist/project/deployment-bridge.js +6 -5
  46. package/dist/project/deployment-doc.js +5 -5
  47. package/dist/project/edit-planner.d.ts +123 -0
  48. package/dist/project/edit-planner.js +1371 -0
  49. package/dist/project/evaluation.js +314 -14
  50. package/dist/project/graph-builder.js +6 -1
  51. package/dist/project/handlers.d.ts +99 -2
  52. package/dist/project/handlers.js +358 -16
  53. package/dist/project/stage-gate.js +4 -4
  54. package/dist/schema/call/allocation.js +2 -2
  55. package/dist/schema/call/arbitration.js +19 -6
  56. package/dist/schema/call/contact.js +2 -2
  57. package/dist/schema/call/demand.js +2 -2
  58. package/dist/schema/call/guard.js +1 -1
  59. package/dist/schema/call/machine.d.ts +1975 -777
  60. package/dist/schema/call/machine.js +50 -4
  61. package/dist/schema/call/order.js +3 -6
  62. package/dist/schema/call/permission.js +2 -2
  63. package/dist/schema/call/repository.js +2 -2
  64. package/dist/schema/call/reward.js +3 -3
  65. package/dist/schema/call/semantic.js +7 -1
  66. package/dist/schema/call/service.d.ts +180 -8
  67. package/dist/schema/call/service.js +82 -27
  68. package/dist/schema/call/treasury.js +3 -3
  69. package/dist/schema/common/index.d.ts +2 -0
  70. package/dist/schema/common/index.js +46 -10
  71. package/dist/schema/local/index.js +5 -1
  72. package/dist/schema/operations.d.ts +755 -176
  73. package/dist/schema/operations.js +43 -7
  74. package/dist/schema/project/index.d.ts +969 -6
  75. package/dist/schema/project/index.js +268 -4
  76. package/dist/schema/query/index.d.ts +217 -0
  77. package/dist/schema/query/index.js +63 -33
  78. package/dist/schema/schema-query/index.d.ts +53 -3
  79. package/dist/schema/schema-query/index.js +17 -2
  80. package/dist/schema/utils/node-parser.js +13 -0
  81. package/dist/schema/utils/object-type-utils.d.ts +12 -0
  82. package/dist/schema/utils/object-type-utils.js +35 -0
  83. package/dist/schema/utils/permission-machine-check.d.ts +49 -0
  84. package/dist/schema/utils/permission-machine-check.js +121 -0
  85. package/dist/schema/utils/skills-recommendation.d.ts +2 -0
  86. package/dist/schema/utils/skills-recommendation.js +76 -0
  87. package/dist/schema-query/index.d.ts +14 -1
  88. package/dist/schema-query/index.js +104 -2
  89. package/dist/schemas/account_operation.schema.json +1 -1
  90. package/dist/schemas/index.json +1 -1
  91. package/dist/schemas/onchain_events.output.json +1 -1
  92. package/dist/schemas/onchain_operations.output.json +2820 -0
  93. package/dist/schemas/onchain_operations.schema.json +115 -53
  94. package/dist/schemas/onchain_operations_allocation.schema.json +5 -5
  95. package/dist/schemas/onchain_operations_arbitration.schema.json +9 -7
  96. package/dist/schemas/onchain_operations_contact.schema.json +3 -3
  97. package/dist/schemas/onchain_operations_demand.schema.json +3 -3
  98. package/dist/schemas/onchain_operations_gen_passport.schema.json +2 -2
  99. package/dist/schemas/onchain_operations_guard.schema.json +1 -1
  100. package/dist/schemas/onchain_operations_machine.schema.json +4 -4
  101. package/dist/schemas/onchain_operations_order.schema.json +3 -3
  102. package/dist/schemas/onchain_operations_payment.schema.json +1 -1
  103. package/dist/schemas/onchain_operations_permission.schema.json +2 -2
  104. package/dist/schemas/onchain_operations_progress.schema.json +1 -1
  105. package/dist/schemas/onchain_operations_proof.schema.json +1 -1
  106. package/dist/schemas/onchain_operations_repository.schema.json +3 -3
  107. package/dist/schemas/onchain_operations_reward.schema.json +6 -6
  108. package/dist/schemas/onchain_operations_service.schema.json +77 -17
  109. package/dist/schemas/onchain_operations_treasury.schema.json +4 -4
  110. package/dist/schemas/onchain_table_data.output.json +1 -1
  111. package/dist/schemas/onchain_table_data.schema.json +10 -9
  112. package/dist/schemas/project_operation.output.json +1026 -7
  113. package/dist/schemas/project_operation.schema.json +46 -4
  114. package/dist/schemas/query_toolkit.output.json +15 -15
  115. package/dist/schemas/query_toolkit.schema.json +3 -3
  116. package/dist/schemas/schema_query.output.json +64 -1
  117. package/dist/schemas/schema_query.schema.json +3 -2
  118. package/dist/schemas/wowok_buildin_info.output.json +81 -8
  119. package/dist/schemas/wowok_buildin_info.schema.json +46 -2
  120. package/dist/tools/handlers/onchain.js +571 -6
  121. package/dist/tools/handlers/project.js +25 -2
  122. package/dist/tools/handlers/schema-query.js +24 -1
  123. package/dist/tools/index.d.ts +8 -0
  124. package/dist/tools/index.js +177 -6
  125. package/package.json +2 -2
@@ -1,4 +1,5 @@
1
1
  import { IndustryModeRegistry } from "../extensions/registry.js";
2
+ import { collectPermissionIndexes, checkPermissionAuthorization, } from "../schema/utils/permission-machine-check.js";
2
3
  const CRITICAL_BINDINGS = [
3
4
  { sourceType: "Service", targetType: "Machine", fieldName: "machine", critical: true },
4
5
  { sourceType: "Service", targetType: "Permission", fieldName: "permission", critical: true },
@@ -21,7 +22,7 @@ const MERCHANT_REQUIRED_ITEMS = [
21
22
  { id: "R11", objectType: "Repository", fieldName: "repositories", required: false, description: "Documentation — published data" },
22
23
  { id: "R12", objectType: "Demand", fieldName: "", required: false, description: "Market discovery — demand signals" },
23
24
  ];
24
- function resolveRequiredItems(industry, compensationFundBalance = 0) {
25
+ function resolveRequiredItems(industry, compensationFundBalance = 0, hasAllocationEscrow = false) {
25
26
  let result = MERCHANT_REQUIRED_ITEMS;
26
27
  if (industry && industry !== "general") {
27
28
  let mode;
@@ -42,6 +43,14 @@ function resolveRequiredItems(industry, compensationFundBalance = 0) {
42
43
  }
43
44
  }
44
45
  }
46
+ if (hasAllocationEscrow && compensationFundBalance === 0) {
47
+ result = result.map(item => {
48
+ if (item.id === "R6") {
49
+ return { ...item, required: false };
50
+ }
51
+ return item;
52
+ });
53
+ }
45
54
  if (compensationFundBalance > 0) {
46
55
  result = result.map(item => item.id === "R7" ? { ...item, required: true } : item);
47
56
  }
@@ -130,6 +139,26 @@ export function getMachineNodeCount(data) {
130
139
  }
131
140
  return 0;
132
141
  }
142
+ function extractMachineNodesFromCache(data) {
143
+ if (!data)
144
+ return [];
145
+ const nodesArr = data["nodes"];
146
+ if (Array.isArray(nodesArr)) {
147
+ return nodesArr;
148
+ }
149
+ const config = data["config"];
150
+ if (config && Array.isArray(config["nodes"])) {
151
+ return config["nodes"];
152
+ }
153
+ const nodesObj = data["nodes"];
154
+ if (nodesObj && typeof nodesObj === "object") {
155
+ const fieldsObj = nodesObj["fields"];
156
+ if (fieldsObj && Array.isArray(fieldsObj["contents"])) {
157
+ return fieldsObj["contents"];
158
+ }
159
+ }
160
+ return [];
161
+ }
133
162
  function getBalanceValue(data, field) {
134
163
  if (!data)
135
164
  return 0;
@@ -192,7 +221,7 @@ function getMaxSalePrice(data) {
192
221
  }
193
222
  return max;
194
223
  }
195
- function detectCircularRefs(edges) {
224
+ function detectCircularRefs(edges, objectTypeMap) {
196
225
  const adj = new Map();
197
226
  for (const e of edges) {
198
227
  if (e.edgeSource === "potential")
@@ -239,12 +268,45 @@ function detectCircularRefs(edges) {
239
268
  else if (recursionStack.has(neighbor)) {
240
269
  const cycleStart = path.indexOf(neighbor);
241
270
  const cycle = path.slice(cycleStart).concat(neighbor);
242
- cycles.push(cycle.join("→"));
271
+ if (!isWoWokNormalFundCycle(cycle, objectTypeMap)) {
272
+ cycles.push(cycle.join("→"));
273
+ }
243
274
  }
244
275
  }
245
276
  }
246
277
  return cycles;
247
278
  }
279
+ function isWoWokNormalFundCycle(cycle, objectTypeMap) {
280
+ if (!objectTypeMap || cycle.length < 3)
281
+ return false;
282
+ const typesInCycle = new Set();
283
+ for (const addr of cycle) {
284
+ const type = objectTypeMap.get(addr);
285
+ if (type) {
286
+ typesInCycle.add(type);
287
+ }
288
+ else {
289
+ return false;
290
+ }
291
+ }
292
+ if (typesInCycle.size === 2 &&
293
+ typesInCycle.has("Order") &&
294
+ typesInCycle.has("Allocation")) {
295
+ return true;
296
+ }
297
+ if (typesInCycle.size === 3 &&
298
+ typesInCycle.has("Order") &&
299
+ typesInCycle.has("Allocation") &&
300
+ typesInCycle.has("Payment")) {
301
+ return true;
302
+ }
303
+ const workflowTypes = ["Service", "Machine", "Progress", "Order"];
304
+ const isWorkflowCycle = Array.from(typesInCycle).every(t => workflowTypes.includes(t));
305
+ if (isWorkflowCycle && typesInCycle.size >= 2) {
306
+ return true;
307
+ }
308
+ return false;
309
+ }
248
310
  function adjustWeightsForPerspective(criterionScores, perspective) {
249
311
  if (perspective === "consumer") {
250
312
  return criterionScores.map(c => {
@@ -334,7 +396,7 @@ function evaluateIndustryPattern(project, objects, objectCache, edges) {
334
396
  if (machines.length > 0) {
335
397
  const machineObj = machines[0];
336
398
  const cached = parseCacheData(objectCache.get(machineObj.objectAddress));
337
- const nodeCount = getNumberField(cached, "node_count") || countArrayField(cached ?? {}, "nodes");
399
+ const nodeCount = getMachineNodeCount(cached);
338
400
  if (nodeCount > 0 && nodeCount >= expectedNodes.length) {
339
401
  matchCount++;
340
402
  result.strengths.push(`Industry pattern match: Machine has ${nodeCount} nodes, covering "${industryName}" mode's ${expectedNodes.length} expected node(s)`);
@@ -444,6 +506,28 @@ function evaluateIndustryPattern(project, objects, objectCache, edges) {
444
506
  deduction: 0,
445
507
  });
446
508
  }
509
+ if (industryName === "freelance") {
510
+ const machines = byType.get("Machine") ?? [];
511
+ for (const m of machines) {
512
+ const mData = parseCacheData(objectCache.get(m.objectAddress));
513
+ if (!mData)
514
+ continue;
515
+ const nodeCount = getMachineNodeCount(mData);
516
+ if (nodeCount > 0) {
517
+ result.findings.push({
518
+ criterion: "industry_pattern",
519
+ severity: "info",
520
+ message: `ISSUE-P1-4: freelance project has a Machine with ${nodeCount} node(s). ` +
521
+ `If the workflow includes a "delivered" state, 48h auto-accept requires ` +
522
+ `an off-chain keeper (WoWok Guard does not support time-based triggers). ` +
523
+ `Keeper should poll Progress objects in "delivered" state and call ` +
524
+ `adminUnhold (permission 224) after 48h timeout.`,
525
+ deduction: 0,
526
+ });
527
+ break;
528
+ }
529
+ }
530
+ }
447
531
  return result;
448
532
  }
449
533
  function evaluateRisk(input) {
@@ -499,8 +583,13 @@ function evaluateRisk(input) {
499
583
  structuralScore = clampScore(structuralScore);
500
584
  let fundScore = 100;
501
585
  const treasuries = byType.get("Treasury") ?? [];
586
+ const allocations = byType.get("Allocation") ?? [];
502
587
  const serviceData = serviceObj ? parseCacheData(objectCache.get(serviceObj.objectAddress)) : null;
503
588
  const compensationBalance = serviceObj ? getBalanceValue(serviceData, "compensation_fund") : 0;
589
+ const orderAllocatorsBinding = serviceObj
590
+ ? bindingIndex.get(`${serviceObj.objectAddress}#order_allocators`)?.size ?? 0
591
+ : 0;
592
+ const hasAllocationEscrow = allocations.length > 0 && orderAllocatorsBinding > 0;
504
593
  let industryRequiresFund = true;
505
594
  if (project.industry && project.industry !== "general") {
506
595
  try {
@@ -512,7 +601,17 @@ function evaluateRisk(input) {
512
601
  catch { }
513
602
  }
514
603
  if (treasuries.length === 0 && compensationBalance === 0) {
515
- if (industryRequiresFund) {
604
+ if (hasAllocationEscrow) {
605
+ fundScore -= 5;
606
+ strengths.push("Allocation escrow mode active — funds locked in contract, released by Guard verification");
607
+ findings.push({
608
+ criterion: "fund_safety",
609
+ severity: "info",
610
+ message: `Using Allocation escrow (${allocations.length} Allocation object(s) + order_allocators bound) — fund safety via Guard verification, no Treasury/compensation_fund needed`,
611
+ deduction: -5,
612
+ });
613
+ }
614
+ else if (industryRequiresFund) {
516
615
  fundScore -= 30;
517
616
  findings.push({
518
617
  criterion: "fund_safety",
@@ -539,13 +638,23 @@ function evaluateRisk(input) {
539
638
  strengths.push(`Service.compensation_fund has ${compensationBalance} units — inline refund fund active`);
540
639
  const maxSalePrice = getMaxSalePrice(serviceData);
541
640
  if (maxSalePrice > 0) {
542
- const requiredThreshold = 5 * maxSalePrice;
641
+ let coverageRatio = 5;
642
+ if (project.industry && project.industry !== "general") {
643
+ try {
644
+ const mode = IndustryModeRegistry.Instance().getMode(project.industry);
645
+ if (mode?.risk_constraints?.compensation_fund_coverage_ratio) {
646
+ coverageRatio = mode.risk_constraints.compensation_fund_coverage_ratio;
647
+ }
648
+ }
649
+ catch { }
650
+ }
651
+ const requiredThreshold = coverageRatio * maxSalePrice;
543
652
  if (compensationBalance < requiredThreshold) {
544
653
  fundScore -= 10;
545
654
  findings.push({
546
655
  criterion: "fund_safety",
547
656
  severity: "warning",
548
- message: `Service.compensation_fund balance (${compensationBalance}) is less than 5× the max order amount (${maxSalePrice} → threshold ${requiredThreshold}). Refund coverage may be insufficient — top up via service.compensation_fund_add to avoid arbitration rulings exceeding the fund.`,
657
+ message: `Service.compensation_fund balance (${compensationBalance}) is less than ${coverageRatio}× the max order amount (${maxSalePrice} → threshold ${requiredThreshold}). Refund coverage may be insufficient — top up via service.compensation_fund_add to avoid arbitration rulings exceeding the fund. (industry: ${project.industry ?? "general"}, ratio: ${coverageRatio}×)`,
549
658
  deduction: -10,
550
659
  });
551
660
  }
@@ -553,7 +662,7 @@ function evaluateRisk(input) {
553
662
  findings.push({
554
663
  criterion: "fund_safety",
555
664
  severity: "info",
556
- message: `Service.compensation_fund balance (${compensationBalance}) covers 5× the max order amount (${maxSalePrice}). Fund is sufficient for refund protection.`,
665
+ message: `Service.compensation_fund balance (${compensationBalance}) covers ${coverageRatio}× the max order amount (${maxSalePrice}). Fund is sufficient for refund protection. (industry: ${project.industry ?? "general"}, ratio: ${coverageRatio}×)`,
557
666
  deduction: 0,
558
667
  });
559
668
  }
@@ -632,6 +741,160 @@ function evaluateRisk(input) {
632
741
  });
633
742
  }
634
743
  }
744
+ const machines = byType.get("Machine") ?? [];
745
+ for (const machineObj of machines) {
746
+ const meta = machineObj.metadata;
747
+ const config = meta?.config;
748
+ if (config?.entry_node_forward_hint) {
749
+ const hint = config.entry_node_forward_hint;
750
+ const exampleFwd = hint.example_forward;
751
+ if (exampleFwd?.namedOperator === "") {
752
+ strengths.push("Machine entry forward uses namedOperator='' (OrderHolder) — " +
753
+ "correct for customer-operable nodes. namedOperator='' represents " +
754
+ "the order holder, distinct from merchant's permission index.");
755
+ }
756
+ }
757
+ const guardObjects = config?.guard_objects;
758
+ if (guardObjects && guardObjects.length > 0) {
759
+ strengths.push(`Machine has ${guardObjects.length} guard object reference(s) — ` +
760
+ `forward-level permission validation configured`);
761
+ }
762
+ const cached = parseCacheData(objectCache.get(machineObj.objectAddress));
763
+ const nodeCount = getMachineNodeCount(cached);
764
+ if (nodeCount > 0 && !config) {
765
+ findings.push({
766
+ criterion: "governance_risk",
767
+ severity: "info",
768
+ message: `Machine has ${nodeCount} node(s). Verify each forward has at least one of ` +
769
+ `namedOperator or permissionIndex. Key: namedOperator='' means OrderHolder ` +
770
+ `(customer), NOT 'anyone'. Use non-empty namedOperator for specific roles, ` +
771
+ `or permissionIndex for permission-based access. Both set = OR semantic ` +
772
+ `(either can execute).`,
773
+ deduction: 0,
774
+ });
775
+ }
776
+ }
777
+ const machinesForPermCheck = byType.get("Machine") ?? [];
778
+ const permissionsForCheck = byType.get("Permission") ?? [];
779
+ const permDataMap = new Map();
780
+ for (const permObj of permissionsForCheck) {
781
+ const cached = parseCacheData(objectCache.get(permObj.objectAddress));
782
+ if (cached) {
783
+ permDataMap.set(permObj.objectAddress, {
784
+ address: permObj.objectAddress,
785
+ entity_count: typeof cached.entity_count === "number" ? cached.entity_count : undefined,
786
+ perm_remark: Array.isArray(cached.perm_remark) ? cached.perm_remark : undefined,
787
+ owner: typeof cached.owner === "string" ? cached.owner : (typeof cached.builder === "string" ? cached.builder : undefined),
788
+ admin: Array.isArray(cached.admin) ? cached.admin : undefined,
789
+ });
790
+ }
791
+ }
792
+ for (const machineObj of machinesForPermCheck) {
793
+ const machinePermKey = `${machineObj.objectAddress}#permission`;
794
+ const machinePermBindings = bindingIndex.get(machinePermKey);
795
+ if (!machinePermBindings || machinePermBindings.size === 0)
796
+ continue;
797
+ let permAddress = null;
798
+ for (const addr of machinePermBindings) {
799
+ permAddress = addr;
800
+ break;
801
+ }
802
+ if (!permAddress)
803
+ continue;
804
+ const permData = permDataMap.get(permAddress);
805
+ if (!permData)
806
+ continue;
807
+ const machineCached = parseCacheData(objectCache.get(machineObj.objectAddress));
808
+ if (!machineCached)
809
+ continue;
810
+ const machineNodes = extractMachineNodesFromCache(machineCached);
811
+ if (machineNodes.length === 0)
812
+ continue;
813
+ const collection = collectPermissionIndexes(machineNodes);
814
+ if (collection.requiredIndexes.length === 0)
815
+ continue;
816
+ const report = checkPermissionAuthorization(collection.requiredIndexes, permData);
817
+ if (!report.allAuthorized) {
818
+ governanceScore -= 25;
819
+ findings.push({
820
+ criterion: "governance_risk",
821
+ severity: "critical",
822
+ message: `Machine ${machineObj.objectAddress.slice(0, 8)} has forwards referencing ` +
823
+ `un-authorized permission indexes: [${report.missingIndexes.join(", ")}]. ` +
824
+ `These forwards can NEVER be executed — Progress will be permanently stuck. ` +
825
+ `Grant entities for these indexes via permission.op="add perm by index" ` +
826
+ `before publishing the Machine.`,
827
+ deduction: -25,
828
+ });
829
+ }
830
+ else {
831
+ strengths.push(`Machine ${machineObj.objectAddress.slice(0, 8)}: all ${collection.requiredIndexes.length} ` +
832
+ `permission index(es) are authorized`);
833
+ }
834
+ }
835
+ if (serviceObj && arbitrations.length > 0) {
836
+ const svcPermKey = `${serviceObj.objectAddress}#permission`;
837
+ const svcPermBindings = bindingIndex.get(svcPermKey);
838
+ const svcPermAddress = svcPermBindings && svcPermBindings.size > 0
839
+ ? Array.from(svcPermBindings)[0]
840
+ : null;
841
+ const svcPermData = svcPermAddress ? permDataMap.get(svcPermAddress) : null;
842
+ for (const arbObj of arbitrations) {
843
+ const arbPermKey = `${arbObj.objectAddress}#permission`;
844
+ const arbPermBindings = bindingIndex.get(arbPermKey);
845
+ const arbPermAddress = arbPermBindings && arbPermBindings.size > 0
846
+ ? Array.from(arbPermBindings)[0]
847
+ : null;
848
+ if (!svcPermAddress || !arbPermAddress)
849
+ continue;
850
+ if (svcPermAddress === arbPermAddress) {
851
+ governanceScore -= 30;
852
+ findings.push({
853
+ criterion: "governance_risk",
854
+ severity: "critical",
855
+ message: `Arbitration ${arbObj.objectAddress.slice(0, 8)} and Service share the SAME ` +
856
+ `Permission object (${svcPermAddress.slice(0, 8)}). This breaks dispute ` +
857
+ `fairness — the merchant fully controls arbitration operations. ` +
858
+ `Use a separate Permission object for Arbitration to ensure independent ` +
859
+ `dispute resolution. (per arbitration.move: the permission field controls ` +
860
+ `who can vote, confirm, and execute arbitration rulings)`,
861
+ deduction: -30,
862
+ });
863
+ continue;
864
+ }
865
+ const arbPermData = permDataMap.get(arbPermAddress);
866
+ if (svcPermData && arbPermData) {
867
+ const svcOwner = svcPermData.owner?.toLowerCase();
868
+ const arbOwner = arbPermData.owner?.toLowerCase();
869
+ const svcAdmins = new Set((svcPermData.admin ?? []).map(a => a.toLowerCase()));
870
+ const arbAdmins = new Set((arbPermData.admin ?? []).map(a => a.toLowerCase()));
871
+ const ownerOverlap = svcOwner && arbOwner && svcOwner === arbOwner;
872
+ const adminOverlap = [...svcAdmins].some(a => arbAdmins.has(a));
873
+ if (ownerOverlap || adminOverlap) {
874
+ const overlapType = ownerOverlap && adminOverlap
875
+ ? "owner AND admin overlap"
876
+ : ownerOverlap ? "same owner" : "admin overlap";
877
+ governanceScore -= 20;
878
+ findings.push({
879
+ criterion: "governance_risk",
880
+ severity: "warning",
881
+ message: `Arbitration ${arbObj.objectAddress.slice(0, 8)} and Service have ` +
882
+ `overlapping Permission control (${overlapType}). Even with separate ` +
883
+ `Permission objects, shared control undermines dispute independence. ` +
884
+ `For mainnet deployment, use a completely independent third-party ` +
885
+ `Permission (different owner and admin list) for Arbitration. ` +
886
+ `(testnet may tolerate this, but mainnet users should treat this as ` +
887
+ `a critical trust factor)`,
888
+ deduction: -20,
889
+ });
890
+ }
891
+ else {
892
+ strengths.push(`Arbitration ${arbObj.objectAddress.slice(0, 8)} has independent ` +
893
+ `Permission (separate owner/admin) — trustworthy dispute resolution`);
894
+ }
895
+ }
896
+ }
897
+ }
635
898
  governanceScore = clampScore(governanceScore);
636
899
  let coherenceScore = 100;
637
900
  const objectAddresses = new Set();
@@ -661,7 +924,13 @@ function evaluateRisk(input) {
661
924
  deduction,
662
925
  });
663
926
  }
664
- const cycles = detectCircularRefs(edges);
927
+ const objectTypeMap = new Map();
928
+ for (const o of objects) {
929
+ if (o.objectAddress) {
930
+ objectTypeMap.set(o.objectAddress, shortTypeName(o.objectType));
931
+ }
932
+ }
933
+ const cycles = detectCircularRefs(edges, objectTypeMap);
665
934
  if (cycles.length > 0) {
666
935
  coherenceScore -= 15;
667
936
  findings.push({
@@ -964,7 +1233,12 @@ function evaluateCompleteness(input) {
964
1233
  ? parseCacheData(objectCache.get(svcObjForRequiredItems.objectAddress))
965
1234
  : null;
966
1235
  const compensationBalanceForItems = getBalanceValue(svcDataForRequiredItems, "compensation_fund");
967
- const requiredItems = resolveRequiredItems(project.industry ?? undefined, compensationBalanceForItems);
1236
+ const allocationsForItems = byType.get("Allocation") ?? [];
1237
+ const orderAllocatorsBindingForItems = svcObjForRequiredItems
1238
+ ? bindingIndex.get(`${svcObjForRequiredItems.objectAddress}#order_allocators`)?.size ?? 0
1239
+ : 0;
1240
+ const hasAllocationEscrowForItems = allocationsForItems.length > 0 && orderAllocatorsBindingForItems > 0;
1241
+ const requiredItems = resolveRequiredItems(project.industry ?? undefined, compensationBalanceForItems, hasAllocationEscrowForItems);
968
1242
  const requiredCount = requiredItems.filter(r => r.required).length;
969
1243
  const optionalItems = requiredItems.filter(r => !r.required);
970
1244
  let requiredMet = 0;
@@ -1077,7 +1351,7 @@ function evaluateCompleteness(input) {
1077
1351
  for (const m of machines) {
1078
1352
  const data = parseCacheData(objectCache.get(m.objectAddress));
1079
1353
  if (data) {
1080
- const nodeCount = getNumberField(data, "node_count") || countArrayField(data, "nodes");
1354
+ const nodeCount = getMachineNodeCount(data);
1081
1355
  if (nodeCount > 0) {
1082
1356
  strengths.push(`Machine has ${nodeCount} node(s)`);
1083
1357
  }
@@ -1227,16 +1501,42 @@ function evaluateCompleteness(input) {
1227
1501
  evaluatedAt: Date.now(),
1228
1502
  };
1229
1503
  }
1230
- function evaluateWorthBuyingStub(_input, llmPrompt) {
1504
+ function evaluateWorthBuyingStub(input, llmPrompt) {
1505
+ const riskResult = evaluateRisk(input);
1506
+ const trustResult = evaluateTrust(input);
1507
+ const completenessResult = evaluateCompleteness(input);
1508
+ const summaryLines = [
1509
+ "=== RULE-BASED EVALUATION SUMMARY (F-08 enriched context) ===",
1510
+ "",
1511
+ `Risk: ${riskResult.score}/100 — ${riskResult.summary}`,
1512
+ ...riskResult.findings.slice(0, 3).map(f => ` - [${f.severity}] ${f.message}`),
1513
+ "",
1514
+ `Trust: ${trustResult.score}/100 — ${trustResult.summary}`,
1515
+ ...trustResult.findings.slice(0, 3).map(f => ` - [${f.severity}] ${f.message}`),
1516
+ "",
1517
+ `Completeness: ${completenessResult.score}/100 — ${completenessResult.summary}`,
1518
+ ...completenessResult.findings.slice(0, 3).map(f => ` - [${f.severity}] ${f.message}`),
1519
+ "",
1520
+ "=== END RULE-BASED SUMMARY ===",
1521
+ "",
1522
+ ];
1523
+ const enrichment = summaryLines.join("\n");
1524
+ const enrichedPrompt = llmPrompt
1525
+ ? `${llmPrompt}\n\n${enrichment}`
1526
+ : `${enrichment}\nInstruction: Based on the rule-based summary above, ` +
1527
+ "evaluate whether this project is worth buying. Return a 0-100 score " +
1528
+ "and a brief rationale. Focus on buyer risk vs. value proposition.";
1231
1529
  return {
1232
1530
  evaluationType: "worth_buying",
1233
1531
  score: 0,
1234
- summary: "Requires LLM evaluation — semantic prompt assembled. Call save_evaluation with the LLM result.",
1532
+ summary: "Requires LLM evaluation — semantic prompt assembled with rule-based " +
1533
+ "context (risk/trust/completeness summary). Call save_evaluation with " +
1534
+ "the LLM result.",
1235
1535
  criterionScores: [],
1236
1536
  findings: [],
1237
1537
  strengths: [],
1238
1538
  needsLlm: true,
1239
- llmPrompt,
1539
+ llmPrompt: enrichedPrompt,
1240
1540
  evaluatedAt: Date.now(),
1241
1541
  };
1242
1542
  }
@@ -9,7 +9,12 @@ function shortTypeName(objectType) {
9
9
  }
10
10
  function extractAddressFields(obj) {
11
11
  const refs = [];
12
- const objType = obj.type;
12
+ const rawType = obj.type;
13
+ let objType = rawType;
14
+ if (rawType && rawType.includes("::")) {
15
+ const parts = rawType.split("::");
16
+ objType = parts[parts.length - 1];
17
+ }
13
18
  const isAddress = (v) => typeof v === "string" && v.startsWith("0x") && v.length >= 10;
14
19
  const addRef = (addr, field, refType) => {
15
20
  if (isAddress(addr) && addr !== "0x0" && addr !== obj.object) {
@@ -1,5 +1,5 @@
1
1
  import type { z } from "zod";
2
- import { type ProjectObject, type EvaluationType } from "@wowok/wowok";
2
+ import { type ProjectObject, type ObjectRole, type EvaluationType } from "@wowok/wowok";
3
3
  import type { ProjectOperationInputSchema } from "../schema/project/index.js";
4
4
  type ProjectInput = z.infer<typeof ProjectOperationInputSchema>;
5
5
  export declare function handleListProjects(v: ProjectInput): Promise<{
@@ -100,14 +100,31 @@ export declare function handleUpdateProject(v: ProjectInput): Promise<{
100
100
  export declare function handleGetProjectDetail(v: ProjectInput): Promise<{
101
101
  action: "get_project_detail";
102
102
  project: import("@wowok/wowok").Project;
103
- objects: ProjectObject[];
103
+ objects: {
104
+ isDraft: boolean;
105
+ id: string;
106
+ projectId: string;
107
+ objectAddress: string;
108
+ objectType: string | null;
109
+ objectName: string | null;
110
+ role: ObjectRole;
111
+ tags: string[] | null;
112
+ addedAt: number;
113
+ metadata: Record<string, unknown> | null;
114
+ }[];
115
+ objectCount: number;
116
+ onchainCount: number;
117
+ draftCount: number;
104
118
  objectGroups: {
105
119
  core: ProjectObject[];
106
120
  dependency: ProjectObject[];
107
121
  reference: ProjectObject[];
108
122
  other: ProjectObject[];
123
+ draft: ProjectObject[];
109
124
  stats: {
110
125
  total: number;
126
+ onchain_count: number;
127
+ draft_count: number;
111
128
  core_count: number;
112
129
  dependency_count: number;
113
130
  reference_count: number;
@@ -212,6 +229,8 @@ export declare function handleEvaluateProject(v: ProjectInput): Promise<{
212
229
  needsLlm: boolean;
213
230
  llmPrompt: string | undefined;
214
231
  evaluationId: string;
232
+ refreshWarning: string | undefined;
233
+ graphFallbackWarning: string | undefined;
215
234
  }>;
216
235
  export declare function handleSaveEvaluation(v: ProjectInput): Promise<{
217
236
  action: "save_evaluation";
@@ -248,6 +267,67 @@ export declare function handleCloneProjectToNetwork(v: ProjectInput): Promise<{
248
267
  message: string;
249
268
  next_steps: string;
250
269
  }>;
270
+ export declare function handleMigrateToMainnet(v: ProjectInput): Promise<{
271
+ action: "migrate_to_mainnet";
272
+ migration_status: string;
273
+ source_project: {
274
+ prefix: string;
275
+ network: string;
276
+ preserved: boolean;
277
+ };
278
+ target_project: {
279
+ prefix: string;
280
+ project_id: string;
281
+ network: string;
282
+ cloned_objects_count: number;
283
+ };
284
+ key_principle: string;
285
+ migration_plan: ({
286
+ step: number;
287
+ status: string;
288
+ action: string;
289
+ description: string;
290
+ result: string;
291
+ deployment_plan?: undefined;
292
+ critical_note?: undefined;
293
+ names_to_register?: undefined;
294
+ } | {
295
+ step: number;
296
+ status: string;
297
+ action: string;
298
+ description: string;
299
+ deployment_plan: {
300
+ order: number;
301
+ object_type: string;
302
+ object_name: string;
303
+ operation_type: string;
304
+ localmark_name: string;
305
+ note: string;
306
+ }[];
307
+ critical_note: string;
308
+ result?: undefined;
309
+ names_to_register?: undefined;
310
+ } | {
311
+ step: number;
312
+ status: string;
313
+ action: string;
314
+ description: string;
315
+ names_to_register: string[];
316
+ result?: undefined;
317
+ deployment_plan?: undefined;
318
+ critical_note?: undefined;
319
+ } | {
320
+ step: number;
321
+ status: string;
322
+ action: string;
323
+ description: string;
324
+ result?: undefined;
325
+ deployment_plan?: undefined;
326
+ critical_note?: undefined;
327
+ names_to_register?: undefined;
328
+ })[];
329
+ summary: string;
330
+ }>;
251
331
  export declare function handleGetObjectDiff(v: ProjectInput): Promise<{
252
332
  action: "get_object_diff";
253
333
  address: string;
@@ -284,6 +364,23 @@ export declare function handleGetMachineGraph(v: ProjectInput): Promise<{
284
364
  }[];
285
365
  published: boolean | null;
286
366
  paused: boolean | null;
367
+ mermaid: string;
368
+ tree_outline: string;
369
+ ascii_art: string;
370
+ markmap: string;
371
+ }>;
372
+ export declare function handleGetGuardGraph(v: ProjectInput): Promise<{
373
+ action: "get_guard_graph";
374
+ guardAddress: string;
375
+ guardName: string | null;
376
+ root: any;
377
+ table: any[];
378
+ rely: any;
379
+ immutable: any;
380
+ mermaid: string;
381
+ tree_outline: string;
382
+ ascii_art: string;
383
+ markmap: string;
287
384
  }>;
288
385
  export declare function handlePreEvaluateCheck(v: ProjectInput): Promise<{
289
386
  action: "pre_evaluate_check";