chainlesschain 0.160.1 → 0.161.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 (191) hide show
  1. package/bin/chainlesschain.js +0 -0
  2. package/package.json +6 -6
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/AIOps-FON6GZIt.js +1 -0
  5. package/src/assets/web-panel/assets/{ActionButton-5QD5uzWP.js → ActionButton-Byb_P_P9.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-D1JxsGBN.js → Analytics-CDG1OwOr.js} +2 -2
  7. package/src/assets/web-panel/assets/AppLayout-lM1Y2Wgo.js +1 -0
  8. package/src/assets/web-panel/assets/Audit-p4krng5l.js +1 -0
  9. package/src/assets/web-panel/assets/Backup-G6AQe6k8.js +1 -0
  10. package/src/assets/web-panel/assets/{BaseInput-joQlVauq.js → BaseInput-tUASXi57.js} +1 -1
  11. package/src/assets/web-panel/assets/Chat-B46MHHAs.js +2 -0
  12. package/src/assets/web-panel/assets/{Checkbox-OEOFA9GM.js → Checkbox-CfDbHGdU.js} +1 -1
  13. package/src/assets/web-panel/assets/Codegen-D1mQ03ap.js +1 -0
  14. package/src/assets/web-panel/assets/{Col-BnLUipDp.js → Col-C0wS_dvU.js} +1 -1
  15. package/src/assets/web-panel/assets/Community-CB4KQIpB.js +1 -0
  16. package/src/assets/web-panel/assets/Compact-CuVvz3Zf.js +1 -0
  17. package/src/assets/web-panel/assets/Compliance-D6bnHyjs.js +1 -0
  18. package/src/assets/web-panel/assets/{Cowork-CCgGSKVR.js → Cowork-Dh3yt9pL.js} +2 -2
  19. package/src/assets/web-panel/assets/{Cron-CZ5pjRxn.js → Cron-DiuKXbnA.js} +2 -2
  20. package/src/assets/web-panel/assets/Crosschain-BFgMa5sQ.js +1 -0
  21. package/src/assets/web-panel/assets/{DID-DPZKMApP.js → DID-Dx7CFjrq.js} +2 -2
  22. package/src/assets/web-panel/assets/Dashboard-D3QHFHex.js +3 -0
  23. package/src/assets/web-panel/assets/{Dropdown-CeywCcVQ.js → Dropdown-sMGnnzUo.js} +1 -1
  24. package/src/assets/web-panel/assets/Federation-CGt7CYhN.js +1 -0
  25. package/src/assets/web-panel/assets/{FormItemContext-CFSiPqbu.js → FormItemContext-DuVk39z3.js} +1 -1
  26. package/src/assets/web-panel/assets/{Git-CjVRJDLg.js → Git-glb99UzZ.js} +2 -2
  27. package/src/assets/web-panel/assets/Governance-CQXGee_r.js +1 -0
  28. package/src/assets/web-panel/assets/Inference-Czm-Q3w3.js +1 -0
  29. package/src/assets/web-panel/assets/KnowledgeGraph-DFrr-B78.js +1 -0
  30. package/src/assets/web-panel/assets/{Logs-BD5C-wTx.js → Logs-ChGXdo0Q.js} +2 -2
  31. package/src/assets/web-panel/assets/Marketplace-DW6P2uIY.js +1 -0
  32. package/src/assets/web-panel/assets/{McpTools-x-Tibae-.js → McpTools-ChOwY-wy.js} +2 -2
  33. package/src/assets/web-panel/assets/{Memory-CR8LXq37.js → Memory-vIbbUTel.js} +2 -2
  34. package/src/assets/web-panel/assets/Mtc-60jSuMAz.js +6 -0
  35. package/src/assets/web-panel/assets/Mtc-Cc8OJxe_.css +1 -0
  36. package/src/assets/web-panel/assets/NLProgramming-fRrjhjpW.js +1 -0
  37. package/src/assets/web-panel/assets/{Notes-BYIn2GOe.js → Notes-C0zhC6_B.js} +3 -3
  38. package/src/assets/web-panel/assets/{Organization-CybJTFN9.js → Organization-Bebfm6lF.js} +4 -4
  39. package/src/assets/web-panel/assets/{Overflow-W4YLQ7yY.js → Overflow-D8ZjaRpc.js} +1 -1
  40. package/src/assets/web-panel/assets/{P2P-kVj43R4j.js → P2P-BjgamPxI.js} +2 -2
  41. package/src/assets/web-panel/assets/{Permissions-CfYE4XFJ.js → Permissions-uwoi4HnY.js} +2 -2
  42. package/src/assets/web-panel/assets/Pipeline-C2aHcq6n.js +1 -0
  43. package/src/assets/web-panel/assets/Privacy-lU34k_c5.js +1 -0
  44. package/src/assets/web-panel/assets/{ProjectSettings-cBqrIhNN.js → ProjectSettings-Dy-Iie9L.js} +2 -2
  45. package/src/assets/web-panel/assets/{Projects-BYY38oZd.js → Projects-B4Vt0iiH.js} +2 -2
  46. package/src/assets/web-panel/assets/{Providers-BsS27cWs.js → Providers-Cu9uRsVk.js} +2 -2
  47. package/src/assets/web-panel/assets/QuickAsk-BE29MB0d.js +1 -0
  48. package/src/assets/web-panel/assets/Recommend-DJ9nU8HM.js +1 -0
  49. package/src/assets/web-panel/assets/Reputation-ThffxFwr.js +1 -0
  50. package/src/assets/web-panel/assets/{Row-N-X7EJ3w.js → Row-CqBtO8lC.js} +1 -1
  51. package/src/assets/web-panel/assets/{RssFeed-D9TjnwgF.js → RssFeed-DaxFEUe6.js} +3 -3
  52. package/src/assets/web-panel/assets/Search-4zVFnx_Y.js +1 -0
  53. package/src/assets/web-panel/assets/{Security-DWbFJK10.js → Security-BEfSoaTM.js} +2 -2
  54. package/src/assets/web-panel/assets/{Services-BPUmhVoH.js → Services-DTAaoYJC.js} +2 -2
  55. package/src/assets/web-panel/assets/{Skeleton-Bo5qPHbE.js → Skeleton-CIZErmoY.js} +2 -2
  56. package/src/assets/web-panel/assets/Skills-CacIwBCt.js +1 -0
  57. package/src/assets/web-panel/assets/Sla-Si0g7a0u.js +1 -0
  58. package/src/assets/web-panel/assets/SpeechSettings-H19DqdAG.js +1 -0
  59. package/src/assets/web-panel/assets/SyncSettings-C6cDrwDR.css +1 -0
  60. package/src/assets/web-panel/assets/SyncSettings-bsC4-4rU.js +1 -0
  61. package/src/assets/web-panel/assets/Tasks-Bxlj8OVW.js +1 -0
  62. package/src/assets/web-panel/assets/Templates-B9YsJQcb.js +1 -0
  63. package/src/assets/web-panel/assets/Tenant-D4YncKb7.js +1 -0
  64. package/src/assets/web-panel/assets/Tokens-B2wJjOdI.js +1 -0
  65. package/src/assets/web-panel/assets/{Trigger-Bhjmjsc5.js → Trigger-DU9-3gN9.js} +1 -1
  66. package/src/assets/web-panel/assets/Trust-_yan18qg.js +1 -0
  67. package/src/assets/web-panel/assets/UkeySign-CZ7Xrq96.js +1 -0
  68. package/src/assets/web-panel/assets/VideoEditing-CUgere5i.js +1 -0
  69. package/src/assets/web-panel/assets/{Wallet-dcRAYsdL.js → Wallet-DSnzYVqY.js} +2 -2
  70. package/src/assets/web-panel/assets/{WebAuthn-oqIS5PCi.js → WebAuthn-De4aHZ87.js} +2 -2
  71. package/src/assets/web-panel/assets/WorkflowEditor-C-QNGwia.js +1 -0
  72. package/src/assets/web-panel/assets/chat-DFt6UJUS.js +1 -0
  73. package/src/assets/web-panel/assets/{colors-D2P6CqS5.js → colors-CHuBSydj.js} +1 -1
  74. package/src/assets/web-panel/assets/{compact-item-CG7qutT_.js → compact-item-DtCmGKIm.js} +1 -1
  75. package/src/assets/web-panel/assets/{createContext-y4UPKgbA.js → createContext-Cetup5Fb.js} +1 -1
  76. package/src/assets/web-panel/assets/{hasIn-Butbu9jZ.js → hasIn-Q509tIlQ.js} +1 -1
  77. package/src/assets/web-panel/assets/icons-zXb7lDZs.js +57 -0
  78. package/src/assets/web-panel/assets/{index-BEfvpbz-.js → index-0KFwdHZg.js} +1 -1
  79. package/src/assets/web-panel/assets/{index-Bs9aHxDD.js → index-7kdZ5ox5.js} +1 -1
  80. package/src/assets/web-panel/assets/index-B2f4ltyM.js +65 -0
  81. package/src/assets/web-panel/assets/{index-C_8hWf5_.js → index-B5d7Dkyp.js} +2 -2
  82. package/src/assets/web-panel/assets/index-BDK2Fkgd.js +13 -0
  83. package/src/assets/web-panel/assets/index-BJFH7IlV.js +21 -0
  84. package/src/assets/web-panel/assets/{index-89HJLKZ-.js → index-BTwIwesN.js} +1 -1
  85. package/src/assets/web-panel/assets/index-Bjz1Y3Gs.js +1 -0
  86. package/src/assets/web-panel/assets/index-BlPG_vWg.js +55 -0
  87. package/src/assets/web-panel/assets/{index-BtuwtDUE.js → index-BmHsGJ8F.js} +1 -1
  88. package/src/assets/web-panel/assets/{index-CWh3IxEh.js → index-BvAwpPN9.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-YmGOWX7h.js → index-C2y5MxfU.js} +2 -2
  90. package/src/assets/web-panel/assets/{index-BYZPJS7A.js → index-C61WQXE3.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-BQr8Y0o5.js → index-C7baQwUM.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-B6U6cYUa.js → index-C8agLSzC.js} +8 -8
  93. package/src/assets/web-panel/assets/{index-DdgjeX4z.js → index-CJjwnpac.js} +1 -1
  94. package/src/assets/web-panel/assets/index-CRZ8WjUK.js +1 -0
  95. package/src/assets/web-panel/assets/index-CX7WO0g5.js +12 -0
  96. package/src/assets/web-panel/assets/index-CbQ3AZcJ.js +3 -0
  97. package/src/assets/web-panel/assets/{index-BvJgRWBq.js → index-CeXoNBLu.js} +2 -2
  98. package/src/assets/web-panel/assets/{index-C1ucrJLg.js → index-Ctdt2gEP.js} +1 -1
  99. package/src/assets/web-panel/assets/index-Cxk-8scO.js +1 -0
  100. package/src/assets/web-panel/assets/index-D0oJF6nX.js +7 -0
  101. package/src/assets/web-panel/assets/index-D7Smgwky.js +1 -0
  102. package/src/assets/web-panel/assets/index-DGAGIqDR.js +1 -0
  103. package/src/assets/web-panel/assets/index-DKWvx42k.js +1 -0
  104. package/src/assets/web-panel/assets/{index-Cc77JZKd.js → index-DVQSXYwb.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-vC5cTycG.js → index-DaMTgJkE.js} +2 -2
  106. package/src/assets/web-panel/assets/index-Dd68wDHG.js +12 -0
  107. package/src/assets/web-panel/assets/{index-BCQ0WlB2.js → index-Dem-mhfD.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CYlDKn3O.js → index-Dq6E-pj8.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Dx_ZTZo_.js → index-DuQfQVBe.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DLMJy9pE.js → index-HqJ94PSG.js} +4 -4
  111. package/src/assets/web-panel/assets/{index-B4Jfv4EB.js → index-R5D_-l07.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-DnI4Aq0q.js → index-SR2lFA_W.js} +2 -2
  113. package/src/assets/web-panel/assets/{index-BJN_3RTO.js → index-hSpRlh93.js} +1 -1
  114. package/src/assets/web-panel/assets/index-jfzI94IT.js +1 -0
  115. package/src/assets/web-panel/assets/{index-DrVnyYpX.js → index-nfLO3XrF.js} +1 -1
  116. package/src/assets/web-panel/assets/{initDefaultProps-CZRZ-1bk.js → initDefaultProps-D7iOaKOY.js} +1 -1
  117. package/src/assets/web-panel/assets/{motion-CvU8SiWF.js → motion-CvCFk7sy.js} +1 -1
  118. package/src/assets/web-panel/assets/{move-ipAfWhya.js → move-BVj5YZrV.js} +1 -1
  119. package/src/assets/web-panel/assets/{omit-D6bJEjz9.js → omit-N_JDguMt.js} +1 -1
  120. package/src/assets/web-panel/assets/{pickAttrs-Dpvzf7sL.js → pickAttrs-BWcuLN5j.js} +1 -1
  121. package/src/assets/web-panel/assets/{placementArrow-D_tEolP1.js → placementArrow--1l0FzZx.js} +1 -1
  122. package/src/assets/web-panel/assets/{responsiveObserve-BEFI7neO.js → responsiveObserve-CGX6EYRt.js} +1 -1
  123. package/src/assets/web-panel/assets/{slide-Bte_KOqM.js → slide-B3hJzlWm.js} +1 -1
  124. package/src/assets/web-panel/assets/{statusUtils-K4xaDRuO.js → statusUtils-BJuExZuw.js} +1 -1
  125. package/src/assets/web-panel/assets/{styleChecker-Cl9YgOVY.js → styleChecker-pshnIK0r.js} +1 -1
  126. package/src/assets/web-panel/assets/{useFlexGapSupport-DNstl1wK.js → useFlexGapSupport-3FQZdpBd.js} +1 -1
  127. package/src/assets/web-panel/assets/useFs-BW1piLQM.js +1 -0
  128. package/src/assets/web-panel/assets/{vnode-ChB-8cXr.js → vnode-D98L6HI1.js} +1 -1
  129. package/src/assets/web-panel/assets/{zoom-meTNBulL.js → zoom-DnmMtXgZ.js} +1 -1
  130. package/src/assets/web-panel/index.html +2 -2
  131. package/src/commands/crosschain.js +564 -8
  132. package/src/commands/mtc.js +1334 -0
  133. package/src/lib/config-manager.js +3 -1
  134. package/src/lib/cross-chain-mtc.js +904 -0
  135. package/src/lib/governance-v2-helpers.js +1 -1
  136. package/src/lib/sync-manager.js +119 -25
  137. package/src/assets/web-panel/assets/AIOps-BHiKMxFI.js +0 -1
  138. package/src/assets/web-panel/assets/AppLayout-DykU9tOE.js +0 -1
  139. package/src/assets/web-panel/assets/Audit-TGBqld9c.js +0 -1
  140. package/src/assets/web-panel/assets/Backup-DjpzIwA6.js +0 -1
  141. package/src/assets/web-panel/assets/Chat-9TYfosy-.js +0 -2
  142. package/src/assets/web-panel/assets/Codegen-5H5UgHJu.js +0 -1
  143. package/src/assets/web-panel/assets/Community-BF3R5GAl.js +0 -1
  144. package/src/assets/web-panel/assets/Compact-C1EkTFek.js +0 -1
  145. package/src/assets/web-panel/assets/Compliance-CpP-ODRU.js +0 -1
  146. package/src/assets/web-panel/assets/Crosschain-C0P-5sm3.js +0 -1
  147. package/src/assets/web-panel/assets/Dashboard-G-BDDAov.js +0 -3
  148. package/src/assets/web-panel/assets/Federation-DuFRY867.js +0 -1
  149. package/src/assets/web-panel/assets/Governance-C0lyocJc.js +0 -1
  150. package/src/assets/web-panel/assets/Inference-BVSAexgk.js +0 -1
  151. package/src/assets/web-panel/assets/KnowledgeGraph-SE4jCwIn.js +0 -1
  152. package/src/assets/web-panel/assets/Marketplace-CL93dFBs.js +0 -1
  153. package/src/assets/web-panel/assets/Mtc-C-PfF5B3.css +0 -1
  154. package/src/assets/web-panel/assets/Mtc-CEtRtMcc.js +0 -1
  155. package/src/assets/web-panel/assets/NLProgramming-B09F6gt2.js +0 -1
  156. package/src/assets/web-panel/assets/Pipeline-BVLo32Ak.js +0 -1
  157. package/src/assets/web-panel/assets/Privacy-Efyb3xpJ.js +0 -1
  158. package/src/assets/web-panel/assets/QuickAsk-6FgX9DC6.js +0 -1
  159. package/src/assets/web-panel/assets/Recommend-BvMXwWFN.js +0 -1
  160. package/src/assets/web-panel/assets/Reputation-DmwTtBfl.js +0 -1
  161. package/src/assets/web-panel/assets/Search-Hapv-QkV.js +0 -1
  162. package/src/assets/web-panel/assets/Skills-JJ8uInMW.js +0 -1
  163. package/src/assets/web-panel/assets/Sla-CEDF9zdV.js +0 -1
  164. package/src/assets/web-panel/assets/SpeechSettings-oIoX_vCx.js +0 -1
  165. package/src/assets/web-panel/assets/Tasks-Cx5wgv5Z.js +0 -1
  166. package/src/assets/web-panel/assets/Templates-BomcBlkN.js +0 -1
  167. package/src/assets/web-panel/assets/Tenant-BxSQZUNh.js +0 -1
  168. package/src/assets/web-panel/assets/Tokens-BlPPoB3C.js +0 -1
  169. package/src/assets/web-panel/assets/Trust-Dsjv7rkb.js +0 -1
  170. package/src/assets/web-panel/assets/UkeySign-Cux8_Ib_.js +0 -1
  171. package/src/assets/web-panel/assets/VideoEditing-BsVR1PN8.js +0 -1
  172. package/src/assets/web-panel/assets/WorkflowEditor-C_fYMBvB.js +0 -1
  173. package/src/assets/web-panel/assets/chat-BQ-Nk2XY.js +0 -1
  174. package/src/assets/web-panel/assets/icons-DvZE-RKs.js +0 -57
  175. package/src/assets/web-panel/assets/index-38mVlGHc.js +0 -1
  176. package/src/assets/web-panel/assets/index-B5FRjJMb.js +0 -1
  177. package/src/assets/web-panel/assets/index-B7FV5EnN.js +0 -1
  178. package/src/assets/web-panel/assets/index-BQfow_sh.js +0 -1
  179. package/src/assets/web-panel/assets/index-C1mK1Ga3.js +0 -1
  180. package/src/assets/web-panel/assets/index-C2K61jP8.js +0 -55
  181. package/src/assets/web-panel/assets/index-CAeKBs9n.js +0 -1
  182. package/src/assets/web-panel/assets/index-Ceaxjpqh.js +0 -13
  183. package/src/assets/web-panel/assets/index-Ci6jXp3l.js +0 -7
  184. package/src/assets/web-panel/assets/index-CyqU4Tck.js +0 -65
  185. package/src/assets/web-panel/assets/index-DtNHlrxp.js +0 -1
  186. package/src/assets/web-panel/assets/index-gWmZm8_Q.js +0 -21
  187. package/src/assets/web-panel/assets/index-hSilB_Q-.js +0 -12
  188. package/src/assets/web-panel/assets/index-qXvwlbkq.js +0 -3
  189. package/src/assets/web-panel/assets/index-rIbVsjde.js +0 -12
  190. package/src/assets/web-panel/assets/useFs-BD-YRwbU.js +0 -1
  191. package/src/assets/web-panel/assets/ws-D_5-FRIb.js +0 -1
@@ -2,8 +2,30 @@
2
2
  * `cc crosschain` — CLI surface for Phase 89 Cross-Chain Interoperability.
3
3
  */
4
4
 
5
+ import fs from "node:fs";
6
+
5
7
  import { Command } from "commander";
6
8
 
9
+ import { bootstrap } from "../runtime/bootstrap.js";
10
+ import { getHomeDir } from "../lib/paths.js";
11
+ import {
12
+ getCrossChainMtcDir,
13
+ getBridgeMtcStatus,
14
+ loadCrossChainMtcConfig,
15
+ addTrustAnchor,
16
+ listTrustAnchors,
17
+ removeTrustAnchor,
18
+ verifyBridgeEnvelope,
19
+ assembleBridgeBatch,
20
+ stageBridgeOp,
21
+ closeBatch,
22
+ buildMultiHopBridgeEnvelope,
23
+ verifyMultiHopBridgeEnvelope,
24
+ shouldCloseBatchGasAware,
25
+ getBridgeMtcSlaMetrics,
26
+ } from "../lib/cross-chain-mtc.js";
27
+ import mtcLib from "@chainlesschain/core-mtc";
28
+
7
29
  import {
8
30
  SUPPORTED_CHAINS,
9
31
  BRIDGE_STATUS,
@@ -48,16 +70,64 @@ import {
48
70
  } from "../lib/cross-chain.js";
49
71
 
50
72
  function _dbFromCtx(cmd) {
51
- const root = cmd?.parent?.parent ?? cmd?.parent;
52
- return root?._db;
73
+ // cmd is typically the action subcommand (e.g. `bridge`).
74
+ // _db may be wired onto cmd itself, the parent (`cc crosschain` group),
75
+ // or the root program — return the first one we find.
76
+ return cmd?._db ?? cmd?.parent?._db ?? cmd?.parent?.parent?._db ?? null;
77
+ }
78
+
79
+ /**
80
+ * Bootstrap a real DB when the crosschain command is invoked headless
81
+ * (e.g. via spawnSync in integration tests). Falls back to whatever the
82
+ * REPL/runtime already wired into _dbFromCtx if present.
83
+ */
84
+ async function _ensureDb(thisCmd) {
85
+ const existing = _dbFromCtx(thisCmd);
86
+ if (existing) {
87
+ ensureCrossChainTables(existing);
88
+ return existing;
89
+ }
90
+ const ctx = await bootstrap({ verbose: false });
91
+ if (!ctx.db) return null;
92
+ const db = ctx.db.getDatabase();
93
+ ensureCrossChainTables(db);
94
+ thisCmd._db = db;
95
+ return db;
96
+ }
97
+
98
+ /**
99
+ * --mtc opt-in hook: when caller passes --mtc and the action succeeded,
100
+ * stage one bridge op for the next batch close. Silent best-effort —
101
+ * an MTC failure must not break the existing crosschain flow.
102
+ */
103
+ function _maybeStageMtc(opts, opBuilder) {
104
+ if (!opts || !opts.mtc) return null;
105
+ try {
106
+ const home = opts.mtcConfigDir || getHomeDir();
107
+ const dir = getCrossChainMtcDir(home);
108
+ return stageBridgeOp(dir, opBuilder(), { requireEnabled: false });
109
+ } catch (err) {
110
+ return { staged: false, path: null, reason: `STAGE_ERROR: ${err.message}` };
111
+ }
53
112
  }
54
113
 
55
114
  export function registerCrossChainCommand(program) {
56
115
  const cc = new Command("crosschain")
57
116
  .description("Cross-chain interoperability (Phase 89)")
58
- .hook("preAction", (thisCmd) => {
59
- const db = _dbFromCtx(thisCmd);
60
- if (db) ensureCrossChainTables(db);
117
+ .hook("preAction", async (thisCmd, actionCommand) => {
118
+ // Skip db bootstrap for MTC-only subcommands that don't touch the
119
+ // crosschain DB — keeps `cc crosschain mtc-status` etc. usable on
120
+ // a fresh box where the SQLite store hasn't been initialized.
121
+ const name = actionCommand?.name?.() || "";
122
+ if (
123
+ name.startsWith("mtc-") ||
124
+ name === "chains" ||
125
+ name === "bridge-statuses" ||
126
+ name === "swap-statuses"
127
+ ) {
128
+ return;
129
+ }
130
+ await _ensureDb(thisCmd);
61
131
  });
62
132
 
63
133
  /* ── Catalogs ────────────────────────────────────── */
@@ -99,6 +169,11 @@ export function registerCrossChainCommand(program) {
99
169
  .option("-a, --asset <asset>", "Asset name", "native")
100
170
  .option("-s, --sender <address>", "Sender address")
101
171
  .option("-r, --recipient <address>", "Recipient address")
172
+ .option(
173
+ "--mtc",
174
+ "On success, stage an MTC bridge envelope (requires cc crosschain mtc-batch to close)",
175
+ )
176
+ .option("--mtc-config-dir <dir>", "Override MTC config root")
102
177
  .option("--json", "JSON output")
103
178
  .action((fromChain, toChain, amount, opts) => {
104
179
  const db = _dbFromCtx(cc);
@@ -110,10 +185,27 @@ export function registerCrossChainCommand(program) {
110
185
  senderAddress: opts.sender,
111
186
  recipientAddress: opts.recipient,
112
187
  });
113
- if (opts.json) return console.log(JSON.stringify(result, null, 2));
188
+ const mtc =
189
+ result.bridgeId &&
190
+ _maybeStageMtc(opts, () => ({
191
+ bridge_op: "lock",
192
+ src_chain: fromChain,
193
+ dst_chain: toChain,
194
+ src_tx_hash: result.bridgeId,
195
+ amount: String(amount),
196
+ asset: opts.asset || "native",
197
+ src_did: opts.sender || null,
198
+ dst_did: opts.recipient || null,
199
+ issued_at: new Date().toISOString(),
200
+ }));
201
+ if (opts.json)
202
+ return console.log(JSON.stringify({ ...result, mtc }, null, 2));
114
203
  if (result.bridgeId)
115
204
  console.log(`Bridge created: ${result.bridgeId} (fee: ${result.fee})`);
116
205
  else console.log(`Failed: ${result.reason}`);
206
+ if (mtc?.staged) console.log(`MTC envelope staged: ${mtc.path}`);
207
+ else if (mtc && !mtc.staged)
208
+ console.log(`MTC stage skipped: ${mtc.reason}`);
117
209
  });
118
210
 
119
211
  cc.command("bridge-status <bridge-id> <status>")
@@ -184,6 +276,8 @@ export function registerCrossChainCommand(program) {
184
276
  .option("-b, --to-asset <asset>", "Target asset", "native")
185
277
  .option("-c, --counterparty <address>", "Counterparty address")
186
278
  .option("-t, --timeout <ms>", "Timeout in ms", parseInt)
279
+ .option("--mtc", "On success, stage an MTC swap-init envelope")
280
+ .option("--mtc-config-dir <dir>", "Override MTC config root")
187
281
  .option("--json", "JSON output")
188
282
  .action((fromChain, toChain, amount, opts) => {
189
283
  const db = _dbFromCtx(cc);
@@ -196,12 +290,27 @@ export function registerCrossChainCommand(program) {
196
290
  counterpartyAddress: opts.counterparty,
197
291
  timeoutMs: opts.timeout,
198
292
  });
199
- if (opts.json) return console.log(JSON.stringify(result, null, 2));
293
+ const mtc =
294
+ result.swapId &&
295
+ _maybeStageMtc(opts, () => ({
296
+ bridge_op: "swap-init",
297
+ src_chain: fromChain,
298
+ dst_chain: toChain,
299
+ swap_id: result.swapId,
300
+ amount: String(amount),
301
+ asset: opts.fromAsset || "native",
302
+ issued_at: new Date().toISOString(),
303
+ }));
304
+ if (opts.json)
305
+ return console.log(JSON.stringify({ ...result, mtc }, null, 2));
200
306
  if (result.swapId) {
201
307
  console.log(`Swap initiated: ${result.swapId}`);
202
308
  console.log(`Hash lock: ${result.hashLock}`);
203
309
  console.log(`Expires: ${new Date(result.expiresAt).toISOString()}`);
204
310
  } else console.log(`Failed: ${result.reason}`);
311
+ if (mtc?.staged) console.log(`MTC envelope staged: ${mtc.path}`);
312
+ else if (mtc && !mtc.staged)
313
+ console.log(`MTC stage skipped: ${mtc.reason}`);
205
314
  });
206
315
 
207
316
  cc.command("swap-claim <swap-id>")
@@ -292,6 +401,8 @@ export function registerCrossChainCommand(program) {
292
401
  .description("Send cross-chain message")
293
402
  .option("-p, --payload <text>", "Message payload")
294
403
  .option("-c, --contract <address>", "Target contract address")
404
+ .option("--mtc", "On success, stage an MTC msg-send envelope")
405
+ .option("--mtc-config-dir <dir>", "Override MTC config root")
295
406
  .option("--json", "JSON output")
296
407
  .action((fromChain, toChain, opts) => {
297
408
  const db = _dbFromCtx(cc);
@@ -301,9 +412,25 @@ export function registerCrossChainCommand(program) {
301
412
  payload: opts.payload,
302
413
  targetContract: opts.contract,
303
414
  });
304
- if (opts.json) return console.log(JSON.stringify(result, null, 2));
415
+ const mtc =
416
+ result.messageId &&
417
+ _maybeStageMtc(opts, () => ({
418
+ bridge_op: "msg-send",
419
+ src_chain: fromChain,
420
+ dst_chain: toChain,
421
+ src_tx_hash: result.messageId,
422
+ msg_payload: opts.payload
423
+ ? Buffer.from(opts.payload, "utf-8").toString("base64url")
424
+ : null,
425
+ issued_at: new Date().toISOString(),
426
+ }));
427
+ if (opts.json)
428
+ return console.log(JSON.stringify({ ...result, mtc }, null, 2));
305
429
  if (result.messageId) console.log(`Message sent: ${result.messageId}`);
306
430
  else console.log(`Failed: ${result.reason}`);
431
+ if (mtc?.staged) console.log(`MTC envelope staged: ${mtc.path}`);
432
+ else if (mtc && !mtc.staged)
433
+ console.log(`MTC stage skipped: ${mtc.reason}`);
307
434
  });
308
435
 
309
436
  cc.command("msg-status <message-id> <status>")
@@ -396,6 +523,15 @@ export function registerCrossChainCommand(program) {
396
523
  console.log(`Messages: ${stats.messages.total}`);
397
524
  });
398
525
 
526
+ /* ══════════════════════════════════════════════════
527
+ * Cross-chain bridge MTC integration (跨链桥设计 v0.1)
528
+ * Design: docs/design/MTC_跨链桥_v1.md
529
+ * Status: opt-in. Default config.enabled = false. Read commands work
530
+ * regardless; envelope generation requires enabled=true.
531
+ * ══════════════════════════════════════════════════ */
532
+
533
+ registerCrossChainMtcSubcommands(cc);
534
+
399
535
  /* ══════════════════════════════════════════════════
400
536
  * Phase 89 — Cross-Chain V2 subcommands
401
537
  * ══════════════════════════════════════════════════ */
@@ -600,6 +736,426 @@ export function registerCrossChainCommand(program) {
600
736
  registerCrossChainV2Command(cc);
601
737
  }
602
738
 
739
+ function _resolveBridgeMtcDir(opts) {
740
+ const home = (opts && opts.configDir) || getHomeDir();
741
+ return getCrossChainMtcDir(home);
742
+ }
743
+
744
+ function registerCrossChainMtcSubcommands(cc) {
745
+ cc.command("mtc-status")
746
+ .description("Show cross-chain bridge MTC config + trust anchors + batches")
747
+ .option(
748
+ "--config-dir <dir>",
749
+ "Override config root (default: ~/.chainlesschain)",
750
+ )
751
+ .option("--json", "JSON output")
752
+ .action((opts) => {
753
+ const dir = _resolveBridgeMtcDir(opts);
754
+ const s = getBridgeMtcStatus(dir);
755
+ if (opts.json) return console.log(JSON.stringify(s, null, 2));
756
+ console.log(
757
+ `Enabled: ${s.enabled ? "yes" : "no (opt-in via config.enabled=true)"}`,
758
+ );
759
+ console.log(`Mode: ${s.mode}`);
760
+ console.log(`Algorithm: ${s.alg}`);
761
+ console.log(`Batch interval: ${s.batch_interval_seconds}s`);
762
+ console.log(`Issuer: ${s.issuer}`);
763
+ console.log(
764
+ `Trust anchors: ${s.trust_anchors.total} across ${s.trust_anchors.chain_count} chain(s)`,
765
+ );
766
+ for (const [chain, count] of Object.entries(s.trust_anchors.by_chain)) {
767
+ console.log(` ${chain}: ${count}`);
768
+ }
769
+ console.log(
770
+ `Batches: ${s.batches.total}${s.batches.latest ? ` (latest: ${s.batches.latest})` : ""}`,
771
+ );
772
+ });
773
+
774
+ cc.command("mtc-serve")
775
+ .description(
776
+ "Run a daemon that periodically closes staged bridge ops into batches",
777
+ )
778
+ .option("--config-dir <dir>", "Override config root")
779
+ .option(
780
+ "--interval <seconds>",
781
+ "Batch close interval (default: config.batch_interval_seconds)",
782
+ parseInt,
783
+ )
784
+ .option("--once", "Close once and exit (no daemon loop)")
785
+ .option("--alg <alg>", "Override config alg")
786
+ .option("--issuer <issuer>", "Override config issuer")
787
+ .option("--json", "Emit per-tick JSON results to stdout")
788
+ .action(async (opts) => {
789
+ const dir = _resolveBridgeMtcDir(opts);
790
+ const cfg = loadCrossChainMtcConfig(dir);
791
+ const intervalSec = opts.interval || cfg.batch_interval_seconds;
792
+ const tick = () => {
793
+ try {
794
+ const result = closeBatch(dir, {
795
+ alg: opts.alg,
796
+ issuer: opts.issuer,
797
+ });
798
+ const stamp = new Date().toISOString();
799
+ if (opts.json) {
800
+ console.log(JSON.stringify({ tick_at: stamp, ...result }, null, 2));
801
+ } else if (!result.skipped) {
802
+ console.log(
803
+ `[${stamp}] closed ${result.batches.length} batch(es): ${result.batches
804
+ .map((b) => `${b.pair}#${b.seq}(${b.count})`)
805
+ .join(", ")}`,
806
+ );
807
+ } else {
808
+ console.log(`[${stamp}] (idle: ${result.skipped.reason})`);
809
+ }
810
+ } catch (err) {
811
+ console.error(
812
+ `[${new Date().toISOString()}] tick error: ${err.message}`,
813
+ );
814
+ }
815
+ };
816
+
817
+ tick();
818
+ if (opts.once) return;
819
+
820
+ console.log(
821
+ `mtc-serve: closing every ${intervalSec}s (config-dir: ${dir}). Ctrl-C to stop.`,
822
+ );
823
+ const handle = setInterval(tick, intervalSec * 1000);
824
+ // Graceful shutdown
825
+ const stop = () => {
826
+ clearInterval(handle);
827
+ console.log("mtc-serve: stopped.");
828
+ process.exit(0);
829
+ };
830
+ process.on("SIGINT", stop);
831
+ process.on("SIGTERM", stop);
832
+ // Keep the event loop alive forever (until signal)
833
+ await new Promise(() => {});
834
+ });
835
+
836
+ cc.command("mtc-batch")
837
+ .description(
838
+ "Close currently-staged bridge ops into batches (one per chain-pair)",
839
+ )
840
+ .option("--config-dir <dir>", "Override config root")
841
+ .option("--alg <alg>", "Override config alg (ed25519 | slh-dsa-128f)")
842
+ .option("--issuer <issuer>", "Override config issuer")
843
+ .option("--json", "JSON output")
844
+ .action((opts) => {
845
+ const dir = _resolveBridgeMtcDir(opts);
846
+ const result = closeBatch(dir, {
847
+ alg: opts.alg,
848
+ issuer: opts.issuer,
849
+ });
850
+ if (opts.json) return console.log(JSON.stringify(result, null, 2));
851
+ if (result.skipped) {
852
+ console.log(`(no batch closed: ${result.skipped.reason})`);
853
+ return;
854
+ }
855
+ for (const b of result.batches) {
856
+ console.log(
857
+ `✓ Closed ${b.pair}#${b.seq} ${b.count} op(s) treeHead=${b.treeHeadId}`,
858
+ );
859
+ console.log(` → ${b.dir}`);
860
+ }
861
+ });
862
+
863
+ cc.command("mtc-envelope")
864
+ .description("Build a bridge MTC envelope from a JSON file of bridge ops")
865
+ .requiredOption("-i, --input <path>", "JSON file: array of bridge ops")
866
+ .requiredOption("--src-chain <chain>", "Source chain")
867
+ .requiredOption("--dst-chain <chain>", "Destination chain")
868
+ .requiredOption("--batch-seq <n>", "Batch sequence number", parseInt)
869
+ .option("--issuer <issuer>", "MTCA issuer (default from config)")
870
+ .option("--alg <alg>", "ed25519 | slh-dsa-128f")
871
+ .option("--config-dir <dir>", "Override config root")
872
+ .option("--json", "JSON output (full landmark + envelopes)")
873
+ .action((opts) => {
874
+ const dir = _resolveBridgeMtcDir(opts);
875
+ const cfg = loadCrossChainMtcConfig(dir);
876
+ const ops = JSON.parse(fs.readFileSync(opts.input, "utf-8"));
877
+ if (!Array.isArray(ops)) {
878
+ console.error("Input file must contain a JSON array of bridge ops.");
879
+ process.exit(2);
880
+ }
881
+ const alg = opts.alg || cfg.alg;
882
+ const signer = alg === "slh-dsa-128f" ? mtcLib.slhDsa : mtcLib.ed25519;
883
+ const keys = signer.generateKeyPair();
884
+ const result = assembleBridgeBatch(ops, keys, {
885
+ src_chain: opts.srcChain,
886
+ dst_chain: opts.dstChain,
887
+ batch_seq: opts.batchSeq,
888
+ issuer: opts.issuer || cfg.issuer,
889
+ signer,
890
+ });
891
+ if (opts.json) return console.log(JSON.stringify(result, null, 2));
892
+ console.log(`Namespace: ${result.namespace}`);
893
+ console.log(`Tree head id: ${result.treeHeadId}`);
894
+ console.log(`Tree size: ${result.envelopes.length}`);
895
+ console.log(`Algorithm: ${alg}`);
896
+ console.log(`(JSON envelope + landmark omitted; pass --json to emit)`);
897
+ });
898
+
899
+ cc.command("mtc-verify <envelope-path> <landmark-path>")
900
+ .description("Verify a bridge MTC envelope against a landmark file")
901
+ .option("--json", "JSON output")
902
+ .action((envPath, lmPath, opts) => {
903
+ const envelope = JSON.parse(fs.readFileSync(envPath, "utf-8"));
904
+ const landmark = JSON.parse(fs.readFileSync(lmPath, "utf-8"));
905
+ const cache = new mtcLib.LandmarkCache({
906
+ signatureVerifier: mtcLib.alwaysAcceptSignatureVerifier,
907
+ });
908
+ try {
909
+ cache.ingest(landmark);
910
+ } catch (err) {
911
+ const out = {
912
+ ok: false,
913
+ code: err.code || "LANDMARK_REJECT",
914
+ error: err.message,
915
+ };
916
+ if (opts.json) return console.log(JSON.stringify(out, null, 2));
917
+ console.log(`✗ Landmark ingest failed: ${err.message}`);
918
+ process.exit(2);
919
+ }
920
+ const result = verifyBridgeEnvelope(envelope, cache);
921
+ if (opts.json) {
922
+ console.log(JSON.stringify(result, null, 2));
923
+ if (!result.ok) process.exit(2);
924
+ return;
925
+ }
926
+ if (result.ok) {
927
+ console.log(`✓ Envelope verified.`);
928
+ console.log(` Bridge op: ${result.bridge_op}`);
929
+ console.log(` Tree size: ${result.treeHead?.tree_size}`);
930
+ console.log(` Issuer: ${result.treeHead?.issuer}`);
931
+ } else {
932
+ console.log(`✗ Verification failed: ${result.code}`);
933
+ process.exit(2);
934
+ }
935
+ });
936
+
937
+ // v0.2 — Multi-hop bridge envelope (envelope-of-envelope)
938
+ cc.command("mtc-multihop-build")
939
+ .description(
940
+ "Build a multi-hop bridge envelope from a JSON file of leg envelopes",
941
+ )
942
+ .requiredOption(
943
+ "-i, --input <path>",
944
+ "JSON file: array of single-hop bridge envelopes (≥ 2)",
945
+ )
946
+ .option("--route-id <id>", "Optional route id (default: auto-generated)")
947
+ .option("--total-amount <amount>", "Optional cumulative amount string")
948
+ .option("--asset <asset>", "Optional asset symbol")
949
+ .option("--out <path>", "Write multi-hop envelope to file")
950
+ .option("--json", "JSON output (default unless --out given)")
951
+ .action((opts) => {
952
+ try {
953
+ const legs = JSON.parse(fs.readFileSync(opts.input, "utf-8"));
954
+ const wrapper = buildMultiHopBridgeEnvelope(legs, {
955
+ route_id: opts.routeId,
956
+ total_amount: opts.totalAmount,
957
+ asset: opts.asset,
958
+ });
959
+ const json = JSON.stringify(wrapper, null, 2);
960
+ if (opts.out) {
961
+ fs.writeFileSync(opts.out, json, "utf-8");
962
+ if (opts.json) console.log(json);
963
+ else
964
+ console.log(
965
+ `✓ Multi-hop envelope written: ${opts.out} (${wrapper.leg_count} legs, route: ${wrapper.chain_path.join(" → ")})`,
966
+ );
967
+ } else {
968
+ console.log(json);
969
+ }
970
+ } catch (err) {
971
+ console.error(`mtc-multihop-build failed: ${err.message}`);
972
+ process.exit(1);
973
+ }
974
+ });
975
+
976
+ cc.command("mtc-multihop-verify <wrapper-path>")
977
+ .description(
978
+ "Verify a multi-hop bridge envelope against per-leg landmark files",
979
+ )
980
+ .requiredOption(
981
+ "--landmarks <path>",
982
+ "JSON file: array of {landmark} entries, one per leg in order",
983
+ )
984
+ .option("--json", "JSON output")
985
+ .action((wrapperPath, opts) => {
986
+ try {
987
+ const wrapper = JSON.parse(fs.readFileSync(wrapperPath, "utf-8"));
988
+ const lmEntries = JSON.parse(fs.readFileSync(opts.landmarks, "utf-8"));
989
+ const result = verifyMultiHopBridgeEnvelope(wrapper, lmEntries);
990
+ if (opts.json) {
991
+ console.log(JSON.stringify(result, null, 2));
992
+ if (!result.ok) process.exit(2);
993
+ return;
994
+ }
995
+ if (result.ok) {
996
+ console.log(
997
+ `✓ Multi-hop verified (${wrapper.leg_count} legs, route: ${wrapper.chain_path.join(" → ")})`,
998
+ );
999
+ } else {
1000
+ console.log(
1001
+ `✗ Multi-hop verification failed: ${result.code || "LEG_FAIL"}`,
1002
+ );
1003
+ process.exit(2);
1004
+ }
1005
+ } catch (err) {
1006
+ console.error(`mtc-multihop-verify failed: ${err.message}`);
1007
+ process.exit(1);
1008
+ }
1009
+ });
1010
+
1011
+ // v0.2 — Gas-aware batch trigger advisor
1012
+ cc.command("mtc-gas-check <target-chain>")
1013
+ .description(
1014
+ "Heuristic: should the bridge MTCA close its batch now given current gas + staged ops?",
1015
+ )
1016
+ .requiredOption("--staged-count <n>", "Currently staged ops", parseInt)
1017
+ .option(
1018
+ "--current-gas-usd <usd>",
1019
+ "Observed gas cost in USD (default: chain baseline)",
1020
+ parseFloat,
1021
+ )
1022
+ .option(
1023
+ "--hard-close-floor <n>",
1024
+ "Always close at or above this staged count (default: 50)",
1025
+ parseInt,
1026
+ )
1027
+ .option(
1028
+ "--defer-multiplier <m>",
1029
+ "Defer when current_gas > baseline * this (default: 1.5)",
1030
+ parseFloat,
1031
+ )
1032
+ .option("--json", "JSON output")
1033
+ .action((targetChain, opts) => {
1034
+ try {
1035
+ const r = shouldCloseBatchGasAware({
1036
+ target_chain: targetChain,
1037
+ staged_count: opts.stagedCount,
1038
+ current_gas_usd: opts.currentGasUsd,
1039
+ hard_close_floor: opts.hardCloseFloor,
1040
+ defer_multiplier: opts.deferMultiplier,
1041
+ });
1042
+ if (opts.json) return console.log(JSON.stringify(r, null, 2));
1043
+ console.log(
1044
+ `${r.close ? "✓ CLOSE" : "✗ DEFER"} reason=${r.reason} baseline=$${r.baseline_usd} current=$${r.current_usd} staged=${r.staged_count}`,
1045
+ );
1046
+ } catch (err) {
1047
+ console.error(`mtc-gas-check failed: ${err.message}`);
1048
+ process.exit(1);
1049
+ }
1050
+ });
1051
+
1052
+ // v0.2 — SLA Manager integration: emit SLA-shaped metrics
1053
+ cc.command("mtc-sla")
1054
+ .description(
1055
+ "Emit cc sla-compatible operational metrics for the bridge MTCA",
1056
+ )
1057
+ .option("--config-dir <dir>", "Override config root")
1058
+ .option("--json", "JSON output")
1059
+ .action((opts) => {
1060
+ const dir = _resolveBridgeMtcDir(opts);
1061
+ const m = getBridgeMtcSlaMetrics(dir);
1062
+ if (opts.json) return console.log(JSON.stringify(m, null, 2));
1063
+ console.log(`SLA Status: ${m.sla_status}`);
1064
+ console.log(`Enabled: ${m.enabled}`);
1065
+ console.log(`Mode: ${m.mode}`);
1066
+ console.log(`Staged pending: ${m.staged_pending_count}`);
1067
+ console.log(`Batches total: ${m.batches_total}`);
1068
+ console.log(`Batches last hour: ${m.batches_last_hour}`);
1069
+ console.log(
1070
+ `Last batch: ${m.seconds_since_last_batch !== null ? `${m.seconds_since_last_batch}s ago` : "—"}`,
1071
+ );
1072
+ });
1073
+
1074
+ const taParent = cc
1075
+ .command("mtc-trust-anchor")
1076
+ .description("Manage Independent-mode trust anchors (per source chain)");
1077
+
1078
+ taParent
1079
+ .command("add <chain> <pubkey-id>")
1080
+ .description("Add a trust anchor for a source chain")
1081
+ .requiredOption("--alg <alg>", "ed25519 | slh-dsa-128f")
1082
+ .requiredOption("--issuer <issuer>", "MTCA issuer string for this anchor")
1083
+ .option("--jwk <path>", "Optional JWK file for the public key")
1084
+ .option("--config-dir <dir>", "Override config root")
1085
+ .option("--json", "JSON output")
1086
+ .action((chain, pubkeyId, opts) => {
1087
+ const dir = _resolveBridgeMtcDir(opts);
1088
+ let pubkeyJwk = null;
1089
+ if (opts.jwk) {
1090
+ pubkeyJwk = JSON.parse(fs.readFileSync(opts.jwk, "utf-8"));
1091
+ }
1092
+ const r = addTrustAnchor(dir, chain, {
1093
+ pubkey_id: pubkeyId,
1094
+ alg: opts.alg,
1095
+ issuer: opts.issuer,
1096
+ pubkey_jwk: pubkeyJwk,
1097
+ });
1098
+ if (opts.json) return console.log(JSON.stringify(r, null, 2));
1099
+ if (r.added) {
1100
+ console.log(`✓ Added trust anchor for ${chain}: ${pubkeyId}`);
1101
+ } else {
1102
+ console.log(`(already exists for ${chain}: ${pubkeyId})`);
1103
+ }
1104
+ console.log(`Total anchors for ${chain}: ${r.total_for_chain}`);
1105
+ });
1106
+
1107
+ taParent
1108
+ .command("list [chain]")
1109
+ .description("List trust anchors (optionally filter by chain)")
1110
+ .option("--config-dir <dir>", "Override config root")
1111
+ .option("--json", "JSON output")
1112
+ .action((chain, opts) => {
1113
+ const dir = _resolveBridgeMtcDir(opts);
1114
+ const result = listTrustAnchors(dir, chain);
1115
+ if (opts.json) return console.log(JSON.stringify(result, null, 2));
1116
+ if (chain) {
1117
+ if (!result || result.length === 0) {
1118
+ console.log(`(no trust anchors for ${chain})`);
1119
+ return;
1120
+ }
1121
+ for (const a of result) {
1122
+ console.log(
1123
+ ` ${a.pubkey_id} alg=${a.alg} issuer=${a.issuer} added=${a.added_at}`,
1124
+ );
1125
+ }
1126
+ } else {
1127
+ const chains = Object.keys(result);
1128
+ if (chains.length === 0) {
1129
+ console.log("(no trust anchors)");
1130
+ return;
1131
+ }
1132
+ for (const c of chains) {
1133
+ console.log(`${c}:`);
1134
+ for (const a of result[c]) {
1135
+ console.log(` ${a.pubkey_id} alg=${a.alg} issuer=${a.issuer}`);
1136
+ }
1137
+ }
1138
+ }
1139
+ });
1140
+
1141
+ taParent
1142
+ .command("remove <chain> <pubkey-id>")
1143
+ .description("Remove a trust anchor by pubkey-id")
1144
+ .option("--config-dir <dir>", "Override config root")
1145
+ .option("--json", "JSON output")
1146
+ .action((chain, pubkeyId, opts) => {
1147
+ const dir = _resolveBridgeMtcDir(opts);
1148
+ const r = removeTrustAnchor(dir, chain, pubkeyId);
1149
+ if (opts.json) return console.log(JSON.stringify(r, null, 2));
1150
+ if (r.removed) {
1151
+ console.log(`✓ Removed trust anchor for ${chain}: ${pubkeyId}`);
1152
+ } else {
1153
+ console.log(`(no matching trust anchor for ${chain}: ${pubkeyId})`);
1154
+ }
1155
+ console.log(`Remaining anchors for ${chain}: ${r.total_for_chain}`);
1156
+ });
1157
+ }
1158
+
603
1159
  import {
604
1160
  XCHAIN_CHANNEL_MATURITY_V2,
605
1161
  XCHAIN_TRANSFER_LIFECYCLE_V2,