@dev.sail.money/sailor 1.3.0-206 → 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.
- package/package.json +1 -1
- package/packages/cli/dist/index.cjs +555 -414
- package/packages/cli/dist/server.cjs +1263 -56
- package/packages/sdk/dist/intelligence.d.ts +1 -1
- package/packages/sdk/dist/intelligence.js +1 -1
- package/packages/sdk/dist/keyring.d.ts +0 -6
- package/packages/sdk/dist/keyring.d.ts.map +1 -1
- package/packages/sdk/dist/keyring.js +1 -8
- package/packages/sdk/dist/keyring.js.map +1 -1
- package/packages/sdk/dist/signing.d.ts +29 -0
- package/packages/sdk/dist/signing.d.ts.map +1 -1
- package/packages/ui/dist/assets/{add-Dj4_n773.js → add-CLs0-B0p.js} +1 -1
- package/packages/ui/dist/assets/{all-wallets-BaFysN1G.js → all-wallets-CDOk28sj.js} +1 -1
- package/packages/ui/dist/assets/{app-store-DOc31zzY.js → app-store-DVzpi1qN.js} +1 -1
- package/packages/ui/dist/assets/{apple-BvrvOkPH.js → apple-C9U9iH1l.js} +1 -1
- package/packages/ui/dist/assets/{arrow-bottom-E1AfjXOT.js → arrow-bottom-DjQ4jGMe.js} +1 -1
- package/packages/ui/dist/assets/{arrow-bottom-circle-sou7Vo1V.js → arrow-bottom-circle-jxial9Si.js} +1 -1
- package/packages/ui/dist/assets/{arrow-left-wk3G9Ywf.js → arrow-left-BjAyI8D1.js} +1 -1
- package/packages/ui/dist/assets/{arrow-right-_a703_Pw.js → arrow-right-BlFO4Tcx.js} +1 -1
- package/packages/ui/dist/assets/{arrow-top-txyg3R3e.js → arrow-top-DJ3oh3DH.js} +1 -1
- package/packages/ui/dist/assets/{bank-BB1kd0NJ.js → bank-B98it1qN.js} +1 -1
- package/packages/ui/dist/assets/{basic-D0dy7nIZ.js → basic-DsgeyPNu.js} +1 -1
- package/packages/ui/dist/assets/{browser-BwHLhsTn.js → browser-j4vCeHwE.js} +1 -1
- package/packages/ui/dist/assets/{card-DRC6HmPF.js → card-CzxbMvEd.js} +1 -1
- package/packages/ui/dist/assets/{ccip-Dq6KeJQl.js → ccip-U9yiu_EK.js} +1 -1
- package/packages/ui/dist/assets/{checkmark-TbAAQGjd.js → checkmark-D5sWBbk3.js} +1 -1
- package/packages/ui/dist/assets/{checkmark-bold-4723vJ0-.js → checkmark-bold-BW6w3KCC.js} +1 -1
- package/packages/ui/dist/assets/{chevron-bottom-DtLoBRe9.js → chevron-bottom-BbHhmTQq.js} +1 -1
- package/packages/ui/dist/assets/{chevron-left-BtydsF9j.js → chevron-left-D8BDH4Wo.js} +1 -1
- package/packages/ui/dist/assets/{chevron-right-BbkU_Kf8.js → chevron-right-BQuQk5zc.js} +1 -1
- package/packages/ui/dist/assets/{chevron-top-BWf-sN-F.js → chevron-top-1oeSXkx4.js} +1 -1
- package/packages/ui/dist/assets/{chrome-store-CVFxc5H2.js → chrome-store-B1OMtzC-.js} +1 -1
- package/packages/ui/dist/assets/{clock-B4hJww1X.js → clock-e0HueehS.js} +1 -1
- package/packages/ui/dist/assets/{close-Ci93jqGe.js → close-Cy1ytr26.js} +1 -1
- package/packages/ui/dist/assets/{coinPlaceholder-cRv_xDgC.js → coinPlaceholder-DqJu3ZPV.js} +1 -1
- package/packages/ui/dist/assets/{compass-_sZZPtm6.js → compass-XDz_N2Hg.js} +1 -1
- package/packages/ui/dist/assets/{copy-DLaiLK0n.js → copy-DmDo3Nob.js} +1 -1
- package/packages/ui/dist/assets/{core-YssZmpJa.js → core-DbkMGSYW.js} +3 -3
- package/packages/ui/dist/assets/cursor-DRFqL8nZ.js +3 -0
- package/packages/ui/dist/assets/{cursor-transparent-CzXQbB2p.js → cursor-transparent-DF2aA10D.js} +1 -1
- package/packages/ui/dist/assets/{desktop-BiqQI1Ss.js → desktop-CVydOWLn.js} +1 -1
- package/packages/ui/dist/assets/{disconnect-DYu7YCzu.js → disconnect-BuN2Whnz.js} +1 -1
- package/packages/ui/dist/assets/{discord-C-ife-UZ.js → discord-DMNPvTB2.js} +1 -1
- package/packages/ui/dist/assets/{etherscan-Dq7ac-p9.js → etherscan-CacW-93f.js} +1 -1
- package/packages/ui/dist/assets/{events-BhTGLk8n.js → events-CZkVDFih.js} +1 -1
- package/packages/ui/dist/assets/{exclamation-triangle-BcOdRdbp.js → exclamation-triangle-B26hIvqO.js} +1 -1
- package/packages/ui/dist/assets/{extension-DmJLIidM.js → extension-B7rI0gv7.js} +1 -1
- package/packages/ui/dist/assets/{external-link-HNjp7-Po.js → external-link-CX8skCbH.js} +1 -1
- package/packages/ui/dist/assets/{facebook-BrSvHNyw.js → facebook-BDqbE6kl.js} +1 -1
- package/packages/ui/dist/assets/{fallback-Ubz80uXP.js → fallback-DWQYKf3l.js} +1 -1
- package/packages/ui/dist/assets/{farcaster-BsjltM6k.js → farcaster-zQ3oQzZ8.js} +1 -1
- package/packages/ui/dist/assets/{filters-B4yQbYZP.js → filters-DCglZYsM.js} +1 -1
- package/packages/ui/dist/assets/{github-CFq82Dds.js → github-BH-BYjss.js} +1 -1
- package/packages/ui/dist/assets/{google-DwZutf4a.js → google-DYFWxZbC.js} +1 -1
- package/packages/ui/dist/assets/{help-circle-CyA_8KQg.js → help-circle-BXH_DtZ_.js} +1 -1
- package/packages/ui/dist/assets/{id-jyZYn4LJ.js → id-Dr2yTeX1.js} +1 -1
- package/packages/ui/dist/assets/{image-Zv0yoBcH.js → image-DeJey1Eg.js} +1 -1
- package/packages/ui/dist/assets/{index-CeGppB9s.js → index-BP-UuQ8g.js} +1 -1
- package/packages/ui/dist/assets/{index-BY8A6EK8.js → index-BksbyFjf.js} +1 -1
- package/packages/ui/dist/assets/{index-BdG43zCl.js → index-C55-Ne92.js} +1 -1
- package/packages/ui/dist/assets/index-D6_Zei-R.js +1790 -0
- package/packages/ui/dist/assets/{index-67NncC_u.js → index-DVjAiPHI.js} +3 -3
- package/packages/ui/dist/assets/{index-BxRaYDiX.js → index-uSdXE5b_.js} +1 -1
- package/packages/ui/dist/assets/{index.es-C8EklrJY.js → index.es-dZlNPpfR.js} +4 -4
- package/packages/ui/dist/assets/{info-BwGEOdmB.js → info-B91pD5Rw.js} +1 -1
- package/packages/ui/dist/assets/{info-circle-BPCcX-Iq.js → info-circle-CySl3_on.js} +1 -1
- package/packages/ui/dist/assets/{lightbulb-BRwr4IaC.js → lightbulb-wwG8LQLo.js} +1 -1
- package/packages/ui/dist/assets/{mail-D-k_Vhe4.js → mail-D617YZ8y.js} +1 -1
- package/packages/ui/dist/assets/{metamask-sdk-AcOgwGrj.js → metamask-sdk-RbLbxUgF.js} +1 -1
- package/packages/ui/dist/assets/{mobile-B1ok9PfY.js → mobile-CD9KlA0m.js} +1 -1
- package/packages/ui/dist/assets/{more-DeMTMLWs.js → more-BQ_rpPXo.js} +1 -1
- package/packages/ui/dist/assets/{network-placeholder-J0Rc1I89.js → network-placeholder-BA7nl9e6.js} +1 -1
- package/packages/ui/dist/assets/{nftPlaceholder-dXGrzzoa.js → nftPlaceholder-D1EaaeDn.js} +1 -1
- package/packages/ui/dist/assets/{off-CS0f77lw.js → off-DnGG35_w.js} +1 -1
- package/packages/ui/dist/assets/{parseSignature-DJ16fHC4.js → parseSignature-E29x8poM.js} +1 -1
- package/packages/ui/dist/assets/{play-store-DmK8UaNC.js → play-store-C5u2FvYB.js} +1 -1
- package/packages/ui/dist/assets/{plus-CSGSnoCh.js → plus-CM4xJkvI.js} +1 -1
- package/packages/ui/dist/assets/{qr-code-BJMH0xmM.js → qr-code-kM3FUIdR.js} +1 -1
- package/packages/ui/dist/assets/{recycle-horizontal-D5XP5VgJ.js → recycle-horizontal-DWrRWIBM.js} +1 -1
- package/packages/ui/dist/assets/{refresh-MLX3Rdp6.js → refresh-CztbjK2d.js} +1 -1
- package/packages/ui/dist/assets/{reown-logo-CVoDFQbM.js → reown-logo-DUHEIodF.js} +1 -1
- package/packages/ui/dist/assets/{search-BDJDyvjC.js → search-BJtb4mn1.js} +1 -1
- package/packages/ui/dist/assets/{secp256k1-BWh3B02k.js → secp256k1-BjrTZpQx.js} +1 -1
- package/packages/ui/dist/assets/{send-BOq2svx_.js → send-B3_kavG1.js} +1 -1
- package/packages/ui/dist/assets/{swapHorizontal-ByjLi_-_.js → swapHorizontal-BrF9POiv.js} +1 -1
- package/packages/ui/dist/assets/{swapHorizontalBold-fmCp_4AE.js → swapHorizontalBold-Dgf8OjXj.js} +1 -1
- package/packages/ui/dist/assets/{swapHorizontalMedium-D6dFseYw.js → swapHorizontalMedium-C6wX0JZj.js} +1 -1
- package/packages/ui/dist/assets/{swapHorizontalRoundedBold-B2V3m4ha.js → swapHorizontalRoundedBold-DTAVw6oF.js} +1 -1
- package/packages/ui/dist/assets/{swapVertical-DVmCsmeT.js → swapVertical-KGlTFNoi.js} +1 -1
- package/packages/ui/dist/assets/{telegram-Bv8JRbMM.js → telegram-DnLrK-4y.js} +1 -1
- package/packages/ui/dist/assets/{three-dots-YYDJ18z6.js → three-dots-C6_oMJfw.js} +1 -1
- package/packages/ui/dist/assets/{twitch-B2_Jy-Ft.js → twitch-DvPqPD4f.js} +1 -1
- package/packages/ui/dist/assets/{twitterIcon-pKQzPQRt.js → twitterIcon-BZdk82Am.js} +1 -1
- package/packages/ui/dist/assets/{verify-Bty2jIav.js → verify-CbESD5G0.js} +1 -1
- package/packages/ui/dist/assets/{verify-filled-CKz2fuKl.js → verify-filled-BRjTrLxw.js} +1 -1
- package/packages/ui/dist/assets/{w3m-modal-Wg1mtmVM.js → w3m-modal-D9b2TGHc.js} +1 -1
- package/packages/ui/dist/assets/{wallet-DslzC8rD.js → wallet-B87E5UId.js} +1 -1
- package/packages/ui/dist/assets/{wallet-placeholder-Dyw8jJ56.js → wallet-placeholder-DmssSbYf.js} +1 -1
- package/packages/ui/dist/assets/{walletconnect-DZBfbgp4.js → walletconnect-CZkLKWMZ.js} +1 -1
- package/packages/ui/dist/assets/{warning-circle-D7NPDx4k.js → warning-circle-BPTpHB1P.js} +1 -1
- package/packages/ui/dist/assets/{x-DRR_9FNs.js → x-D_dEtEDU.js} +1 -1
- package/packages/ui/dist/index.html +1 -1
- package/packages/ui/dist/assets/cursor-B_xyJnjj.js +0 -3
- package/packages/ui/dist/assets/index-_DkPx8RN.js +0 -1790
|
@@ -22626,7 +22626,7 @@ var require_websocket = __commonJS({
|
|
|
22626
22626
|
var EventEmitter = require("events");
|
|
22627
22627
|
var https = require("https");
|
|
22628
22628
|
var http2 = require("http");
|
|
22629
|
-
var
|
|
22629
|
+
var net3 = require("net");
|
|
22630
22630
|
var tls = require("tls");
|
|
22631
22631
|
var { randomBytes: randomBytes4, createHash } = require("crypto");
|
|
22632
22632
|
var { Duplex, Readable } = require("stream");
|
|
@@ -23360,12 +23360,12 @@ var require_websocket = __commonJS({
|
|
|
23360
23360
|
}
|
|
23361
23361
|
function netConnect(options) {
|
|
23362
23362
|
options.path = options.socketPath;
|
|
23363
|
-
return
|
|
23363
|
+
return net3.connect(options);
|
|
23364
23364
|
}
|
|
23365
23365
|
function tlsConnect(options) {
|
|
23366
23366
|
options.path = void 0;
|
|
23367
23367
|
if (!options.servername && options.servername !== "") {
|
|
23368
|
-
options.servername =
|
|
23368
|
+
options.servername = net3.isIP(options.host) ? "" : options.host;
|
|
23369
23369
|
}
|
|
23370
23370
|
return tls.connect(options);
|
|
23371
23371
|
}
|
|
@@ -33756,7 +33756,7 @@ var require_websocket2 = __commonJS({
|
|
|
33756
33756
|
var EventEmitter = require("events");
|
|
33757
33757
|
var https = require("https");
|
|
33758
33758
|
var http2 = require("http");
|
|
33759
|
-
var
|
|
33759
|
+
var net3 = require("net");
|
|
33760
33760
|
var tls = require("tls");
|
|
33761
33761
|
var { randomBytes: randomBytes4, createHash } = require("crypto");
|
|
33762
33762
|
var { Duplex, Readable } = require("stream");
|
|
@@ -34500,12 +34500,12 @@ var require_websocket2 = __commonJS({
|
|
|
34500
34500
|
}
|
|
34501
34501
|
function netConnect(options) {
|
|
34502
34502
|
options.path = options.socketPath;
|
|
34503
|
-
return
|
|
34503
|
+
return net3.connect(options);
|
|
34504
34504
|
}
|
|
34505
34505
|
function tlsConnect(options) {
|
|
34506
34506
|
options.path = void 0;
|
|
34507
34507
|
if (!options.servername && options.servername !== "") {
|
|
34508
|
-
options.servername =
|
|
34508
|
+
options.servername = net3.isIP(options.host) ? "" : options.host;
|
|
34509
34509
|
}
|
|
34510
34510
|
return tls.connect(options);
|
|
34511
34511
|
}
|
|
@@ -37445,18 +37445,12 @@ var LocalKeyring = class _LocalKeyring {
|
|
|
37445
37445
|
this.account = account2;
|
|
37446
37446
|
this.address = account2.address;
|
|
37447
37447
|
this.privateKey = options.privateKey;
|
|
37448
|
-
} else
|
|
37448
|
+
} else {
|
|
37449
37449
|
const account2 = mnemonicToAccount(options.mnemonic, options.derivationPath ? { path: options.derivationPath } : void 0);
|
|
37450
37450
|
this.account = account2;
|
|
37451
37451
|
this.address = account2.address;
|
|
37452
|
-
} else {
|
|
37453
|
-
throw new Error("keystore decryption not implemented \u2014 use type: 'privateKey' or type: 'mnemonic' instead");
|
|
37454
37452
|
}
|
|
37455
37453
|
}
|
|
37456
|
-
/** Returns a lightweight signer stub for read-only contexts where the key is not available. */
|
|
37457
|
-
static fromAddress(address) {
|
|
37458
|
-
return { address };
|
|
37459
|
-
}
|
|
37460
37454
|
/** Generates a brand-new keyring backed by a random private key. */
|
|
37461
37455
|
static generate() {
|
|
37462
37456
|
return new _LocalKeyring({ type: "privateKey", privateKey: generatePrivateKey() });
|
|
@@ -38497,15 +38491,58 @@ function upsertAccountInList(account2, name, baseSailDir = sailDir()) {
|
|
|
38497
38491
|
}
|
|
38498
38492
|
|
|
38499
38493
|
// src/signing/client.ts
|
|
38500
|
-
var
|
|
38494
|
+
var import_node_fs7 = require("node:fs");
|
|
38501
38495
|
var import_node_path5 = require("node:path");
|
|
38502
38496
|
|
|
38503
38497
|
// src/signing/server.ts
|
|
38504
38498
|
var import_node_crypto2 = require("node:crypto");
|
|
38505
|
-
var
|
|
38499
|
+
var import_node_fs6 = require("node:fs");
|
|
38506
38500
|
var import_node_http = require("node:http");
|
|
38507
|
-
var import_node_net = require("node:net");
|
|
38508
38501
|
var import_node_path4 = require("node:path");
|
|
38502
|
+
|
|
38503
|
+
// src/lib/process.ts
|
|
38504
|
+
var import_node_fs5 = __toESM(require("node:fs"), 1);
|
|
38505
|
+
var import_node_net = __toESM(require("node:net"), 1);
|
|
38506
|
+
function agentPidPath(chainId) {
|
|
38507
|
+
return chainId != null ? sailPath(`agent-${chainId}.pid`) : sailPath("agent.pid");
|
|
38508
|
+
}
|
|
38509
|
+
function writeAgentPid(chainId) {
|
|
38510
|
+
import_node_fs5.default.mkdirSync(sailPath(), { recursive: true });
|
|
38511
|
+
import_node_fs5.default.writeFileSync(agentPidPath(chainId), `${process.pid}
|
|
38512
|
+
`);
|
|
38513
|
+
}
|
|
38514
|
+
function clearAgentPid(chainId) {
|
|
38515
|
+
try {
|
|
38516
|
+
import_node_fs5.default.rmSync(agentPidPath(chainId));
|
|
38517
|
+
} catch {
|
|
38518
|
+
}
|
|
38519
|
+
}
|
|
38520
|
+
function readAgentPid(chainId) {
|
|
38521
|
+
try {
|
|
38522
|
+
const pid = Number.parseInt(import_node_fs5.default.readFileSync(agentPidPath(chainId), "utf-8").trim(), 10);
|
|
38523
|
+
return Number.isNaN(pid) ? null : pid;
|
|
38524
|
+
} catch {
|
|
38525
|
+
return null;
|
|
38526
|
+
}
|
|
38527
|
+
}
|
|
38528
|
+
function isProcessAlive(pid) {
|
|
38529
|
+
try {
|
|
38530
|
+
process.kill(pid, 0);
|
|
38531
|
+
return true;
|
|
38532
|
+
} catch (err) {
|
|
38533
|
+
return err.code === "EPERM";
|
|
38534
|
+
}
|
|
38535
|
+
}
|
|
38536
|
+
function findFreePort(from14) {
|
|
38537
|
+
return new Promise((resolve3, reject) => {
|
|
38538
|
+
const server = import_node_net.default.createServer();
|
|
38539
|
+
server.unref();
|
|
38540
|
+
server.on("error", () => findFreePort(from14 + 1).then(resolve3, reject));
|
|
38541
|
+
server.listen(from14, "127.0.0.1", () => server.close(() => resolve3(from14)));
|
|
38542
|
+
});
|
|
38543
|
+
}
|
|
38544
|
+
|
|
38545
|
+
// src/signing/server.ts
|
|
38509
38546
|
init_esm2();
|
|
38510
38547
|
|
|
38511
38548
|
// ../../node_modules/.pnpm/ws@8.21.0_bufferutil@4.1.0_utf-8-validate@5.0.10/node_modules/ws/wrapper.mjs
|
|
@@ -38545,7 +38582,7 @@ function findUiDist() {
|
|
|
38545
38582
|
(0, import_node_path4.join)(process.cwd(), "..", "ui", "dist")
|
|
38546
38583
|
];
|
|
38547
38584
|
for (const c of candidates) {
|
|
38548
|
-
if ((0,
|
|
38585
|
+
if ((0, import_node_fs6.existsSync)((0, import_node_path4.join)(c, "index.html"))) return c;
|
|
38549
38586
|
}
|
|
38550
38587
|
return null;
|
|
38551
38588
|
}
|
|
@@ -38593,7 +38630,7 @@ var SigningServer = class {
|
|
|
38593
38630
|
return this.httpServer?.listening ?? false;
|
|
38594
38631
|
}
|
|
38595
38632
|
async start() {
|
|
38596
|
-
this.port = await
|
|
38633
|
+
this.port = await findFreePort(this.port);
|
|
38597
38634
|
this._url = `http://localhost:${this.port}`;
|
|
38598
38635
|
this.requestSecret = (0, import_node_crypto2.randomBytes)(16).toString("hex");
|
|
38599
38636
|
const http2 = (0, import_node_http.createServer)((req, res) => this.handleHttp(req, res));
|
|
@@ -38773,13 +38810,13 @@ var SigningServer = class {
|
|
|
38773
38810
|
const path11 = this.sailFile("config.json");
|
|
38774
38811
|
let config = {};
|
|
38775
38812
|
try {
|
|
38776
|
-
config = JSON.parse((0,
|
|
38813
|
+
config = JSON.parse((0, import_node_fs6.readFileSync)(path11, "utf-8"));
|
|
38777
38814
|
} catch {
|
|
38778
38815
|
}
|
|
38779
38816
|
if (Number(config.chainId) === Number(chainId)) return;
|
|
38780
38817
|
config.chainId = Number(chainId);
|
|
38781
|
-
(0,
|
|
38782
|
-
(0,
|
|
38818
|
+
(0, import_node_fs6.mkdirSync)(this.sailFile(), { recursive: true });
|
|
38819
|
+
(0, import_node_fs6.writeFileSync)(path11, `${JSON.stringify(config, null, 2)}
|
|
38783
38820
|
`);
|
|
38784
38821
|
} catch {
|
|
38785
38822
|
}
|
|
@@ -38787,7 +38824,7 @@ var SigningServer = class {
|
|
|
38787
38824
|
/** Stream a JSON file back, or a fallback body when it is missing/invalid. */
|
|
38788
38825
|
sendJsonFile(res, filePath, fallback2) {
|
|
38789
38826
|
try {
|
|
38790
|
-
const raw = (0,
|
|
38827
|
+
const raw = (0, import_node_fs6.readFileSync)(filePath, "utf-8");
|
|
38791
38828
|
JSON.parse(raw);
|
|
38792
38829
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
38793
38830
|
res.end(raw);
|
|
@@ -38854,8 +38891,8 @@ var SigningServer = class {
|
|
|
38854
38891
|
};
|
|
38855
38892
|
const baseSailDir = this.sailFile();
|
|
38856
38893
|
upsertAccountInList(record, void 0, baseSailDir);
|
|
38857
|
-
(0,
|
|
38858
|
-
(0,
|
|
38894
|
+
(0, import_node_fs6.mkdirSync)(baseSailDir, { recursive: true });
|
|
38895
|
+
(0, import_node_fs6.writeFileSync)(this.sailFile("account.json"), `${JSON.stringify(record, null, 2)}
|
|
38859
38896
|
`);
|
|
38860
38897
|
this.syncConfigChainId(chainId);
|
|
38861
38898
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
@@ -38870,12 +38907,12 @@ var SigningServer = class {
|
|
|
38870
38907
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
38871
38908
|
let active = null;
|
|
38872
38909
|
try {
|
|
38873
|
-
active = JSON.parse((0,
|
|
38910
|
+
active = JSON.parse((0, import_node_fs6.readFileSync)(this.sailFile("account.json"), "utf-8")).safe;
|
|
38874
38911
|
} catch {
|
|
38875
38912
|
}
|
|
38876
38913
|
try {
|
|
38877
38914
|
const accounts = JSON.parse(
|
|
38878
|
-
(0,
|
|
38915
|
+
(0, import_node_fs6.readFileSync)(this.sailFile("state", "accounts.json"), "utf-8")
|
|
38879
38916
|
);
|
|
38880
38917
|
res.end(
|
|
38881
38918
|
JSON.stringify(
|
|
@@ -38888,7 +38925,7 @@ var SigningServer = class {
|
|
|
38888
38925
|
} catch {
|
|
38889
38926
|
try {
|
|
38890
38927
|
const a = JSON.parse(
|
|
38891
|
-
(0,
|
|
38928
|
+
(0, import_node_fs6.readFileSync)(this.sailFile("account.json"), "utf-8")
|
|
38892
38929
|
);
|
|
38893
38930
|
res.end(JSON.stringify([{ ...a, name: "My SMA", active: true, addedAt: null }]));
|
|
38894
38931
|
} catch {
|
|
@@ -39011,16 +39048,16 @@ var SigningServer = class {
|
|
|
39011
39048
|
res.end();
|
|
39012
39049
|
return;
|
|
39013
39050
|
}
|
|
39014
|
-
if ((0,
|
|
39051
|
+
if ((0, import_node_fs6.existsSync)(filePath)) {
|
|
39015
39052
|
const mime = MIME[(0, import_node_path4.extname)(filePath)] ?? "application/octet-stream";
|
|
39016
39053
|
res.writeHead(200, { "Content-Type": mime });
|
|
39017
|
-
res.end((0,
|
|
39054
|
+
res.end((0, import_node_fs6.readFileSync)(filePath));
|
|
39018
39055
|
return;
|
|
39019
39056
|
}
|
|
39020
39057
|
const indexHtml = (0, import_node_path4.join)(this.uiDist, "index.html");
|
|
39021
|
-
if ((0,
|
|
39058
|
+
if ((0, import_node_fs6.existsSync)(indexHtml)) {
|
|
39022
39059
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
39023
|
-
res.end((0,
|
|
39060
|
+
res.end((0, import_node_fs6.readFileSync)(indexHtml));
|
|
39024
39061
|
return;
|
|
39025
39062
|
}
|
|
39026
39063
|
}
|
|
@@ -39107,15 +39144,15 @@ var SigningServer = class {
|
|
|
39107
39144
|
}
|
|
39108
39145
|
writeRuntimeState() {
|
|
39109
39146
|
const path11 = (0, import_node_path4.join)(this.runtimeDir, SERVER_STATE_FILE);
|
|
39110
|
-
if ((0,
|
|
39147
|
+
if ((0, import_node_fs6.existsSync)(path11)) {
|
|
39111
39148
|
try {
|
|
39112
|
-
const existing = JSON.parse((0,
|
|
39113
|
-
if (existing.pid != null && existing.pid !== process.pid &&
|
|
39149
|
+
const existing = JSON.parse((0, import_node_fs6.readFileSync)(path11, "utf8"));
|
|
39150
|
+
if (existing.pid != null && existing.pid !== process.pid && isProcessAlive(existing.pid)) return;
|
|
39114
39151
|
} catch {
|
|
39115
39152
|
}
|
|
39116
39153
|
}
|
|
39117
|
-
if (!(0,
|
|
39118
|
-
(0,
|
|
39154
|
+
if (!(0, import_node_fs6.existsSync)(this.runtimeDir)) (0, import_node_fs6.mkdirSync)(this.runtimeDir, { recursive: true });
|
|
39155
|
+
(0, import_node_fs6.writeFileSync)(
|
|
39119
39156
|
(0, import_node_path4.join)(this.runtimeDir, SERVER_STATE_FILE),
|
|
39120
39157
|
JSON.stringify(
|
|
39121
39158
|
{
|
|
@@ -39134,43 +39171,25 @@ var SigningServer = class {
|
|
|
39134
39171
|
removeRuntimeState() {
|
|
39135
39172
|
const path11 = (0, import_node_path4.join)(this.runtimeDir, SERVER_STATE_FILE);
|
|
39136
39173
|
try {
|
|
39137
|
-
if (!(0,
|
|
39138
|
-
const state = JSON.parse((0,
|
|
39174
|
+
if (!(0, import_node_fs6.existsSync)(path11)) return;
|
|
39175
|
+
const state = JSON.parse((0, import_node_fs6.readFileSync)(path11, "utf8"));
|
|
39139
39176
|
if (state.pid != null && state.pid !== process.pid) return;
|
|
39140
|
-
(0,
|
|
39177
|
+
(0, import_node_fs6.unlinkSync)(path11);
|
|
39141
39178
|
} catch {
|
|
39142
39179
|
}
|
|
39143
39180
|
}
|
|
39144
39181
|
};
|
|
39145
|
-
function pidAlive(pid) {
|
|
39146
|
-
try {
|
|
39147
|
-
process.kill(pid, 0);
|
|
39148
|
-
return true;
|
|
39149
|
-
} catch (err) {
|
|
39150
|
-
return err.code === "EPERM";
|
|
39151
|
-
}
|
|
39152
|
-
}
|
|
39153
39182
|
function reapStaleRuntimeState(projectRoot = process.cwd()) {
|
|
39154
39183
|
const path11 = (0, import_node_path4.join)(projectRoot, RUNTIME_SUBDIR, SERVER_STATE_FILE);
|
|
39155
39184
|
try {
|
|
39156
|
-
if (!(0,
|
|
39157
|
-
const state = JSON.parse((0,
|
|
39158
|
-
if (state.pid != null && state.pid !== process.pid && !
|
|
39159
|
-
(0,
|
|
39185
|
+
if (!(0, import_node_fs6.existsSync)(path11)) return;
|
|
39186
|
+
const state = JSON.parse((0, import_node_fs6.readFileSync)(path11, "utf8"));
|
|
39187
|
+
if (state.pid != null && state.pid !== process.pid && !isProcessAlive(state.pid)) {
|
|
39188
|
+
(0, import_node_fs6.unlinkSync)(path11);
|
|
39160
39189
|
}
|
|
39161
39190
|
} catch {
|
|
39162
39191
|
}
|
|
39163
39192
|
}
|
|
39164
|
-
async function findAvailablePort(startPort) {
|
|
39165
|
-
return new Promise((res) => {
|
|
39166
|
-
const probe = (0, import_node_net.createServer)();
|
|
39167
|
-
probe.listen(startPort, "127.0.0.1", () => {
|
|
39168
|
-
const addr = probe.address();
|
|
39169
|
-
probe.close(() => res(addr.port));
|
|
39170
|
-
});
|
|
39171
|
-
probe.on("error", () => res(findAvailablePort(startPort + 1)));
|
|
39172
|
-
});
|
|
39173
|
-
}
|
|
39174
39193
|
|
|
39175
39194
|
// src/signing/client.ts
|
|
39176
39195
|
var RUNTIME_SERVER_FILE = (0, import_node_path5.join)(".sail", "runtime", "server.json");
|
|
@@ -39252,14 +39271,14 @@ function toLoopbackIPv4(url) {
|
|
|
39252
39271
|
}
|
|
39253
39272
|
function readRuntimeServerState(projectRoot) {
|
|
39254
39273
|
const file = (0, import_node_path5.join)(projectRoot, RUNTIME_SERVER_FILE);
|
|
39255
|
-
if (!(0,
|
|
39274
|
+
if (!(0, import_node_fs7.existsSync)(file)) return null;
|
|
39256
39275
|
try {
|
|
39257
|
-
return JSON.parse((0,
|
|
39276
|
+
return JSON.parse((0, import_node_fs7.readFileSync)(file, "utf8"));
|
|
39258
39277
|
} catch {
|
|
39259
39278
|
return null;
|
|
39260
39279
|
}
|
|
39261
39280
|
}
|
|
39262
|
-
function signingPageUrl(
|
|
39281
|
+
function signingPageUrl(dashboardPort) {
|
|
39263
39282
|
return `http://localhost:${dashboardPort}/#/station`;
|
|
39264
39283
|
}
|
|
39265
39284
|
async function discoverDaemon(projectRoot = process.cwd()) {
|
|
@@ -39530,7 +39549,7 @@ Deploying SMA on ${getChainById(targetChainId).name} (chain ${targetChainId})\u2
|
|
|
39530
39549
|
const channel = await createSigningChannel(process.cwd());
|
|
39531
39550
|
try {
|
|
39532
39551
|
await channel.start();
|
|
39533
|
-
const stationUrl = signingPageUrl(
|
|
39552
|
+
const stationUrl = signingPageUrl(projectPort(process.cwd()));
|
|
39534
39553
|
if (json) {
|
|
39535
39554
|
console.log(
|
|
39536
39555
|
JSON.stringify(
|
|
@@ -39667,100 +39686,6 @@ function emit(json, human, payload) {
|
|
|
39667
39686
|
|
|
39668
39687
|
// src/lib/project.ts
|
|
39669
39688
|
init_esm2();
|
|
39670
|
-
|
|
39671
|
-
// src/lib/keys.ts
|
|
39672
|
-
init_esm2();
|
|
39673
|
-
var ROLES = ["manager", "permissionSigner"];
|
|
39674
|
-
function normalizeRole(input) {
|
|
39675
|
-
const n = input.trim().toLowerCase().replace(/[-_\s]/g, "");
|
|
39676
|
-
if (n === "manager" || n === "mgr" || n === "m" || n === "agent" || n === "agentwallet") {
|
|
39677
|
-
return "manager";
|
|
39678
|
-
}
|
|
39679
|
-
if (n === "permissionsigner" || n === "signer" || n === "ps" || n === "permission" || n === "mandatesigner" || n === "mandate") {
|
|
39680
|
-
return "permissionSigner";
|
|
39681
|
-
}
|
|
39682
|
-
return null;
|
|
39683
|
-
}
|
|
39684
|
-
function roleLabel(role) {
|
|
39685
|
-
return role === "manager" ? "agent wallet" : "mandate signer";
|
|
39686
|
-
}
|
|
39687
|
-
function safeHex(safe) {
|
|
39688
|
-
return safe.toLowerCase().replace(/^0x/, "").replace(/[^0-9a-f]/g, "");
|
|
39689
|
-
}
|
|
39690
|
-
function keyPath(role, safe) {
|
|
39691
|
-
if (safe) {
|
|
39692
|
-
return sailPath("keys", `${role}-0x${safeHex(safe)}.json`);
|
|
39693
|
-
}
|
|
39694
|
-
return sailPath("keys", `${role}.json`);
|
|
39695
|
-
}
|
|
39696
|
-
function legacyKeyPath(role, safe) {
|
|
39697
|
-
return sailPath("keys", `${role}-${safeHex(safe)}.json`);
|
|
39698
|
-
}
|
|
39699
|
-
function resolveKeyPath(role, safe) {
|
|
39700
|
-
if (safe) {
|
|
39701
|
-
const perSma = keyPath(role, safe);
|
|
39702
|
-
if (fileExists(perSma)) return perSma;
|
|
39703
|
-
const legacy = legacyKeyPath(role, safe);
|
|
39704
|
-
if (fileExists(legacy)) return legacy;
|
|
39705
|
-
}
|
|
39706
|
-
return keyPath(role);
|
|
39707
|
-
}
|
|
39708
|
-
function keyExists(role, safe) {
|
|
39709
|
-
return fileExists(resolveKeyPath(role, safe));
|
|
39710
|
-
}
|
|
39711
|
-
async function loadKeyring(role, safe) {
|
|
39712
|
-
const keystore = readJsonFile(resolveKeyPath(role, safe));
|
|
39713
|
-
if (!keystore) {
|
|
39714
|
-
throw new Error(
|
|
39715
|
-
`No ${roleLabel(role)} found.
|
|
39716
|
-
Run "sailor keys generate" and choose "${roleLabel(role)}" first.`
|
|
39717
|
-
);
|
|
39718
|
-
}
|
|
39719
|
-
const password = await promptHidden(`Password for ${roleLabel(role)} key`);
|
|
39720
|
-
try {
|
|
39721
|
-
return await LocalKeyring.fromKeystore(keystore, password);
|
|
39722
|
-
} catch {
|
|
39723
|
-
throw new Error("Invalid password.");
|
|
39724
|
-
}
|
|
39725
|
-
}
|
|
39726
|
-
async function loadManagerSigner(safe) {
|
|
39727
|
-
const passphrase = process.env.SAIL_PASSPHRASE;
|
|
39728
|
-
if (passphrase) {
|
|
39729
|
-
const keystore = readJsonFile(resolveKeyPath("manager", safe));
|
|
39730
|
-
if (!keystore) {
|
|
39731
|
-
throw new Error(
|
|
39732
|
-
'No agent wallet found.\nRun "sailor keys generate" and choose "agent wallet".'
|
|
39733
|
-
);
|
|
39734
|
-
}
|
|
39735
|
-
try {
|
|
39736
|
-
return await LocalKeyring.fromKeystore(keystore, passphrase);
|
|
39737
|
-
} catch {
|
|
39738
|
-
throw new Error(
|
|
39739
|
-
"SAIL_PASSPHRASE does not match this keystore.\nCheck the value in .sail/.env.local (or the SAIL_PASSPHRASE CI secret) \u2014 it must be the passphrase the agent wallet was encrypted with."
|
|
39740
|
-
);
|
|
39741
|
-
}
|
|
39742
|
-
}
|
|
39743
|
-
if (process.stdin.isTTY !== true && keyExists("manager", safe)) {
|
|
39744
|
-
throw new Error(
|
|
39745
|
-
'Agent keystore found but SAIL_PASSPHRASE is not set.\nIf you created the key in the dashboard, add SAIL_PASSPHRASE to .sail/.env.local, or run "sailor keys generate".\nFor CI, set the SAIL_PASSPHRASE GitHub Actions secret.'
|
|
39746
|
-
);
|
|
39747
|
-
}
|
|
39748
|
-
return loadKeyring("manager", safe);
|
|
39749
|
-
}
|
|
39750
|
-
function managerKeystorePath(managerAddr) {
|
|
39751
|
-
if (!isAddress(managerAddr, { strict: false })) {
|
|
39752
|
-
throw new Error(`managerKeystorePath: invalid address "${managerAddr}"`);
|
|
39753
|
-
}
|
|
39754
|
-
const hex = managerAddr.toLowerCase().replace(/^0x/, "");
|
|
39755
|
-
return sailPath("keys", "managers", `${hex}.json`);
|
|
39756
|
-
}
|
|
39757
|
-
async function loadAnySigner() {
|
|
39758
|
-
if (keyExists("permissionSigner")) return loadKeyring("permissionSigner");
|
|
39759
|
-
if (keyExists("manager")) return loadKeyring("manager");
|
|
39760
|
-
throw new Error('No signing key found.\nRun "sailor keys generate" first.');
|
|
39761
|
-
}
|
|
39762
|
-
|
|
39763
|
-
// src/lib/project.ts
|
|
39764
39689
|
function nonEmpty(value) {
|
|
39765
39690
|
return typeof value === "string" && value.trim().length > 0;
|
|
39766
39691
|
}
|
|
@@ -39819,24 +39744,6 @@ var ProjectContext = class {
|
|
|
39819
39744
|
});
|
|
39820
39745
|
}
|
|
39821
39746
|
};
|
|
39822
|
-
async function loadManagerSigner2() {
|
|
39823
|
-
if (!process.env.SAIL_PASSPHRASE) {
|
|
39824
|
-
try {
|
|
39825
|
-
const env = parseEnvFile(sailPath(".env.local"));
|
|
39826
|
-
if (env.SAIL_PASSPHRASE) process.env.SAIL_PASSPHRASE = env.SAIL_PASSPHRASE;
|
|
39827
|
-
} catch {
|
|
39828
|
-
}
|
|
39829
|
-
}
|
|
39830
|
-
const passphrase = process.env.SAIL_PASSPHRASE;
|
|
39831
|
-
if (passphrase) {
|
|
39832
|
-
const keystore = readJsonFile(keyPath("manager"));
|
|
39833
|
-
if (!keystore) {
|
|
39834
|
-
throw new Error('No manager key found.\nRun "sailor keys generate" and choose "manager".');
|
|
39835
|
-
}
|
|
39836
|
-
return LocalKeyring.fromKeystore(keystore, passphrase);
|
|
39837
|
-
}
|
|
39838
|
-
return loadKeyring("manager");
|
|
39839
|
-
}
|
|
39840
39747
|
|
|
39841
39748
|
// src/commands/capabilities.ts
|
|
39842
39749
|
function chainName(chainId) {
|
|
@@ -40044,6 +39951,101 @@ function checkSelectorRoutes(calldata, bytecode) {
|
|
|
40044
39951
|
return { selector, routes: body.includes(selector) };
|
|
40045
39952
|
}
|
|
40046
39953
|
|
|
39954
|
+
// src/lib/keys.ts
|
|
39955
|
+
init_esm2();
|
|
39956
|
+
var ROLES = ["manager", "permissionSigner"];
|
|
39957
|
+
function normalizeRole(input) {
|
|
39958
|
+
const n = input.trim().toLowerCase().replace(/[-_\s]/g, "");
|
|
39959
|
+
if (n === "manager" || n === "mgr" || n === "m" || n === "agent" || n === "agentwallet") {
|
|
39960
|
+
return "manager";
|
|
39961
|
+
}
|
|
39962
|
+
if (n === "permissionsigner" || n === "signer" || n === "ps" || n === "permission" || n === "mandatesigner" || n === "mandate") {
|
|
39963
|
+
return "permissionSigner";
|
|
39964
|
+
}
|
|
39965
|
+
return null;
|
|
39966
|
+
}
|
|
39967
|
+
function roleLabel(role) {
|
|
39968
|
+
return role === "manager" ? "agent wallet" : "mandate signer";
|
|
39969
|
+
}
|
|
39970
|
+
function safeHex(safe) {
|
|
39971
|
+
return safe.toLowerCase().replace(/^0x/, "").replace(/[^0-9a-f]/g, "");
|
|
39972
|
+
}
|
|
39973
|
+
function keyPath(role, safe) {
|
|
39974
|
+
if (safe) {
|
|
39975
|
+
return sailPath("keys", `${role}-0x${safeHex(safe)}.json`);
|
|
39976
|
+
}
|
|
39977
|
+
return sailPath("keys", `${role}.json`);
|
|
39978
|
+
}
|
|
39979
|
+
function legacyKeyPath(role, safe) {
|
|
39980
|
+
return sailPath("keys", `${role}-${safeHex(safe)}.json`);
|
|
39981
|
+
}
|
|
39982
|
+
function resolveKeyPath(role, safe) {
|
|
39983
|
+
if (safe) {
|
|
39984
|
+
const perSma = keyPath(role, safe);
|
|
39985
|
+
if (fileExists(perSma)) return perSma;
|
|
39986
|
+
const legacy = legacyKeyPath(role, safe);
|
|
39987
|
+
if (fileExists(legacy)) return legacy;
|
|
39988
|
+
}
|
|
39989
|
+
return keyPath(role);
|
|
39990
|
+
}
|
|
39991
|
+
function keyExists(role, safe) {
|
|
39992
|
+
return fileExists(resolveKeyPath(role, safe));
|
|
39993
|
+
}
|
|
39994
|
+
async function loadKeyring(role, safe) {
|
|
39995
|
+
const keystore = readJsonFile(resolveKeyPath(role, safe));
|
|
39996
|
+
if (!keystore) {
|
|
39997
|
+
throw new Error(
|
|
39998
|
+
`No ${roleLabel(role)} found.
|
|
39999
|
+
Run "sailor keys generate" and choose "${roleLabel(role)}" first.`
|
|
40000
|
+
);
|
|
40001
|
+
}
|
|
40002
|
+
const passphrase = process.env.SAIL_PASSPHRASE;
|
|
40003
|
+
if (passphrase) {
|
|
40004
|
+
try {
|
|
40005
|
+
return await LocalKeyring.fromKeystore(keystore, passphrase);
|
|
40006
|
+
} catch {
|
|
40007
|
+
throw new Error(
|
|
40008
|
+
`SAIL_PASSPHRASE does not match the ${roleLabel(role)} keystore.
|
|
40009
|
+
Check the value in .sail/.env.local (or the SAIL_PASSPHRASE CI secret) \u2014 it must be the passphrase this key was encrypted with.`
|
|
40010
|
+
);
|
|
40011
|
+
}
|
|
40012
|
+
}
|
|
40013
|
+
if (process.stdin.isTTY !== true) {
|
|
40014
|
+
throw new Error(
|
|
40015
|
+
`${roleLabel(role)} keystore found but SAIL_PASSPHRASE is not set.
|
|
40016
|
+
Set SAIL_PASSPHRASE in .sail/.env.local (or as a CI secret) to run non-interactively.`
|
|
40017
|
+
);
|
|
40018
|
+
}
|
|
40019
|
+
const password = await promptHidden(`Password for ${roleLabel(role)} key`);
|
|
40020
|
+
try {
|
|
40021
|
+
return await LocalKeyring.fromKeystore(keystore, password);
|
|
40022
|
+
} catch {
|
|
40023
|
+
throw new Error("Invalid password.");
|
|
40024
|
+
}
|
|
40025
|
+
}
|
|
40026
|
+
async function loadManagerSigner(safe) {
|
|
40027
|
+
if (!process.env.SAIL_PASSPHRASE) {
|
|
40028
|
+
try {
|
|
40029
|
+
const env = parseEnvFile(sailPath(".env.local"));
|
|
40030
|
+
if (env.SAIL_PASSPHRASE) process.env.SAIL_PASSPHRASE = env.SAIL_PASSPHRASE;
|
|
40031
|
+
} catch {
|
|
40032
|
+
}
|
|
40033
|
+
}
|
|
40034
|
+
return loadKeyring("manager", safe);
|
|
40035
|
+
}
|
|
40036
|
+
function managerKeystorePath(managerAddr) {
|
|
40037
|
+
if (!isAddress(managerAddr, { strict: false })) {
|
|
40038
|
+
throw new Error(`managerKeystorePath: invalid address "${managerAddr}"`);
|
|
40039
|
+
}
|
|
40040
|
+
const hex = managerAddr.toLowerCase().replace(/^0x/, "");
|
|
40041
|
+
return sailPath("keys", "managers", `${hex}.json`);
|
|
40042
|
+
}
|
|
40043
|
+
async function loadAnySigner() {
|
|
40044
|
+
if (keyExists("permissionSigner")) return loadKeyring("permissionSigner");
|
|
40045
|
+
if (keyExists("manager")) return loadKeyring("manager");
|
|
40046
|
+
throw new Error('No signing key found.\nRun "sailor keys generate" first.');
|
|
40047
|
+
}
|
|
40048
|
+
|
|
40047
40049
|
// src/lib/permission-resolver.ts
|
|
40048
40050
|
var IPERMISSION_ABI = [
|
|
40049
40051
|
{
|
|
@@ -40439,11 +40441,11 @@ Probe is heuristic: an unknown selector (${PROBE_SELECTOR}) to a neutral target
|
|
|
40439
40441
|
}
|
|
40440
40442
|
|
|
40441
40443
|
// src/commands/init.ts
|
|
40442
|
-
var
|
|
40444
|
+
var import_node_fs10 = __toESM(require("node:fs"), 1);
|
|
40443
40445
|
var import_node_path8 = __toESM(require("node:path"), 1);
|
|
40444
40446
|
|
|
40445
40447
|
// src/lib/foundry.ts
|
|
40446
|
-
var
|
|
40448
|
+
var import_node_fs8 = require("node:fs");
|
|
40447
40449
|
var import_node_path6 = require("node:path");
|
|
40448
40450
|
var FOUNDRY_TOML = `[profile.default]
|
|
40449
40451
|
src = "mandates"
|
|
@@ -40592,7 +40594,7 @@ Compiled artifacts are written to \`out/\` and the deployed address is tracked i
|
|
|
40592
40594
|
function scaffoldFoundryWorkspace(root) {
|
|
40593
40595
|
const dirs = [(0, import_node_path6.join)(root, "mandates"), (0, import_node_path6.join)(root, ".sail", "contracts", "interfaces")];
|
|
40594
40596
|
for (const d of dirs) {
|
|
40595
|
-
if (!(0,
|
|
40597
|
+
if (!(0, import_node_fs8.existsSync)(d)) (0, import_node_fs8.mkdirSync)(d, { recursive: true });
|
|
40596
40598
|
}
|
|
40597
40599
|
writeIfMissing((0, import_node_path6.join)(root, "foundry.toml"), FOUNDRY_TOML);
|
|
40598
40600
|
writeIfMissing(
|
|
@@ -40607,11 +40609,11 @@ function scaffoldFoundryWorkspace(root) {
|
|
|
40607
40609
|
writeIfMissing((0, import_node_path6.join)(root, "mandates", "README.md"), MANDATES_README);
|
|
40608
40610
|
}
|
|
40609
40611
|
function writeIfMissing(path11, content) {
|
|
40610
|
-
if (!(0,
|
|
40612
|
+
if (!(0, import_node_fs8.existsSync)(path11)) (0, import_node_fs8.writeFileSync)(path11, content, "utf8");
|
|
40611
40613
|
}
|
|
40612
40614
|
|
|
40613
40615
|
// src/lib/template.ts
|
|
40614
|
-
var
|
|
40616
|
+
var import_node_fs9 = __toESM(require("node:fs"), 1);
|
|
40615
40617
|
var import_node_path7 = __toESM(require("node:path"), 1);
|
|
40616
40618
|
var TEMPLATE_COPY_EXCLUDES = /* @__PURE__ */ new Set([
|
|
40617
40619
|
"node_modules",
|
|
@@ -40622,8 +40624,8 @@ var TEMPLATE_COPY_EXCLUDES = /* @__PURE__ */ new Set([
|
|
|
40622
40624
|
".git"
|
|
40623
40625
|
]);
|
|
40624
40626
|
function copyDirSync(src, dest) {
|
|
40625
|
-
|
|
40626
|
-
for (const entry of
|
|
40627
|
+
import_node_fs9.default.mkdirSync(dest, { recursive: true });
|
|
40628
|
+
for (const entry of import_node_fs9.default.readdirSync(src, { withFileTypes: true })) {
|
|
40627
40629
|
if (TEMPLATE_COPY_EXCLUDES.has(entry.name)) continue;
|
|
40628
40630
|
const srcPath = import_node_path7.default.join(src, entry.name);
|
|
40629
40631
|
const destName = entry.name.startsWith("_") ? `.${entry.name.slice(1)}` : entry.name;
|
|
@@ -40631,24 +40633,24 @@ function copyDirSync(src, dest) {
|
|
|
40631
40633
|
if (entry.isDirectory()) {
|
|
40632
40634
|
copyDirSync(srcPath, destPath);
|
|
40633
40635
|
} else {
|
|
40634
|
-
|
|
40636
|
+
import_node_fs9.default.copyFileSync(srcPath, destPath);
|
|
40635
40637
|
}
|
|
40636
40638
|
}
|
|
40637
40639
|
}
|
|
40638
40640
|
function writeIfMissing2(file, content) {
|
|
40639
|
-
if (!
|
|
40641
|
+
if (!import_node_fs9.default.existsSync(file)) import_node_fs9.default.writeFileSync(file, content, "utf-8");
|
|
40640
40642
|
}
|
|
40641
40643
|
function copyDirSyncIfMissing(src, dest, added = [], base2 = dest) {
|
|
40642
|
-
|
|
40643
|
-
for (const entry of
|
|
40644
|
+
import_node_fs9.default.mkdirSync(dest, { recursive: true });
|
|
40645
|
+
for (const entry of import_node_fs9.default.readdirSync(src, { withFileTypes: true })) {
|
|
40644
40646
|
if (TEMPLATE_COPY_EXCLUDES.has(entry.name)) continue;
|
|
40645
40647
|
const srcPath = import_node_path7.default.join(src, entry.name);
|
|
40646
40648
|
const destName = entry.name.startsWith("_") ? `.${entry.name.slice(1)}` : entry.name;
|
|
40647
40649
|
const destPath = import_node_path7.default.join(dest, destName);
|
|
40648
40650
|
if (entry.isDirectory()) {
|
|
40649
40651
|
copyDirSyncIfMissing(srcPath, destPath, added, base2);
|
|
40650
|
-
} else if (!
|
|
40651
|
-
|
|
40652
|
+
} else if (!import_node_fs9.default.existsSync(destPath)) {
|
|
40653
|
+
import_node_fs9.default.copyFileSync(srcPath, destPath);
|
|
40652
40654
|
added.push(import_node_path7.default.relative(base2, destPath));
|
|
40653
40655
|
}
|
|
40654
40656
|
}
|
|
@@ -40674,7 +40676,7 @@ var DEV_PKG = "@dev.sail.money/sailor";
|
|
|
40674
40676
|
function cliPackageInfo() {
|
|
40675
40677
|
try {
|
|
40676
40678
|
const pkg = JSON.parse(
|
|
40677
|
-
|
|
40679
|
+
import_node_fs10.default.readFileSync(import_node_path8.default.join(packageRoot(), "package.json"), "utf-8")
|
|
40678
40680
|
);
|
|
40679
40681
|
return {
|
|
40680
40682
|
name: pkg.name ?? CANONICAL_PKG,
|
|
@@ -40691,13 +40693,13 @@ function scaffoldProjectWorkspace(dest, name, options) {
|
|
|
40691
40693
|
return n;
|
|
40692
40694
|
})() : null;
|
|
40693
40695
|
const sailDir2 = import_node_path8.default.join(dest, ".sail");
|
|
40694
|
-
|
|
40695
|
-
|
|
40696
|
-
|
|
40696
|
+
import_node_fs10.default.mkdirSync(import_node_path8.default.join(sailDir2, "keys"), { recursive: true });
|
|
40697
|
+
import_node_fs10.default.mkdirSync(import_node_path8.default.join(sailDir2, "runtime"), { recursive: true });
|
|
40698
|
+
import_node_fs10.default.mkdirSync(import_node_path8.default.join(sailDir2, "state"), { recursive: true });
|
|
40697
40699
|
const installMode = process.env.SAILOR_INSTALL_MODE === "docker" ? "docker" : "local";
|
|
40698
40700
|
const _rawContainerName = process.env.SAILOR_CONTAINER_NAME ?? "agent";
|
|
40699
40701
|
const containerName = /^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(_rawContainerName) ? _rawContainerName : "agent";
|
|
40700
|
-
|
|
40702
|
+
import_node_fs10.default.writeFileSync(
|
|
40701
40703
|
import_node_path8.default.join(sailDir2, "config.json"),
|
|
40702
40704
|
`${JSON.stringify(
|
|
40703
40705
|
{
|
|
@@ -40724,7 +40726,7 @@ function scaffoldProjectWorkspace(dest, name, options) {
|
|
|
40724
40726
|
const chainEntries = Object.values(chains);
|
|
40725
40727
|
const perChainVarLines = chainEntries.map((c) => `# ${c.rpcEnvVar}=https://your-${c.name.toLowerCase().replace(/\s+/g, "-")}-endpoint`).join("\n");
|
|
40726
40728
|
const chainIdExample = chainId != null ? `CHAIN_ID=${chainId}` : `# CHAIN_ID=8453 # set after choosing your chain in Stage 1`;
|
|
40727
|
-
|
|
40729
|
+
import_node_fs10.default.writeFileSync(
|
|
40728
40730
|
import_node_path8.default.join(dest, ".env.example"),
|
|
40729
40731
|
`# Sailor agent environment
|
|
40730
40732
|
#
|
|
@@ -40750,7 +40752,7 @@ ${perChainVarLines}
|
|
|
40750
40752
|
const val = isActive && options.rpcUrl ? options.rpcUrl : `https://your-${c.name.toLowerCase().replace(/\s+/g, "-")}-endpoint`;
|
|
40751
40753
|
return isActive && options.rpcUrl ? `${c.rpcEnvVar}=${val}` : `# ${c.rpcEnvVar}=${val}`;
|
|
40752
40754
|
}).join("\n");
|
|
40753
|
-
|
|
40755
|
+
import_node_fs10.default.writeFileSync(
|
|
40754
40756
|
import_node_path8.default.join(sailDir2, ".env.local"),
|
|
40755
40757
|
`# Real values \u2014 never commit this file.
|
|
40756
40758
|
#
|
|
@@ -40777,8 +40779,8 @@ async function initCommand(dir, options = {}) {
|
|
|
40777
40779
|
throw new Error(`Invalid template name: "${templateName}"`);
|
|
40778
40780
|
}
|
|
40779
40781
|
const templateSrc = import_node_path8.default.join(templatesDir, templateName);
|
|
40780
|
-
const availableTemplates = () =>
|
|
40781
|
-
if (!
|
|
40782
|
+
const availableTemplates = () => import_node_fs10.default.existsSync(templatesDir) ? import_node_fs10.default.readdirSync(templatesDir).filter((e) => import_node_fs10.default.existsSync(import_node_path8.default.join(templatesDir, e, "package.json"))).join(", ") || "none" : "none";
|
|
40783
|
+
if (!import_node_fs10.default.existsSync(templateSrc) || !import_node_fs10.default.existsSync(import_node_path8.default.join(templateSrc, "package.json"))) {
|
|
40782
40784
|
const available = availableTemplates();
|
|
40783
40785
|
const hint = available === "none" ? `
|
|
40784
40786
|
No templates found under ${templatesDir}.
|
|
@@ -40791,19 +40793,19 @@ run from the repo root.` : ` Available: ${available}`;
|
|
|
40791
40793
|
if (!inPlace && !dest.startsWith(cwd + import_node_path8.default.sep) && dest !== cwd) {
|
|
40792
40794
|
throw new Error(`Directory must be inside the current working directory`);
|
|
40793
40795
|
}
|
|
40794
|
-
if (!inPlace &&
|
|
40796
|
+
if (!inPlace && import_node_fs10.default.existsSync(dest) && !options.force) {
|
|
40795
40797
|
throw new Error(`Directory already exists: ${dest}
|
|
40796
40798
|
Pass --force to scaffold into it anyway (existing files with the same name are overwritten).`);
|
|
40797
40799
|
}
|
|
40798
|
-
if (inPlace &&
|
|
40800
|
+
if (inPlace && import_node_fs10.default.existsSync(import_node_path8.default.join(dest, ".sail", "config.json")) && !options.force) {
|
|
40799
40801
|
throw new Error(
|
|
40800
40802
|
"This project is already initialized.\nRun `sailor update` to re-sync template files, or `sailor init --force` to re-initialize (overwrites scaffold files; your .sail/keys/ and .sail/state/ are left in place)."
|
|
40801
40803
|
);
|
|
40802
40804
|
}
|
|
40803
40805
|
const existingConfigPath = import_node_path8.default.join(dest, ".sail", "config.json");
|
|
40804
|
-
const previousConfig =
|
|
40806
|
+
const previousConfig = import_node_fs10.default.existsSync(existingConfigPath) ? (() => {
|
|
40805
40807
|
try {
|
|
40806
|
-
return JSON.parse(
|
|
40808
|
+
return JSON.parse(import_node_fs10.default.readFileSync(existingConfigPath, "utf-8"));
|
|
40807
40809
|
} catch {
|
|
40808
40810
|
return null;
|
|
40809
40811
|
}
|
|
@@ -40811,37 +40813,37 @@ Pass --force to scaffold into it anyway (existing files with the same name are o
|
|
|
40811
40813
|
copyDirSync(templateSrc, dest);
|
|
40812
40814
|
const pkgRoot = packageRoot();
|
|
40813
40815
|
const examplesPermSrc = import_node_path8.default.join(pkgRoot, "examples", "permissions");
|
|
40814
|
-
if (
|
|
40816
|
+
if (import_node_fs10.default.existsSync(examplesPermSrc)) {
|
|
40815
40817
|
copyDirSync(examplesPermSrc, import_node_path8.default.join(dest, "examples", "permissions"));
|
|
40816
40818
|
}
|
|
40817
40819
|
const customMandateSrc = import_node_path8.default.join(pkgRoot, "examples", "custom-mandate");
|
|
40818
|
-
if (
|
|
40820
|
+
if (import_node_fs10.default.existsSync(customMandateSrc)) {
|
|
40819
40821
|
copyDirSync(customMandateSrc, import_node_path8.default.join(dest, "examples", "custom-mandate"));
|
|
40820
40822
|
}
|
|
40821
40823
|
const permModelSrc = import_node_path8.default.join(pkgRoot, "docs", "PERMISSION_MODEL.md");
|
|
40822
|
-
if (
|
|
40823
|
-
|
|
40824
|
-
writeIfMissing2(import_node_path8.default.join(dest, "docs", "PERMISSION_MODEL.md"),
|
|
40824
|
+
if (import_node_fs10.default.existsSync(permModelSrc)) {
|
|
40825
|
+
import_node_fs10.default.mkdirSync(import_node_path8.default.join(dest, "docs"), { recursive: true });
|
|
40826
|
+
writeIfMissing2(import_node_path8.default.join(dest, "docs", "PERMISSION_MODEL.md"), import_node_fs10.default.readFileSync(permModelSrc, "utf-8"));
|
|
40825
40827
|
}
|
|
40826
40828
|
const pkgPath = import_node_path8.default.join(dest, "package.json");
|
|
40827
|
-
if (
|
|
40828
|
-
const pkg = JSON.parse(
|
|
40829
|
+
if (import_node_fs10.default.existsSync(pkgPath)) {
|
|
40830
|
+
const pkg = JSON.parse(import_node_fs10.default.readFileSync(pkgPath, "utf-8"));
|
|
40829
40831
|
pkg.name = name;
|
|
40830
40832
|
const devDeps = pkg.devDependencies ?? {};
|
|
40831
40833
|
const { name: cliName, version: cliVer } = cliPackageInfo();
|
|
40832
40834
|
devDeps[CANONICAL_PKG] = cliName === DEV_PKG ? `npm:${DEV_PKG}@^${cliVer}` : `^${cliVer}`;
|
|
40833
40835
|
pkg.devDependencies = devDeps;
|
|
40834
|
-
|
|
40836
|
+
import_node_fs10.default.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
40835
40837
|
`);
|
|
40836
40838
|
}
|
|
40837
40839
|
const tsconfigPath = import_node_path8.default.join(dest, "tsconfig.json");
|
|
40838
|
-
if (
|
|
40839
|
-
const tsconfig = JSON.parse(
|
|
40840
|
+
if (import_node_fs10.default.existsSync(tsconfigPath)) {
|
|
40841
|
+
const tsconfig = JSON.parse(import_node_fs10.default.readFileSync(tsconfigPath, "utf-8"));
|
|
40840
40842
|
const co = tsconfig.compilerOptions;
|
|
40841
40843
|
if (co && "paths" in co) {
|
|
40842
40844
|
delete co.paths;
|
|
40843
40845
|
delete co.baseUrl;
|
|
40844
|
-
|
|
40846
|
+
import_node_fs10.default.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
|
|
40845
40847
|
`);
|
|
40846
40848
|
}
|
|
40847
40849
|
}
|
|
@@ -40879,20 +40881,20 @@ function chainLabel(chainId) {
|
|
|
40879
40881
|
}
|
|
40880
40882
|
function detectState(dest) {
|
|
40881
40883
|
try {
|
|
40882
|
-
const configRaw =
|
|
40884
|
+
const configRaw = import_node_fs10.default.readFileSync(import_node_path8.default.join(dest, ".sail", "config.json"), "utf-8");
|
|
40883
40885
|
const config = JSON.parse(configRaw);
|
|
40884
40886
|
const projectName = config.name ?? import_node_path8.default.basename(dest);
|
|
40885
40887
|
const accountPath = import_node_path8.default.join(dest, ".sail", "account.json");
|
|
40886
|
-
if (!
|
|
40888
|
+
if (!import_node_fs10.default.existsSync(accountPath)) {
|
|
40887
40889
|
return { kind: "B", projectName, chain: chainLabel(config.chainId ?? 0) };
|
|
40888
40890
|
}
|
|
40889
|
-
const accountRaw =
|
|
40891
|
+
const accountRaw = import_node_fs10.default.readFileSync(accountPath, "utf-8");
|
|
40890
40892
|
const account2 = JSON.parse(accountRaw);
|
|
40891
40893
|
const sma = account2.safe ?? "";
|
|
40892
40894
|
const chain2 = chainLabel(account2.chainId ?? config.chainId ?? 0);
|
|
40893
40895
|
let permissionCount = 0;
|
|
40894
40896
|
try {
|
|
40895
|
-
const mandatesRaw =
|
|
40897
|
+
const mandatesRaw = import_node_fs10.default.readFileSync(
|
|
40896
40898
|
import_node_path8.default.join(dest, ".sail", "state", "mandates.json"),
|
|
40897
40899
|
"utf-8"
|
|
40898
40900
|
);
|
|
@@ -40981,7 +40983,7 @@ Created ${name}/`);
|
|
|
40981
40983
|
}
|
|
40982
40984
|
|
|
40983
40985
|
// src/commands/update.ts
|
|
40984
|
-
var
|
|
40986
|
+
var import_node_fs11 = __toESM(require("node:fs"), 1);
|
|
40985
40987
|
var import_node_path9 = __toESM(require("node:path"), 1);
|
|
40986
40988
|
var UPDATE_PATHS = [
|
|
40987
40989
|
".agents",
|
|
@@ -40997,18 +40999,18 @@ var STALE_PATHS = [
|
|
|
40997
40999
|
];
|
|
40998
41000
|
async function updateCommand() {
|
|
40999
41001
|
const dest = process.cwd();
|
|
41000
|
-
if (!
|
|
41002
|
+
if (!import_node_fs11.default.existsSync(import_node_path9.default.join(dest, ".sail", "config.json"))) {
|
|
41001
41003
|
throw new Error("Not a sailor project \u2014 .sail/config.json not found. Run `sailor init` first.");
|
|
41002
41004
|
}
|
|
41003
41005
|
const templateSrc = import_node_path9.default.join(packageRoot(), "templates", "default");
|
|
41004
|
-
if (!
|
|
41006
|
+
if (!import_node_fs11.default.existsSync(templateSrc)) {
|
|
41005
41007
|
throw new Error(`Template directory not found at ${templateSrc}`);
|
|
41006
41008
|
}
|
|
41007
41009
|
const removed = [];
|
|
41008
41010
|
for (const p of STALE_PATHS) {
|
|
41009
41011
|
const target = import_node_path9.default.join(dest, p);
|
|
41010
|
-
if (
|
|
41011
|
-
|
|
41012
|
+
if (import_node_fs11.default.existsSync(target)) {
|
|
41013
|
+
import_node_fs11.default.rmSync(target, { recursive: true, force: true });
|
|
41012
41014
|
removed.push(p);
|
|
41013
41015
|
}
|
|
41014
41016
|
}
|
|
@@ -41016,13 +41018,13 @@ async function updateCommand() {
|
|
|
41016
41018
|
for (const p of UPDATE_PATHS) {
|
|
41017
41019
|
const src = import_node_path9.default.join(templateSrc, p);
|
|
41018
41020
|
const dst = import_node_path9.default.join(dest, p);
|
|
41019
|
-
if (!
|
|
41020
|
-
const stat =
|
|
41021
|
+
if (!import_node_fs11.default.existsSync(src)) continue;
|
|
41022
|
+
const stat = import_node_fs11.default.statSync(src);
|
|
41021
41023
|
if (stat.isDirectory()) {
|
|
41022
41024
|
copyDirSync(src, dst);
|
|
41023
41025
|
} else {
|
|
41024
|
-
|
|
41025
|
-
|
|
41026
|
+
import_node_fs11.default.mkdirSync(import_node_path9.default.dirname(dst), { recursive: true });
|
|
41027
|
+
import_node_fs11.default.copyFileSync(src, dst);
|
|
41026
41028
|
}
|
|
41027
41029
|
updated.push(p);
|
|
41028
41030
|
}
|
|
@@ -41030,7 +41032,7 @@ async function updateCommand() {
|
|
|
41030
41032
|
copyDirSyncIfMissing(templateSrc, dest, added);
|
|
41031
41033
|
const configPath = import_node_path9.default.join(dest, ".sail", "config.json");
|
|
41032
41034
|
try {
|
|
41033
|
-
const config = JSON.parse(
|
|
41035
|
+
const config = JSON.parse(import_node_fs11.default.readFileSync(configPath, "utf-8"));
|
|
41034
41036
|
const newMode = process.env.SAILOR_INSTALL_MODE === "docker" ? "docker" : "local";
|
|
41035
41037
|
const _rawContainerName = process.env.SAILOR_CONTAINER_NAME ?? "agent";
|
|
41036
41038
|
const containerName = /^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(_rawContainerName) ? _rawContainerName : "agent";
|
|
@@ -41043,7 +41045,7 @@ async function updateCommand() {
|
|
|
41043
41045
|
} else {
|
|
41044
41046
|
delete config.containerName;
|
|
41045
41047
|
}
|
|
41046
|
-
|
|
41048
|
+
import_node_fs11.default.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
|
|
41047
41049
|
`, "utf-8");
|
|
41048
41050
|
if (previousMode === "docker" && newMode === "local") {
|
|
41049
41051
|
const prev = previousContainer ?? "agent";
|
|
@@ -41057,7 +41059,7 @@ Switched to Docker install (container: ${containerName}).`);
|
|
|
41057
41059
|
}
|
|
41058
41060
|
} else if (newMode === "docker" && config.containerName !== containerName) {
|
|
41059
41061
|
config.containerName = containerName;
|
|
41060
|
-
|
|
41062
|
+
import_node_fs11.default.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
|
|
41061
41063
|
`, "utf-8");
|
|
41062
41064
|
}
|
|
41063
41065
|
} catch {
|
|
@@ -41086,7 +41088,7 @@ Added (new in template):`);
|
|
|
41086
41088
|
}
|
|
41087
41089
|
|
|
41088
41090
|
// src/commands/keys.ts
|
|
41089
|
-
var
|
|
41091
|
+
var import_node_fs12 = __toESM(require("node:fs"), 1);
|
|
41090
41092
|
var import_node_path10 = __toESM(require("node:path"), 1);
|
|
41091
41093
|
function readStdin() {
|
|
41092
41094
|
return new Promise((resolve3, reject) => {
|
|
@@ -41193,14 +41195,14 @@ async function keysExportCi() {
|
|
|
41193
41195
|
);
|
|
41194
41196
|
}
|
|
41195
41197
|
const dest = import_node_path10.default.resolve(process.cwd(), "ci-keystore.json");
|
|
41196
|
-
|
|
41198
|
+
import_node_fs12.default.copyFileSync(src, dest);
|
|
41197
41199
|
console.log(`\u2713 Keystore copied to ci-keystore.json`);
|
|
41198
41200
|
console.log(` Source: ${src}`);
|
|
41199
41201
|
const gitignorePath = import_node_path10.default.resolve(process.cwd(), ".gitignore");
|
|
41200
|
-
if (
|
|
41201
|
-
const content =
|
|
41202
|
+
if (import_node_fs12.default.existsSync(gitignorePath)) {
|
|
41203
|
+
const content = import_node_fs12.default.readFileSync(gitignorePath, "utf-8");
|
|
41202
41204
|
if (!content.includes("ci-keystore.json")) {
|
|
41203
|
-
|
|
41205
|
+
import_node_fs12.default.appendFileSync(
|
|
41204
41206
|
gitignorePath,
|
|
41205
41207
|
"\n# CI keystore \u2014 encrypted agent wallet, safe to commit\n!ci-keystore.json\n"
|
|
41206
41208
|
);
|
|
@@ -41238,10 +41240,125 @@ async function keysShow() {
|
|
|
41238
41240
|
|
|
41239
41241
|
// src/commands/mandate-contracts.ts
|
|
41240
41242
|
var import_node_child_process = require("node:child_process");
|
|
41241
|
-
var
|
|
41242
|
-
var
|
|
41243
|
+
var import_node_fs14 = require("node:fs");
|
|
41244
|
+
var import_node_path12 = require("node:path");
|
|
41243
41245
|
init_esm2();
|
|
41244
41246
|
|
|
41247
|
+
// src/lib/permission-explainer.ts
|
|
41248
|
+
var import_node_fs13 = require("node:fs");
|
|
41249
|
+
var import_node_path11 = require("node:path");
|
|
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
|
+
}
|
|
41361
|
+
|
|
41245
41362
|
// src/lib/mandates.ts
|
|
41246
41363
|
var MandateStore = class {
|
|
41247
41364
|
filePath;
|
|
@@ -41370,7 +41487,7 @@ Project: ${project.name}`));
|
|
|
41370
41487
|
if (!keyExists("manager")) {
|
|
41371
41488
|
throw new Error('No agent wallet found. Run "sailor keys generate" and choose "agent wallet" first.');
|
|
41372
41489
|
}
|
|
41373
|
-
const agentSigner = await
|
|
41490
|
+
const agentSigner = await loadManagerSigner();
|
|
41374
41491
|
const agentAddress = agentSigner.address;
|
|
41375
41492
|
say(() => console.log("\u2713", `Agent wallet: ${agentAddress}`));
|
|
41376
41493
|
const chain2 = getChainById(project.chainId);
|
|
@@ -41383,7 +41500,7 @@ Project: ${project.name}`));
|
|
|
41383
41500
|
() => console.log(
|
|
41384
41501
|
`
|
|
41385
41502
|
\u2192 Open the Sailor dashboard to approve signing requests:
|
|
41386
|
-
${signingPageUrl(
|
|
41503
|
+
${signingPageUrl(projectPort(process.cwd()))}
|
|
41387
41504
|
`
|
|
41388
41505
|
)
|
|
41389
41506
|
);
|
|
@@ -41706,6 +41823,8 @@ Pushing signing request for "${template.label}" permission\u2026`));
|
|
|
41706
41823
|
` The mandate signer (${permissionSigner}) must sign in the browser \u2014 not the agent wallet.`
|
|
41707
41824
|
)
|
|
41708
41825
|
);
|
|
41826
|
+
const permRecord = new MandateStore().find(templateAddress);
|
|
41827
|
+
const permExplanation = (permRecord ? explainPermission(permRecord.name, permRecord.sourcePath) : explainPermission(template.label)) ?? void 0;
|
|
41709
41828
|
const response = await channel.requestSignature({
|
|
41710
41829
|
type: "typed-data",
|
|
41711
41830
|
kind: "register-permission",
|
|
@@ -41718,6 +41837,7 @@ Pushing signing request for "${template.label}" permission\u2026`));
|
|
|
41718
41837
|
{ label: "Permission", value: template.label },
|
|
41719
41838
|
{ label: "Mandate signer", value: permissionSigner }
|
|
41720
41839
|
],
|
|
41840
|
+
explanation: permExplanation,
|
|
41721
41841
|
typedData
|
|
41722
41842
|
});
|
|
41723
41843
|
if (response.status === "rejected") {
|
|
@@ -41884,7 +42004,7 @@ Mandate command failed: ${msg}`), {
|
|
|
41884
42004
|
process.exit(1);
|
|
41885
42005
|
}
|
|
41886
42006
|
function announceSigningUrl(json) {
|
|
41887
|
-
const url = signingPageUrl(
|
|
42007
|
+
const url = signingPageUrl(projectPort(process.cwd()));
|
|
41888
42008
|
if (json) {
|
|
41889
42009
|
process.stdout.write(`${JSON.stringify({ status: "waiting_for_signature", url })}
|
|
41890
42010
|
`);
|
|
@@ -41932,12 +42052,12 @@ async function runDeploy(project, channel, options) {
|
|
|
41932
42052
|
)
|
|
41933
42053
|
);
|
|
41934
42054
|
}
|
|
41935
|
-
const { abi: abi2, bytecode, contractName, artifactPath } = resolveArtifact(options);
|
|
42055
|
+
const { abi: abi2, bytecode, contractName, artifactPath, sourcePath } = resolveArtifact(options);
|
|
41936
42056
|
let argsJson;
|
|
41937
42057
|
if (options.argsFile) {
|
|
41938
|
-
const argsFilePath = (0,
|
|
42058
|
+
const argsFilePath = (0, import_node_path12.resolve)(options.argsFile);
|
|
41939
42059
|
try {
|
|
41940
|
-
argsJson = (0,
|
|
42060
|
+
argsJson = (0, import_node_fs14.readFileSync)(argsFilePath, "utf8").trim();
|
|
41941
42061
|
} catch {
|
|
41942
42062
|
throw new Error(`Cannot read --args-file: ${argsFilePath}`);
|
|
41943
42063
|
}
|
|
@@ -41950,6 +42070,7 @@ async function runDeploy(project, channel, options) {
|
|
|
41950
42070
|
const publicClient = publicClientFor(project);
|
|
41951
42071
|
announceSigningUrl(json);
|
|
41952
42072
|
say(() => console.log(`Pushing deploy request for "${contractName}"\u2026`));
|
|
42073
|
+
const explanation = explainPermission(contractName, sourcePath) ?? void 0;
|
|
41953
42074
|
const response = await channel.requestSignature({
|
|
41954
42075
|
type: "transaction",
|
|
41955
42076
|
kind: "deploy-mandate",
|
|
@@ -41964,7 +42085,8 @@ async function runDeploy(project, channel, options) {
|
|
|
41964
42085
|
label: options.argsFile ? "Constructor args (from file)" : "Constructor args",
|
|
41965
42086
|
value: argsJson ? argsJson : "(none)"
|
|
41966
42087
|
}
|
|
41967
|
-
]
|
|
42088
|
+
],
|
|
42089
|
+
explanation
|
|
41968
42090
|
});
|
|
41969
42091
|
if (response.status === "rejected") {
|
|
41970
42092
|
throw new Error(`User rejected permission deployment: ${response.reason ?? "no reason given"}`);
|
|
@@ -41984,6 +42106,7 @@ async function runDeploy(project, channel, options) {
|
|
|
41984
42106
|
address: deployed,
|
|
41985
42107
|
txHash: response.txHash,
|
|
41986
42108
|
chainId,
|
|
42109
|
+
sourcePath,
|
|
41987
42110
|
artifactPath,
|
|
41988
42111
|
constructorArgs: parseArgsRaw(options.args),
|
|
41989
42112
|
deployedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -42145,7 +42268,7 @@ async function runDeployClone(project, channel, options) {
|
|
|
42145
42268
|
}
|
|
42146
42269
|
const chain2 = getChainById(project.chainId);
|
|
42147
42270
|
const publicClient = publicClientFor(project);
|
|
42148
|
-
const agentSigner = await
|
|
42271
|
+
const agentSigner = await loadManagerSigner();
|
|
42149
42272
|
const registered = await publicClient.readContract({
|
|
42150
42273
|
address: project.contracts.kernel,
|
|
42151
42274
|
abi: SailKernelAbi,
|
|
@@ -42489,7 +42612,7 @@ Connect the owner wallet (mandate signer) in the browser \u2014 the agent wallet
|
|
|
42489
42612
|
} catch (err) {
|
|
42490
42613
|
if (err.message.startsWith("Security:")) throw err;
|
|
42491
42614
|
}
|
|
42492
|
-
const agentSigner = await
|
|
42615
|
+
const agentSigner = await loadManagerSigner();
|
|
42493
42616
|
const walletClient = createWalletClient({
|
|
42494
42617
|
account: agentSigner.viemAccount,
|
|
42495
42618
|
chain: getChainById(project.chainId),
|
|
@@ -42531,7 +42654,7 @@ async function attachToSma(project, channel, publicClient, sma, mandate2, label,
|
|
|
42531
42654
|
const say = (fn) => {
|
|
42532
42655
|
if (!json) fn();
|
|
42533
42656
|
};
|
|
42534
|
-
const agentSigner = await
|
|
42657
|
+
const agentSigner = await loadManagerSigner();
|
|
42535
42658
|
const registered = await publicClient.readContract({
|
|
42536
42659
|
address: project.contracts.kernel,
|
|
42537
42660
|
abi: SailKernelAbi,
|
|
@@ -42572,7 +42695,7 @@ async function attachBatchToSma(project, channel, publicClient, sma, permissions
|
|
|
42572
42695
|
const say = (fn) => {
|
|
42573
42696
|
if (!json) fn();
|
|
42574
42697
|
};
|
|
42575
|
-
const agentSigner = await
|
|
42698
|
+
const agentSigner = await loadManagerSigner();
|
|
42576
42699
|
const registered = await publicClient.readContract({
|
|
42577
42700
|
address: project.contracts.kernel,
|
|
42578
42701
|
abi: SailKernelAbi,
|
|
@@ -42618,6 +42741,15 @@ async function attachBatchToSma(project, channel, publicClient, sma, permissions
|
|
|
42618
42741
|
Attaching ${permissions.length} permissions in one signature \u2014 the mandate signer (${permissionSigner}) signs in the browser\u2026`
|
|
42619
42742
|
)
|
|
42620
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
|
+
});
|
|
42621
42753
|
const response = await channel.requestSignature({
|
|
42622
42754
|
type: "typed-data",
|
|
42623
42755
|
kind: "register-permission",
|
|
@@ -42629,6 +42761,7 @@ Attaching ${permissions.length} permissions in one signature \u2014 the mandate
|
|
|
42629
42761
|
{ label: "Permissions", value: String(permissions.length) },
|
|
42630
42762
|
{ label: "Mandate signer", value: permissionSigner }
|
|
42631
42763
|
],
|
|
42764
|
+
permissions: permExplanations,
|
|
42632
42765
|
typedData
|
|
42633
42766
|
});
|
|
42634
42767
|
if (response.status === "rejected") {
|
|
@@ -42776,11 +42909,11 @@ function resolveArtifact(options) {
|
|
|
42776
42909
|
let contractName = options.contract ?? options.name ?? "";
|
|
42777
42910
|
if (!artifactPath) {
|
|
42778
42911
|
if (!options.contract) throw new Error("Provide --artifact <path> or --contract <name>");
|
|
42779
|
-
artifactPath = (0,
|
|
42912
|
+
artifactPath = (0, import_node_path12.join)(options.out, `${options.contract}.sol`, `${options.contract}.json`);
|
|
42780
42913
|
}
|
|
42781
|
-
const resolved = (0,
|
|
42782
|
-
const projectRoot = (0,
|
|
42783
|
-
if (!resolved.startsWith(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) {
|
|
42784
42917
|
throw new Error(
|
|
42785
42918
|
`Artifact path must be inside the project directory.
|
|
42786
42919
|
Resolved: ${resolved}`
|
|
@@ -42788,14 +42921,14 @@ Resolved: ${resolved}`
|
|
|
42788
42921
|
}
|
|
42789
42922
|
artifactPath = resolved;
|
|
42790
42923
|
if (options.build) runForgeBuild();
|
|
42791
|
-
if (!(0,
|
|
42924
|
+
if (!(0, import_node_fs14.existsSync)(artifactPath)) {
|
|
42792
42925
|
ensureForgeHint();
|
|
42793
42926
|
throw new Error(
|
|
42794
42927
|
`Artifact not found: ${artifactPath}
|
|
42795
42928
|
Compile your mandate first (e.g. \`forge build\`), or pass --build.`
|
|
42796
42929
|
);
|
|
42797
42930
|
}
|
|
42798
|
-
const artifact = JSON.parse((0,
|
|
42931
|
+
const artifact = JSON.parse((0, import_node_fs14.readFileSync)(artifactPath, "utf8"));
|
|
42799
42932
|
const abi2 = artifact.abi;
|
|
42800
42933
|
const bytecodeRaw = artifact.bytecode?.object ?? artifact.bytecode;
|
|
42801
42934
|
if (!bytecodeRaw || typeof bytecodeRaw !== "string") {
|
|
@@ -42806,7 +42939,16 @@ Compile your mandate first (e.g. \`forge build\`), or pass --build.`
|
|
|
42806
42939
|
const m = artifactPath.match(/([^/\\]+)\.json$/);
|
|
42807
42940
|
contractName = m ? m[1] : "Mandate";
|
|
42808
42941
|
}
|
|
42809
|
-
|
|
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 };
|
|
42810
42952
|
}
|
|
42811
42953
|
function parseArgsRaw(argsJson) {
|
|
42812
42954
|
if (!argsJson) return void 0;
|
|
@@ -42876,88 +43018,6 @@ function runForgeBuild() {
|
|
|
42876
43018
|
|
|
42877
43019
|
// src/commands/mandate.ts
|
|
42878
43020
|
init_esm2();
|
|
42879
|
-
|
|
42880
|
-
// src/lib/permission-explainer.ts
|
|
42881
|
-
var import_node_fs13 = require("node:fs");
|
|
42882
|
-
var import_node_path12 = require("node:path");
|
|
42883
|
-
function explainPermission(name, sourcePath) {
|
|
42884
|
-
const resolved = sourcePath ?? (0, import_node_path12.join)(process.cwd(), "mandates", `${name}.sol`);
|
|
42885
|
-
let src;
|
|
42886
|
-
try {
|
|
42887
|
-
src = (0, import_node_fs13.readFileSync)(resolved, "utf8");
|
|
42888
|
-
} catch {
|
|
42889
|
-
return null;
|
|
42890
|
-
}
|
|
42891
|
-
return parseStructured(src) ?? parseNatSpec(src) ?? parseRequires(src);
|
|
42892
|
-
}
|
|
42893
|
-
function parseStructured(src) {
|
|
42894
|
-
if (!src.includes("ENFORCED ON-CHAIN")) return null;
|
|
42895
|
-
const lines = src.split("\n");
|
|
42896
|
-
const result = {
|
|
42897
|
-
source: "structured",
|
|
42898
|
-
enforced: [],
|
|
42899
|
-
notEnforced: []
|
|
42900
|
-
};
|
|
42901
|
-
const headerLines = [];
|
|
42902
|
-
for (const line of lines) {
|
|
42903
|
-
const t = line.trim();
|
|
42904
|
-
if (t.startsWith("import ") || t.startsWith("contract ") || t.startsWith("abstract contract ")) break;
|
|
42905
|
-
if (t.startsWith("//")) headerLines.push(t.slice(2));
|
|
42906
|
-
}
|
|
42907
|
-
let section = null;
|
|
42908
|
-
for (const raw of headerLines) {
|
|
42909
|
-
const trimmed = raw.trim();
|
|
42910
|
-
if (/^─+$/.test(trimmed)) continue;
|
|
42911
|
-
if (trimmed.includes("ENFORCED ON-CHAIN")) {
|
|
42912
|
-
section = "enforced";
|
|
42913
|
-
continue;
|
|
42914
|
-
}
|
|
42915
|
-
if (trimmed.includes("NOT ENFORCED")) {
|
|
42916
|
-
section = "notEnforced";
|
|
42917
|
-
continue;
|
|
42918
|
-
}
|
|
42919
|
-
if (trimmed.includes("VERIFY BEFORE USE")) {
|
|
42920
|
-
section = null;
|
|
42921
|
-
continue;
|
|
42922
|
-
}
|
|
42923
|
-
if (section === null) {
|
|
42924
|
-
const kv = trimmed.match(/^(Protocol|Version|Chain|Target)\s*:\s*(.+)$/i);
|
|
42925
|
-
if (kv) {
|
|
42926
|
-
const key = kv[1].toLowerCase();
|
|
42927
|
-
result[key] = kv[2].trim();
|
|
42928
|
-
}
|
|
42929
|
-
}
|
|
42930
|
-
if (section && trimmed.startsWith("\u2022")) {
|
|
42931
|
-
const bullet = trimmed.slice(1).trim();
|
|
42932
|
-
if (bullet) result[section].push(bullet);
|
|
42933
|
-
}
|
|
42934
|
-
}
|
|
42935
|
-
if (result.enforced.length === 0 && !result.protocol) return null;
|
|
42936
|
-
return result;
|
|
42937
|
-
}
|
|
42938
|
-
function parseNatSpec(src) {
|
|
42939
|
-
const enforced = [];
|
|
42940
|
-
const notEnforced = [];
|
|
42941
|
-
for (const line of src.split("\n")) {
|
|
42942
|
-
const t = line.trim();
|
|
42943
|
-
const notice = t.match(/^\/\/\/\s*@notice\s+(.+)$/);
|
|
42944
|
-
if (notice) enforced.push(notice[1].trim());
|
|
42945
|
-
const dev = t.match(/^\/\/\/\s*@dev\s+(.+)$/);
|
|
42946
|
-
if (dev) notEnforced.push(dev[1].trim());
|
|
42947
|
-
}
|
|
42948
|
-
if (enforced.length === 0 && notEnforced.length === 0) return null;
|
|
42949
|
-
return { source: "natspec", enforced, notEnforced };
|
|
42950
|
-
}
|
|
42951
|
-
function parseRequires(src) {
|
|
42952
|
-
const enforced = [];
|
|
42953
|
-
const re = /require\s*\([^,)]+,\s*["']([^"']+)["']\)/g;
|
|
42954
|
-
let m;
|
|
42955
|
-
while ((m = re.exec(src)) !== null) enforced.push(m[1]);
|
|
42956
|
-
if (enforced.length === 0) return null;
|
|
42957
|
-
return { source: "require-only", enforced, notEnforced: [] };
|
|
42958
|
-
}
|
|
42959
|
-
|
|
42960
|
-
// src/commands/mandate.ts
|
|
42961
43021
|
function resolveActiveChain(account2) {
|
|
42962
43022
|
try {
|
|
42963
43023
|
const project = new ProjectContext();
|
|
@@ -43033,7 +43093,9 @@ ${permissions.length} permission(s) tracked for SMA ${account2.safe}:
|
|
|
43033
43093
|
const draft = {
|
|
43034
43094
|
account: account2.safe,
|
|
43035
43095
|
chainId,
|
|
43036
|
-
|
|
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) => {
|
|
43037
43099
|
const mandate2 = store.find(p.address);
|
|
43038
43100
|
const explanation = explainPermission(p.label, mandate2?.sourcePath) ?? void 0;
|
|
43039
43101
|
return { address: p.address, label: p.label, explanation };
|
|
@@ -43106,7 +43168,7 @@ ${unregistered.length} permission(s) are not yet registered on this SMA. Initiat
|
|
|
43106
43168
|
}
|
|
43107
43169
|
|
|
43108
43170
|
// src/commands/mandate-simulate.ts
|
|
43109
|
-
var
|
|
43171
|
+
var import_node_fs15 = require("node:fs");
|
|
43110
43172
|
init_esm2();
|
|
43111
43173
|
function parseExpect(raw, where) {
|
|
43112
43174
|
if (raw === void 0) return void 0;
|
|
@@ -43122,7 +43184,7 @@ function resolveSampleCalls(options) {
|
|
|
43122
43184
|
if (options.calls) {
|
|
43123
43185
|
let raw;
|
|
43124
43186
|
try {
|
|
43125
|
-
raw = JSON.parse((0,
|
|
43187
|
+
raw = JSON.parse((0, import_node_fs15.readFileSync)(options.calls, "utf8"));
|
|
43126
43188
|
} catch (err) {
|
|
43127
43189
|
throw new Error(`Could not read --calls file "${options.calls}": ${err.message}`);
|
|
43128
43190
|
}
|
|
@@ -43338,7 +43400,7 @@ async function mandateSimulate(options) {
|
|
|
43338
43400
|
}
|
|
43339
43401
|
|
|
43340
43402
|
// src/commands/rotate-signer.ts
|
|
43341
|
-
var
|
|
43403
|
+
var import_node_fs16 = require("node:fs");
|
|
43342
43404
|
init_esm2();
|
|
43343
43405
|
var PENDING_REATTACH_FILE = ["state", "pending-reattach.json"];
|
|
43344
43406
|
async function rotateSigner(options) {
|
|
@@ -43468,7 +43530,7 @@ SMA: ${smaAddress}`);
|
|
|
43468
43530
|
console.log(
|
|
43469
43531
|
`
|
|
43470
43532
|
\u2192 Open the Sailor dashboard to approve signing requests:
|
|
43471
|
-
${signingPageUrl(
|
|
43533
|
+
${signingPageUrl(projectPort(process.cwd()))}
|
|
43472
43534
|
`
|
|
43473
43535
|
);
|
|
43474
43536
|
});
|
|
@@ -43726,7 +43788,7 @@ ensure the agent that signs dispatches holds this key.`
|
|
|
43726
43788
|
const keystore = await keyring.exportKeystore(password);
|
|
43727
43789
|
writeJsonFile(target, keystore, 384);
|
|
43728
43790
|
const perManagerPath = managerKeystorePath(keyring.address);
|
|
43729
|
-
(0,
|
|
43791
|
+
(0, import_node_fs16.mkdirSync)(sailPath("keys", "managers"), { recursive: true });
|
|
43730
43792
|
writeJsonFile(perManagerPath, keystore, 384);
|
|
43731
43793
|
say(
|
|
43732
43794
|
() => console.log(
|
|
@@ -43738,7 +43800,7 @@ ensure the agent that signs dispatches holds this key.`
|
|
|
43738
43800
|
function promoteManagerKeystore(newManager, say) {
|
|
43739
43801
|
const stored = readJsonFile(managerKeystorePath(newManager));
|
|
43740
43802
|
if (!stored) return;
|
|
43741
|
-
(0,
|
|
43803
|
+
(0, import_node_fs16.mkdirSync)(sailPath("keys", "managers"), { recursive: true });
|
|
43742
43804
|
const activeTarget = keyPath("manager");
|
|
43743
43805
|
const displaced = readJsonFile(activeTarget);
|
|
43744
43806
|
if (displaced?.address) {
|
|
@@ -43790,7 +43852,7 @@ function writePending(pending) {
|
|
|
43790
43852
|
}
|
|
43791
43853
|
function clearPending() {
|
|
43792
43854
|
try {
|
|
43793
|
-
(0,
|
|
43855
|
+
(0, import_node_fs16.rmSync)(sailPath(...PENDING_REATTACH_FILE), { force: true });
|
|
43794
43856
|
} catch {
|
|
43795
43857
|
}
|
|
43796
43858
|
}
|
|
@@ -43844,7 +43906,7 @@ async function ownerConnect(options) {
|
|
|
43844
43906
|
await channel.start();
|
|
43845
43907
|
if (!options.json) {
|
|
43846
43908
|
console.log("\u2192 Open the Sailor dashboard and connect your wallet:");
|
|
43847
|
-
console.log(` ${signingPageUrl(
|
|
43909
|
+
console.log(` ${signingPageUrl(projectPort(projectRoot))}`);
|
|
43848
43910
|
if (channel.remote) console.log(" (using the running signing station)");
|
|
43849
43911
|
console.log("\nWaiting for a wallet connection\u2026");
|
|
43850
43912
|
}
|
|
@@ -43893,41 +43955,6 @@ var import_node_fs17 = __toESM(require("node:fs"), 1);
|
|
|
43893
43955
|
var import_node_path13 = __toESM(require("node:path"), 1);
|
|
43894
43956
|
var import_node_url = require("node:url");
|
|
43895
43957
|
init_esm2();
|
|
43896
|
-
|
|
43897
|
-
// src/lib/process.ts
|
|
43898
|
-
var import_node_fs16 = __toESM(require("node:fs"), 1);
|
|
43899
|
-
function agentPidPath(chainId) {
|
|
43900
|
-
return chainId != null ? sailPath(`agent-${chainId}.pid`) : sailPath("agent.pid");
|
|
43901
|
-
}
|
|
43902
|
-
function writeAgentPid(chainId) {
|
|
43903
|
-
import_node_fs16.default.mkdirSync(sailPath(), { recursive: true });
|
|
43904
|
-
import_node_fs16.default.writeFileSync(agentPidPath(chainId), `${process.pid}
|
|
43905
|
-
`);
|
|
43906
|
-
}
|
|
43907
|
-
function clearAgentPid(chainId) {
|
|
43908
|
-
try {
|
|
43909
|
-
import_node_fs16.default.rmSync(agentPidPath(chainId));
|
|
43910
|
-
} catch {
|
|
43911
|
-
}
|
|
43912
|
-
}
|
|
43913
|
-
function readAgentPid(chainId) {
|
|
43914
|
-
try {
|
|
43915
|
-
const pid = Number.parseInt(import_node_fs16.default.readFileSync(agentPidPath(chainId), "utf-8").trim(), 10);
|
|
43916
|
-
return Number.isNaN(pid) ? null : pid;
|
|
43917
|
-
} catch {
|
|
43918
|
-
return null;
|
|
43919
|
-
}
|
|
43920
|
-
}
|
|
43921
|
-
function isProcessAlive(pid) {
|
|
43922
|
-
try {
|
|
43923
|
-
process.kill(pid, 0);
|
|
43924
|
-
return true;
|
|
43925
|
-
} catch {
|
|
43926
|
-
return false;
|
|
43927
|
-
}
|
|
43928
|
-
}
|
|
43929
|
-
|
|
43930
|
-
// src/commands/run.ts
|
|
43931
43958
|
var DEFAULT_INTERVAL_SEC = 60;
|
|
43932
43959
|
var sleep2 = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
43933
43960
|
var ERC20_READ_ABI = [
|
|
@@ -44972,7 +44999,7 @@ function requireAccount() {
|
|
|
44972
44999
|
}
|
|
44973
45000
|
return account2;
|
|
44974
45001
|
}
|
|
44975
|
-
async function sessionPause() {
|
|
45002
|
+
async function sessionPause(opts = {}) {
|
|
44976
45003
|
const account2 = requireAccount();
|
|
44977
45004
|
const signer = await loadAnySigner();
|
|
44978
45005
|
const client = makeClient(account2.chainId);
|
|
@@ -44987,9 +45014,10 @@ async function sessionPause() {
|
|
|
44987
45014
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
44988
45015
|
};
|
|
44989
45016
|
writeJsonFile(sailPath("session.json"), session2);
|
|
44990
|
-
console.log(
|
|
45017
|
+
if (opts.json) console.log(JSON.stringify(session2));
|
|
45018
|
+
else console.log("Session paused \u2014 agent dispatch rights revoked.");
|
|
44991
45019
|
}
|
|
44992
|
-
async function sessionResume() {
|
|
45020
|
+
async function sessionResume(opts = {}) {
|
|
44993
45021
|
const account2 = requireAccount();
|
|
44994
45022
|
const signer = await loadAnySigner();
|
|
44995
45023
|
const client = makeClient(account2.chainId);
|
|
@@ -45004,7 +45032,8 @@ async function sessionResume() {
|
|
|
45004
45032
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
45005
45033
|
};
|
|
45006
45034
|
writeJsonFile(sailPath("session.json"), session2);
|
|
45007
|
-
console.log(
|
|
45035
|
+
if (opts.json) console.log(JSON.stringify(session2));
|
|
45036
|
+
else console.log("Session resumed \u2014 agent dispatch rights restored.");
|
|
45008
45037
|
}
|
|
45009
45038
|
|
|
45010
45039
|
// src/commands/station.ts
|
|
@@ -45122,7 +45151,11 @@ async function status() {
|
|
|
45122
45151
|
const hasManager = keyExists("manager");
|
|
45123
45152
|
const hasPermissionSigner = keyExists("permissionSigner");
|
|
45124
45153
|
const account2 = readJsonFile(sailPath("account.json"));
|
|
45125
|
-
const
|
|
45154
|
+
const mandateRaw = readJsonFile(sailPath("mandate.json"));
|
|
45155
|
+
const mandates = (Array.isArray(mandateRaw) ? mandateRaw : mandateRaw ? [mandateRaw] : []).filter(
|
|
45156
|
+
Boolean
|
|
45157
|
+
);
|
|
45158
|
+
const hasMandate = mandates.length > 0;
|
|
45126
45159
|
const session2 = readJsonFile(sailPath("session.json"));
|
|
45127
45160
|
console.log("Sailor status");
|
|
45128
45161
|
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
@@ -45138,9 +45171,12 @@ async function status() {
|
|
|
45138
45171
|
console.log(' \u2717 not deployed run "sailor onboard --new-sma"');
|
|
45139
45172
|
}
|
|
45140
45173
|
console.log("Mandate:");
|
|
45141
|
-
if (
|
|
45142
|
-
const n =
|
|
45143
|
-
|
|
45174
|
+
if (hasMandate) {
|
|
45175
|
+
const n = mandates.reduce((sum, m) => sum + (m?.permissions?.length ?? 0), 0);
|
|
45176
|
+
const permLabel = `${n} permission${n === 1 ? "" : "s"}`;
|
|
45177
|
+
console.log(
|
|
45178
|
+
mandates.length > 1 ? ` \u2713 signed ${mandates.length} mandates, ${permLabel}` : ` \u2713 signed ${permLabel}`
|
|
45179
|
+
);
|
|
45144
45180
|
} else {
|
|
45145
45181
|
console.log(' \u2717 not signed run "sailor mandate sign"');
|
|
45146
45182
|
}
|
|
@@ -45150,7 +45186,7 @@ async function status() {
|
|
|
45150
45186
|
let agentState;
|
|
45151
45187
|
if (running) {
|
|
45152
45188
|
agentState = `running (PID ${pid})`;
|
|
45153
|
-
} else if (!
|
|
45189
|
+
} else if (!hasMandate) {
|
|
45154
45190
|
agentState = "not configured";
|
|
45155
45191
|
} else if (session2 && session2.active === false) {
|
|
45156
45192
|
agentState = "stopped (session paused)";
|
|
@@ -45161,10 +45197,55 @@ async function status() {
|
|
|
45161
45197
|
}
|
|
45162
45198
|
|
|
45163
45199
|
// src/commands/ui.ts
|
|
45164
|
-
var
|
|
45200
|
+
var import_node_child_process5 = require("node:child_process");
|
|
45165
45201
|
var import_node_fs20 = __toESM(require("node:fs"), 1);
|
|
45166
45202
|
var import_node_net2 = __toESM(require("node:net"), 1);
|
|
45167
45203
|
var import_node_path16 = __toESM(require("node:path"), 1);
|
|
45204
|
+
|
|
45205
|
+
// src/lib/tailscale.ts
|
|
45206
|
+
var import_node_child_process4 = require("node:child_process");
|
|
45207
|
+
function tailscaleAvailable() {
|
|
45208
|
+
try {
|
|
45209
|
+
return (0, import_node_child_process4.spawnSync)("tailscale", ["version"], { stdio: "ignore" }).status === 0;
|
|
45210
|
+
} catch {
|
|
45211
|
+
return false;
|
|
45212
|
+
}
|
|
45213
|
+
}
|
|
45214
|
+
function tailnetDnsName() {
|
|
45215
|
+
const r = (0, import_node_child_process4.spawnSync)("tailscale", ["status", "--json"], { encoding: "utf-8" });
|
|
45216
|
+
if (r.status !== 0 || !r.stdout) return null;
|
|
45217
|
+
try {
|
|
45218
|
+
const j = JSON.parse(r.stdout);
|
|
45219
|
+
if (j.BackendState && j.BackendState !== "Running") return null;
|
|
45220
|
+
const dns = j.Self?.DNSName;
|
|
45221
|
+
if (typeof dns !== "string" || dns.length === 0) return null;
|
|
45222
|
+
return dns.replace(/\.$/, "");
|
|
45223
|
+
} catch {
|
|
45224
|
+
return null;
|
|
45225
|
+
}
|
|
45226
|
+
}
|
|
45227
|
+
function tailscaleServeUp(port) {
|
|
45228
|
+
const r = (0, import_node_child_process4.spawnSync)(
|
|
45229
|
+
"tailscale",
|
|
45230
|
+
["serve", "--bg", "--https=443", `http://127.0.0.1:${port}`],
|
|
45231
|
+
{ encoding: "utf-8" }
|
|
45232
|
+
);
|
|
45233
|
+
const out = `${r.stdout ?? ""}${r.stderr ?? ""}`;
|
|
45234
|
+
if (r.status !== 0) {
|
|
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());
|
|
45239
|
+
}
|
|
45240
|
+
}
|
|
45241
|
+
function tailscaleServeDown() {
|
|
45242
|
+
try {
|
|
45243
|
+
(0, import_node_child_process4.spawnSync)("tailscale", ["serve", "--https=443", "off"], { stdio: "ignore" });
|
|
45244
|
+
} catch {
|
|
45245
|
+
}
|
|
45246
|
+
}
|
|
45247
|
+
|
|
45248
|
+
// src/commands/ui.ts
|
|
45168
45249
|
var UI_STATE_FILE = import_node_path16.default.join(".sail", "runtime", "ui.json");
|
|
45169
45250
|
function readState2(projectRoot) {
|
|
45170
45251
|
const file = import_node_path16.default.join(projectRoot, UI_STATE_FILE);
|
|
@@ -45175,21 +45256,33 @@ function readState2(projectRoot) {
|
|
|
45175
45256
|
return null;
|
|
45176
45257
|
}
|
|
45177
45258
|
}
|
|
45178
|
-
function
|
|
45259
|
+
function installedCliVersion() {
|
|
45179
45260
|
try {
|
|
45180
|
-
|
|
45181
|
-
|
|
45261
|
+
const pkg = JSON.parse(
|
|
45262
|
+
import_node_fs20.default.readFileSync(import_node_path16.default.join(packageRoot(), "package.json"), "utf-8")
|
|
45263
|
+
);
|
|
45264
|
+
return pkg.version ?? null;
|
|
45182
45265
|
} catch {
|
|
45183
|
-
return
|
|
45266
|
+
return null;
|
|
45184
45267
|
}
|
|
45185
45268
|
}
|
|
45186
|
-
function
|
|
45187
|
-
|
|
45188
|
-
|
|
45189
|
-
|
|
45190
|
-
|
|
45191
|
-
|
|
45192
|
-
|
|
45269
|
+
async function warnIfVersionSkew(port) {
|
|
45270
|
+
const cli = installedCliVersion();
|
|
45271
|
+
if (!cli) return;
|
|
45272
|
+
try {
|
|
45273
|
+
const res = await fetch(`http://127.0.0.1:${port}/api/version`, {
|
|
45274
|
+
signal: AbortSignal.timeout(500)
|
|
45275
|
+
});
|
|
45276
|
+
if (!res.ok) return;
|
|
45277
|
+
const { running } = await res.json();
|
|
45278
|
+
if (running && running !== cli) {
|
|
45279
|
+
console.warn(
|
|
45280
|
+
`\u26A0 Version skew: the running dashboard is v${running}, but the installed CLI is v${cli}.
|
|
45281
|
+
Restart it to load the new version: sailor ui stop && sailor ui start`
|
|
45282
|
+
);
|
|
45283
|
+
}
|
|
45284
|
+
} catch {
|
|
45285
|
+
}
|
|
45193
45286
|
}
|
|
45194
45287
|
function waitForPort(port, timeoutMs) {
|
|
45195
45288
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -45209,7 +45302,7 @@ function waitForPort(port, timeoutMs) {
|
|
|
45209
45302
|
attempt();
|
|
45210
45303
|
});
|
|
45211
45304
|
}
|
|
45212
|
-
async function uiCommand() {
|
|
45305
|
+
async function uiCommand(opts = {}) {
|
|
45213
45306
|
const distDir = cliDistDir();
|
|
45214
45307
|
const uiDistDir = import_node_path16.default.join(packageRoot(), "packages", "ui", "dist");
|
|
45215
45308
|
const serverBundle = import_node_path16.default.resolve(distDir, "server.cjs");
|
|
@@ -45223,19 +45316,49 @@ async function uiCommand() {
|
|
|
45223
45316
|
if (!import_node_fs20.default.existsSync(import_node_path16.default.join(uiDistDir, "index.html"))) {
|
|
45224
45317
|
throw new Error(`UI dist not found at ${uiDistDir}. Re-run the sailor build.`);
|
|
45225
45318
|
}
|
|
45319
|
+
let tailnetUrl = null;
|
|
45320
|
+
if (opts.expose) {
|
|
45321
|
+
if (opts.expose !== "tailscale") {
|
|
45322
|
+
throw new Error(`Unknown --expose mode "${opts.expose}". Supported: tailscale.`);
|
|
45323
|
+
}
|
|
45324
|
+
if (!tailscaleAvailable()) {
|
|
45325
|
+
throw new Error(
|
|
45326
|
+
"tailscale CLI not found. Install Tailscale and run `tailscale up`, or start the dashboard without --expose to keep it local-only."
|
|
45327
|
+
);
|
|
45328
|
+
}
|
|
45329
|
+
const dns = tailnetDnsName();
|
|
45330
|
+
if (!dns) {
|
|
45331
|
+
throw new Error(
|
|
45332
|
+
"Could not resolve this node's tailnet name. Is tailscale running and logged in? Run `tailscale status` to check."
|
|
45333
|
+
);
|
|
45334
|
+
}
|
|
45335
|
+
tailnetUrl = `https://${dns}`;
|
|
45336
|
+
}
|
|
45226
45337
|
const existing = readState2(projectRoot);
|
|
45227
|
-
if (existing &&
|
|
45338
|
+
if (existing && isProcessAlive(existing.pid)) {
|
|
45228
45339
|
console.log(`Sailor UI is already running (pid ${existing.pid}) at http://localhost:${existing.port}`);
|
|
45340
|
+
if (opts.expose) {
|
|
45341
|
+
console.log("To expose it on the tailnet, stop it first: sailor ui stop && sailor ui start --expose tailscale");
|
|
45342
|
+
}
|
|
45343
|
+
await warnIfVersionSkew(existing.port);
|
|
45229
45344
|
return;
|
|
45230
45345
|
}
|
|
45231
45346
|
const runtimeDir = import_node_path16.default.join(projectRoot, ".sail", "runtime");
|
|
45232
45347
|
import_node_fs20.default.mkdirSync(runtimeDir, { recursive: true });
|
|
45233
45348
|
const logFile = import_node_path16.default.join(runtimeDir, "ui.log");
|
|
45234
45349
|
const logFd = import_node_fs20.default.openSync(logFile, "a");
|
|
45235
|
-
const
|
|
45350
|
+
const corsOrigins = [process.env.SAILOR_CORS_ORIGINS, tailnetUrl].filter(Boolean).join(",");
|
|
45351
|
+
const child = (0, import_node_child_process5.spawn)(process.execPath, [serverBundle], {
|
|
45236
45352
|
detached: true,
|
|
45237
45353
|
stdio: ["ignore", logFd, logFd],
|
|
45238
|
-
env: {
|
|
45354
|
+
env: {
|
|
45355
|
+
...process.env,
|
|
45356
|
+
SAIL_DIR: sailDir2,
|
|
45357
|
+
SERVE_DIST: "1",
|
|
45358
|
+
PORT: String(port),
|
|
45359
|
+
SAILOR_UI_DIST: uiDistDir,
|
|
45360
|
+
...corsOrigins ? { SAILOR_CORS_ORIGINS: corsOrigins } : {}
|
|
45361
|
+
}
|
|
45239
45362
|
});
|
|
45240
45363
|
child.unref();
|
|
45241
45364
|
import_node_fs20.default.closeSync(logFd);
|
|
@@ -45243,7 +45366,7 @@ async function uiCommand() {
|
|
|
45243
45366
|
const deadline = Date.now() + READY_TIMEOUT_MS;
|
|
45244
45367
|
let ready = false;
|
|
45245
45368
|
while (Date.now() < deadline) {
|
|
45246
|
-
if (!
|
|
45369
|
+
if (!isProcessAlive(child.pid)) break;
|
|
45247
45370
|
if (await waitForPort(port, 500)) {
|
|
45248
45371
|
ready = true;
|
|
45249
45372
|
break;
|
|
@@ -45262,17 +45385,31 @@ Server output:
|
|
|
45262
45385
|
${tail}` : ` See ${import_node_path16.default.relative(projectRoot, logFile)}.`)
|
|
45263
45386
|
);
|
|
45264
45387
|
}
|
|
45388
|
+
let exposed = false;
|
|
45389
|
+
if (tailnetUrl) {
|
|
45390
|
+
try {
|
|
45391
|
+
tailscaleServeUp(port);
|
|
45392
|
+
exposed = true;
|
|
45393
|
+
} catch (err) {
|
|
45394
|
+
console.warn(
|
|
45395
|
+
`\u26A0 Could not expose on the tailnet: ${err.message}
|
|
45396
|
+
The dashboard is still running locally.`
|
|
45397
|
+
);
|
|
45398
|
+
}
|
|
45399
|
+
}
|
|
45265
45400
|
import_node_fs20.default.writeFileSync(
|
|
45266
45401
|
import_node_path16.default.join(projectRoot, UI_STATE_FILE),
|
|
45267
|
-
JSON.stringify({ pid: child.pid, port, startedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)
|
|
45402
|
+
JSON.stringify({ pid: child.pid, port, startedAt: (/* @__PURE__ */ new Date()).toISOString(), exposed }, null, 2)
|
|
45268
45403
|
);
|
|
45269
45404
|
console.log(`Sailor UI started at http://localhost:${port} (pid ${child.pid})`);
|
|
45405
|
+
if (exposed) console.log(`Exposed on your tailnet at ${tailnetUrl}/`);
|
|
45270
45406
|
console.log(`Stop it with: sailor ui stop`);
|
|
45271
45407
|
}
|
|
45272
|
-
function uiStatus() {
|
|
45408
|
+
async function uiStatus() {
|
|
45273
45409
|
const state = readState2(process.cwd());
|
|
45274
|
-
if (state &&
|
|
45410
|
+
if (state && isProcessAlive(state.pid)) {
|
|
45275
45411
|
console.log(`\u25CF running http://localhost:${state.port} (pid ${state.pid})`);
|
|
45412
|
+
await warnIfVersionSkew(state.port);
|
|
45276
45413
|
} else {
|
|
45277
45414
|
if (state) import_node_fs20.default.rmSync(import_node_path16.default.join(process.cwd(), UI_STATE_FILE), { force: true });
|
|
45278
45415
|
console.log("\u25CB Sailor UI is not running");
|
|
@@ -45285,12 +45422,16 @@ function uiStop() {
|
|
|
45285
45422
|
console.log("Sailor UI is not running.");
|
|
45286
45423
|
return;
|
|
45287
45424
|
}
|
|
45288
|
-
if (!
|
|
45425
|
+
if (!isProcessAlive(state.pid)) {
|
|
45289
45426
|
import_node_fs20.default.rmSync(import_node_path16.default.join(projectRoot, UI_STATE_FILE), { force: true });
|
|
45290
45427
|
console.log("Sailor UI is not running (stale state file removed).");
|
|
45291
45428
|
return;
|
|
45292
45429
|
}
|
|
45293
45430
|
process.kill(state.pid, "SIGTERM");
|
|
45431
|
+
if (state.exposed) {
|
|
45432
|
+
tailscaleServeDown();
|
|
45433
|
+
console.log("Tailnet exposure removed.");
|
|
45434
|
+
}
|
|
45294
45435
|
import_node_fs20.default.rmSync(import_node_path16.default.join(projectRoot, UI_STATE_FILE), { force: true });
|
|
45295
45436
|
console.log(`Stopped Sailor UI (pid ${state.pid}).`);
|
|
45296
45437
|
}
|
|
@@ -45342,7 +45483,7 @@ program2.command("init [dir]").description("Scaffold a new Sail agent into the c
|
|
|
45342
45483
|
);
|
|
45343
45484
|
program2.command("update").description("Re-sync agent tooling files (skills, AGENTS.md, Dockerfile) from the latest template").action(action(updateCommand));
|
|
45344
45485
|
var ui = program2.command("ui").description("Manage the local Sailor dashboard");
|
|
45345
|
-
ui.command("start").description("Start the dashboard at localhost:3333 (default)").
|
|
45486
|
+
ui.command("start").description("Start the dashboard at localhost:3333 (default)").option("--expose <mode>", "Expose the dashboard over HTTPS on your tailnet (mode: tailscale)").action(actionWith(uiCommand));
|
|
45346
45487
|
ui.command("stop").description("Stop the running dashboard").action(() => uiStop());
|
|
45347
45488
|
ui.command("status").description("Show whether the dashboard is running").action(() => uiStatus());
|
|
45348
45489
|
ui.action(action(uiCommand));
|
|
@@ -45407,8 +45548,8 @@ program2.command("run").description("Run the agent execution loop (use --once fo
|
|
|
45407
45548
|
var trigger = program2.command("trigger").description("Wake the agent on demand from an external system");
|
|
45408
45549
|
trigger.command("github").description("Fire the agent's GitHub Actions workflow_dispatch (the same job the cron runs)").option("--workflow <file>", "Workflow file to dispatch", "agent-tick.yml").option("--ref <branch>", "Git ref to run the workflow on", "main").option("--reason <text>", "Why this run fired \u2014 recorded as the workflow's reason input").option("--repo <owner/repo>", "Override the repository (default: from the git origin remote)").option("--json", "Emit machine-readable JSON").action(actionWith(triggerGithub));
|
|
45409
45550
|
var session = program2.command("session").description("Control the agent session");
|
|
45410
|
-
session.command("pause").description("Pause the agent session (revoke dispatch rights)").
|
|
45411
|
-
session.command("resume").description("Resume a paused session").
|
|
45551
|
+
session.command("pause").description("Pause the agent session (revoke dispatch rights)").option("--json", "Emit machine-readable JSON").action(actionWith(sessionPause));
|
|
45552
|
+
session.command("resume").description("Resume a paused session").option("--json", "Emit machine-readable JSON").action(actionWith(sessionResume));
|
|
45412
45553
|
program2.command("doctor").description(
|
|
45413
45554
|
"Preflight (read-only): kernel model, permission health, RPC + gas balances, before spending gas"
|
|
45414
45555
|
).option("--json", "Output machine-readable JSON").option("--account <address>", "SMA to check (defaults to .sail/account.json)").action(actionWith(doctor));
|