@dev.sail.money/sailor 0.0.2-30 → 0.0.2-34
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/AGENTS.md +11 -12
- package/README.md +100 -118
- package/package.json +1 -1
- package/packages/cli/dist/index.cjs +44 -20
- package/packages/cli/dist/server.cjs +24 -7
- package/packages/sdk/dist/intelligence.d.ts +1 -1
- package/packages/sdk/dist/intelligence.js +1 -1
- package/packages/ui/dist/assets/{add-BtPPKW_S.js → add-BqSzokiL.js} +1 -1
- package/packages/ui/dist/assets/{all-wallets-CliTUt-P.js → all-wallets-DRghRzBH.js} +1 -1
- package/packages/ui/dist/assets/{app-store-Dn-qzfPP.js → app-store-CHQohbxT.js} +1 -1
- package/packages/ui/dist/assets/{apple-CCxYFT90.js → apple-DyXS52Cz.js} +1 -1
- package/packages/ui/dist/assets/{arrow-bottom-Bo24o32F.js → arrow-bottom-CvZE3jWY.js} +1 -1
- package/packages/ui/dist/assets/{arrow-bottom-circle-DEnDTNB2.js → arrow-bottom-circle-BP_2WEkR.js} +1 -1
- package/packages/ui/dist/assets/{arrow-left-ufrfqGG4.js → arrow-left--QDrrrK2.js} +1 -1
- package/packages/ui/dist/assets/{arrow-right-BkX5DoAK.js → arrow-right-AdmPdxdO.js} +1 -1
- package/packages/ui/dist/assets/{arrow-top-CtvgpoOn.js → arrow-top-Bwg6vVDn.js} +1 -1
- package/packages/ui/dist/assets/{bank-CfyC7KhE.js → bank-Cz2q0uEn.js} +1 -1
- package/packages/ui/dist/assets/{basic-GLsmxA9Q.js → basic-yFwOroQX.js} +1 -1
- package/packages/ui/dist/assets/{browser-BXl5SSvD.js → browser-oL-NMPhY.js} +1 -1
- package/packages/ui/dist/assets/{card-BwTrNMXe.js → card-CF8mKo0W.js} +1 -1
- package/packages/ui/dist/assets/{ccip-BMqD_Aug.js → ccip-C4BRVTyT.js} +1 -1
- package/packages/ui/dist/assets/{checkmark-Dv3bs_r-.js → checkmark-CGcssumz.js} +1 -1
- package/packages/ui/dist/assets/{checkmark-bold-v3XYVY9B.js → checkmark-bold-CEx1x56A.js} +1 -1
- package/packages/ui/dist/assets/{chevron-bottom-BtuSFYmE.js → chevron-bottom-B17SVO6Z.js} +1 -1
- package/packages/ui/dist/assets/{chevron-left-Bj0j6Cyx.js → chevron-left-Bmlagpn4.js} +1 -1
- package/packages/ui/dist/assets/{chevron-right-QsZgfMHX.js → chevron-right-Ce0oTagP.js} +1 -1
- package/packages/ui/dist/assets/{chevron-top-B2LmuCUs.js → chevron-top-Ou3mYfjQ.js} +1 -1
- package/packages/ui/dist/assets/{chrome-store-Be1HnDGs.js → chrome-store-DWdtrqUk.js} +1 -1
- package/packages/ui/dist/assets/{clock-CCcblz1f.js → clock-gBTuGt5c.js} +1 -1
- package/packages/ui/dist/assets/{close-rdnFQxXT.js → close-c4Ordvo2.js} +1 -1
- package/packages/ui/dist/assets/{coinPlaceholder-fRMoMI0y.js → coinPlaceholder-DKx_73vx.js} +1 -1
- package/packages/ui/dist/assets/{compass-CSPR58D9.js → compass-Blxk0h-Z.js} +1 -1
- package/packages/ui/dist/assets/{copy-C5WgEU7N.js → copy-Cn01fjX1.js} +1 -1
- package/packages/ui/dist/assets/{core-CVXQL7tu.js → core-KcoX-IO2.js} +3 -3
- package/packages/ui/dist/assets/cursor-D7a2ynBo.js +3 -0
- package/packages/ui/dist/assets/{cursor-transparent-zEBpsOE4.js → cursor-transparent-DiQTwo8L.js} +1 -1
- package/packages/ui/dist/assets/{desktop-CdkiOqLx.js → desktop-c0OGFp4k.js} +1 -1
- package/packages/ui/dist/assets/{disconnect-B8I112zP.js → disconnect-D6nYEXxt.js} +1 -1
- package/packages/ui/dist/assets/{discord-x2BbO6cW.js → discord-CU6UsGj5.js} +1 -1
- package/packages/ui/dist/assets/{etherscan-C2OxN9Au.js → etherscan-H4xFZDt1.js} +1 -1
- package/packages/ui/dist/assets/{events-DwmWfwqa.js → events-Bh5TaEvc.js} +1 -1
- package/packages/ui/dist/assets/{exclamation-triangle-IY-Iojhj.js → exclamation-triangle-k3JV87dF.js} +1 -1
- package/packages/ui/dist/assets/{extension-Clnc3k0E.js → extension-Db7in92k.js} +1 -1
- package/packages/ui/dist/assets/{external-link-DKjw-POo.js → external-link-M8ucb8_c.js} +1 -1
- package/packages/ui/dist/assets/{facebook-DA_F9Z5R.js → facebook-DqyDwZLk.js} +1 -1
- package/packages/ui/dist/assets/{fallback-CWZLJXZ9.js → fallback-CpXrChod.js} +1 -1
- package/packages/ui/dist/assets/{farcaster-CulNjKFL.js → farcaster-BhXVEUn7.js} +1 -1
- package/packages/ui/dist/assets/{filters-BpETqr4_.js → filters-BsmF8Lsr.js} +1 -1
- package/packages/ui/dist/assets/{github-DywjW1rE.js → github-CTlGk78L.js} +1 -1
- package/packages/ui/dist/assets/{google-DH_kH7BK.js → google-IbDv5sDf.js} +1 -1
- package/packages/ui/dist/assets/{help-circle-DsMbG4i7.js → help-circle-CxsLWQrd.js} +1 -1
- package/packages/ui/dist/assets/{id-O5zOjYCk.js → id-CiF75iBE.js} +1 -1
- package/packages/ui/dist/assets/{image-BBJ-S1oj.js → image-B5bE_jY7.js} +1 -1
- package/packages/ui/dist/assets/{index-CkNlzfQa.js → index-C4oDoM-t.js} +1 -1
- package/packages/ui/dist/assets/{index-C9Q98LC_.js → index-CGF5V3MX.js} +1 -1
- package/packages/ui/dist/assets/{index-BP0G8SWV.js → index-CNQ6HiTi.js} +3 -3
- package/packages/ui/dist/assets/{index-EVUMkF7X.js → index-DE_m8aQ1.js} +78 -78
- package/packages/ui/dist/assets/{index-9Als8Pk1.js → index-DKKjEVeH.js} +1 -1
- package/packages/ui/dist/assets/{index-CMLePJSP.js → index-DcrJPNJt.js} +1 -1
- package/packages/ui/dist/assets/{index.es-BS-p_sCc.js → index.es-B6xObjNP.js} +4 -4
- package/packages/ui/dist/assets/{info-CD3CYp-i.js → info-DPW3VbOc.js} +1 -1
- package/packages/ui/dist/assets/{info-circle-CXbPnDro.js → info-circle-lcMYVscf.js} +1 -1
- package/packages/ui/dist/assets/{lightbulb-Bz1DT8Ju.js → lightbulb-DZeX-zL3.js} +1 -1
- package/packages/ui/dist/assets/{mail-Lj8n2gbA.js → mail-BXAoBPf-.js} +1 -1
- package/packages/ui/dist/assets/{metamask-sdk-DwS0o7ov.js → metamask-sdk-EP1I3cQl.js} +1 -1
- package/packages/ui/dist/assets/{mobile-O_sAbq2l.js → mobile-Bacg80DQ.js} +1 -1
- package/packages/ui/dist/assets/{more-DdiT_mbp.js → more-HXg_jFBb.js} +1 -1
- package/packages/ui/dist/assets/{network-placeholder-Dx9MDHLN.js → network-placeholder-BeKgcBFu.js} +1 -1
- package/packages/ui/dist/assets/{nftPlaceholder-K9kW2r88.js → nftPlaceholder-CbZ8lpZw.js} +1 -1
- package/packages/ui/dist/assets/{off-BOYfR8XB.js → off-DbC3cKAC.js} +1 -1
- package/packages/ui/dist/assets/{parseSignature-NiLF290o.js → parseSignature-Diak-ncT.js} +1 -1
- package/packages/ui/dist/assets/{play-store-DRuPz3YP.js → play-store-CGxL9l1V.js} +1 -1
- package/packages/ui/dist/assets/{plus-BhHn5k_7.js → plus-Bxn8ifny.js} +1 -1
- package/packages/ui/dist/assets/{qr-code-XQgVWw1M.js → qr-code-86kM91qz.js} +1 -1
- package/packages/ui/dist/assets/{recycle-horizontal-B3DKBHl3.js → recycle-horizontal-Cn7PmrIT.js} +1 -1
- package/packages/ui/dist/assets/{refresh-Bdt5zEiy.js → refresh-Dsn4oWtE.js} +1 -1
- package/packages/ui/dist/assets/{reown-logo-B3-LoRif.js → reown-logo-BfLGU5kY.js} +1 -1
- package/packages/ui/dist/assets/{search-CT85WnLr.js → search-BkrouRbM.js} +1 -1
- package/packages/ui/dist/assets/{secp256k1-CSD4IkAn.js → secp256k1-DnPEOQhM.js} +1 -1
- package/packages/ui/dist/assets/{send-DFlOyILV.js → send-Bj15h9aG.js} +1 -1
- package/packages/ui/dist/assets/{swapHorizontal-BnJarCPM.js → swapHorizontal-DHL_fMHx.js} +1 -1
- package/packages/ui/dist/assets/{swapHorizontalBold-BdXwQcVw.js → swapHorizontalBold-CZFfrlj9.js} +1 -1
- package/packages/ui/dist/assets/{swapHorizontalMedium-DruY4Nll.js → swapHorizontalMedium-BbRRKxwu.js} +1 -1
- package/packages/ui/dist/assets/{swapHorizontalRoundedBold-BmU0rX2_.js → swapHorizontalRoundedBold-BCd9TFoe.js} +1 -1
- package/packages/ui/dist/assets/{swapVertical-BDYBLaB-.js → swapVertical-DUlxeXRd.js} +1 -1
- package/packages/ui/dist/assets/{telegram-Dj0PC8gI.js → telegram-Z7oqwOYs.js} +1 -1
- package/packages/ui/dist/assets/{three-dots-DCjLXmgH.js → three-dots-N_HHY4eF.js} +1 -1
- package/packages/ui/dist/assets/{twitch-DtF7PahJ.js → twitch-LHuomK7F.js} +1 -1
- package/packages/ui/dist/assets/{twitterIcon-D5fHAEXR.js → twitterIcon-aqwTGFUp.js} +1 -1
- package/packages/ui/dist/assets/{verify-CvDrZusr.js → verify-Dk65Ky3F.js} +1 -1
- package/packages/ui/dist/assets/{verify-filled-CPKWSwyP.js → verify-filled-CYnRVU40.js} +1 -1
- package/packages/ui/dist/assets/{w3m-modal-DdzuRc6-.js → w3m-modal-CIO-YdMF.js} +1 -1
- package/packages/ui/dist/assets/{wallet-BDKdLwf0.js → wallet-NSBhLacz.js} +1 -1
- package/packages/ui/dist/assets/{wallet-placeholder-DjYKf3de.js → wallet-placeholder-DZOTp3gD.js} +1 -1
- package/packages/ui/dist/assets/{walletconnect-DtsEmRsg.js → walletconnect-T36vfDCB.js} +1 -1
- package/packages/ui/dist/assets/{warning-circle-vXvip1Eh.js → warning-circle-D3dtMC5l.js} +1 -1
- package/packages/ui/dist/assets/{x-CIVAuGSw.js → x-wOYd1xe3.js} +1 -1
- package/packages/ui/dist/index.html +1 -1
- package/packages/ui/dist/assets/cursor-C04TRGDh.js +0 -3
package/AGENTS.md
CHANGED
|
@@ -28,16 +28,15 @@ Use the user-facing terms in all CLI output, prompts, and errors. The code ident
|
|
|
28
28
|
|
|
29
29
|
## Dispatch model
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
All six chains share the same kernel at the same CREATE2 address, verified on-chain via `DISPATCH_TYPEHASH()`:
|
|
32
32
|
|
|
33
|
-
|
|
|
34
|
-
|
|
35
|
-
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
| Unichain 130 | `0xD985029960a9B7C2E7E38e102C448b8b8539B156` | **selective** | `0xbe50c539...` |
|
|
33
|
+
| Kernel (all 6 chains) | Model | DISPATCH_TYPEHASH |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `0x02ABC18B65A328de2e749F56ba79ACF2718a6659` | **selective** | `0xbe50c539...` |
|
|
36
|
+
|
|
37
|
+
Supported chains: Ethereum (1), Base (8453), Arbitrum (42161), Unichain (130), Base Sepolia (84532), Eth Sepolia (11155111).
|
|
39
38
|
|
|
40
|
-
All
|
|
39
|
+
All six kernels are live and bootstrapped (genesis allowlist set, `createAccount` verified working, zero fees). No templates are deployed against the current kernel on any chain yet — `knownTemplates` and `standaloneTemplates` are empty for all six entries. `packages/sdk/src/deployments.ts` is the canonical source of truth for kernel addresses, templates, and metadata.
|
|
41
40
|
|
|
42
41
|
**Always use `detectKernelCapabilities` for the real model** — it reads the on-chain typehash and
|
|
43
42
|
overrides the static label in `deployments.ts`. The static label is a fallback for offline use only.
|
|
@@ -56,11 +55,11 @@ Pass the detected value — never hardcode the type shape.
|
|
|
56
55
|
|
|
57
56
|
## Active addresses
|
|
58
57
|
|
|
59
|
-
All
|
|
58
|
+
All six chain records in `packages/sdk/src/deployments.ts` are live — no commented-out or pending
|
|
60
59
|
addresses remain. This file is the source of truth this guide mirrors.
|
|
61
60
|
|
|
62
61
|
- `packages/sdk/src/deployments.ts` — `SailDeployment` records; canonical source of truth
|
|
63
|
-
- `packages/
|
|
62
|
+
- `packages/sdk/src/chains.ts` — `ChainConfig` per chainId; canonical per-chain registry
|
|
64
63
|
|
|
65
64
|
## Key files
|
|
66
65
|
|
|
@@ -78,10 +77,10 @@ addresses remain. This file is the source of truth this guide mirrors.
|
|
|
78
77
|
|
|
79
78
|
```bash
|
|
80
79
|
pnpm install
|
|
81
|
-
pnpm build # builds all packages; dependency order: sdk →
|
|
80
|
+
pnpm build # builds all packages; dependency order: sdk → cli → ui
|
|
82
81
|
```
|
|
83
82
|
|
|
84
|
-
Build order matters — `cli` imports from `sdk
|
|
83
|
+
Build order matters — `cli` imports from `sdk`.
|
|
85
84
|
|
|
86
85
|
## Test
|
|
87
86
|
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Sailor
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> The operator toolkit for Sail Protocol — SDK, CLI, and local dashboard for building and running mandated agents.
|
|
4
4
|
|
|
5
|
-
Sailor is the operator layer for [Sail Protocol](
|
|
5
|
+
Sailor is the off-chain operator layer for [Sail Protocol](https://github.com/sail-money/SailProtocol): the tooling an operator uses to create a Separately Managed Account, register a mandate, and run a strategy agent against it. It wraps SailKernel dispatch, MandateFactory registration, and EIP-712 mandate signing behind a TypeScript SDK, a CLI, and a local dashboard. It does not deploy the protocol or author permission templates — those live in Sail Protocol. It targets already-deployed SailKernel instances and gives operators the tooling to drive them.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -10,38 +10,60 @@ Sailor is the operator layer for [Sail Protocol](../SailProtocol): the tooling a
|
|
|
10
10
|
|
|
11
11
|
| Package | Name | Role |
|
|
12
12
|
|---|---|---|
|
|
13
|
-
| `packages/sdk` | `@sail/sdk`
|
|
13
|
+
| `packages/sdk` | `@sail.money/sdk` / `@sail.money/sailor/sdk` | TypeScript library: SailorClient, EIP-712 helpers, ABIs, deployment registry, chain registry |
|
|
14
14
|
| `packages/cli` | `@sail.money/sailor` | CLI for account setup, mandate signing, and agent execution |
|
|
15
|
-
| `packages/ui` | `sailor-ui` | Local dashboard running
|
|
15
|
+
| `packages/ui` | `sailor-ui` | Local dashboard running at localhost:3333 |
|
|
16
16
|
| `templates/default` | — | Default agent starter (neutral; what `sailor init` scaffolds) |
|
|
17
17
|
| `templates/custom-mandate` | — | Solidity reference: IPermission scaffold (not a project template) |
|
|
18
18
|
| `templates/lifi-permissions` | — | Solidity reference: LiFi clone permission contracts (not a project template) |
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
-
##
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
## Protocol model
|
|
23
|
+
|
|
24
|
+
```mermaid
|
|
25
|
+
flowchart TD
|
|
26
|
+
Owner["**Owner**<br/>holds the Safe · signs the mandate"]
|
|
27
|
+
Manager["**Manager**<br/>agent · signs dispatches"]
|
|
28
|
+
SMA["**SMA**<br/>Safe · holds assets · executes"]
|
|
29
|
+
Mandate["**Mandate**<br/>set of permission contracts"]
|
|
30
|
+
Kernel["**Sail Kernel**<br/>evaluates permission · trusted core<br/>dispatches to Safe on success"]
|
|
31
|
+
|
|
32
|
+
Owner -- "01 deploys & owns" --> SMA
|
|
33
|
+
Owner -- "02 signs mandate (EIP-712)" --> Mandate
|
|
34
|
+
Owner -- "03 appoints · instant revocation" --> Manager
|
|
35
|
+
Manager -- "04 signs dispatch (EIP-712)" --> Kernel
|
|
36
|
+
Mandate -- "05 defines bounds" --> Kernel
|
|
37
|
+
Kernel -- "06 ✓ executes · ✗ outside mandate: reverts" --> SMA
|
|
38
|
+
```
|
|
31
39
|
|
|
32
|
-
|
|
40
|
+
Sailor is the operator tooling that drives the Manager/dispatch and mandate-registration flows (steps 02–05).
|
|
33
41
|
|
|
34
42
|
---
|
|
35
43
|
|
|
36
44
|
## Roles
|
|
37
45
|
|
|
38
|
-
|
|
46
|
+
Sail Protocol separates three authority roles. Sailor operates all of them:
|
|
39
47
|
|
|
40
48
|
| Role | Authority | Held by |
|
|
41
49
|
|---|---|---|
|
|
42
|
-
| **Owner** | Holds the Safe. Custody anchor. | The LP (Safe owner)
|
|
43
|
-
| **Permission Signer** |
|
|
44
|
-
| **Manager** | Executes dispatches within
|
|
50
|
+
| **Owner** | Holds the Safe. Custody anchor. Always self-custodial. | The LP (Safe owner) |
|
|
51
|
+
| **Permission Signer** | Authorizes the mandate. Signs registration and revocation via EIP-712. | Same as Owner, or a separate signing key |
|
|
52
|
+
| **Manager** | Executes dispatches within mandate bounds. Signs each dispatch. | The agent wallet — encrypted in `.sail/keys/manager.json` |
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## How it works
|
|
57
|
+
|
|
58
|
+
The path from nothing to a running agent follows the protocol lifecycle:
|
|
59
|
+
|
|
60
|
+
1. **Deploy your SMA** — `sailor onboard --new-sma` creates the SMA on-chain. `sailor account predict` computes the deterministic address in advance. The same owner, permission signer, manager, and salt produce the same SMA address on every supported chain.
|
|
61
|
+
2. **Author your permissions** — describe what the agent may do. Permission contracts encode the bounds: tokens, amounts, venues, call targets. Author them in the scaffolded Foundry workspace.
|
|
62
|
+
3. **Simulate, deploy, and sign your mandate** — `sailor mandate simulate` probes a permission off-chain before authorizing it. `sailor mandate deploy --attach` deploys and registers it on-chain. `sailor mandate sign` builds and signs the registration payload against live on-chain state.
|
|
63
|
+
4. **Run** — `sailor run` executes the agent locally on a schedule, or via the GitHub Actions workflow the scaffold provides.
|
|
64
|
+
5. **Operate** — `sailor doctor` checks kernel health and gas balances; `sailor chains` lists supported chains and deployment addresses; `sailor session pause` instantly revokes dispatch rights without touching Safe custody.
|
|
65
|
+
|
|
66
|
+
Run `npx sailor init my-agent`, open the scaffolded folder in Claude Code, Cursor, or any AI coding assistant, and say **"start"**. The `AGENTS.md` in the project guides the assistant through all five stages.
|
|
45
67
|
|
|
46
68
|
---
|
|
47
69
|
|
|
@@ -71,9 +93,9 @@ sailor init my-agent
|
|
|
71
93
|
Prerequisites:
|
|
72
94
|
|
|
73
95
|
- Node.js 18+
|
|
74
|
-
- A wallet (MetaMask
|
|
96
|
+
- A wallet (MetaMask, Rabby, Phantom, and more)
|
|
75
97
|
- An RPC URL (e.g. Alchemy free tier)
|
|
76
|
-
- A supported chain: **Base, Base Sepolia,
|
|
98
|
+
- A supported chain: **Ethereum, Base, Arbitrum, Unichain, Base Sepolia, or Eth Sepolia** — verified deployments are bundled in `@sail.money/sailor`.
|
|
77
99
|
|
|
78
100
|
### Recommended — assistant-driven
|
|
79
101
|
|
|
@@ -84,18 +106,31 @@ npm install
|
|
|
84
106
|
|
|
85
107
|
Open this folder in Claude Code, Cursor, Codex, or any AI coding assistant and say **"start"**. The scaffolded `AGENTS.md` guides the assistant through all five stages — SMA deployment, strategy definition, mandate authoring, running, and automation. No manual steps required.
|
|
86
108
|
|
|
87
|
-
### Direct CLI reference
|
|
88
|
-
|
|
89
|
-
For users who prefer the terminal:
|
|
109
|
+
### Direct CLI reference
|
|
90
110
|
|
|
91
111
|
```bash
|
|
92
|
-
|
|
93
|
-
sailor
|
|
94
|
-
sailor
|
|
95
|
-
sailor
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
sailor
|
|
112
|
+
# Discovery
|
|
113
|
+
sailor chains # list supported chains and kernel addresses
|
|
114
|
+
sailor capabilities # what you can build on this chain — read-only, no gas
|
|
115
|
+
sailor doctor # kernel model + RPC reachability + gas balances
|
|
116
|
+
|
|
117
|
+
# SMA setup
|
|
118
|
+
sailor account predict # compute deterministic SMA address before deploying
|
|
119
|
+
sailor onboard --new-sma # deploy SMA and optionally attach a mandate
|
|
120
|
+
|
|
121
|
+
# Mandate lifecycle
|
|
122
|
+
sailor mandate simulate # probe a permission off-chain (no gas) before registering
|
|
123
|
+
sailor mandate sign # sign the mandate — reconciles against live on-chain state
|
|
124
|
+
sailor mandate deploy # deploy a Foundry-compiled permission contract
|
|
125
|
+
sailor mandate attach # register an already-deployed permission on an SMA
|
|
126
|
+
|
|
127
|
+
# Agent operation
|
|
128
|
+
sailor run --once # single tick — confirm it works before automating
|
|
129
|
+
sailor run # start the agent (continuous)
|
|
130
|
+
sailor keys export-ci # copy encrypted agent wallet to ci-keystore.json for CI
|
|
131
|
+
|
|
132
|
+
# Dashboard
|
|
133
|
+
sailor ui start # open http://localhost:3333
|
|
99
134
|
```
|
|
100
135
|
|
|
101
136
|
`sailor run` writes reverted transactions to stderr as `reverted: <txHash> (gas used: N)`; successful dispatches are appended to `.sail/activity.jsonl`.
|
|
@@ -186,19 +221,19 @@ sailor ui stop
|
|
|
186
221
|
|
|
187
222
|
## Agent-driven onboarding & custom mandates
|
|
188
223
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
224
|
+
On any of the six supported chains, an agent can drive the whole setup through
|
|
225
|
+
a browser **signing station**. The station is a local HTTP + WebSocket daemon
|
|
226
|
+
that bridges the CLI and the owner's wallet: the agent never holds the owner
|
|
227
|
+
key — it pushes signing requests, the owner approves them in the browser, and
|
|
228
|
+
the agent submits the transactions it's allowed to.
|
|
194
229
|
|
|
195
230
|
```bash
|
|
196
|
-
sailor keys generate # manager (agent) key
|
|
197
|
-
sailor station start &
|
|
231
|
+
sailor keys generate # create the manager (agent) key
|
|
232
|
+
sailor station start & # signing daemon (serves the UI)
|
|
198
233
|
# owner opens the printed URL once and connects their wallet
|
|
199
|
-
sailor owner connect
|
|
200
|
-
sailor scan
|
|
201
|
-
sailor onboard --new-sma
|
|
234
|
+
sailor owner connect # detect & persist the owner
|
|
235
|
+
sailor scan # discover the owner's Safes + state
|
|
236
|
+
sailor onboard --new-sma # create an SMA + (optionally) attach a mandate
|
|
202
237
|
```
|
|
203
238
|
|
|
204
239
|
Agents author their own permission contracts and deploy them from the scaffolded
|
|
@@ -258,14 +293,16 @@ The SDK is available as a subpath export for use in agent code:
|
|
|
258
293
|
import type { Agent, AgentContext, Dispatch } from '@sail.money/sailor/sdk'
|
|
259
294
|
```
|
|
260
295
|
|
|
296
|
+
The SDK is also published separately as `@sail.money/sdk` for projects that consume it independently of the CLI.
|
|
297
|
+
|
|
261
298
|
### npm (`publish-npm.yml`)
|
|
262
299
|
|
|
263
300
|
Published to the public npm registry under the `@sail.money` scope.
|
|
264
301
|
|
|
265
302
|
| Trigger | Package | Version | dist-tag |
|
|
266
303
|
|---|---|---|---|
|
|
267
|
-
| Tag push (`v*`) | `@sail.money/sailor` | `1.0
|
|
268
|
-
| Manual dispatch | `@dev.sail.money/sailor` | `1.0
|
|
304
|
+
| Tag push (`v*`) | `@sail.money/sailor` | `0.1.0` | `latest` |
|
|
305
|
+
| Manual dispatch | `@dev.sail.money/sailor` | `0.1.0-42` | `dev` |
|
|
269
306
|
|
|
270
307
|
```bash
|
|
271
308
|
npm install @sail.money/sailor # latest stable (tag push)
|
|
@@ -313,36 +350,6 @@ Either way, `@sail.money/sailor/sdk` imports work unchanged.
|
|
|
313
350
|
|
|
314
351
|
---
|
|
315
352
|
|
|
316
|
-
## Architecture
|
|
317
|
-
|
|
318
|
-
```
|
|
319
|
-
┌────────────────────┐ ┌────────────────────┐
|
|
320
|
-
│ Permission Signer │ │ Manager/Agent │
|
|
321
|
-
│ MetaMask / local │ │ .sail/keys/manager │
|
|
322
|
-
└─────────┬──────────┘ └─────────┬──────────┘
|
|
323
|
-
│ │
|
|
324
|
-
│ EIP-712 mandate │ dispatch
|
|
325
|
-
▼ ▼
|
|
326
|
-
┌─────────────────────────────────────────────────────────────────────┐
|
|
327
|
-
│ SailKernel │
|
|
328
|
-
│ (Sail Protocol) │
|
|
329
|
-
└─────────┬───────────────────────┬───────────────────────┬───────────┘
|
|
330
|
-
│ │ │
|
|
331
|
-
│ registration │ execution │ evaluation
|
|
332
|
-
▼ ▼ ▼
|
|
333
|
-
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
|
|
334
|
-
│ MandateFactory │ │ Safe │ │ Permissions │
|
|
335
|
-
│ (register perms) │ │ (custody) │ │ (named, per-call) │
|
|
336
|
-
└────────────────────┘ └────────────────────┘ └────────────────────┘
|
|
337
|
-
|
|
338
|
-
sailor CLI / @sail.money/sailor/sdk drive both signing paths above.
|
|
339
|
-
.sail/ (account · mandate · activity) ──→ sailor-ui (localhost:3333)
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
The CLI and SDK sit between the operator and SailKernel: they build the EIP-712 payloads, submit dispatches, and read kernel state via viem. The permission signer authorizes the mandate — registration runs through MandateFactory — while the manager key signs each dispatch the kernel evaluates against a named permission before executing it through the Safe. All local state — the deployed account, the signed mandate, and the agent's activity log — lives under `.sail/` on disk, which the dashboard reads through a small local server. Sailor never holds the Owner key and runs no hosted backend; the wallet talks to the chain directly.
|
|
343
|
-
|
|
344
|
-
---
|
|
345
|
-
|
|
346
353
|
## Security model
|
|
347
354
|
|
|
348
355
|
- The agent signs dispatches; the kernel evaluates the named permission on every call. A permission returning false or exceeding its gas cap is treated as denial — fail-closed.
|
|
@@ -355,67 +362,42 @@ The CLI and SDK sit between the operator and SailKernel: they build the EIP-712
|
|
|
355
362
|
|
|
356
363
|
## State of the project
|
|
357
364
|
|
|
358
|
-
Sailor is functional and published as [`@sail.money/sailor`](https://www.npmjs.com/package/@sail.money/sailor) on npm (v0.0
|
|
365
|
+
Sailor is functional and published as [`@sail.money/sailor`](https://www.npmjs.com/package/@sail.money/sailor) on npm (v0.1.0). The SDK, CLI, keystore, mandate flows, agent runner, and dashboard are implemented and have been exercised end to end.
|
|
359
366
|
|
|
360
|
-
The Sail Protocol trusted core is deployed on Base, Base Sepolia,
|
|
367
|
+
The Sail Protocol trusted core is deployed on six chains — Ethereum, Base, Arbitrum, Unichain, Base Sepolia, and Eth Sepolia — via CREATE2, with every core contract at the same address on every chain. All six run the selective dispatch model with zero fees and are bootstrapped with a genesis allowlist so `createAccount` is usable immediately. These deployments are under an ongoing external audit by [Octane Security](https://octane.security) and are not final — do not use them with funds you are not prepared to lose.
|
|
368
|
+
|
|
369
|
+
Permission templates have not yet been deployed against the current kernel on any chain; `knownTemplates` and `standaloneTemplates` are empty for all six chains in `packages/sdk/src/deployments.ts` and will be populated as templates are deployed and verified against the new kernel.
|
|
361
370
|
|
|
362
371
|
---
|
|
363
372
|
|
|
364
373
|
## Deployments
|
|
365
374
|
|
|
366
|
-
|
|
375
|
+
All core contracts are deployed at the same address on every supported chain via CREATE2 (commit `1199b33`, 2026-06-09). An SMA created with the same owner, permission signer, manager, fee policy, and salt has the same address on every supported chain.
|
|
367
376
|
|
|
368
|
-
###
|
|
377
|
+
### Core addresses (identical on all 6 chains)
|
|
369
378
|
|
|
370
379
|
| Contract | Address |
|
|
371
380
|
|---|---|
|
|
372
|
-
| SailKernel | `
|
|
373
|
-
| SailGovernance | `
|
|
374
|
-
|
|
|
375
|
-
|
|
|
376
|
-
| StandardFeePolicy | `
|
|
377
|
-
| SafeModuleEnabler | `
|
|
381
|
+
| SailKernel | `0x02ABC18B65A328de2e749F56ba79ACF2718a6659` |
|
|
382
|
+
| SailGovernance | `0x7A478118715791728BDE3bc7A4D7ECfdEB89C6EC` |
|
|
383
|
+
| TimelockController | `0xE48Ba8DB6d748adafD13155c3590f62e58a77f56` |
|
|
384
|
+
| MandateFactory | `0x14EDd6c2a56EfC0d71E215ab13094B9AF90543d2` |
|
|
385
|
+
| StandardFeePolicy | `0xe7B5901b839cFFDEd9D4108A22712C8BfdA1D80D` |
|
|
386
|
+
| SafeModuleEnabler | `0x7897Cb53a4be4a2eaAf46D60573C4Fd83b33fE1F` |
|
|
378
387
|
| Treasury | `0xB01dCE443d052e44b7D13726c0EC9fFB7f5815B6` |
|
|
379
388
|
|
|
380
|
-
|
|
389
|
+
These addresses are bundled in `@sail.money/sailor` and exposed via `getSailDeployment(chainId)` in the SDK. The Protocol repository is the canonical source of truth for deployment details — see [deployments/addresses.md](https://github.com/sail-money/Protocol/blob/main/deployments/addresses.md).
|
|
381
390
|
|
|
382
|
-
|
|
383
|
-
|---|---|
|
|
384
|
-
| SailKernel | `0x2716B12832DED0EF5688519c5Fe069EFc0374E02` |
|
|
385
|
-
| SailGovernance | `0xd6AbB7A1036ADc7958Abffec9Da03450c5a2Ec8e` |
|
|
386
|
-
| Timelock | `0x114CB7110C780f7E3a6093AfE0B52463a569857C` |
|
|
387
|
-
| PermissionFactory | `0x23681A8A4C9819D8EaB37E46B858da6F3c85E683` |
|
|
388
|
-
| StandardFeePolicy | `0xAdfB986D48480bC67a7cF3751d30599161632e0D` |
|
|
389
|
-
| SafeModuleEnabler | `0xabe2a6D03F592BC602cA1dBDCD885ba2493274f9` |
|
|
390
|
-
| Treasury | `0xB01dCE443d052e44b7D13726c0EC9fFB7f5815B6` |
|
|
391
|
+
### Supported chains
|
|
391
392
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
| Contract | Address |
|
|
393
|
+
| Chain | Chain ID |
|
|
395
394
|
|---|---|
|
|
396
|
-
|
|
|
397
|
-
|
|
|
398
|
-
|
|
|
399
|
-
|
|
|
400
|
-
|
|
|
401
|
-
|
|
|
402
|
-
| Treasury | `0xB01dCE443d052e44b7D13726c0EC9fFB7f5815B6` |
|
|
403
|
-
|
|
404
|
-
### Unichain (130)
|
|
405
|
-
|
|
406
|
-
First chain to ship the full permission-template suite (7 shared + 12 standalone, source-verified on [uniscan.xyz](https://uniscan.xyz)). Genesis allowlist bootstrap — onboarding usable without the 48h timelock.
|
|
407
|
-
|
|
408
|
-
| Contract | Address |
|
|
409
|
-
|---|---|
|
|
410
|
-
| SailKernel | `0xD985029960a9B7C2E7E38e102C448b8b8539B156` |
|
|
411
|
-
| SailGovernance | `0xAb5C90ECfF2763f6f20f8E553E3b8778dD9C349A` |
|
|
412
|
-
| Timelock | `0xd44FbBB37f01e235E0EE5386948F216d36D0CEf2` |
|
|
413
|
-
| PermissionFactory | `0x8edDb62Aa49CeB837abf2653be2d93Ad9Fe6777D` |
|
|
414
|
-
| StandardFeePolicy | `0x7bBA8BE3c01c972757aA4a230A00D58aB600A1F1` |
|
|
415
|
-
| SafeModuleEnabler | `0xFE9227A9F2baf704060c604466df354a5A137b9B` |
|
|
416
|
-
| Treasury | `0xB01dCE443d052e44b7D13726c0EC9fFB7f5815B6` |
|
|
417
|
-
|
|
418
|
-
The 19 template addresses are in `packages/sdk/src/deployments.ts` (`knownTemplates` + `standaloneTemplates` for chain 130).
|
|
395
|
+
| Ethereum | 1 |
|
|
396
|
+
| Base | 8453 |
|
|
397
|
+
| Arbitrum | 42161 |
|
|
398
|
+
| Unichain | 130 |
|
|
399
|
+
| Base Sepolia | 84532 |
|
|
400
|
+
| Eth Sepolia | 11155111 |
|
|
419
401
|
|
|
420
402
|
---
|
|
421
403
|
|
package/package.json
CHANGED
|
@@ -38484,6 +38484,8 @@ function getRpcUrl(chainId) {
|
|
|
38484
38484
|
const perChainVar = chains[chainId]?.rpcEnvVar;
|
|
38485
38485
|
const fromProjectChain = perChainVar ? env[perChainVar] : void 0;
|
|
38486
38486
|
if (fromProjectChain?.trim()) return fromProjectChain.trim();
|
|
38487
|
+
const fromProjectChainId = env[`RPC_URL_${chainId}`];
|
|
38488
|
+
if (fromProjectChainId?.trim()) return fromProjectChainId.trim();
|
|
38487
38489
|
if (env.RPC_URL?.trim()) return env.RPC_URL.trim();
|
|
38488
38490
|
const fromEnvChain = perChainVar ? process.env[perChainVar] : void 0;
|
|
38489
38491
|
if (fromEnvChain?.trim()) return fromEnvChain.trim();
|
|
@@ -39294,6 +39296,15 @@ var SigningClient = class {
|
|
|
39294
39296
|
throw new Error("Timed out waiting for wallet connection in the signing UI");
|
|
39295
39297
|
}
|
|
39296
39298
|
};
|
|
39299
|
+
function toLoopbackIPv4(url) {
|
|
39300
|
+
try {
|
|
39301
|
+
const u = new URL(url);
|
|
39302
|
+
if (u.hostname === "localhost") u.hostname = "127.0.0.1";
|
|
39303
|
+
return u.toString().replace(/\/$/, "");
|
|
39304
|
+
} catch {
|
|
39305
|
+
return url;
|
|
39306
|
+
}
|
|
39307
|
+
}
|
|
39297
39308
|
function readRuntimeServerState(projectRoot) {
|
|
39298
39309
|
const file = (0, import_node_path5.join)(projectRoot, RUNTIME_SERVER_FILE);
|
|
39299
39310
|
if (!(0, import_node_fs6.existsSync)(file)) return null;
|
|
@@ -39303,10 +39314,13 @@ function readRuntimeServerState(projectRoot) {
|
|
|
39303
39314
|
return null;
|
|
39304
39315
|
}
|
|
39305
39316
|
}
|
|
39317
|
+
function signingPageUrl(_channel, dashboardPort) {
|
|
39318
|
+
return `http://localhost:${dashboardPort}/#/station`;
|
|
39319
|
+
}
|
|
39306
39320
|
async function discoverDaemon(projectRoot = process.cwd()) {
|
|
39307
39321
|
const state = readRuntimeServerState(projectRoot);
|
|
39308
39322
|
if (!state?.url) return null;
|
|
39309
|
-
const client = new SigningClient(state.url, state.requestSecret ?? "");
|
|
39323
|
+
const client = new SigningClient(toLoopbackIPv4(state.url), state.requestSecret ?? "");
|
|
39310
39324
|
return await client.ping() ? client : null;
|
|
39311
39325
|
}
|
|
39312
39326
|
async function createSigningChannel(projectRoot = process.cwd()) {
|
|
@@ -39650,7 +39664,7 @@ Deploying SMA on ${getChainById(targetChainId).name} (chain ${targetChainId})\u2
|
|
|
39650
39664
|
const channel = await createSigningChannel(process.cwd());
|
|
39651
39665
|
try {
|
|
39652
39666
|
await channel.start();
|
|
39653
|
-
const stationUrl =
|
|
39667
|
+
const stationUrl = signingPageUrl(channel, projectPort(process.cwd()));
|
|
39654
39668
|
if (json) {
|
|
39655
39669
|
console.log(
|
|
39656
39670
|
JSON.stringify(
|
|
@@ -39801,7 +39815,9 @@ var ProjectContext = class {
|
|
|
39801
39815
|
throw new Error('No Sailor project found here. Run "sailor init" first.');
|
|
39802
39816
|
}
|
|
39803
39817
|
this.config = cfg;
|
|
39804
|
-
|
|
39818
|
+
const envLocal = parseEnvFile(sailPath(".env.local"));
|
|
39819
|
+
const envChainId = process.env.CHAIN_ID ?? envLocal.CHAIN_ID;
|
|
39820
|
+
this.chainId = envChainId ? Number(envChainId) : cfg.chainId ?? 8453;
|
|
39805
39821
|
this.deployment = getSailDeployment(this.chainId);
|
|
39806
39822
|
const overrides = cfg.contracts ?? {};
|
|
39807
39823
|
this.contracts = {
|
|
@@ -41076,7 +41092,7 @@ Project: ${project.name}`));
|
|
|
41076
41092
|
() => console.log(
|
|
41077
41093
|
`
|
|
41078
41094
|
\u2192 Open the Sailor dashboard to approve signing requests:
|
|
41079
|
-
|
|
41095
|
+
${signingPageUrl(channel, projectPort(process.cwd()))}
|
|
41080
41096
|
`
|
|
41081
41097
|
)
|
|
41082
41098
|
);
|
|
@@ -41633,7 +41649,7 @@ async function runDeploy(project, channel, options) {
|
|
|
41633
41649
|
console.log(
|
|
41634
41650
|
`
|
|
41635
41651
|
\u2192 Open the Sailor dashboard to approve signing requests:
|
|
41636
|
-
|
|
41652
|
+
${signingPageUrl(channel, projectPort(process.cwd()))}
|
|
41637
41653
|
`
|
|
41638
41654
|
);
|
|
41639
41655
|
console.log(`Pushing deploy request for "${contractName}"\u2026`);
|
|
@@ -41865,7 +41881,7 @@ ${spec.label} clone (${options.template})`);
|
|
|
41865
41881
|
for (const d of spec.describe(initParams)) console.log(` ${d.label}: ${d.value}`);
|
|
41866
41882
|
console.log(`
|
|
41867
41883
|
\u2192 Open the Sailor dashboard to approve signing requests:
|
|
41868
|
-
|
|
41884
|
+
${signingPageUrl(channel, projectPort(process.cwd()))}
|
|
41869
41885
|
`);
|
|
41870
41886
|
});
|
|
41871
41887
|
const nonce = await publicClient.readContract({
|
|
@@ -42029,7 +42045,7 @@ async function runAttach(project, channel, options) {
|
|
|
42029
42045
|
console.log(
|
|
42030
42046
|
`
|
|
42031
42047
|
\u2192 Open the Sailor dashboard to approve signing requests:
|
|
42032
|
-
|
|
42048
|
+
${signingPageUrl(channel, projectPort(process.cwd()))}
|
|
42033
42049
|
`
|
|
42034
42050
|
);
|
|
42035
42051
|
}
|
|
@@ -42112,7 +42128,7 @@ Revoking ${targets.length} permission(s) from ${sma}:`);
|
|
|
42112
42128
|
console.log(
|
|
42113
42129
|
`
|
|
42114
42130
|
\u2192 Open the Sailor dashboard to approve signing requests:
|
|
42115
|
-
|
|
42131
|
+
${signingPageUrl(channel, projectPort(process.cwd()))}
|
|
42116
42132
|
`
|
|
42117
42133
|
);
|
|
42118
42134
|
});
|
|
@@ -42642,7 +42658,9 @@ ${unregistered.length} permission(s) are not yet registered on this SMA. Initiat
|
|
|
42642
42658
|
// Only include permissions that are currently active on-chain.
|
|
42643
42659
|
permissions: activePermissions.map((p) => ({ template: p.label, params: {} }))
|
|
42644
42660
|
};
|
|
42645
|
-
|
|
42661
|
+
const existingRaw = readJsonFile(sailPath("mandate.json"));
|
|
42662
|
+
const existing = existingRaw ? Array.isArray(existingRaw) ? existingRaw : [existingRaw] : [];
|
|
42663
|
+
writeJsonFile(sailPath("mandate.json"), [...existing, storedMandate]);
|
|
42646
42664
|
console.log(`
|
|
42647
42665
|
\u2713 Saved to .sail/mandate.json \u2014 agent is ready to run.`);
|
|
42648
42666
|
}
|
|
@@ -43010,7 +43028,7 @@ SMA: ${smaAddress}`);
|
|
|
43010
43028
|
console.log(
|
|
43011
43029
|
`
|
|
43012
43030
|
\u2192 Open the Sailor dashboard to approve signing requests:
|
|
43013
|
-
|
|
43031
|
+
${signingPageUrl(channel, projectPort(process.cwd()))}
|
|
43014
43032
|
`
|
|
43015
43033
|
);
|
|
43016
43034
|
});
|
|
@@ -43386,7 +43404,7 @@ async function ownerConnect(options) {
|
|
|
43386
43404
|
await channel.start();
|
|
43387
43405
|
if (!options.json) {
|
|
43388
43406
|
console.log("\u2192 Open the Sailor dashboard and connect your wallet:");
|
|
43389
|
-
console.log(`
|
|
43407
|
+
console.log(` ${signingPageUrl(channel, projectPort(projectRoot))}`);
|
|
43390
43408
|
if (channel.remote) console.log(" (using the running signing station)");
|
|
43391
43409
|
console.log("\nWaiting for a wallet connection\u2026");
|
|
43392
43410
|
}
|
|
@@ -43536,7 +43554,8 @@ async function runCommand(opts) {
|
|
|
43536
43554
|
if (!account2) {
|
|
43537
43555
|
throw new Error('No account found at .sail/account.json.\nRun "sailor account create" first.');
|
|
43538
43556
|
}
|
|
43539
|
-
const
|
|
43557
|
+
const mandateRaw = readJsonFile(sailPath("mandate.json"));
|
|
43558
|
+
const mandate2 = Array.isArray(mandateRaw) ? mandateRaw[0] : mandateRaw;
|
|
43540
43559
|
if (!mandate2) {
|
|
43541
43560
|
throw new Error('No mandate found at .sail/mandate.json.\nRun "sailor mandate sign" first.');
|
|
43542
43561
|
}
|
|
@@ -43544,18 +43563,23 @@ async function runCommand(opts) {
|
|
|
43544
43563
|
for (const [k, v] of Object.entries(env)) {
|
|
43545
43564
|
if (v && !process.env[k]) process.env[k] = v;
|
|
43546
43565
|
}
|
|
43547
|
-
const rpcUrl = env.RPC_URL ?? process.env.RPC_URL;
|
|
43548
43566
|
const configChainId = readJsonFile(sailPath("config.json"))?.chainId;
|
|
43549
|
-
const chainIdRaw = env.CHAIN_ID ??
|
|
43550
|
-
if (!
|
|
43567
|
+
const chainIdRaw = opts.chain != null ? String(opts.chain) : process.env.CHAIN_ID ?? env.CHAIN_ID ?? (configChainId != null ? String(configChainId) : void 0);
|
|
43568
|
+
if (!chainIdRaw) {
|
|
43551
43569
|
throw new Error(
|
|
43552
|
-
"
|
|
43570
|
+
"CHAIN_ID must be set in .sail/.env.local or .sail/config.json.\n CHAIN_ID=8453 (Base) or CHAIN_ID=42161 (Arbitrum)"
|
|
43553
43571
|
);
|
|
43554
43572
|
}
|
|
43555
43573
|
const chainId = Number(chainIdRaw);
|
|
43556
43574
|
if (Number.isNaN(chainId)) {
|
|
43557
43575
|
throw new Error(`Invalid CHAIN_ID: "${chainIdRaw}".`);
|
|
43558
43576
|
}
|
|
43577
|
+
const rpcUrl = getRpcUrl(chainId);
|
|
43578
|
+
if (!rpcUrl) {
|
|
43579
|
+
throw new Error(
|
|
43580
|
+
"RPC_URL must be set in .sail/.env.local.\n RPC_URL=https://your-rpc-endpoint (or BASE_RPC_URL / RPC_URL_8453 for per-chain config)"
|
|
43581
|
+
);
|
|
43582
|
+
}
|
|
43559
43583
|
try {
|
|
43560
43584
|
const parsed = new URL(rpcUrl);
|
|
43561
43585
|
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
@@ -43625,7 +43649,7 @@ Configure the chain in @sail/chains or set KERNEL_ADDRESS in .sail/.env.local.`
|
|
|
43625
43649
|
} catch {
|
|
43626
43650
|
}
|
|
43627
43651
|
const intervalSec = (() => {
|
|
43628
|
-
const raw = env.SAILOR_INTERVAL ??
|
|
43652
|
+
const raw = process.env.SAILOR_INTERVAL ?? env.SAILOR_INTERVAL;
|
|
43629
43653
|
const n = raw === void 0 ? DEFAULT_INTERVAL_SEC : Number(raw);
|
|
43630
43654
|
return Number.isNaN(n) || n <= 0 ? DEFAULT_INTERVAL_SEC : n;
|
|
43631
43655
|
})();
|
|
@@ -43634,7 +43658,7 @@ Configure the chain in @sail/chains or set KERNEL_ADDRESS in .sail/.env.local.`
|
|
|
43634
43658
|
appendActivity({ ts: nowIso(), actor: "agent", type: "log", msg });
|
|
43635
43659
|
};
|
|
43636
43660
|
const agentData = {
|
|
43637
|
-
...loadAgentData(env.SAILOR_DATA ??
|
|
43661
|
+
...loadAgentData(process.env.SAILOR_DATA ?? env.SAILOR_DATA),
|
|
43638
43662
|
_publicClient: publicClient
|
|
43639
43663
|
};
|
|
43640
43664
|
const readBalance = async (token) => {
|
|
@@ -44349,9 +44373,9 @@ owner.command("connect").description("Open the signing station, wait for your wa
|
|
|
44349
44373
|
owner.command("show").description("Show the saved project owner").option("--json", "Emit machine-readable JSON").action(actionWith(ownerShow));
|
|
44350
44374
|
program2.command("scan").description("Discover the owner's SMAs, their permissions, and local keys; save to context.json").option("--owner <address>", "Owner address to scan (defaults to the saved project owner)").option("--json", "Emit machine-readable JSON").action(actionWith(scan));
|
|
44351
44375
|
program2.command("status").description("Show current account, permission, and session status").action(action(status));
|
|
44352
|
-
program2.command("run").description("Run the agent execution loop (use --once for a single tick)").option("--once", "Run a single tick then exit").action(async (opts) => {
|
|
44376
|
+
program2.command("run").description("Run the agent execution loop (use --once for a single tick)").option("--once", "Run a single tick then exit").option("--chain <chainId>", "Chain ID to run on (overrides CHAIN_ID env and .env.local)").action(async (opts) => {
|
|
44353
44377
|
try {
|
|
44354
|
-
await runCommand({ once: opts.once });
|
|
44378
|
+
await runCommand({ once: opts.once, chain: opts.chain ? Number(opts.chain) : void 0 });
|
|
44355
44379
|
} catch (err) {
|
|
44356
44380
|
console.error(`Error: ${err.message}`);
|
|
44357
44381
|
closePrompts();
|