@dev.sail.money/sailor 1.3.0-208 → 1.3.0-209

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 (99) hide show
  1. package/package.json +1 -1
  2. package/packages/cli/dist/index.cjs +160 -97
  3. package/packages/cli/dist/server.cjs +1256 -48
  4. package/packages/sdk/dist/intelligence.d.ts +1 -1
  5. package/packages/sdk/dist/intelligence.js +1 -1
  6. package/packages/sdk/dist/signing.d.ts +29 -0
  7. package/packages/sdk/dist/signing.d.ts.map +1 -1
  8. package/packages/ui/dist/assets/{add-CfTRVkh-.js → add-CLs0-B0p.js} +1 -1
  9. package/packages/ui/dist/assets/{all-wallets-VZChJwJf.js → all-wallets-CDOk28sj.js} +1 -1
  10. package/packages/ui/dist/assets/{app-store-CuFK1xBJ.js → app-store-DVzpi1qN.js} +1 -1
  11. package/packages/ui/dist/assets/{apple-DETqVk_I.js → apple-C9U9iH1l.js} +1 -1
  12. package/packages/ui/dist/assets/{arrow-bottom-CnNYsZfo.js → arrow-bottom-DjQ4jGMe.js} +1 -1
  13. package/packages/ui/dist/assets/{arrow-bottom-circle-DZwJF3UO.js → arrow-bottom-circle-jxial9Si.js} +1 -1
  14. package/packages/ui/dist/assets/{arrow-left-CBnisTAa.js → arrow-left-BjAyI8D1.js} +1 -1
  15. package/packages/ui/dist/assets/{arrow-right-DA3Y1Yzf.js → arrow-right-BlFO4Tcx.js} +1 -1
  16. package/packages/ui/dist/assets/{arrow-top-e8-FE_fo.js → arrow-top-DJ3oh3DH.js} +1 -1
  17. package/packages/ui/dist/assets/{bank-DdwromQn.js → bank-B98it1qN.js} +1 -1
  18. package/packages/ui/dist/assets/{basic-DLYER2un.js → basic-DsgeyPNu.js} +1 -1
  19. package/packages/ui/dist/assets/{browser-BJNrv4Zj.js → browser-j4vCeHwE.js} +1 -1
  20. package/packages/ui/dist/assets/{card-DB6j4DSk.js → card-CzxbMvEd.js} +1 -1
  21. package/packages/ui/dist/assets/{ccip-Dy_s323Y.js → ccip-U9yiu_EK.js} +1 -1
  22. package/packages/ui/dist/assets/{checkmark-Db9oicko.js → checkmark-D5sWBbk3.js} +1 -1
  23. package/packages/ui/dist/assets/{checkmark-bold-D9MgGHxv.js → checkmark-bold-BW6w3KCC.js} +1 -1
  24. package/packages/ui/dist/assets/{chevron-bottom-IGUDJRKN.js → chevron-bottom-BbHhmTQq.js} +1 -1
  25. package/packages/ui/dist/assets/{chevron-left-CWpfP-rw.js → chevron-left-D8BDH4Wo.js} +1 -1
  26. package/packages/ui/dist/assets/{chevron-right-BejY0vtE.js → chevron-right-BQuQk5zc.js} +1 -1
  27. package/packages/ui/dist/assets/{chevron-top-BaUN0LGF.js → chevron-top-1oeSXkx4.js} +1 -1
  28. package/packages/ui/dist/assets/{chrome-store-fox1tIqs.js → chrome-store-B1OMtzC-.js} +1 -1
  29. package/packages/ui/dist/assets/{clock-DlqB4Ehi.js → clock-e0HueehS.js} +1 -1
  30. package/packages/ui/dist/assets/{close-03e52feP.js → close-Cy1ytr26.js} +1 -1
  31. package/packages/ui/dist/assets/{coinPlaceholder-BO3nv4hx.js → coinPlaceholder-DqJu3ZPV.js} +1 -1
  32. package/packages/ui/dist/assets/{compass-CIqPRE0k.js → compass-XDz_N2Hg.js} +1 -1
  33. package/packages/ui/dist/assets/{copy-D5cJBwZq.js → copy-DmDo3Nob.js} +1 -1
  34. package/packages/ui/dist/assets/{core-COelOg3-.js → core-DbkMGSYW.js} +3 -3
  35. package/packages/ui/dist/assets/cursor-DRFqL8nZ.js +3 -0
  36. package/packages/ui/dist/assets/{cursor-transparent-Cvbiq9Br.js → cursor-transparent-DF2aA10D.js} +1 -1
  37. package/packages/ui/dist/assets/{desktop-Dp2wtF3n.js → desktop-CVydOWLn.js} +1 -1
  38. package/packages/ui/dist/assets/{disconnect-Dx_IGM73.js → disconnect-BuN2Whnz.js} +1 -1
  39. package/packages/ui/dist/assets/{discord-Cxryn14a.js → discord-DMNPvTB2.js} +1 -1
  40. package/packages/ui/dist/assets/{etherscan-D8aNXWCx.js → etherscan-CacW-93f.js} +1 -1
  41. package/packages/ui/dist/assets/{events-DR6OOHz2.js → events-CZkVDFih.js} +1 -1
  42. package/packages/ui/dist/assets/{exclamation-triangle-BBCaPLj1.js → exclamation-triangle-B26hIvqO.js} +1 -1
  43. package/packages/ui/dist/assets/{extension-bACRNBl5.js → extension-B7rI0gv7.js} +1 -1
  44. package/packages/ui/dist/assets/{external-link-BZRqHo3q.js → external-link-CX8skCbH.js} +1 -1
  45. package/packages/ui/dist/assets/{facebook-TAdUitg4.js → facebook-BDqbE6kl.js} +1 -1
  46. package/packages/ui/dist/assets/{fallback-DGiwrboN.js → fallback-DWQYKf3l.js} +1 -1
  47. package/packages/ui/dist/assets/{farcaster-YzdobBfR.js → farcaster-zQ3oQzZ8.js} +1 -1
  48. package/packages/ui/dist/assets/{filters-CT-xLEoI.js → filters-DCglZYsM.js} +1 -1
  49. package/packages/ui/dist/assets/{github-DxPBbmEL.js → github-BH-BYjss.js} +1 -1
  50. package/packages/ui/dist/assets/{google-B0TMgFhK.js → google-DYFWxZbC.js} +1 -1
  51. package/packages/ui/dist/assets/{help-circle-Be6sRPTw.js → help-circle-BXH_DtZ_.js} +1 -1
  52. package/packages/ui/dist/assets/{id-Dem_akbE.js → id-Dr2yTeX1.js} +1 -1
  53. package/packages/ui/dist/assets/{image-CszBzFVG.js → image-DeJey1Eg.js} +1 -1
  54. package/packages/ui/dist/assets/{index-DXqj6oYp.js → index-BP-UuQ8g.js} +1 -1
  55. package/packages/ui/dist/assets/{index-DAawBKd2.js → index-BksbyFjf.js} +1 -1
  56. package/packages/ui/dist/assets/{index-homh6mWC.js → index-C55-Ne92.js} +1 -1
  57. package/packages/ui/dist/assets/{index-Cb5eBfrN.js → index-D6_Zei-R.js} +71 -71
  58. package/packages/ui/dist/assets/{index-C2n9XvGG.js → index-DVjAiPHI.js} +3 -3
  59. package/packages/ui/dist/assets/{index-B0FDHAiK.js → index-uSdXE5b_.js} +1 -1
  60. package/packages/ui/dist/assets/{index.es-DJgl78dj.js → index.es-dZlNPpfR.js} +4 -4
  61. package/packages/ui/dist/assets/{info-BimGN4NK.js → info-B91pD5Rw.js} +1 -1
  62. package/packages/ui/dist/assets/{info-circle-lnKEJu2R.js → info-circle-CySl3_on.js} +1 -1
  63. package/packages/ui/dist/assets/{lightbulb-DS1vEMce.js → lightbulb-wwG8LQLo.js} +1 -1
  64. package/packages/ui/dist/assets/{mail-DoS3Wibk.js → mail-D617YZ8y.js} +1 -1
  65. package/packages/ui/dist/assets/{metamask-sdk-CMIU3BwW.js → metamask-sdk-RbLbxUgF.js} +1 -1
  66. package/packages/ui/dist/assets/{mobile-B09Cs95_.js → mobile-CD9KlA0m.js} +1 -1
  67. package/packages/ui/dist/assets/{more-CLBZT8WI.js → more-BQ_rpPXo.js} +1 -1
  68. package/packages/ui/dist/assets/{network-placeholder-C45Cp8rY.js → network-placeholder-BA7nl9e6.js} +1 -1
  69. package/packages/ui/dist/assets/{nftPlaceholder-CAVclL3u.js → nftPlaceholder-D1EaaeDn.js} +1 -1
  70. package/packages/ui/dist/assets/{off-CwE8HoZ0.js → off-DnGG35_w.js} +1 -1
  71. package/packages/ui/dist/assets/{parseSignature-kmMNHYjl.js → parseSignature-E29x8poM.js} +1 -1
  72. package/packages/ui/dist/assets/{play-store-DiFF_6n4.js → play-store-C5u2FvYB.js} +1 -1
  73. package/packages/ui/dist/assets/{plus-aygpl_pZ.js → plus-CM4xJkvI.js} +1 -1
  74. package/packages/ui/dist/assets/{qr-code-DpIS4fFK.js → qr-code-kM3FUIdR.js} +1 -1
  75. package/packages/ui/dist/assets/{recycle-horizontal-Qk2N74JE.js → recycle-horizontal-DWrRWIBM.js} +1 -1
  76. package/packages/ui/dist/assets/{refresh-sWRq9Vnt.js → refresh-CztbjK2d.js} +1 -1
  77. package/packages/ui/dist/assets/{reown-logo-YQxBa9i9.js → reown-logo-DUHEIodF.js} +1 -1
  78. package/packages/ui/dist/assets/{search-Bt6BSPcC.js → search-BJtb4mn1.js} +1 -1
  79. package/packages/ui/dist/assets/{secp256k1-BUh3OoFd.js → secp256k1-BjrTZpQx.js} +1 -1
  80. package/packages/ui/dist/assets/{send-ym-Fn17O.js → send-B3_kavG1.js} +1 -1
  81. package/packages/ui/dist/assets/{swapHorizontal-fBE2gnqc.js → swapHorizontal-BrF9POiv.js} +1 -1
  82. package/packages/ui/dist/assets/{swapHorizontalBold-CekQ22FJ.js → swapHorizontalBold-Dgf8OjXj.js} +1 -1
  83. package/packages/ui/dist/assets/{swapHorizontalMedium-B9BI9ovU.js → swapHorizontalMedium-C6wX0JZj.js} +1 -1
  84. package/packages/ui/dist/assets/{swapHorizontalRoundedBold-DOC75mBH.js → swapHorizontalRoundedBold-DTAVw6oF.js} +1 -1
  85. package/packages/ui/dist/assets/{swapVertical-CSQAPH0z.js → swapVertical-KGlTFNoi.js} +1 -1
  86. package/packages/ui/dist/assets/{telegram-BPjzFxKU.js → telegram-DnLrK-4y.js} +1 -1
  87. package/packages/ui/dist/assets/{three-dots-DP6hdXH8.js → three-dots-C6_oMJfw.js} +1 -1
  88. package/packages/ui/dist/assets/{twitch-CgHMd-f3.js → twitch-DvPqPD4f.js} +1 -1
  89. package/packages/ui/dist/assets/{twitterIcon-BrR8ynXm.js → twitterIcon-BZdk82Am.js} +1 -1
  90. package/packages/ui/dist/assets/{verify-D35D7Wtv.js → verify-CbESD5G0.js} +1 -1
  91. package/packages/ui/dist/assets/{verify-filled-DCP5CT59.js → verify-filled-BRjTrLxw.js} +1 -1
  92. package/packages/ui/dist/assets/{w3m-modal-B-ZptWk0.js → w3m-modal-D9b2TGHc.js} +1 -1
  93. package/packages/ui/dist/assets/{wallet-Cnb4dkr3.js → wallet-B87E5UId.js} +1 -1
  94. package/packages/ui/dist/assets/{wallet-placeholder-CCzk0PqU.js → wallet-placeholder-DmssSbYf.js} +1 -1
  95. package/packages/ui/dist/assets/{walletconnect-f6tQZYRi.js → walletconnect-CZkLKWMZ.js} +1 -1
  96. package/packages/ui/dist/assets/{warning-circle-zxMagvfx.js → warning-circle-BPTpHB1P.js} +1 -1
  97. package/packages/ui/dist/assets/{x-D0nEGO1G.js → x-D_dEtEDU.js} +1 -1
  98. package/packages/ui/dist/index.html +1 -1
  99. package/packages/ui/dist/assets/cursor-CRb7R3u1.js +0 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev.sail.money/sailor",
3
- "version": "1.3.0-208",
3
+ "version": "1.3.0-209",
4
4
  "description": "Operator toolkit for Sail Protocol",
5
5
  "bin": {
6
6
  "sailor": "packages/cli/dist/index.cjs"
@@ -41240,9 +41240,124 @@ async function keysShow() {
41240
41240
 
41241
41241
  // src/commands/mandate-contracts.ts
41242
41242
  var import_node_child_process = require("node:child_process");
41243
+ var import_node_fs14 = require("node:fs");
41244
+ var import_node_path12 = require("node:path");
41245
+ init_esm2();
41246
+
41247
+ // src/lib/permission-explainer.ts
41243
41248
  var import_node_fs13 = require("node:fs");
41244
41249
  var import_node_path11 = require("node:path");
41245
- init_esm2();
41250
+ function explainPermission(name, sourcePath) {
41251
+ const resolved = sourcePath ?? (0, import_node_path11.join)(process.cwd(), "mandates", `${name}.sol`);
41252
+ let src;
41253
+ try {
41254
+ src = (0, import_node_fs13.readFileSync)(resolved, "utf8");
41255
+ } catch {
41256
+ return null;
41257
+ }
41258
+ return parseStructured(src) ?? parseNatSpec(src) ?? parseRequires(src);
41259
+ }
41260
+ var ENFORCED_HEADER = /ENFORCE[SD]\s+ON-CHAIN/i;
41261
+ var NOT_ENFORCED_HEADER = /NOT\s+(ENFORCED|BOUNDED)/i;
41262
+ function parseStructured(src) {
41263
+ if (!ENFORCED_HEADER.test(src)) return null;
41264
+ const lines = src.split("\n");
41265
+ const result = {
41266
+ source: "structured",
41267
+ enforced: [],
41268
+ notEnforced: []
41269
+ };
41270
+ const headerLines = [];
41271
+ for (const line of lines) {
41272
+ const t = line.trim();
41273
+ if (t.startsWith("import ") || t.startsWith("contract ") || t.startsWith("abstract contract ")) break;
41274
+ if (t.startsWith("//")) headerLines.push(t.slice(2));
41275
+ }
41276
+ let section = null;
41277
+ for (const raw of headerLines) {
41278
+ const trimmed = raw.trim();
41279
+ if (/^─+$/.test(trimmed)) continue;
41280
+ if (NOT_ENFORCED_HEADER.test(trimmed)) {
41281
+ section = "notEnforced";
41282
+ continue;
41283
+ }
41284
+ if (ENFORCED_HEADER.test(trimmed)) {
41285
+ section = "enforced";
41286
+ continue;
41287
+ }
41288
+ if (trimmed.includes("VERIFY BEFORE USE")) {
41289
+ section = null;
41290
+ continue;
41291
+ }
41292
+ if (section === null) {
41293
+ const kv = trimmed.match(/^(Protocol|Version|Chain|Target)\s*:\s*(.+)$/i);
41294
+ if (kv) {
41295
+ const key = kv[1].toLowerCase();
41296
+ result[key] = kv[2].trim();
41297
+ }
41298
+ }
41299
+ if (section && trimmed.startsWith("\u2022")) {
41300
+ const bullet = trimmed.slice(1).trim();
41301
+ if (bullet) result[section].push(bullet);
41302
+ }
41303
+ }
41304
+ if (result.enforced.length === 0 && !result.protocol) return null;
41305
+ return result;
41306
+ }
41307
+ function parseNatSpec(src) {
41308
+ const enforced = [];
41309
+ const notEnforced = [];
41310
+ let current = null;
41311
+ let buf = [];
41312
+ const flush = () => {
41313
+ if (current && buf.length) {
41314
+ const text = buf.join(" ").replace(/\s+/g, " ").trim();
41315
+ if (text) (current === "enforced" ? enforced : notEnforced).push(text);
41316
+ }
41317
+ buf = [];
41318
+ };
41319
+ for (const line of src.split("\n")) {
41320
+ const t = line.trim();
41321
+ const tagged = t.match(/^\/\/\/\s*@(\w+)\s+(.+)$/);
41322
+ if (tagged) {
41323
+ const [, tag, text] = tagged;
41324
+ if (tag === "notice") {
41325
+ flush();
41326
+ current = "enforced";
41327
+ buf.push(text.trim());
41328
+ } else if (tag === "dev") {
41329
+ flush();
41330
+ current = "notEnforced";
41331
+ buf.push(text.trim());
41332
+ } else {
41333
+ flush();
41334
+ current = null;
41335
+ }
41336
+ continue;
41337
+ }
41338
+ const cont = t.match(/^\/\/\/\s?(.*)$/);
41339
+ if (cont && current) {
41340
+ const text = cont[1].trim();
41341
+ if (text) buf.push(text);
41342
+ continue;
41343
+ }
41344
+ if (!t.startsWith("///")) {
41345
+ flush();
41346
+ current = null;
41347
+ }
41348
+ }
41349
+ flush();
41350
+ if (enforced.length === 0 && notEnforced.length === 0) return null;
41351
+ return { source: "natspec", enforced, notEnforced };
41352
+ }
41353
+ function parseRequires(src) {
41354
+ const enforced = [];
41355
+ const re = /require\s*\([^,)]+,\s*["']([^"']+)["']\)/g;
41356
+ let m;
41357
+ while ((m = re.exec(src)) !== null) enforced.push(m[1]);
41358
+ if (enforced.length === 0) return null;
41359
+ return { source: "require-only", enforced, notEnforced: [] };
41360
+ }
41246
41361
 
41247
41362
  // src/lib/mandates.ts
41248
41363
  var MandateStore = class {
@@ -41708,6 +41823,8 @@ Pushing signing request for "${template.label}" permission\u2026`));
41708
41823
  ` The mandate signer (${permissionSigner}) must sign in the browser \u2014 not the agent wallet.`
41709
41824
  )
41710
41825
  );
41826
+ const permRecord = new MandateStore().find(templateAddress);
41827
+ const permExplanation = (permRecord ? explainPermission(permRecord.name, permRecord.sourcePath) : explainPermission(template.label)) ?? void 0;
41711
41828
  const response = await channel.requestSignature({
41712
41829
  type: "typed-data",
41713
41830
  kind: "register-permission",
@@ -41720,6 +41837,7 @@ Pushing signing request for "${template.label}" permission\u2026`));
41720
41837
  { label: "Permission", value: template.label },
41721
41838
  { label: "Mandate signer", value: permissionSigner }
41722
41839
  ],
41840
+ explanation: permExplanation,
41723
41841
  typedData
41724
41842
  });
41725
41843
  if (response.status === "rejected") {
@@ -41934,12 +42052,12 @@ async function runDeploy(project, channel, options) {
41934
42052
  )
41935
42053
  );
41936
42054
  }
41937
- const { abi: abi2, bytecode, contractName, artifactPath } = resolveArtifact(options);
42055
+ const { abi: abi2, bytecode, contractName, artifactPath, sourcePath } = resolveArtifact(options);
41938
42056
  let argsJson;
41939
42057
  if (options.argsFile) {
41940
- const argsFilePath = (0, import_node_path11.resolve)(options.argsFile);
42058
+ const argsFilePath = (0, import_node_path12.resolve)(options.argsFile);
41941
42059
  try {
41942
- argsJson = (0, import_node_fs13.readFileSync)(argsFilePath, "utf8").trim();
42060
+ argsJson = (0, import_node_fs14.readFileSync)(argsFilePath, "utf8").trim();
41943
42061
  } catch {
41944
42062
  throw new Error(`Cannot read --args-file: ${argsFilePath}`);
41945
42063
  }
@@ -41952,6 +42070,7 @@ async function runDeploy(project, channel, options) {
41952
42070
  const publicClient = publicClientFor(project);
41953
42071
  announceSigningUrl(json);
41954
42072
  say(() => console.log(`Pushing deploy request for "${contractName}"\u2026`));
42073
+ const explanation = explainPermission(contractName, sourcePath) ?? void 0;
41955
42074
  const response = await channel.requestSignature({
41956
42075
  type: "transaction",
41957
42076
  kind: "deploy-mandate",
@@ -41966,7 +42085,8 @@ async function runDeploy(project, channel, options) {
41966
42085
  label: options.argsFile ? "Constructor args (from file)" : "Constructor args",
41967
42086
  value: argsJson ? argsJson : "(none)"
41968
42087
  }
41969
- ]
42088
+ ],
42089
+ explanation
41970
42090
  });
41971
42091
  if (response.status === "rejected") {
41972
42092
  throw new Error(`User rejected permission deployment: ${response.reason ?? "no reason given"}`);
@@ -41986,6 +42106,7 @@ async function runDeploy(project, channel, options) {
41986
42106
  address: deployed,
41987
42107
  txHash: response.txHash,
41988
42108
  chainId,
42109
+ sourcePath,
41989
42110
  artifactPath,
41990
42111
  constructorArgs: parseArgsRaw(options.args),
41991
42112
  deployedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -42620,6 +42741,15 @@ async function attachBatchToSma(project, channel, publicClient, sma, permissions
42620
42741
  Attaching ${permissions.length} permissions in one signature \u2014 the mandate signer (${permissionSigner}) signs in the browser\u2026`
42621
42742
  )
42622
42743
  );
42744
+ const permStore = new MandateStore();
42745
+ const permExplanations = permissions.map((addr) => {
42746
+ const rec = permStore.find(addr);
42747
+ return {
42748
+ label: rec?.name ?? addr,
42749
+ address: addr,
42750
+ explanation: (rec ? explainPermission(rec.name, rec.sourcePath) : null) ?? void 0
42751
+ };
42752
+ });
42623
42753
  const response = await channel.requestSignature({
42624
42754
  type: "typed-data",
42625
42755
  kind: "register-permission",
@@ -42631,6 +42761,7 @@ Attaching ${permissions.length} permissions in one signature \u2014 the mandate
42631
42761
  { label: "Permissions", value: String(permissions.length) },
42632
42762
  { label: "Mandate signer", value: permissionSigner }
42633
42763
  ],
42764
+ permissions: permExplanations,
42634
42765
  typedData
42635
42766
  });
42636
42767
  if (response.status === "rejected") {
@@ -42778,11 +42909,11 @@ function resolveArtifact(options) {
42778
42909
  let contractName = options.contract ?? options.name ?? "";
42779
42910
  if (!artifactPath) {
42780
42911
  if (!options.contract) throw new Error("Provide --artifact <path> or --contract <name>");
42781
- artifactPath = (0, import_node_path11.join)(options.out, `${options.contract}.sol`, `${options.contract}.json`);
42912
+ artifactPath = (0, import_node_path12.join)(options.out, `${options.contract}.sol`, `${options.contract}.json`);
42782
42913
  }
42783
- const resolved = (0, import_node_path11.resolve)(artifactPath);
42784
- const projectRoot = (0, import_node_path11.resolve)(process.cwd());
42785
- if (!resolved.startsWith(projectRoot + import_node_path11.sep) && resolved !== projectRoot) {
42914
+ const resolved = (0, import_node_path12.resolve)(artifactPath);
42915
+ const projectRoot = (0, import_node_path12.resolve)(process.cwd());
42916
+ if (!resolved.startsWith(projectRoot + import_node_path12.sep) && resolved !== projectRoot) {
42786
42917
  throw new Error(
42787
42918
  `Artifact path must be inside the project directory.
42788
42919
  Resolved: ${resolved}`
@@ -42790,14 +42921,14 @@ Resolved: ${resolved}`
42790
42921
  }
42791
42922
  artifactPath = resolved;
42792
42923
  if (options.build) runForgeBuild();
42793
- if (!(0, import_node_fs13.existsSync)(artifactPath)) {
42924
+ if (!(0, import_node_fs14.existsSync)(artifactPath)) {
42794
42925
  ensureForgeHint();
42795
42926
  throw new Error(
42796
42927
  `Artifact not found: ${artifactPath}
42797
42928
  Compile your mandate first (e.g. \`forge build\`), or pass --build.`
42798
42929
  );
42799
42930
  }
42800
- const artifact = JSON.parse((0, import_node_fs13.readFileSync)(artifactPath, "utf8"));
42931
+ const artifact = JSON.parse((0, import_node_fs14.readFileSync)(artifactPath, "utf8"));
42801
42932
  const abi2 = artifact.abi;
42802
42933
  const bytecodeRaw = artifact.bytecode?.object ?? artifact.bytecode;
42803
42934
  if (!bytecodeRaw || typeof bytecodeRaw !== "string") {
@@ -42808,7 +42939,16 @@ Compile your mandate first (e.g. \`forge build\`), or pass --build.`
42808
42939
  const m = artifactPath.match(/([^/\\]+)\.json$/);
42809
42940
  contractName = m ? m[1] : "Mandate";
42810
42941
  }
42811
- return { abi: abi2, bytecode, contractName, artifactPath };
42942
+ let sourcePath;
42943
+ const compilationTarget = artifact.metadata?.settings?.compilationTarget;
42944
+ if (compilationTarget && typeof compilationTarget === "object") {
42945
+ sourcePath = Object.keys(compilationTarget)[0];
42946
+ }
42947
+ sourcePath = sourcePath ?? artifact.ast?.absolutePath;
42948
+ if (sourcePath && !sourcePath.startsWith("/")) {
42949
+ sourcePath = (0, import_node_path12.resolve)(projectRoot, sourcePath);
42950
+ }
42951
+ return { abi: abi2, bytecode, contractName, artifactPath, sourcePath };
42812
42952
  }
42813
42953
  function parseArgsRaw(argsJson) {
42814
42954
  if (!argsJson) return void 0;
@@ -42878,88 +43018,6 @@ function runForgeBuild() {
42878
43018
 
42879
43019
  // src/commands/mandate.ts
42880
43020
  init_esm2();
42881
-
42882
- // src/lib/permission-explainer.ts
42883
- var import_node_fs14 = require("node:fs");
42884
- var import_node_path12 = require("node:path");
42885
- function explainPermission(name, sourcePath) {
42886
- const resolved = sourcePath ?? (0, import_node_path12.join)(process.cwd(), "mandates", `${name}.sol`);
42887
- let src;
42888
- try {
42889
- src = (0, import_node_fs14.readFileSync)(resolved, "utf8");
42890
- } catch {
42891
- return null;
42892
- }
42893
- return parseStructured(src) ?? parseNatSpec(src) ?? parseRequires(src);
42894
- }
42895
- function parseStructured(src) {
42896
- if (!src.includes("ENFORCED ON-CHAIN")) return null;
42897
- const lines = src.split("\n");
42898
- const result = {
42899
- source: "structured",
42900
- enforced: [],
42901
- notEnforced: []
42902
- };
42903
- const headerLines = [];
42904
- for (const line of lines) {
42905
- const t = line.trim();
42906
- if (t.startsWith("import ") || t.startsWith("contract ") || t.startsWith("abstract contract ")) break;
42907
- if (t.startsWith("//")) headerLines.push(t.slice(2));
42908
- }
42909
- let section = null;
42910
- for (const raw of headerLines) {
42911
- const trimmed = raw.trim();
42912
- if (/^─+$/.test(trimmed)) continue;
42913
- if (trimmed.includes("ENFORCED ON-CHAIN")) {
42914
- section = "enforced";
42915
- continue;
42916
- }
42917
- if (trimmed.includes("NOT ENFORCED")) {
42918
- section = "notEnforced";
42919
- continue;
42920
- }
42921
- if (trimmed.includes("VERIFY BEFORE USE")) {
42922
- section = null;
42923
- continue;
42924
- }
42925
- if (section === null) {
42926
- const kv = trimmed.match(/^(Protocol|Version|Chain|Target)\s*:\s*(.+)$/i);
42927
- if (kv) {
42928
- const key = kv[1].toLowerCase();
42929
- result[key] = kv[2].trim();
42930
- }
42931
- }
42932
- if (section && trimmed.startsWith("\u2022")) {
42933
- const bullet = trimmed.slice(1).trim();
42934
- if (bullet) result[section].push(bullet);
42935
- }
42936
- }
42937
- if (result.enforced.length === 0 && !result.protocol) return null;
42938
- return result;
42939
- }
42940
- function parseNatSpec(src) {
42941
- const enforced = [];
42942
- const notEnforced = [];
42943
- for (const line of src.split("\n")) {
42944
- const t = line.trim();
42945
- const notice = t.match(/^\/\/\/\s*@notice\s+(.+)$/);
42946
- if (notice) enforced.push(notice[1].trim());
42947
- const dev = t.match(/^\/\/\/\s*@dev\s+(.+)$/);
42948
- if (dev) notEnforced.push(dev[1].trim());
42949
- }
42950
- if (enforced.length === 0 && notEnforced.length === 0) return null;
42951
- return { source: "natspec", enforced, notEnforced };
42952
- }
42953
- function parseRequires(src) {
42954
- const enforced = [];
42955
- const re = /require\s*\([^,)]+,\s*["']([^"']+)["']\)/g;
42956
- let m;
42957
- while ((m = re.exec(src)) !== null) enforced.push(m[1]);
42958
- if (enforced.length === 0) return null;
42959
- return { source: "require-only", enforced, notEnforced: [] };
42960
- }
42961
-
42962
- // src/commands/mandate.ts
42963
43021
  function resolveActiveChain(account2) {
42964
43022
  try {
42965
43023
  const project = new ProjectContext();
@@ -43035,7 +43093,9 @@ ${permissions.length} permission(s) tracked for SMA ${account2.safe}:
43035
43093
  const draft = {
43036
43094
  account: account2.safe,
43037
43095
  chainId,
43038
- permissions: permissions.filter((p) => !p.revokedOnChain).map((p) => {
43096
+ // Only permissions not already registered on this SMA belong in the signing
43097
+ // draft — re-registering an already-registered permission reverts on-chain.
43098
+ permissions: permissions.filter((p) => !p.revokedOnChain && !p.registeredOnSma).map((p) => {
43039
43099
  const mandate2 = store.find(p.address);
43040
43100
  const explanation = explainPermission(p.label, mandate2?.sourcePath) ?? void 0;
43041
43101
  return { address: p.address, label: p.label, explanation };
@@ -45170,9 +45230,12 @@ function tailscaleServeUp(port) {
45170
45230
  ["serve", "--bg", "--https=443", `http://127.0.0.1:${port}`],
45171
45231
  { encoding: "utf-8" }
45172
45232
  );
45233
+ const out = `${r.stdout ?? ""}${r.stderr ?? ""}`;
45173
45234
  if (r.status !== 0) {
45174
- const detail = (r.stderr || r.stdout || "").trim() || `exit ${r.status ?? "?"}`;
45175
- throw new Error(detail);
45235
+ throw new Error(out.trim() || `exit ${r.status ?? "?"}`);
45236
+ }
45237
+ if (/serve is not enabled/i.test(out)) {
45238
+ throw new Error(out.trim());
45176
45239
  }
45177
45240
  }
45178
45241
  function tailscaleServeDown() {