@dev.sail.money/sailor 0.0.2 → 0.1.0-local

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 (211) hide show
  1. package/AGENTS.md +140 -111
  2. package/LICENSE +21 -21
  3. package/README.md +430 -337
  4. package/docs/PERMISSION_MODEL.md +93 -93
  5. package/examples/permissions/BoundedApproveAndCallBatch.sol +179 -0
  6. package/examples/permissions/BoundedBet_Limitless_Base.sol +97 -96
  7. package/examples/permissions/BoundedBorrow_AaveV3_Arbitrum.sol +94 -94
  8. package/examples/permissions/BoundedPerp_GMXv2_Arbitrum.sol +154 -143
  9. package/examples/permissions/BoundedStake_Venice_Base.sol +85 -0
  10. package/examples/permissions/BoundedSupply_AaveV3_Arbitrum.sol +82 -0
  11. package/examples/permissions/BoundedSwap_UniswapV3_Base.sol +116 -113
  12. package/examples/permissions/BoundedSwap_UniswapV4_Unichain.sol +150 -144
  13. package/examples/permissions/BoundedTransfer_ERC20_Ethereum.sol +73 -73
  14. package/examples/permissions/BoundedVault_ERC4626_Base.sol +97 -0
  15. package/examples/permissions/README.md +79 -52
  16. package/examples/permissions/SailCalldata.sol +118 -0
  17. package/examples/permissions/foundry.toml +10 -10
  18. package/examples/permissions/interfaces/IBatchPermission.sol +38 -0
  19. package/examples/permissions/interfaces/IPermission.sol +18 -18
  20. package/package.json +45 -39
  21. package/packages/cli/README.md +34 -34
  22. package/packages/cli/dist/index.cjs +4571 -2944
  23. package/packages/cli/dist/server.cjs +1252 -2010
  24. package/packages/sdk/README.md +65 -65
  25. package/packages/sdk/dist/chains.d.ts +12 -0
  26. package/packages/sdk/dist/chains.d.ts.map +1 -0
  27. package/packages/sdk/dist/chains.js +94 -0
  28. package/packages/sdk/dist/chains.js.map +1 -0
  29. package/packages/sdk/dist/deployments.d.ts +14 -7
  30. package/packages/sdk/dist/deployments.d.ts.map +1 -1
  31. package/packages/sdk/dist/deployments.js +132 -141
  32. package/packages/sdk/dist/deployments.js.map +1 -1
  33. package/packages/sdk/dist/index.d.ts +3 -2
  34. package/packages/sdk/dist/index.d.ts.map +1 -1
  35. package/packages/sdk/dist/index.js +3 -2
  36. package/packages/sdk/dist/index.js.map +1 -1
  37. package/packages/sdk/dist/intelligence.d.ts +1 -1
  38. package/packages/sdk/dist/intelligence.js +1 -1
  39. package/packages/sdk/dist/lifi.d.ts +17 -0
  40. package/packages/sdk/dist/lifi.d.ts.map +1 -1
  41. package/packages/sdk/dist/lifi.js +24 -0
  42. package/packages/sdk/dist/lifi.js.map +1 -1
  43. package/packages/sdk/dist/safe.d.ts +83 -0
  44. package/packages/sdk/dist/safe.d.ts.map +1 -1
  45. package/packages/sdk/dist/safe.js +92 -1
  46. package/packages/sdk/dist/safe.js.map +1 -1
  47. package/packages/sdk/dist/templates/ammLiquidity.d.ts +24 -11
  48. package/packages/sdk/dist/templates/ammLiquidity.d.ts.map +1 -1
  49. package/packages/sdk/dist/templates/ammLiquidity.js +39 -31
  50. package/packages/sdk/dist/templates/ammLiquidity.js.map +1 -1
  51. package/packages/sdk/dist/templates/approveAndCallBatch.d.ts +24 -10
  52. package/packages/sdk/dist/templates/approveAndCallBatch.d.ts.map +1 -1
  53. package/packages/sdk/dist/templates/approveAndCallBatch.js +36 -23
  54. package/packages/sdk/dist/templates/approveAndCallBatch.js.map +1 -1
  55. package/packages/sdk/dist/templates/boundedBorrow.d.ts +19 -9
  56. package/packages/sdk/dist/templates/boundedBorrow.d.ts.map +1 -1
  57. package/packages/sdk/dist/templates/boundedBorrow.js +28 -19
  58. package/packages/sdk/dist/templates/boundedBorrow.js.map +1 -1
  59. package/packages/sdk/dist/templates/boundedSwap.d.ts +19 -9
  60. package/packages/sdk/dist/templates/boundedSwap.d.ts.map +1 -1
  61. package/packages/sdk/dist/templates/boundedSwap.js +30 -20
  62. package/packages/sdk/dist/templates/boundedSwap.js.map +1 -1
  63. package/packages/sdk/dist/templates/defiBundle.d.ts +35 -9
  64. package/packages/sdk/dist/templates/defiBundle.d.ts.map +1 -1
  65. package/packages/sdk/dist/templates/defiBundle.js +84 -22
  66. package/packages/sdk/dist/templates/defiBundle.js.map +1 -1
  67. package/packages/sdk/dist/templates/pendle.d.ts +23 -8
  68. package/packages/sdk/dist/templates/pendle.d.ts.map +1 -1
  69. package/packages/sdk/dist/templates/pendle.js +34 -14
  70. package/packages/sdk/dist/templates/pendle.js.map +1 -1
  71. package/packages/sdk/dist/templates/transferTarget.d.ts +11 -3
  72. package/packages/sdk/dist/templates/transferTarget.d.ts.map +1 -1
  73. package/packages/sdk/dist/templates/transferTarget.js +14 -7
  74. package/packages/sdk/dist/templates/transferTarget.js.map +1 -1
  75. package/packages/sdk/dist/types.d.ts +19 -1
  76. package/packages/sdk/dist/types.d.ts.map +1 -1
  77. package/packages/sdk/package.json +80 -52
  78. package/packages/ui/dist/assets/{add-DaJhwIBV.js → add-BxpXfVWe.js} +1 -1
  79. package/packages/ui/dist/assets/{all-wallets-BUxsqWXi.js → all-wallets-BKTn_sWK.js} +1 -1
  80. package/packages/ui/dist/assets/{app-store-DkltwTqE.js → app-store-CfuKbwxR.js} +1 -1
  81. package/packages/ui/dist/assets/{apple-owVOeaIT.js → apple-BKSBbNYg.js} +1 -1
  82. package/packages/ui/dist/assets/{arrow-bottom-D2mmNJve.js → arrow-bottom-D4bG6gZi.js} +1 -1
  83. package/packages/ui/dist/assets/{arrow-bottom-circle-CbNYijx-.js → arrow-bottom-circle-BNTs1p0T.js} +1 -1
  84. package/packages/ui/dist/assets/{arrow-left-DJB61s4C.js → arrow-left-2uee3vYv.js} +1 -1
  85. package/packages/ui/dist/assets/{arrow-right-BBrsQ9R4.js → arrow-right-BktjMV6h.js} +1 -1
  86. package/packages/ui/dist/assets/{arrow-top-Cil6bOc8.js → arrow-top-Izu28fX4.js} +1 -1
  87. package/packages/ui/dist/assets/{bank-CbwEmRo3.js → bank-USBaAyFM.js} +1 -1
  88. package/packages/ui/dist/assets/{basic-CLNfjw3m.js → basic-C_9KjTEH.js} +1 -1
  89. package/packages/ui/dist/assets/{browser-B5TtF4Pb.js → browser-DAEMAKV7.js} +1 -1
  90. package/packages/ui/dist/assets/{card-CO7BVB-C.js → card-DT8yDkKN.js} +1 -1
  91. package/packages/ui/dist/assets/{ccip-2W7K3_J3.js → ccip-CkqfGSxX.js} +1 -1
  92. package/packages/ui/dist/assets/{checkmark-BEtSHq9m.js → checkmark-CsgdEXFj.js} +1 -1
  93. package/packages/ui/dist/assets/{checkmark-bold-D9xGHzPE.js → checkmark-bold-D2gjOQo2.js} +1 -1
  94. package/packages/ui/dist/assets/{chevron-bottom-BDztht6i.js → chevron-bottom-tprFynYV.js} +1 -1
  95. package/packages/ui/dist/assets/{chevron-left-EV4GFNbc.js → chevron-left-D2Zj1gNB.js} +1 -1
  96. package/packages/ui/dist/assets/{chevron-right-B4_bB9oR.js → chevron-right-D1rRuAVe.js} +1 -1
  97. package/packages/ui/dist/assets/{chevron-top-D54xPNzF.js → chevron-top-24dL1mbL.js} +1 -1
  98. package/packages/ui/dist/assets/{chrome-store-DYUpAJJq.js → chrome-store-Vy-5niYX.js} +1 -1
  99. package/packages/ui/dist/assets/{clock-Ca1T1Soz.js → clock-qBjLnVdJ.js} +1 -1
  100. package/packages/ui/dist/assets/{close-BZqWjurK.js → close-DARDwgcu.js} +1 -1
  101. package/packages/ui/dist/assets/{coinPlaceholder-e6fl2XDo.js → coinPlaceholder-BvpIbPlD.js} +1 -1
  102. package/packages/ui/dist/assets/{compass-DCLC7zIh.js → compass-BMTO0ayt.js} +1 -1
  103. package/packages/ui/dist/assets/{copy-Th2AaD-O.js → copy-PaXeRHza.js} +1 -1
  104. package/packages/ui/dist/assets/{core-Ckx_cyuH.js → core-BFnStQd-.js} +3 -3
  105. package/packages/ui/dist/assets/cursor-BDvw-B17.js +3 -0
  106. package/packages/ui/dist/assets/{cursor-transparent-BKHeABKB.js → cursor-transparent-BEMdi-8q.js} +1 -1
  107. package/packages/ui/dist/assets/{desktop-CBjY8t6F.js → desktop-CfuLLThw.js} +1 -1
  108. package/packages/ui/dist/assets/{disconnect-DbSs2cli.js → disconnect-DhwgJMiR.js} +1 -1
  109. package/packages/ui/dist/assets/{discord-ZlLOAUkM.js → discord-po8qoN1s.js} +1 -1
  110. package/packages/ui/dist/assets/{etherscan-CKUrqWYN.js → etherscan-BEsz0_yx.js} +1 -1
  111. package/packages/ui/dist/assets/{events-CiKP71cK.js → events-Bz33Unzu.js} +1 -1
  112. package/packages/ui/dist/assets/{exclamation-triangle-DA1QzFiO.js → exclamation-triangle-7CjTAGOQ.js} +1 -1
  113. package/packages/ui/dist/assets/{extension-BVJkmvpJ.js → extension-CmxjEWEt.js} +1 -1
  114. package/packages/ui/dist/assets/{external-link-D_bsR7B2.js → external-link-CmQ--bNS.js} +1 -1
  115. package/packages/ui/dist/assets/{facebook-CmFmhojx.js → facebook-CIBn9b65.js} +1 -1
  116. package/packages/ui/dist/assets/{fallback-Ofl6uSnB.js → fallback-DATyrQlb.js} +1 -1
  117. package/packages/ui/dist/assets/{farcaster-Co-M3Ss8.js → farcaster-OJ3Jasxg.js} +1 -1
  118. package/packages/ui/dist/assets/{filters-B1WwNaFU.js → filters-D4x09zeL.js} +1 -1
  119. package/packages/ui/dist/assets/{github-CP4fP6gn.js → github-ZlIuMArp.js} +1 -1
  120. package/packages/ui/dist/assets/{google-CsOIXJ6V.js → google-Gwg85sfv.js} +1 -1
  121. package/packages/ui/dist/assets/{help-circle-DiMkomdF.js → help-circle-D1uOWYcX.js} +1 -1
  122. package/packages/ui/dist/assets/{id-lmscL5LX.js → id-C0-5UdYk.js} +1 -1
  123. package/packages/ui/dist/assets/{image-B-ubJrY5.js → image-D_DUsv8-.js} +1 -1
  124. package/packages/ui/dist/assets/{index-CZR1Qjhs.js → index-BCzex_R6.js} +1 -1
  125. package/packages/ui/dist/assets/index-BUhrHLpY.js +1775 -0
  126. package/packages/ui/dist/assets/index-Cq02kQmy.css +1 -0
  127. package/packages/ui/dist/assets/{index-BaukYv-x.js → index-CrYzBWfD.js} +1 -1
  128. package/packages/ui/dist/assets/{index-CF0KMmke.js → index-DdbJhIdl.js} +3 -3
  129. package/packages/ui/dist/assets/{index-DVgfCzCo.js → index-DiojfeVM.js} +1 -1
  130. package/packages/ui/dist/assets/{index-Dbh5V1Z0.js → index-izd7vu_r.js} +1 -1
  131. package/packages/ui/dist/assets/{index.es-C78cE5SI.js → index.es-DdkHhQAj.js} +4 -4
  132. package/packages/ui/dist/assets/{info-Cqg57EVo.js → info-CiRd_kEG.js} +1 -1
  133. package/packages/ui/dist/assets/{info-circle-DkeSWNKV.js → info-circle-ypxjqarK.js} +1 -1
  134. package/packages/ui/dist/assets/{lightbulb-DNlO4qKh.js → lightbulb-B-pxLxd8.js} +1 -1
  135. package/packages/ui/dist/assets/{mail-kVQ8Jb9Y.js → mail-BYmicuVZ.js} +1 -1
  136. package/packages/ui/dist/assets/{metamask-sdk-CBalSvz7.js → metamask-sdk-Ccl6DG7Q.js} +1 -1
  137. package/packages/ui/dist/assets/{mobile-BEteuhF7.js → mobile-CtP5PqVT.js} +1 -1
  138. package/packages/ui/dist/assets/{more-DBWmXQli.js → more-6C2733we.js} +1 -1
  139. package/packages/ui/dist/assets/{network-placeholder-Dg1uUHiL.js → network-placeholder-CdhxMzqd.js} +1 -1
  140. package/packages/ui/dist/assets/{nftPlaceholder-i3AHSiD9.js → nftPlaceholder-DVmTWEAY.js} +1 -1
  141. package/packages/ui/dist/assets/{off-BtMm0fi2.js → off-DNYLughs.js} +1 -1
  142. package/packages/ui/dist/assets/{parseSignature-Cb5FlWWg.js → parseSignature-Dq2B5Bu3.js} +1 -1
  143. package/packages/ui/dist/assets/{play-store-iKKkXa6a.js → play-store-D7Qut5ta.js} +1 -1
  144. package/packages/ui/dist/assets/{plus-CA5NaRtb.js → plus-kqMyjt3q.js} +1 -1
  145. package/packages/ui/dist/assets/{qr-code-D2kiqR7h.js → qr-code-DiUCWRbz.js} +1 -1
  146. package/packages/ui/dist/assets/{recycle-horizontal-Dcme7R03.js → recycle-horizontal-Boe3XiS-.js} +1 -1
  147. package/packages/ui/dist/assets/{refresh-Dega3sDp.js → refresh-CrBgBQYO.js} +1 -1
  148. package/packages/ui/dist/assets/{reown-logo-xNkksyWJ.js → reown-logo-CFZCCHSx.js} +1 -1
  149. package/packages/ui/dist/assets/{search-HYl7NO8x.js → search-ChTDrghU.js} +1 -1
  150. package/packages/ui/dist/assets/{secp256k1-Cxd6_SiH.js → secp256k1-DAV5Q_FR.js} +1 -1
  151. package/packages/ui/dist/assets/{send-CJU8CUAo.js → send-DLFbBFe1.js} +1 -1
  152. package/packages/ui/dist/assets/{swapHorizontal-IMUKiUre.js → swapHorizontal-BEs3emfG.js} +1 -1
  153. package/packages/ui/dist/assets/{swapHorizontalBold-CNYnNJ9-.js → swapHorizontalBold-CC-Hfa7W.js} +1 -1
  154. package/packages/ui/dist/assets/{swapHorizontalMedium-B9VxEYsT.js → swapHorizontalMedium-BmR0H8DC.js} +1 -1
  155. package/packages/ui/dist/assets/{swapHorizontalRoundedBold-Dz33l_Jh.js → swapHorizontalRoundedBold-BdP5NGIH.js} +1 -1
  156. package/packages/ui/dist/assets/{swapVertical-CHUmjVJ0.js → swapVertical-CPrGEJPY.js} +1 -1
  157. package/packages/ui/dist/assets/{telegram-kl9S2mbU.js → telegram-CxNoZ80Q.js} +1 -1
  158. package/packages/ui/dist/assets/{three-dots-U5lhA1Am.js → three-dots-BRa6SBpL.js} +1 -1
  159. package/packages/ui/dist/assets/{twitch-KTEUWXEp.js → twitch-BC338bG5.js} +1 -1
  160. package/packages/ui/dist/assets/{twitterIcon-BHiq8mRg.js → twitterIcon-BGZmt2i9.js} +1 -1
  161. package/packages/ui/dist/assets/{verify-CfN-BXNd.js → verify-CEstW0zw.js} +1 -1
  162. package/packages/ui/dist/assets/{verify-filled-DwZccetj.js → verify-filled-OkZb0weU.js} +1 -1
  163. package/packages/ui/dist/assets/{w3m-modal-CS-PFqPE.js → w3m-modal-pS09ECwE.js} +1 -1
  164. package/packages/ui/dist/assets/{wallet-DVlGkhOY.js → wallet-BXVKCgC9.js} +1 -1
  165. package/packages/ui/dist/assets/{wallet-placeholder-CvR_iEWX.js → wallet-placeholder-C_kNhB1c.js} +1 -1
  166. package/packages/ui/dist/assets/{walletconnect-8pZBDvVI.js → walletconnect-CRKIuUHH.js} +1 -1
  167. package/packages/ui/dist/assets/{warning-circle-ylLEE0Yp.js → warning-circle-DB2NnwlJ.js} +1 -1
  168. package/packages/ui/dist/assets/{x-C_TBsTMj.js → x-DT4RmwL5.js} +1 -1
  169. package/packages/ui/dist/index.html +14 -14
  170. package/scripts/check-docs.mjs +262 -262
  171. package/scripts/check-init.mjs +108 -109
  172. package/scripts/postinstall.js +81 -366
  173. package/templates/custom-mandate/.sail/contracts/interfaces/IPermission.sol +18 -18
  174. package/templates/custom-mandate/README.md +116 -85
  175. package/templates/custom-mandate/foundry.toml +8 -8
  176. package/templates/custom-mandate/mandates/BoundedCallPermission.sol +41 -35
  177. package/templates/custom-mandate/mandates/README.md +16 -16
  178. package/templates/custom-mandate/mandates/SailCalldata.sol +118 -0
  179. package/templates/{dca-rebalancer → default}/.cursor/rules +25 -25
  180. package/templates/default/.env.example +20 -0
  181. package/templates/{dca-rebalancer → default}/.github/workflows/agent-tick.yml +33 -32
  182. package/templates/{dca-rebalancer → default}/.sail/README.md +13 -13
  183. package/templates/{dca-rebalancer → default}/.sail/config.json +10 -10
  184. package/templates/default/AGENTS.md +171 -0
  185. package/templates/{dca-rebalancer → default}/CLAUDE.md +2 -2
  186. package/templates/default/README.md +16 -0
  187. package/templates/{dca-rebalancer → default}/_gitignore +13 -13
  188. package/templates/{dca-rebalancer → default}/docs/PERMISSION_MODEL.md +93 -93
  189. package/templates/default/examples/dca/README.md +16 -0
  190. package/templates/default/examples/dca/agent.ts +174 -0
  191. package/templates/{dca-rebalancer/src → default/examples/dca}/mandate.ts +45 -67
  192. package/templates/{dca-rebalancer → default}/package.json +17 -17
  193. package/templates/default/src/agent.ts +37 -0
  194. package/templates/default/src/config.ts +24 -0
  195. package/templates/default/src/mandate.ts +22 -0
  196. package/templates/default/tsconfig.json +17 -0
  197. package/templates/{dca-rebalancer → default}/ui/README.md +3 -3
  198. package/templates/lifi-permissions/LifiBoundedApprovePermissionCloneable.sol +84 -84
  199. package/templates/lifi-permissions/LifiDiamondSwapPermissionCloneable.sol +97 -97
  200. package/templates/lifi-permissions/README.md +53 -53
  201. package/packages/ui/dist/assets/cursor-DV7rOqbJ.js +0 -3
  202. package/packages/ui/dist/assets/index-CKxgNxS9.css +0 -1
  203. package/packages/ui/dist/assets/index-Q2Yai4Fe.js +0 -2103
  204. package/templates/dca-rebalancer/.env.example +0 -6
  205. package/templates/dca-rebalancer/AGENTS.md +0 -246
  206. package/templates/dca-rebalancer/AGENT_PLAYBOOK.md +0 -110
  207. package/templates/dca-rebalancer/README.md +0 -16
  208. package/templates/dca-rebalancer/src/agent.ts +0 -253
  209. package/templates/dca-rebalancer/src/config.ts +0 -27
  210. package/templates/dca-rebalancer/tsconfig.json +0 -8
  211. /package/templates/{dca-rebalancer → default}/.sail/.gitkeep +0 -0
@@ -1,109 +1,108 @@
1
- #!/usr/bin/env node
2
- /**
3
- * `sailor init` smoke test.
4
- *
5
- * Scaffolds a fresh project from the in-tree CLI bundle into a temp dir and
6
- * asserts the scaffold succeeded. This exists to catch the class of regression
7
- * the doc-drift gate structurally cannot — e.g. `packageRoot()` resolving to a
8
- * `bin.sailor` package that ships no `templates/`, which made `init` fail from a
9
- * monorepo checkout with "Template ... not found. Available: none".
10
- *
11
- * It runs the REAL built bundle from a monorepo layout, which is exactly the
12
- * in-tree path that broke before. Pure Node + child_process; the only build
13
- * dependency is the CLI bundle (`pnpm --filter sailor build`).
14
- *
15
- * Run: node scripts/check-init.mjs (CI builds the CLI first)
16
- * Exit: 0 = scaffold OK, 1 = failure (prints what was missing).
17
- */
18
-
19
- import { execFileSync } from "node:child_process";
20
- import fs from "node:fs";
21
- import os from "node:os";
22
- import path from "node:path";
23
- import { fileURLToPath } from "node:url";
24
-
25
- const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
26
- const BUNDLE = path.join(ROOT, "packages/cli/dist/index.cjs");
27
- const PROJECT = "smoke-agent";
28
-
29
- function fail(msg) {
30
- console.error(`✗ init smoke test FAILED: ${msg}`);
31
- process.exit(1);
32
- }
33
-
34
- if (!fs.existsSync(BUNDLE)) {
35
- fail(`CLI bundle not found at ${BUNDLE}.\n Build it first: pnpm --filter sailor build`);
36
- }
37
-
38
- // Scaffold into a temp dir. `init` requires the destination to live inside the
39
- // process cwd, so we run the bundle with cwd set to a fresh temp root.
40
- const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "sailor-init-smoke-"));
41
- const dest = path.join(tmpRoot, PROJECT);
42
-
43
- try {
44
- let stdout = "";
45
- try {
46
- stdout = execFileSync(process.execPath, [BUNDLE, "init", PROJECT], {
47
- cwd: tmpRoot,
48
- encoding: "utf-8",
49
- stdio: ["ignore", "pipe", "pipe"],
50
- });
51
- } catch (err) {
52
- const out = `${err.stdout ?? ""}${err.stderr ?? ""}`.trim();
53
- fail(`\`sailor init ${PROJECT}\` exited non-zero.\n ${out || err.message}`);
54
- }
55
-
56
- // A successful fresh init prints the welcome + next steps, ending with the
57
- // `Say: "start"` call-to-action. (Older builds printed "Done!".)
58
- if (!/Say: "start"/.test(stdout)) {
59
- fail(`init did not report success.\n stdout: ${stdout.trim()}`);
60
- }
61
-
62
- // Assert the scaffold landed.
63
- const mustExist = [
64
- ".sail/config.json",
65
- "package.json",
66
- "foundry.toml",
67
- "mandates",
68
- "AGENTS.md",
69
- ];
70
- for (const rel of mustExist) {
71
- if (!fs.existsSync(path.join(dest, rel))) fail(`expected scaffolded "${rel}" — not found`);
72
- }
73
-
74
- // config.json is valid JSON named after the project.
75
- const config = JSON.parse(fs.readFileSync(path.join(dest, ".sail/config.json"), "utf-8"));
76
- if (config.name !== PROJECT) fail(`config.json name is "${config.name}", expected "${PROJECT}"`);
77
-
78
- // package.json is valid, renamed, and the workspace protocol was resolved away
79
- // (a leftover "workspace:*" would make the scaffold un-installable for users).
80
- const pkg = JSON.parse(fs.readFileSync(path.join(dest, "package.json"), "utf-8"));
81
- if (pkg.name !== PROJECT) fail(`package.json name is "${pkg.name}", expected "${PROJECT}"`);
82
- if (pkg.dependencies?.["@sail/sdk"] === "workspace:*") {
83
- fail(`package.json still has "@sail/sdk": "workspace:*" — init did not resolve it`);
84
- }
85
-
86
- // Regression guard: an absolute path outside the cwd must be REJECTED, not
87
- // silently nested into `<cwd>/<abs path>`. (Pre-fix, `path.join` swallowed the
88
- // leading slash and scaffolded a bogus nested tree while printing success.)
89
- const outside = path.join(os.tmpdir(), "sailor-init-outside", "agent");
90
- let rejected = false;
91
- try {
92
- execFileSync(process.execPath, [BUNDLE, "init", outside], {
93
- cwd: tmpRoot,
94
- stdio: ["ignore", "pipe", "pipe"],
95
- });
96
- } catch {
97
- rejected = true; // non-zero exit = correctly refused
98
- }
99
- if (!rejected) fail(`an absolute path outside cwd ("${outside}") was accepted — should be rejected`);
100
- if (fs.existsSync(path.join(outside, ".sail/config.json"))) {
101
- fail(`init scaffolded into an out-of-cwd absolute path "${outside}"`);
102
- }
103
-
104
- console.log(`✓ init smoke test passed — scaffolded ${PROJECT}/ from the in-tree bundle`);
105
- console.log("✓ init guard passed — absolute path outside cwd rejected, not silently nested");
106
- } finally {
107
- fs.rmSync(path.join(os.tmpdir(), "sailor-init-outside"), { recursive: true, force: true });
108
- fs.rmSync(tmpRoot, { recursive: true, force: true });
109
- }
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `sailor init` smoke test.
4
+ *
5
+ * Scaffolds a fresh project from the in-tree CLI bundle into a temp dir and
6
+ * asserts the scaffold succeeded. This exists to catch the class of regression
7
+ * the doc-drift gate structurally cannot — e.g. `packageRoot()` resolving to a
8
+ * `bin.sailor` package that ships no `templates/`, which made `init` fail from a
9
+ * monorepo checkout with "Template ... not found. Available: none".
10
+ *
11
+ * It runs the REAL built bundle from a monorepo layout, which is exactly the
12
+ * in-tree path that broke before. Pure Node + child_process; the only build
13
+ * dependency is the CLI bundle (`pnpm --filter sailor build`).
14
+ *
15
+ * Run: node scripts/check-init.mjs (CI builds the CLI first)
16
+ * Exit: 0 = scaffold OK, 1 = failure (prints what was missing).
17
+ */
18
+
19
+ import { execFileSync } from "node:child_process";
20
+ import fs from "node:fs";
21
+ import os from "node:os";
22
+ import path from "node:path";
23
+ import { fileURLToPath } from "node:url";
24
+
25
+ const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
26
+ const BUNDLE = path.join(ROOT, "packages/cli/dist/index.cjs");
27
+ const PROJECT = "smoke-agent";
28
+
29
+ function fail(msg) {
30
+ console.error(`✗ init smoke test FAILED: ${msg}`);
31
+ process.exit(1);
32
+ }
33
+
34
+ if (!fs.existsSync(BUNDLE)) {
35
+ fail(`CLI bundle not found at ${BUNDLE}.\n Build it first: pnpm --filter sailor build`);
36
+ }
37
+
38
+ // Scaffold into a temp dir. `init` requires the destination to live inside the
39
+ // process cwd, so we run the bundle with cwd set to a fresh temp root.
40
+ const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "sailor-init-smoke-"));
41
+ const dest = path.join(tmpRoot, PROJECT);
42
+
43
+ try {
44
+ let stdout = "";
45
+ try {
46
+ stdout = execFileSync(process.execPath, [BUNDLE, "init", PROJECT], {
47
+ cwd: tmpRoot,
48
+ encoding: "utf-8",
49
+ stdio: ["ignore", "pipe", "pipe"],
50
+ });
51
+ } catch (err) {
52
+ const out = `${err.stdout ?? ""}${err.stderr ?? ""}`.trim();
53
+ fail(`\`sailor init ${PROJECT}\` exited non-zero.\n ${out || err.message}`);
54
+ }
55
+
56
+ // A successful fresh init prints the single-line handoff to the AI assistant.
57
+ if (!/say start/i.test(stdout)) {
58
+ fail(`init did not report success.\n stdout: ${stdout.trim()}`);
59
+ }
60
+
61
+ // Assert the scaffold landed.
62
+ const mustExist = [
63
+ ".sail/config.json",
64
+ "package.json",
65
+ "foundry.toml",
66
+ "mandates",
67
+ "AGENTS.md",
68
+ ];
69
+ for (const rel of mustExist) {
70
+ if (!fs.existsSync(path.join(dest, rel))) fail(`expected scaffolded "${rel}" — not found`);
71
+ }
72
+
73
+ // config.json is valid JSON named after the project.
74
+ const config = JSON.parse(fs.readFileSync(path.join(dest, ".sail/config.json"), "utf-8"));
75
+ if (config.name !== PROJECT) fail(`config.json name is "${config.name}", expected "${PROJECT}"`);
76
+
77
+ // package.json is valid, renamed, and the workspace protocol was resolved away
78
+ // (a leftover "workspace:*" would make the scaffold un-installable for users).
79
+ const pkg = JSON.parse(fs.readFileSync(path.join(dest, "package.json"), "utf-8"));
80
+ if (pkg.name !== PROJECT) fail(`package.json name is "${pkg.name}", expected "${PROJECT}"`);
81
+ if (pkg.dependencies?.["@sail/sdk"] === "workspace:*") {
82
+ fail(`package.json still has "@sail/sdk": "workspace:*" — init did not resolve it`);
83
+ }
84
+
85
+ // Regression guard: an absolute path outside the cwd must be REJECTED, not
86
+ // silently nested into `<cwd>/<abs path>`. (Pre-fix, `path.join` swallowed the
87
+ // leading slash and scaffolded a bogus nested tree while printing success.)
88
+ const outside = path.join(os.tmpdir(), "sailor-init-outside", "agent");
89
+ let rejected = false;
90
+ try {
91
+ execFileSync(process.execPath, [BUNDLE, "init", outside], {
92
+ cwd: tmpRoot,
93
+ stdio: ["ignore", "pipe", "pipe"],
94
+ });
95
+ } catch {
96
+ rejected = true; // non-zero exit = correctly refused
97
+ }
98
+ if (!rejected) fail(`an absolute path outside cwd ("${outside}") was accepted — should be rejected`);
99
+ if (fs.existsSync(path.join(outside, ".sail/config.json"))) {
100
+ fail(`init scaffolded into an out-of-cwd absolute path "${outside}"`);
101
+ }
102
+
103
+ console.log(`✓ init smoke test passed — scaffolded ${PROJECT}/ from the in-tree bundle`);
104
+ console.log("✓ init guard passed — absolute path outside cwd rejected, not silently nested");
105
+ } finally {
106
+ fs.rmSync(path.join(os.tmpdir(), "sailor-init-outside"), { recursive: true, force: true });
107
+ fs.rmSync(tmpRoot, { recursive: true, force: true });
108
+ }