@dev.sail.money/sailor 1.0.0-41 → 1.1.0-43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/AGENTS.md +5 -3
  2. package/README.md +29 -20
  3. package/docs/PERMISSION_MODEL.md +1 -1
  4. package/examples/README.md +24 -0
  5. package/package.json +1 -1
  6. package/packages/cli/README.md +0 -1
  7. package/packages/cli/dist/index.cjs +146 -185
  8. package/packages/cli/dist/server.cjs +11 -10
  9. package/packages/sdk/dist/intelligence.d.ts +1 -1
  10. package/packages/sdk/dist/intelligence.js +1 -1
  11. package/packages/ui/dist/assets/{add-DbjK_KOY.js → add-BjqRem-K.js} +1 -1
  12. package/packages/ui/dist/assets/{all-wallets-D-pRl2aR.js → all-wallets-Ce2n1Z8I.js} +1 -1
  13. package/packages/ui/dist/assets/{app-store-CGPMFKRx.js → app-store-C7E_7mH6.js} +1 -1
  14. package/packages/ui/dist/assets/{apple-CD0_2QLO.js → apple-BC7kAskQ.js} +1 -1
  15. package/packages/ui/dist/assets/{arrow-bottom-CxjDQwTG.js → arrow-bottom-Dq_l3FWT.js} +1 -1
  16. package/packages/ui/dist/assets/{arrow-bottom-circle-BOMbSnUT.js → arrow-bottom-circle-CjACGJGK.js} +1 -1
  17. package/packages/ui/dist/assets/{arrow-left-BjsweW6y.js → arrow-left-5W_pClNR.js} +1 -1
  18. package/packages/ui/dist/assets/{arrow-right-C0eZfPlR.js → arrow-right-DXy553gM.js} +1 -1
  19. package/packages/ui/dist/assets/{arrow-top-B4cVP0zb.js → arrow-top-DD0q04nr.js} +1 -1
  20. package/packages/ui/dist/assets/{bank-CxRmdPHn.js → bank-CCXCwaWG.js} +1 -1
  21. package/packages/ui/dist/assets/{basic-BKiQJvSY.js → basic-CAwLXzDD.js} +1 -1
  22. package/packages/ui/dist/assets/{browser-CT-PmzMC.js → browser-DWmAo_2s.js} +1 -1
  23. package/packages/ui/dist/assets/{card-Cwr0ZA0B.js → card-C_tjSBK2.js} +1 -1
  24. package/packages/ui/dist/assets/{ccip-8NLWAk-v.js → ccip-B4SUIV1s.js} +1 -1
  25. package/packages/ui/dist/assets/{checkmark-C7q-mH5M.js → checkmark-W_dSsbPW.js} +1 -1
  26. package/packages/ui/dist/assets/{checkmark-bold-Ds0vEbdx.js → checkmark-bold-C9Xi2fBZ.js} +1 -1
  27. package/packages/ui/dist/assets/{chevron-bottom-DykPQ8Vw.js → chevron-bottom-Dxo8Hw1W.js} +1 -1
  28. package/packages/ui/dist/assets/{chevron-left-IdV7mUty.js → chevron-left-CD7UuRQl.js} +1 -1
  29. package/packages/ui/dist/assets/{chevron-right-D7R7ycHG.js → chevron-right-D6kOGOGy.js} +1 -1
  30. package/packages/ui/dist/assets/{chevron-top-BGSS3FDn.js → chevron-top-ynjtovar.js} +1 -1
  31. package/packages/ui/dist/assets/{chrome-store-BGnrkOSx.js → chrome-store-CB5wu9g8.js} +1 -1
  32. package/packages/ui/dist/assets/{clock-DIqM2bTR.js → clock-B3H1XYXj.js} +1 -1
  33. package/packages/ui/dist/assets/{close-B7lg1PGj.js → close-DVSIOMF5.js} +1 -1
  34. package/packages/ui/dist/assets/{coinPlaceholder-PvGiH3tt.js → coinPlaceholder-Co_HN9AE.js} +1 -1
  35. package/packages/ui/dist/assets/{compass-BhHuxeT9.js → compass-CaY11Job.js} +1 -1
  36. package/packages/ui/dist/assets/{copy-GbypvZa2.js → copy-D7gntTj6.js} +1 -1
  37. package/packages/ui/dist/assets/{core-DJKvcaym.js → core-CqvnE8sM.js} +3 -3
  38. package/packages/ui/dist/assets/cursor-rLwK_mXz.js +3 -0
  39. package/packages/ui/dist/assets/{cursor-transparent-DqndT7J-.js → cursor-transparent-BrL6QUeS.js} +1 -1
  40. package/packages/ui/dist/assets/{desktop-DDSy_oKC.js → desktop-BLH7DXoy.js} +1 -1
  41. package/packages/ui/dist/assets/{disconnect-DVfCfqhj.js → disconnect-BxnvzLHz.js} +1 -1
  42. package/packages/ui/dist/assets/{discord-CfmEZPK5.js → discord-CfV-36UX.js} +1 -1
  43. package/packages/ui/dist/assets/{etherscan-CfB9edN9.js → etherscan-CyMQ7xaE.js} +1 -1
  44. package/packages/ui/dist/assets/{events-cYLbpQpi.js → events-D_3qqJ93.js} +1 -1
  45. package/packages/ui/dist/assets/{exclamation-triangle-CbV9d5Gt.js → exclamation-triangle-DWjoM6jA.js} +1 -1
  46. package/packages/ui/dist/assets/{extension-To0EKkgs.js → extension-D3fVJAol.js} +1 -1
  47. package/packages/ui/dist/assets/{external-link-Cjt_oHSe.js → external-link-D1vHHGXX.js} +1 -1
  48. package/packages/ui/dist/assets/{facebook-VPqhEho1.js → facebook-Dzk6W-1X.js} +1 -1
  49. package/packages/ui/dist/assets/{fallback-mNp6Xdgm.js → fallback-BDBC0epM.js} +1 -1
  50. package/packages/ui/dist/assets/{farcaster-BV_jqIfZ.js → farcaster-BkJt6sOG.js} +1 -1
  51. package/packages/ui/dist/assets/{filters-BVmnJIrJ.js → filters-Btr-hO6b.js} +1 -1
  52. package/packages/ui/dist/assets/{github-Dz01qVZ-.js → github-ulrStu89.js} +1 -1
  53. package/packages/ui/dist/assets/{google-D61au46N.js → google-BTTDuZjf.js} +1 -1
  54. package/packages/ui/dist/assets/{help-circle-3xbpZnpn.js → help-circle-DcSMbQJh.js} +1 -1
  55. package/packages/ui/dist/assets/{id-Din3068v.js → id-7WOxEl6j.js} +1 -1
  56. package/packages/ui/dist/assets/{image-CKfGfDIM.js → image-D2GBTxnU.js} +1 -1
  57. package/packages/ui/dist/assets/index-BODuSfdj.css +1 -0
  58. package/packages/ui/dist/assets/{index-CIs_sD9M.js → index-BfABWjw0.js} +1 -1
  59. package/packages/ui/dist/assets/{index-CxpO9LVP.js → index-BjpGs3bJ.js} +3 -3
  60. package/packages/ui/dist/assets/{index-CxhKjz7v.js → index-Bvqcol0e.js} +1 -1
  61. package/packages/ui/dist/assets/{index-DH1S9O_2.js → index-C35kUMRo.js} +1 -1
  62. package/packages/ui/dist/assets/{index-CBEcDgJN.js → index-DOy_BvMy.js} +58 -58
  63. package/packages/ui/dist/assets/{index-C4virBcr.js → index-jNjVgIvi.js} +1 -1
  64. package/packages/ui/dist/assets/{index.es-D8L0a50U.js → index.es-Cz1WraDz.js} +4 -4
  65. package/packages/ui/dist/assets/{info-DRtyKxfe.js → info-CezLTebu.js} +1 -1
  66. package/packages/ui/dist/assets/{info-circle-C2kPOuUX.js → info-circle-BHDy0RH1.js} +1 -1
  67. package/packages/ui/dist/assets/{lightbulb-BN5kFg8c.js → lightbulb-DvUuugiy.js} +1 -1
  68. package/packages/ui/dist/assets/{mail-_DRdYVZn.js → mail-D6W2cU_-.js} +1 -1
  69. package/packages/ui/dist/assets/{metamask-sdk-jYYI1ijS.js → metamask-sdk-Cj8b59wb.js} +1 -1
  70. package/packages/ui/dist/assets/{mobile-CYGolrjP.js → mobile-DD4cG8mI.js} +1 -1
  71. package/packages/ui/dist/assets/{more-5BeEuz7E.js → more-RsHIPHXv.js} +1 -1
  72. package/packages/ui/dist/assets/{network-placeholder-Cxnb3rOe.js → network-placeholder-E2lpOWE4.js} +1 -1
  73. package/packages/ui/dist/assets/{nftPlaceholder-B4rjN_Hx.js → nftPlaceholder-Cm9qGJHf.js} +1 -1
  74. package/packages/ui/dist/assets/{off-CdpeUxA1.js → off-7ALa1e8N.js} +1 -1
  75. package/packages/ui/dist/assets/{parseSignature-u9UVA_Bl.js → parseSignature-EU-GmuA0.js} +1 -1
  76. package/packages/ui/dist/assets/{play-store-BWayr9aI.js → play-store-YmFLoPbj.js} +1 -1
  77. package/packages/ui/dist/assets/{plus-DfuMhUM_.js → plus-CljVpN-Y.js} +1 -1
  78. package/packages/ui/dist/assets/{qr-code-Do9ZALD6.js → qr-code-DVGz15q5.js} +1 -1
  79. package/packages/ui/dist/assets/{recycle-horizontal-DooA8q8W.js → recycle-horizontal-Ch_2PFBB.js} +1 -1
  80. package/packages/ui/dist/assets/{refresh-BZJGp6uc.js → refresh-B1yJjeZR.js} +1 -1
  81. package/packages/ui/dist/assets/{reown-logo-9mp7ukyl.js → reown-logo-B4gHTrkG.js} +1 -1
  82. package/packages/ui/dist/assets/{search-CziyZpj-.js → search-C7OPO4bC.js} +1 -1
  83. package/packages/ui/dist/assets/{secp256k1-DIBahqDI.js → secp256k1-ZHPkrWDd.js} +1 -1
  84. package/packages/ui/dist/assets/{send-1Muyywuj.js → send-C5Aj89yl.js} +1 -1
  85. package/packages/ui/dist/assets/{swapHorizontal-CEgWi6Pm.js → swapHorizontal-D5l_jKrZ.js} +1 -1
  86. package/packages/ui/dist/assets/{swapHorizontalBold-gMkraANQ.js → swapHorizontalBold-TxFZ3Umb.js} +1 -1
  87. package/packages/ui/dist/assets/{swapHorizontalMedium-D-Y4qbU1.js → swapHorizontalMedium-M_yuNi0o.js} +1 -1
  88. package/packages/ui/dist/assets/{swapHorizontalRoundedBold-CAMvP_dz.js → swapHorizontalRoundedBold-G73a-cMg.js} +1 -1
  89. package/packages/ui/dist/assets/{swapVertical-BJ7q0h0y.js → swapVertical-Gy7GjYS4.js} +1 -1
  90. package/packages/ui/dist/assets/{telegram-GpnTfdCQ.js → telegram-BnO9isY5.js} +1 -1
  91. package/packages/ui/dist/assets/{three-dots-BUhvTyOi.js → three-dots-B616bG-O.js} +1 -1
  92. package/packages/ui/dist/assets/{twitch-BrGPOA5o.js → twitch-DUpzj8Dd.js} +1 -1
  93. package/packages/ui/dist/assets/{twitterIcon-BjM7MxdG.js → twitterIcon-itK0Mrgj.js} +1 -1
  94. package/packages/ui/dist/assets/{verify-HbFWmb2f.js → verify-B1Gtl5H9.js} +1 -1
  95. package/packages/ui/dist/assets/{verify-filled-SlXjIy2_.js → verify-filled-D3noLrZ3.js} +1 -1
  96. package/packages/ui/dist/assets/{w3m-modal-DbUCvIfl.js → w3m-modal-CiZVJcHR.js} +1 -1
  97. package/packages/ui/dist/assets/{wallet-CioTciNz.js → wallet-BK1sp3ca.js} +1 -1
  98. package/packages/ui/dist/assets/{wallet-placeholder-DS4wDXQo.js → wallet-placeholder-CatD0vru.js} +1 -1
  99. package/packages/ui/dist/assets/{walletconnect-ioE7leyd.js → walletconnect-DmCqpZUB.js} +1 -1
  100. package/packages/ui/dist/assets/{warning-circle-CfXfQlpb.js → warning-circle-bT7aRO8J.js} +1 -1
  101. package/packages/ui/dist/assets/{x-DB1YTl_6.js → x-DuFufU-Y.js} +1 -1
  102. package/packages/ui/dist/index.html +2 -2
  103. package/scripts/check-docs.mjs +51 -4
  104. package/scripts/check-init.mjs +12 -0
  105. package/templates/default/.agents/skills/sail-ci/SKILL.md +66 -0
  106. package/templates/default/.agents/skills/sail-extend/SKILL.md +74 -0
  107. package/templates/default/.agents/skills/sail-mandates/SKILL.md +93 -0
  108. package/templates/default/.agents/skills/sail-mandates/references/approvals.md +42 -0
  109. package/templates/default/.agents/skills/sail-mandates/references/calls-schema.md +42 -0
  110. package/templates/default/.agents/skills/sail-mandates/references/constructor-args.md +45 -0
  111. package/templates/default/.agents/skills/sail-mandates/references/examples-index.md +31 -0
  112. package/templates/default/.agents/skills/sail-mandates/references/simulate-calls.md +58 -0
  113. package/templates/default/.agents/skills/sail-onboarding/SKILL.md +73 -0
  114. package/templates/default/.agents/skills/sail-project-info/SKILL.md +30 -0
  115. package/templates/default/.agents/skills/sail-servers/SKILL.md +43 -0
  116. package/templates/default/.agents/skills/sail-transactions/SKILL.md +63 -0
  117. package/templates/default/AGENTS.md +37 -126
  118. package/templates/default/test/BoundedCallPermission.t.sol +73 -0
  119. package/packages/ui/dist/assets/cursor-DwpKqtX4.js +0 -3
  120. package/packages/ui/dist/assets/index-DS-4Qz48.css +0 -1
  121. /package/{templates → examples}/custom-mandate/.sail/contracts/interfaces/IPermission.sol +0 -0
  122. /package/{templates → examples}/custom-mandate/README.md +0 -0
  123. /package/{templates → examples}/custom-mandate/foundry.toml +0 -0
  124. /package/{templates → examples}/custom-mandate/mandates/BoundedCallPermission.sol +0 -0
  125. /package/{templates → examples}/custom-mandate/mandates/README.md +0 -0
  126. /package/{templates → examples}/custom-mandate/mandates/SailCalldata.sol +0 -0
  127. /package/{templates → examples}/lifi-permissions/LifiBoundedApprovePermissionCloneable.sol +0 -0
  128. /package/{templates → examples}/lifi-permissions/LifiDiamondSwapPermissionCloneable.sol +0 -0
  129. /package/{templates → examples}/lifi-permissions/README.md +0 -0
package/AGENTS.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Sailor — Codebase Guide
2
2
 
3
+ This guide is for contributors to the Sailor codebase. The user-facing agent guide ships in templates/default/AGENTS.md.
4
+
3
5
  Sailor is the operator toolkit for Sail Protocol. It does **not** deploy the protocol or author
4
6
  permission templates — it targets already-deployed SailKernel instances and gives operators the
5
7
  tooling to create SMAs, register permission contracts, and run strategy agents.
@@ -8,11 +10,11 @@ tooling to create SMAs, register permission contracts, and run strategy agents.
8
10
 
9
11
  | Package / path | Name | Role |
10
12
  |---|---|---|
11
- | `packages/sdk` | `@sail/sdk` | SailorClient, LocalKeyring, kernel ABIs, EIP-712 builders, deployment registry, per-chain address registry |
13
+ | `packages/sdk` | `@sail/sdk` | SailorClient, LocalKeyring, kernel ABIs, EIP-712 builders, deployment registry, per-chain address registry (publishes to npm as `@sail.money/sdk`) |
12
14
  | `packages/cli` | `sailor` | CLI: init, keys, account, mandate, onboard, station, ui, run, session, scan, status, owner, doctor, capabilities |
13
- | `packages/ui` | `sailor-ui` | Local dashboard + browser-driven onboarding wizard at localhost:3333 |
15
+ | `packages/ui` | `sailor-ui` | Local dashboard + browser-driven onboarding wizard (per-project port, 3333–3999) |
14
16
  | `templates/default` | — | Default agent starter: neutral blank scaffold + Foundry workspace + onboarding guide (AGENTS.md) |
15
- | `templates/custom-mandate` | — | Solidity reference: IPermission scaffold (not a project template) |
17
+ | `examples/custom-mandate` | — | Solidity reference: IPermission scaffold (not a project template) |
16
18
 
17
19
  ## Protocol roles
18
20
 
package/README.md CHANGED
@@ -12,10 +12,11 @@ Sailor is the off-chain operator layer for [Sail Protocol](https://github.com/sa
12
12
  |---|---|---|
13
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 at localhost:3333 |
16
- | `templates/default` | — | Default agent starter (neutral; what `sailor init` scaffolds) |
17
- | `templates/custom-mandate` | — | Solidity reference: IPermission scaffold (not a project template) |
18
- | `templates/lifi-permissions` | — | Solidity reference: LiFi clone permission contracts (not a project template) |
15
+ | `packages/ui` | `sailor-ui` | Local dashboard (per-project port; see Dashboard below) |
16
+ | `templates/default` | — | The agent starter `sailor init` scaffolds: slim `AGENTS.md` + on-demand skills under `.agents/skills/` |
17
+ | `examples/permissions` | — | Worked permission contracts by protocol and chain (reference, unaudited) |
18
+ | `examples/custom-mandate` | — | Solidity reference: IPermission authoring scaffold |
19
+ | `examples/lifi-permissions` | — | Solidity reference: LiFi clone permission contracts (source of the clone implementations) |
19
20
 
20
21
  ---
21
22
 
@@ -63,7 +64,11 @@ The path from nothing to a running agent follows the protocol lifecycle:
63
64
  4. **Run** — `sailor run` executes the agent locally on a schedule, or via the GitHub Actions workflow the scaffold provides.
64
65
  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
 
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.
67
+ Run `npx sailor init my-agent`, open the scaffolded folder in Claude Code, Cursor, or any AI coding assistant, and say **"start"**.
68
+
69
+ ### How the assistant is guided
70
+
71
+ The scaffold follows the open [Agent Skills](https://agentskills.io) standard: a slim, always-loaded `AGENTS.md` carries the welcome flow, project-state map, and hard invariants, while detailed procedures live in seven on-demand skills under `.agents/skills/` (onboarding, project info, servers, transactions, mandates, CI, extensions). Assistants that scan skills load each one only when relevant; assistants that don't follow the routing table in `AGENTS.md` to the same plain-markdown files. Works in Claude Code, Cursor, Copilot, and Codex.
67
72
 
68
73
  ---
69
74
 
@@ -120,7 +125,7 @@ mkdir my-agent && cd my-agent && npm i @sail.money/sailor && npx sailor init &&
120
125
  mkdir my-agent ; cd my-agent ; npm i @sail.money/sailor ; npx sailor init ; npm install
121
126
  ```
122
127
 
123
- 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.
128
+ Open this folder in Claude Code, Cursor, Codex, or any AI coding assistant and say **"start"**. The scaffolded `AGENTS.md` and its skills guide the assistant through the whole flow — SMA deployment, strategy definition, mandate authoring, running, and automation. No manual steps required.
124
129
 
125
130
  ### Direct CLI reference
126
131
 
@@ -146,7 +151,7 @@ sailor run # start the agent (continuous)
146
151
  sailor keys export-ci # copy encrypted agent wallet to ci-keystore.json for CI
147
152
 
148
153
  # Dashboard
149
- sailor ui start # open http://localhost:3333
154
+ sailor ui start # prints the per-project dashboard URL
150
155
  ```
151
156
 
152
157
  `sailor run` writes reverted transactions to stderr as `reverted: <txHash> (gas used: N)`; successful dispatches are appended to `.sail/activity.jsonl`.
@@ -174,9 +179,9 @@ sailor init my-agent --template <name> # named subdirectory + specific templat
174
179
  ### What makes a valid template
175
180
 
176
181
  A valid template is any directory under `templates/` that contains a
177
- `package.json`. Directories without one (e.g. `custom-mandate`,
178
- `lifi-permissions`) are Solidity reference sources, not project scaffolds, and
179
- are excluded from the available list.
182
+ `package.json`. Solidity reference sources live under `examples/`
183
+ (`examples/permissions`, `examples/custom-mandate`, `examples/lifi-permissions`)
184
+ — they are not project scaffolds and never appear in the template list.
180
185
 
181
186
  ### Adding a template
182
187
 
@@ -193,18 +198,22 @@ Template files are bundled into the published `sailor` npm package via the
193
198
 
194
199
  ## Dashboard (`sailor ui`)
195
200
 
196
- The Sailor dashboard is a local React app served at `http://localhost:3333`.
197
- It shows live account state, mandate health, signer balances, and recent
198
- activity — all read from the project's `.sail/` directory with no hosted
199
- backend.
201
+ The Sailor dashboard is a local React app. It shows live account state, mandate
202
+ health, signer balances, and recent activity — all read from the project's
203
+ `.sail/` directory with no hosted backend.
204
+
205
+ Each project gets its own deterministic port in the 3333–3999 range (derived
206
+ from the project path, so several projects can run dashboards side by side).
207
+ Use the URL the command prints, or read it from `.sail/runtime/ui.json` —
208
+ do not assume port 3333.
200
209
 
201
210
  ### Commands
202
211
 
203
212
  ```bash
204
213
  sailor ui # start the dashboard (same as sailor ui start)
205
- sailor ui start # start the dashboard at http://localhost:3333
214
+ sailor ui start # start the dashboard and print its URL
206
215
  sailor ui stop # stop the running dashboard
207
- sailor ui status # show whether the dashboard is running + pid
216
+ sailor ui status # show whether the dashboard is running + URL + pid
208
217
  ```
209
218
 
210
219
  ### How it works
@@ -224,7 +233,7 @@ This means you can start the dashboard in one terminal and stop it from another.
224
233
  ```bash
225
234
  # macOS / Linux
226
235
  sailor ui start &
227
- sailor ui status # ● running http://localhost:3333 (pid 12345)
236
+ sailor ui status # ● running http://localhost:<port> (pid 12345)
228
237
  sailor ui stop # Stopped Sailor UI (pid 12345).
229
238
 
230
239
  # Windows (PowerShell)
@@ -317,8 +326,8 @@ Published to the public npm registry under the `@sail.money` scope.
317
326
 
318
327
  | Trigger | Package | Version | dist-tag |
319
328
  |---|---|---|---|
320
- | Tag push (`v*`) | `@sail.money/sailor` | `0.1.0` | `latest` |
321
- | Manual dispatch | `@dev.sail.money/sailor` | `0.1.0-42` | `dev` |
329
+ | Tag push (`v*`) | `@sail.money/sailor` | `1.1.0` | `latest` |
330
+ | Manual dispatch | `@dev.sail.money/sailor` | `1.1.0-42` | `dev` |
322
331
 
323
332
  ```bash
324
333
  npm install @sail.money/sailor # latest stable (tag push)
@@ -378,7 +387,7 @@ Either way, `@sail.money/sailor/sdk` imports work unchanged.
378
387
 
379
388
  ## State of the project
380
389
 
381
- 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.
390
+ Sailor is functional and published as [`@sail.money/sailor`](https://www.npmjs.com/package/@sail.money/sailor) on npm (v1.1.0). The SDK, CLI, keystore, mandate flows, agent runner, and dashboard are implemented and have been exercised end to end.
382
391
 
383
392
  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.
384
393
 
@@ -45,7 +45,7 @@ other." The fix was to redeploy every permission with pass-through semantics.
45
45
  Corollary: on a conjunctive kernel you **cannot** have two permissions that each
46
46
  enforce a different token's approve — each would reject the other's token. To support
47
47
  approving both DAI and USDC you need **one** approve permission that allows both (see
48
- `templates/lifi-permissions/`), not two narrow ones.
48
+ `examples/lifi-permissions/`), not two narrow ones.
49
49
 
50
50
  Selective kernels don't have this problem: each dispatch names one permission and
51
51
  only that one is consulted.
@@ -0,0 +1,24 @@
1
+ # examples/
2
+
3
+ Reference material for building Sail permission contracts. Nothing here is part of
4
+ Sail Protocol and nothing here is audited.
5
+
6
+ ## What's in here
7
+
8
+ ### `permissions/`
9
+
10
+ Protocol-specific permission examples (Uniswap, Aave, GMX, Vault, Pendle, and others).
11
+ These are copied into your project by `sailor init` so you have local starting points to
12
+ adapt. They are not a supported or exhaustive library — review them before using.
13
+
14
+ ### `custom-mandate/`
15
+
16
+ A standalone Foundry workspace scaffold for authoring your own `IPermission` contract as a
17
+ separate project. Fork it, rename it, and build from `BoundedCallPermission.sol`.
18
+
19
+ ### `lifi-permissions/`
20
+
21
+ Reference-only source for the deployed LiFi EIP-1167 clone implementations
22
+ (`LifiBoundedApprovePermissionCloneable`, `LifiDiamondSwapPermissionCloneable`).
23
+ These document live deployed contracts — do not adapt them directly for new projects.
24
+ See the `README.md` inside for deployment addresses and the conjunctive-kernel caveat.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev.sail.money/sailor",
3
- "version": "1.0.0-41",
3
+ "version": "1.1.0-43",
4
4
  "description": "Operator toolkit for Sail Protocol",
5
5
  "bin": {
6
6
  "sailor": "packages/cli/dist/index.cjs"
@@ -14,7 +14,6 @@ sailor init my-fund
14
14
 
15
15
  - `sailor init [name]` — scaffold a new agent project from a template
16
16
  - `sailor keys generate|show` — generate/show the agent wallet and mandate signer keys
17
- - `sailor account create` — create a new SMA on-chain
18
17
  - `sailor onboard` — set up an SMA, register a permission, and confirm the agent is operational
19
18
  - `sailor mandate prepare` — review the permissions attached to your SMA
20
19
  - `sailor mandate sign` — confirm the permissions authorized for your SMA
@@ -35189,6 +35189,10 @@ var require_websocket_server2 = __commonJS({
35189
35189
  }
35190
35190
  });
35191
35191
 
35192
+ // src/index.ts
35193
+ var import_node_fs18 = require("node:fs");
35194
+ var import_node_path14 = require("node:path");
35195
+
35192
35196
  // ../../node_modules/.pnpm/commander@12.1.0/node_modules/commander/esm.mjs
35193
35197
  var import_index = __toESM(require_commander(), 1);
35194
35198
  var {
@@ -38442,14 +38446,6 @@ async function confirm(question) {
38442
38446
  const answer = (await prompt(`${question} (y/N)`)).toLowerCase();
38443
38447
  return answer === "y" || answer === "yes";
38444
38448
  }
38445
- async function promptAddress(label, def) {
38446
- for (let attempt = 0; attempt < 5; attempt++) {
38447
- const raw = await prompt(label, def);
38448
- if (isAddress(raw)) return getAddress(raw);
38449
- console.log(` "${raw}" is not a valid EVM address \u2014 try again.`);
38450
- }
38451
- throw new Error(`No valid address provided for: ${label}`);
38452
- }
38453
38449
  async function promptHidden(question) {
38454
38450
  const isTty = process.stdin.isTTY === true;
38455
38451
  if (isTty) muted = true;
@@ -38492,87 +38488,6 @@ function getRpcUrl(chainId) {
38492
38488
  return process.env.RPC_URL?.trim() || void 0;
38493
38489
  }
38494
38490
 
38495
- // src/lib/keys.ts
38496
- init_esm2();
38497
- var ROLES = ["manager", "permissionSigner"];
38498
- function normalizeRole(input) {
38499
- const n = input.trim().toLowerCase().replace(/[-_\s]/g, "");
38500
- if (n === "manager" || n === "mgr" || n === "m" || n === "agent" || n === "agentwallet") {
38501
- return "manager";
38502
- }
38503
- if (n === "permissionsigner" || n === "signer" || n === "ps" || n === "permission" || n === "mandatesigner" || n === "mandate") {
38504
- return "permissionSigner";
38505
- }
38506
- return null;
38507
- }
38508
- function roleLabel(role) {
38509
- return role === "manager" ? "agent wallet" : "mandate signer";
38510
- }
38511
- function safeHex(safe) {
38512
- return safe.toLowerCase().replace(/^0x/, "").replace(/[^0-9a-f]/g, "");
38513
- }
38514
- function keyPath(role, safe) {
38515
- if (safe) {
38516
- return sailPath("keys", `${role}-0x${safeHex(safe)}.json`);
38517
- }
38518
- return sailPath("keys", `${role}.json`);
38519
- }
38520
- function legacyKeyPath(role, safe) {
38521
- return sailPath("keys", `${role}-${safeHex(safe)}.json`);
38522
- }
38523
- function resolveKeyPath(role, safe) {
38524
- if (safe) {
38525
- const perSma = keyPath(role, safe);
38526
- if (fileExists(perSma)) return perSma;
38527
- const legacy = legacyKeyPath(role, safe);
38528
- if (fileExists(legacy)) return legacy;
38529
- }
38530
- return keyPath(role);
38531
- }
38532
- function keyExists(role, safe) {
38533
- return fileExists(resolveKeyPath(role, safe));
38534
- }
38535
- async function loadKeyring(role, safe) {
38536
- const keystore = readJsonFile(resolveKeyPath(role, safe));
38537
- if (!keystore) {
38538
- throw new Error(
38539
- `No ${roleLabel(role)} found.
38540
- Run "sailor keys generate" and choose "${roleLabel(role)}" first.`
38541
- );
38542
- }
38543
- const password = await promptHidden(`Password for ${roleLabel(role)} key`);
38544
- try {
38545
- return await LocalKeyring.fromKeystore(keystore, password);
38546
- } catch {
38547
- throw new Error("Invalid password.");
38548
- }
38549
- }
38550
- async function loadManagerSigner(safe) {
38551
- const passphrase = process.env.SAIL_PASSPHRASE;
38552
- if (passphrase) {
38553
- const keystore = readJsonFile(resolveKeyPath("manager", safe));
38554
- if (!keystore) {
38555
- throw new Error(
38556
- 'No agent wallet found.\nRun "sailor keys generate" and choose "agent wallet".'
38557
- );
38558
- }
38559
- return LocalKeyring.fromKeystore(keystore, passphrase);
38560
- }
38561
- return loadKeyring("manager", safe);
38562
- }
38563
- function managerKeystorePath(managerAddr) {
38564
- if (!isAddress(managerAddr, { strict: false })) {
38565
- throw new Error(`managerKeystorePath: invalid address "${managerAddr}"`);
38566
- }
38567
- const hex = managerAddr.toLowerCase().replace(/^0x/, "");
38568
- return sailPath("keys", "managers", `${hex}.json`);
38569
- }
38570
- async function loadAnySigner() {
38571
- if (keyExists("permissionSigner")) return loadKeyring("permissionSigner");
38572
- if (keyExists("manager")) return loadKeyring("manager");
38573
- throw new Error('No signing key found.\nRun "sailor keys generate" first.');
38574
- }
38575
-
38576
38491
  // src/lib/packagePaths.ts
38577
38492
  var import_node_fs3 = __toESM(require("node:fs"), 1);
38578
38493
  var import_node_path2 = __toESM(require("node:path"), 1);
@@ -39330,86 +39245,6 @@ async function createSigningChannel(projectRoot = process.cwd()) {
39330
39245
  }
39331
39246
 
39332
39247
  // src/commands/account.ts
39333
- function resolveChain(chainId) {
39334
- try {
39335
- return getChain(chainId);
39336
- } catch {
39337
- throw new Error(
39338
- `Chain ${chainId} is not yet configured in @sail/chains.
39339
- The SailKernel and mandate-factory addresses for this chain are unknown,
39340
- so an account cannot be created yet. Add the chain to @sail/chains once
39341
- SailKernel is deployed there.`
39342
- );
39343
- }
39344
- }
39345
- async function accountCreate() {
39346
- if (!keyExists("manager")) {
39347
- throw new Error(
39348
- 'No agent wallet found.\nRun "sailor keys generate" and choose "agent wallet" first.'
39349
- );
39350
- }
39351
- const env = parseEnvFile(sailPath(".env.local"));
39352
- const rpcUrl = env["RPC_URL"] ?? process.env["RPC_URL"];
39353
- const chainIdRaw = env["CHAIN_ID"] ?? process.env["CHAIN_ID"];
39354
- if (!rpcUrl || !chainIdRaw) {
39355
- throw new Error(
39356
- "RPC_URL and CHAIN_ID must be set in .sail/.env.local.\nCreate that file with, for example:\n RPC_URL=https://your-rpc-endpoint\n CHAIN_ID=8453"
39357
- );
39358
- }
39359
- const chainId = Number(chainIdRaw);
39360
- if (Number.isNaN(chainId)) {
39361
- throw new Error(`Invalid CHAIN_ID: "${chainIdRaw}" \u2014 must be a number.`);
39362
- }
39363
- const chain2 = resolveChain(chainId);
39364
- console.log(`Chain ${chainId} (${chain2.name})`);
39365
- console.log(` SailKernel: ${checksum4(chain2.kernel)}`);
39366
- console.log(` Mandate factory: ${checksum4(chain2.mandateFactory)}
39367
- `);
39368
- const manager = await loadKeyring("manager");
39369
- const managerAddr = checksum4(manager.address);
39370
- const safeFactory = await promptAddress("Safe factory address");
39371
- const safeSingleton = await promptAddress("Safe singleton address");
39372
- const owner2 = await promptAddress("Owner (EOA) address", managerAddr);
39373
- const permissionSigner = await promptAddress("Mandate signer address", managerAddr);
39374
- const feePolicy = await prompt("Fee policy", "none");
39375
- console.log("\nCreating SMA with:");
39376
- console.log(` Owner: ${owner2}`);
39377
- console.log(` Agent wallet: ${managerAddr}`);
39378
- console.log(` Mandate signer: ${permissionSigner}`);
39379
- console.log(` Safe factory: ${safeFactory}`);
39380
- console.log(` Safe singleton: ${safeSingleton}`);
39381
- console.log(` Fee policy: ${feePolicy}`);
39382
- const client = makeClient(chainId);
39383
- try {
39384
- const account2 = await client.account.create({
39385
- owner: owner2,
39386
- permissionSigner,
39387
- manager: managerAddr,
39388
- chainId
39389
- });
39390
- const stored = {
39391
- safe: checksum4(account2.safe),
39392
- owner: checksum4(account2.owner),
39393
- permissionSigner: checksum4(account2.permissionSigner),
39394
- manager: checksum4(account2.manager),
39395
- chainId: account2.chainId,
39396
- createdAtBlock: account2.createdAtBlock.toString()
39397
- };
39398
- upsertAccountInList(stored);
39399
- writeJsonFile(sailPath("account.json"), stored);
39400
- console.log(`
39401
- SMA created. Address: ${stored.safe}`);
39402
- console.log("Saved to .sail/account.json");
39403
- } catch (err) {
39404
- if (err.message === "not implemented") {
39405
- console.log(
39406
- "\nOn-chain account creation is not wired up in this build yet \u2014\nclient.account.create is a stub until SailKernel is deployed and the\nSDK is connected. Nothing was created on-chain."
39407
- );
39408
- return;
39409
- }
39410
- throw err;
39411
- }
39412
- }
39413
39248
  var SAIL_MAINNET_CHAINS = [1, 8453, 42161, 130];
39414
39249
  async function fetchProxyCreationCode(preferredChainId) {
39415
39250
  const rpcUrl = getRpcUrl(preferredChainId) ?? void 0;
@@ -39801,6 +39636,89 @@ function emit(json, human, payload) {
39801
39636
 
39802
39637
  // src/lib/project.ts
39803
39638
  init_esm2();
39639
+
39640
+ // src/lib/keys.ts
39641
+ init_esm2();
39642
+ var ROLES = ["manager", "permissionSigner"];
39643
+ function normalizeRole(input) {
39644
+ const n = input.trim().toLowerCase().replace(/[-_\s]/g, "");
39645
+ if (n === "manager" || n === "mgr" || n === "m" || n === "agent" || n === "agentwallet") {
39646
+ return "manager";
39647
+ }
39648
+ if (n === "permissionsigner" || n === "signer" || n === "ps" || n === "permission" || n === "mandatesigner" || n === "mandate") {
39649
+ return "permissionSigner";
39650
+ }
39651
+ return null;
39652
+ }
39653
+ function roleLabel(role) {
39654
+ return role === "manager" ? "agent wallet" : "mandate signer";
39655
+ }
39656
+ function safeHex(safe) {
39657
+ return safe.toLowerCase().replace(/^0x/, "").replace(/[^0-9a-f]/g, "");
39658
+ }
39659
+ function keyPath(role, safe) {
39660
+ if (safe) {
39661
+ return sailPath("keys", `${role}-0x${safeHex(safe)}.json`);
39662
+ }
39663
+ return sailPath("keys", `${role}.json`);
39664
+ }
39665
+ function legacyKeyPath(role, safe) {
39666
+ return sailPath("keys", `${role}-${safeHex(safe)}.json`);
39667
+ }
39668
+ function resolveKeyPath(role, safe) {
39669
+ if (safe) {
39670
+ const perSma = keyPath(role, safe);
39671
+ if (fileExists(perSma)) return perSma;
39672
+ const legacy = legacyKeyPath(role, safe);
39673
+ if (fileExists(legacy)) return legacy;
39674
+ }
39675
+ return keyPath(role);
39676
+ }
39677
+ function keyExists(role, safe) {
39678
+ return fileExists(resolveKeyPath(role, safe));
39679
+ }
39680
+ async function loadKeyring(role, safe) {
39681
+ const keystore = readJsonFile(resolveKeyPath(role, safe));
39682
+ if (!keystore) {
39683
+ throw new Error(
39684
+ `No ${roleLabel(role)} found.
39685
+ Run "sailor keys generate" and choose "${roleLabel(role)}" first.`
39686
+ );
39687
+ }
39688
+ const password = await promptHidden(`Password for ${roleLabel(role)} key`);
39689
+ try {
39690
+ return await LocalKeyring.fromKeystore(keystore, password);
39691
+ } catch {
39692
+ throw new Error("Invalid password.");
39693
+ }
39694
+ }
39695
+ async function loadManagerSigner(safe) {
39696
+ const passphrase = process.env.SAIL_PASSPHRASE;
39697
+ if (passphrase) {
39698
+ const keystore = readJsonFile(resolveKeyPath("manager", safe));
39699
+ if (!keystore) {
39700
+ throw new Error(
39701
+ 'No agent wallet found.\nRun "sailor keys generate" and choose "agent wallet".'
39702
+ );
39703
+ }
39704
+ return LocalKeyring.fromKeystore(keystore, passphrase);
39705
+ }
39706
+ return loadKeyring("manager", safe);
39707
+ }
39708
+ function managerKeystorePath(managerAddr) {
39709
+ if (!isAddress(managerAddr, { strict: false })) {
39710
+ throw new Error(`managerKeystorePath: invalid address "${managerAddr}"`);
39711
+ }
39712
+ const hex = managerAddr.toLowerCase().replace(/^0x/, "");
39713
+ return sailPath("keys", "managers", `${hex}.json`);
39714
+ }
39715
+ async function loadAnySigner() {
39716
+ if (keyExists("permissionSigner")) return loadKeyring("permissionSigner");
39717
+ if (keyExists("manager")) return loadKeyring("manager");
39718
+ throw new Error('No signing key found.\nRun "sailor keys generate" first.');
39719
+ }
39720
+
39721
+ // src/lib/project.ts
39804
39722
  function nonEmpty(value) {
39805
39723
  return typeof value === "string" && value.trim().length > 0;
39806
39724
  }
@@ -40480,6 +40398,40 @@ interface IPermission {
40480
40398
  function discriminator() external view returns (bytes32);
40481
40399
  }
40482
40400
  `;
40401
+ var IBATCHPERMISSION_SOL = `// SPDX-License-Identifier: MIT
40402
+ pragma solidity 0.8.26;
40403
+
40404
+ /// @notice A single subcall in a batch dispatch.
40405
+ /// @dev The kernel executes each Call as safe.execTransactionFromModule(target, value, data, 0)
40406
+ /// \u2014 operation is always CALL, never DELEGATECALL.
40407
+ struct Call {
40408
+ address target; // MUST NOT equal the kernel (enforced by the kernel)
40409
+ uint256 value; // native ETH forwarded (wei)
40410
+ bytes data; // calldata for the subcall
40411
+ }
40412
+
40413
+ /// @notice Execution context passed to evaluateBatch on each batch dispatch (read-only snapshot).
40414
+ struct BatchContext {
40415
+ address account; // the Safe (SMA) whose assets are moved
40416
+ address manager; // the delegated signer who authorised the batch
40417
+ address submitter; // msg.sender of the dispatch (may differ from manager via a relayer)
40418
+ address permission; // this batch permission contract
40419
+ bytes32 batchHash; // keccak256(abi.encode(calls)) \u2014 stable id for the exact sequence
40420
+ uint256 blockTimestamp; // block.timestamp at dispatch
40421
+ uint256 blockNumber; // block.number at dispatch
40422
+ }
40423
+
40424
+ /// @title IBatchPermission
40425
+ /// @notice Gates an atomic batch of subcalls. Evaluated via staticcall under a gas cap;
40426
+ /// a revert / OOG / malformed return is treated as \`false\` (fail-closed).
40427
+ interface IBatchPermission {
40428
+ /// @notice Validate an entire batch of subcalls and their cross-call invariants.
40429
+ function evaluateBatch(Call[] calldata calls, BatchContext calldata ctx) external view returns (bool);
40430
+
40431
+ /// @notice Marker the kernel uses (try/catch) to detect batch-aware permissions. MUST return true.
40432
+ function isBatchPermission() external pure returns (bool);
40433
+ }
40434
+ `;
40483
40435
  var EXAMPLE_MANDATE_SOL = `// SPDX-License-Identifier: MIT
40484
40436
  pragma solidity 0.8.26;
40485
40437
 
@@ -40561,6 +40513,10 @@ function scaffoldFoundryWorkspace(root) {
40561
40513
  (0, import_node_path6.join)(root, ".sail", "contracts", "interfaces", "IPermission.sol"),
40562
40514
  IPERMISSION_SOL
40563
40515
  );
40516
+ writeIfMissing(
40517
+ (0, import_node_path6.join)(root, ".sail", "contracts", "interfaces", "IBatchPermission.sol"),
40518
+ IBATCHPERMISSION_SOL
40519
+ );
40564
40520
  writeIfMissing((0, import_node_path6.join)(root, "mandates", "BoundedCallPermission.sol"), EXAMPLE_MANDATE_SOL);
40565
40521
  writeIfMissing((0, import_node_path6.join)(root, "mandates", "README.md"), MANDATES_README);
40566
40522
  }
@@ -40722,6 +40678,10 @@ run from the repo root.` : ` Available: ${available}`;
40722
40678
  if (import_node_fs8.default.existsSync(examplesPermSrc)) {
40723
40679
  copyDirSync(examplesPermSrc, import_node_path7.default.join(dest, "examples", "permissions"));
40724
40680
  }
40681
+ const customMandateSrc = import_node_path7.default.join(pkgRoot, "examples", "custom-mandate");
40682
+ if (import_node_fs8.default.existsSync(customMandateSrc)) {
40683
+ copyDirSync(customMandateSrc, import_node_path7.default.join(dest, "examples", "custom-mandate"));
40684
+ }
40725
40685
  const permModelSrc = import_node_path7.default.join(pkgRoot, "docs", "PERMISSION_MODEL.md");
40726
40686
  if (import_node_fs8.default.existsSync(permModelSrc)) {
40727
40687
  import_node_fs8.default.mkdirSync(import_node_path7.default.join(dest, "docs"), { recursive: true });
@@ -40849,7 +40809,7 @@ Created ${name}/`);
40849
40809
  "\u2551 \u2551",
40850
40810
  "\u2551 DO THIS FIRST: \u2551",
40851
40811
  "\u2551 1. Read AGENTS.md in the project root (FULL FILE, not a skim) \u2551",
40852
- "\u2551 2. Complete every step listed under Stage 1 \u2014 Onboarding \u2551",
40812
+ "\u2551 2. Follow it \u2014 the detailed steps live in .agents/skills/ \u2551",
40853
40813
  '\u2551 3. Confirm to the user: "I have read AGENTS.md and am ready." \u2551',
40854
40814
  "\u2551 \u2551",
40855
40815
  "\u2551 If you skip this step, setup WILL break and you will have to \u2551",
@@ -42317,7 +42277,7 @@ function mandateTemplates(options) {
42317
42277
  console.log(" 2. Implement IPermission.evaluate(txData, ctx) with your policy logic");
42318
42278
  console.log(" 3. forge build");
42319
42279
  console.log(" 4. sailor mandate deploy --contract <Name> --attach --sma <yourSMA>");
42320
- console.log("\n See templates/custom-mandate/README.md for the full guide.");
42280
+ console.log("\n See examples/custom-mandate/README.md for the full guide.");
42321
42281
  if (community.length > 0) {
42322
42282
  console.log(
42323
42283
  "\nCommunity-deployed permission contracts (informational \u2014 NOT audited or\nendorsed by Sail; review the source before registering any of them):"
@@ -42599,7 +42559,7 @@ function printNoPermissionsGuidance() {
42599
42559
  async function mandatePrepare() {
42600
42560
  const account2 = readJsonFile(sailPath("account.json"));
42601
42561
  if (!account2) {
42602
- throw new Error('No account found at .sail/account.json.\nRun "sailor account create" first.');
42562
+ throw new Error('No account found at .sail/account.json.\nRun "sailor onboard --new-sma" first.');
42603
42563
  }
42604
42564
  const permissions = await trackedPermissionsFor(account2);
42605
42565
  if (permissions.length === 0) {
@@ -42632,7 +42592,7 @@ ${permissions.length} permission(s) tracked for SMA ${account2.safe}:
42632
42592
  async function mandateSign(opts = {}) {
42633
42593
  const account2 = readJsonFile(sailPath("account.json"));
42634
42594
  if (!account2) {
42635
- throw new Error('No account found at .sail/account.json.\nRun "sailor account create" first.');
42595
+ throw new Error('No account found at .sail/account.json.\nRun "sailor onboard --new-sma" first.');
42636
42596
  }
42637
42597
  const permissions = await trackedPermissionsFor(account2);
42638
42598
  if (permissions.length === 0) {
@@ -43575,7 +43535,7 @@ async function runCommand(opts) {
43575
43535
  const once = opts.once === true;
43576
43536
  const account2 = readJsonFile(sailPath("account.json"));
43577
43537
  if (!account2) {
43578
- throw new Error('No account found at .sail/account.json.\nRun "sailor account create" first.');
43538
+ throw new Error('No account found at .sail/account.json.\nRun "sailor onboard --new-sma" first.');
43579
43539
  }
43580
43540
  const mandateRaw = readJsonFile(sailPath("mandate.json"));
43581
43541
  const mandate2 = Array.isArray(mandateRaw) ? mandateRaw[0] : mandateRaw;
@@ -43638,7 +43598,7 @@ async function runCommand(opts) {
43638
43598
  if (!kernel) {
43639
43599
  throw new Error(
43640
43600
  `No SailKernel address for chain ${chainId}.
43641
- Configure the chain in @sail/chains or set KERNEL_ADDRESS in .sail/.env.local.`
43601
+ Configure the chain in the SDK chain registry or set KERNEL_ADDRESS in .sail/.env.local.`
43642
43602
  );
43643
43603
  }
43644
43604
  const manager = await loadManagerSigner(account2.safe);
@@ -44029,7 +43989,7 @@ function requireAccount() {
44029
43989
  const account2 = readJsonFile(sailPath("account.json"));
44030
43990
  if (!account2) {
44031
43991
  throw new Error(
44032
- 'No account found at .sail/account.json.\nRun "sailor account create" first.'
43992
+ 'No account found at .sail/account.json.\nRun "sailor onboard --new-sma" first.'
44033
43993
  );
44034
43994
  }
44035
43995
  return account2;
@@ -44197,7 +44157,7 @@ async function status() {
44197
44157
  if (account2) {
44198
44158
  console.log(` \u2713 deployed ${checksum4(account2.safe)} (chain ${account2.chainId})`);
44199
44159
  } else {
44200
- console.log(' \u2717 not deployed run "sailor account create"');
44160
+ console.log(' \u2717 not deployed run "sailor onboard --new-sma"');
44201
44161
  }
44202
44162
  console.log("Mandate:");
44203
44163
  if (mandate2) {
@@ -44316,8 +44276,16 @@ function uiStop() {
44316
44276
  }
44317
44277
 
44318
44278
  // src/index.ts
44279
+ function cliVersion() {
44280
+ try {
44281
+ const pkg = JSON.parse((0, import_node_fs18.readFileSync)((0, import_node_path14.join)(packageRoot(), "package.json"), "utf-8"));
44282
+ return pkg.version ?? "0.0.0";
44283
+ } catch {
44284
+ return "0.0.0";
44285
+ }
44286
+ }
44319
44287
  var program2 = new Command();
44320
- program2.name("sailor").description("Operator toolkit for Sail Protocol").version("0.1.0");
44288
+ program2.name("sailor").description("Operator toolkit for Sail Protocol").version(cliVersion());
44321
44289
  function action(fn) {
44322
44290
  return async () => {
44323
44291
  try {
@@ -44364,7 +44332,6 @@ keys.command("export-ci").description(
44364
44332
  "Copy the encrypted agent wallet keystore to ci-keystore.json for committing to CI"
44365
44333
  ).action(action(keysExportCi));
44366
44334
  var account = program2.command("account").description("Manage the Sail SMA");
44367
- account.command("create").description("Create a new Sail SMA on-chain").action(action(accountCreate));
44368
44335
  account.command("predict").description(
44369
44336
  "Compute the deterministic Safe address for a given owner + manager + salt (no gas, no deployment)"
44370
44337
  ).option("--owner <address>", "Owner EOA address (defaults to .sail/account.json)").option(
@@ -44416,12 +44383,6 @@ program2.command("capabilities").description(
44416
44383
  "Feasibility map (read-only): chains, kernel model, mandate templates, strategy primitives"
44417
44384
  ).option("--json", "Emit machine-readable JSON").action(actionWith(capabilities));
44418
44385
  program2.command("chains").description("List supported chains and their SailKernel deployment addresses").option("--verify", "Verify each kernel is deployed via eth_getCode (one RPC call per chain)").option("--json", "Emit machine-readable JSON").action(actionWith(chainsCommand));
44419
- function stub(name, description) {
44420
- program2.command(name).description(description).allowUnknownOption().action(() => {
44421
- console.log(`sailor ${name}: not implemented yet`);
44422
- });
44423
- }
44424
- stub("dispatch preview", "Preview a dispatch without submitting");
44425
44386
  program2.parse(process.argv);
44426
44387
  /*! Bundled license information:
44427
44388