@needmoretruth/nmts-cli 0.17.2 → 0.34.2

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 (419) hide show
  1. package/AGENTS.md +125 -517
  2. package/CHANGELOG.md +104 -0
  3. package/README.ko.md +377 -469
  4. package/README.md +394 -474
  5. package/dist/account-proof.d.ts +29 -0
  6. package/dist/account-proof.js +6 -6
  7. package/dist/account.d.ts +18 -0
  8. package/dist/account.js +5 -5
  9. package/dist/agent-host.d.ts +71 -0
  10. package/dist/agent-host.js +169 -0
  11. package/dist/api-advice.d.ts +2 -0
  12. package/dist/api-advice.js +210 -0
  13. package/dist/api-key.d.ts +79 -0
  14. package/dist/api-key.js +7 -7
  15. package/dist/api-refusal.d.ts +14 -0
  16. package/dist/api-refusal.js +8 -0
  17. package/dist/api.d.ts +114 -0
  18. package/dist/api.js +59 -162
  19. package/dist/args.d.ts +160 -0
  20. package/dist/args.js +118 -30
  21. package/dist/artifact-about.d.ts +49 -0
  22. package/dist/autonomy.d.ts +39 -0
  23. package/dist/autonomy.js +110 -32
  24. package/dist/code-access.d.ts +29 -0
  25. package/dist/code-access.js +3 -3
  26. package/dist/code-vault.d.ts +38 -0
  27. package/dist/code-vault.js +8 -8
  28. package/dist/collision.d.ts +67 -0
  29. package/dist/collision.js +1 -1
  30. package/dist/commands/accept-terms.d.ts +11 -0
  31. package/dist/commands/accept-terms.js +106 -0
  32. package/dist/commands/balance.d.ts +7 -0
  33. package/dist/commands/balance.js +54 -1
  34. package/dist/commands/create-code-file.d.ts +24 -0
  35. package/dist/commands/create-code-file.js +93 -0
  36. package/dist/commands/create-link.d.ts +10 -0
  37. package/dist/commands/create-link.js +232 -0
  38. package/dist/commands/create.d.ts +20 -0
  39. package/dist/commands/create.js +43 -102
  40. package/dist/commands/credits.d.ts +9 -0
  41. package/dist/commands/credits.js +110 -0
  42. package/dist/commands/delete-account.d.ts +11 -0
  43. package/dist/commands/delete-account.js +63 -0
  44. package/dist/commands/deposit.d.ts +7 -0
  45. package/dist/commands/deposit.js +85 -0
  46. package/dist/commands/devices.d.ts +12 -0
  47. package/dist/commands/devices.js +144 -0
  48. package/dist/commands/documents.d.ts +35 -0
  49. package/dist/commands/documents.js +212 -0
  50. package/dist/commands/env.d.ts +5 -0
  51. package/dist/commands/env.js +10 -2
  52. package/dist/commands/erase.d.ts +13 -0
  53. package/dist/commands/erase.js +193 -0
  54. package/dist/commands/expiring.d.ts +19 -0
  55. package/dist/commands/extend.d.ts +33 -0
  56. package/dist/commands/extend.js +54 -15
  57. package/dist/commands/get.d.ts +18 -0
  58. package/dist/commands/key-manage.d.ts +11 -0
  59. package/dist/commands/key-manage.js +162 -0
  60. package/dist/commands/key.d.ts +28 -0
  61. package/dist/commands/key.js +249 -0
  62. package/dist/commands/kit.d.ts +11 -0
  63. package/dist/commands/kit.js +7 -7
  64. package/dist/commands/listfile.d.ts +13 -0
  65. package/dist/commands/listfile.js +12 -5
  66. package/dist/commands/login.d.ts +18 -0
  67. package/dist/commands/login.js +19 -19
  68. package/dist/commands/logout.d.ts +1 -0
  69. package/dist/commands/logout.js +1 -1
  70. package/dist/commands/losses.d.ts +12 -0
  71. package/dist/commands/losses.js +180 -0
  72. package/dist/commands/ls.d.ts +23 -0
  73. package/dist/commands/marks-dispatch.d.ts +2 -0
  74. package/dist/commands/marks-dispatch.js +51 -0
  75. package/dist/commands/marks.d.ts +46 -0
  76. package/dist/commands/marks.js +80 -0
  77. package/dist/commands/mcp.d.ts +24 -0
  78. package/dist/commands/mcp.js +70 -5
  79. package/dist/commands/mode.d.ts +8 -0
  80. package/dist/commands/mode.js +60 -24
  81. package/dist/commands/on-collision.d.ts +6 -0
  82. package/dist/commands/organise.d.ts +46 -0
  83. package/dist/commands/padding.d.ts +7 -0
  84. package/dist/commands/padding.js +114 -0
  85. package/dist/commands/public-code.d.ts +9 -0
  86. package/dist/commands/public-code.js +8 -8
  87. package/dist/commands/pull.d.ts +27 -0
  88. package/dist/commands/push-wallet.d.ts +19 -0
  89. package/dist/commands/push-wallet.js +69 -0
  90. package/dist/commands/push.d.ts +47 -0
  91. package/dist/commands/push.js +37 -7
  92. package/dist/commands/put-wallet.d.ts +77 -0
  93. package/dist/commands/put-wallet.js +316 -0
  94. package/dist/commands/put.d.ts +56 -0
  95. package/dist/commands/put.js +53 -6
  96. package/dist/commands/rebuild.d.ts +18 -0
  97. package/dist/commands/rebuild.js +108 -10
  98. package/dist/commands/receive.d.ts +24 -0
  99. package/dist/commands/recovery-dispatch.d.ts +2 -0
  100. package/dist/commands/recovery-dispatch.js +34 -0
  101. package/dist/commands/recovery-list.d.ts +11 -0
  102. package/dist/commands/recovery-list.js +6 -6
  103. package/dist/commands/recovery.d.ts +25 -0
  104. package/dist/commands/recovery.js +2 -2
  105. package/dist/commands/rollback.d.ts +9 -0
  106. package/dist/commands/rollback.js +118 -0
  107. package/dist/commands/s3.d.ts +23 -0
  108. package/dist/commands/s3.js +6 -6
  109. package/dist/commands/settings.d.ts +5 -0
  110. package/dist/commands/settings.js +21 -6
  111. package/dist/commands/share-dispatch.d.ts +2 -0
  112. package/dist/commands/share-dispatch.js +46 -0
  113. package/dist/commands/share.d.ts +14 -0
  114. package/dist/commands/share.js +13 -3
  115. package/dist/commands/shares-sent.d.ts +18 -0
  116. package/dist/commands/shares-sent.js +95 -0
  117. package/dist/commands/support.d.ts +24 -0
  118. package/dist/commands/support.js +321 -0
  119. package/dist/commands/sweep.d.ts +11 -0
  120. package/dist/commands/tip.d.ts +11 -0
  121. package/dist/commands/tip.js +86 -0
  122. package/dist/commands/trash.d.ts +17 -0
  123. package/dist/commands/trash.js +1 -1
  124. package/dist/commands/trial.d.ts +7 -0
  125. package/dist/commands/trial.js +16 -18
  126. package/dist/commands/unlock.d.ts +16 -0
  127. package/dist/commands/unlock.js +159 -0
  128. package/dist/commands/update.d.ts +42 -0
  129. package/dist/commands/update.js +1 -1
  130. package/dist/commands/usage.d.ts +8 -0
  131. package/dist/commands/verify.d.ts +18 -0
  132. package/dist/commands/verify.js +10 -6
  133. package/dist/commands/wallet-activity.d.ts +26 -0
  134. package/dist/commands/wallet-activity.js +117 -0
  135. package/dist/commands/wallet-donate.d.ts +26 -0
  136. package/dist/commands/wallet-donate.js +163 -0
  137. package/dist/commands/wallet-hall.d.ts +35 -0
  138. package/dist/commands/wallet-hall.js +214 -0
  139. package/dist/commands/wallet-send.d.ts +22 -0
  140. package/dist/commands/wallet-send.js +153 -0
  141. package/dist/commands/wallet-storage-ops.d.ts +24 -0
  142. package/dist/commands/wallet-storage-ops.js +215 -0
  143. package/dist/commands/wallet-storage.d.ts +18 -0
  144. package/dist/commands/wallet-storage.js +95 -0
  145. package/dist/commands/wallet-swap.d.ts +32 -0
  146. package/dist/commands/wallet-swap.js +287 -0
  147. package/dist/commands/wallet.d.ts +36 -0
  148. package/dist/commands/wallet.js +57 -15
  149. package/dist/commands/whoami.d.ts +10 -0
  150. package/dist/commands/whoami.js +24 -6
  151. package/dist/consent.d.ts +140 -0
  152. package/dist/consent.js +89 -30
  153. package/dist/credentials.d.ts +146 -0
  154. package/dist/credentials.js +10 -10
  155. package/dist/crypto-surface.d.ts +197 -0
  156. package/dist/crypto.d.ts +81 -0
  157. package/dist/crypto.js +13 -0
  158. package/dist/deposit.d.ts +25 -0
  159. package/dist/deposit.js +78 -0
  160. package/dist/download-part.d.ts +40 -0
  161. package/dist/download-sink.d.ts +76 -0
  162. package/dist/download.d.ts +79 -0
  163. package/dist/download.js +3 -3
  164. package/dist/drive-paths.d.ts +73 -0
  165. package/dist/environment.d.ts +62 -0
  166. package/dist/environment.js +29 -9
  167. package/dist/errors.d.ts +22 -0
  168. package/dist/errors.js +3 -3
  169. package/dist/exit.d.ts +44 -0
  170. package/dist/expiry.d.ts +58 -0
  171. package/dist/extend-budget.d.ts +35 -0
  172. package/dist/extend-budget.js +81 -0
  173. package/dist/extend-chain.d.ts +43 -0
  174. package/dist/extend-chain.js +40 -3
  175. package/dist/extend-plan.d.ts +148 -0
  176. package/dist/extend-plan.js +1 -1
  177. package/dist/gate.d.ts +18 -0
  178. package/dist/gate.js +100 -0
  179. package/dist/guards.d.ts +2 -0
  180. package/dist/help.d.ts +20 -0
  181. package/dist/help.js +199 -33
  182. package/dist/human-check.d.ts +23 -0
  183. package/dist/index.d.ts +42 -0
  184. package/dist/index.js +49 -0
  185. package/dist/item-trash.d.ts +1 -0
  186. package/dist/kit-file.d.ts +56 -0
  187. package/dist/kit-file.js +10 -10
  188. package/dist/list-file.d.ts +88 -0
  189. package/dist/list-file.js +90 -7
  190. package/dist/list-view-find.d.ts +15 -0
  191. package/dist/list-view-order.d.ts +32 -0
  192. package/dist/main.d.ts +12 -0
  193. package/dist/main.js +112 -113
  194. package/dist/manifest-chunk-cache.d.ts +14 -0
  195. package/dist/manifest-chunk-cache.js +103 -0
  196. package/dist/manifest-chunk-flow.d.ts +81 -0
  197. package/dist/manifest-chunk-flow.js +307 -0
  198. package/dist/manifest-create.d.ts +23 -0
  199. package/dist/manifest-create.js +26 -30
  200. package/dist/manifest-write.d.ts +161 -0
  201. package/dist/manifest-write.js +42 -33
  202. package/dist/manifest.d.ts +82 -0
  203. package/dist/manifest.js +69 -21
  204. package/dist/mark-render.d.ts +26 -0
  205. package/dist/mcp-args.d.ts +17 -0
  206. package/dist/mcp-ask.d.ts +43 -0
  207. package/dist/mcp-ask.js +100 -0
  208. package/dist/mcp-tools/context.d.ts +46 -0
  209. package/dist/mcp-tools/credits.d.ts +3 -0
  210. package/dist/mcp-tools/credits.js +61 -0
  211. package/dist/mcp-tools/files.d.ts +3 -0
  212. package/dist/mcp-tools/files.js +34 -0
  213. package/dist/mcp-tools/organise.d.ts +3 -0
  214. package/dist/mcp-tools/organise.js +82 -2
  215. package/dist/mcp-tools/reads.d.ts +3 -0
  216. package/dist/mcp-tools/reads.js +132 -4
  217. package/dist/mcp-tools/share.d.ts +3 -0
  218. package/dist/mcp-tools/share.js +26 -7
  219. package/dist/mcp-tools/support.d.ts +3 -0
  220. package/dist/mcp-tools/support.js +140 -0
  221. package/dist/mcp-tools/tiers.d.ts +31 -0
  222. package/dist/mcp-tools/tiers.js +147 -0
  223. package/dist/mcp.d.ts +80 -0
  224. package/dist/mcp.js +110 -9
  225. package/dist/net-retry.d.ts +38 -0
  226. package/dist/network.d.ts +10 -0
  227. package/dist/notice.d.ts +7 -0
  228. package/dist/notice.js +7 -7
  229. package/dist/product.d.ts +29 -0
  230. package/dist/product.js +1 -1
  231. package/dist/progress.d.ts +37 -0
  232. package/dist/prompt.d.ts +31 -0
  233. package/dist/prompt.js +1 -1
  234. package/dist/rebuild-key-check.d.ts +26 -0
  235. package/dist/rebuild-key-check.js +90 -0
  236. package/dist/rebuild.d.ts +87 -0
  237. package/dist/rebuild.js +26 -4
  238. package/dist/recovery-assemble.d.ts +40 -0
  239. package/dist/recovery-assemble.js +1 -1
  240. package/dist/recovery-build.d.ts +40 -0
  241. package/dist/recovery-map-file.d.ts +53 -0
  242. package/dist/recovery-map-file.js +4 -4
  243. package/dist/recovery-map.d.ts +197 -0
  244. package/dist/recovery-release.d.ts +104 -0
  245. package/dist/recovery-seq.d.ts +10 -0
  246. package/dist/recovery-source.d.ts +50 -0
  247. package/dist/redact.d.ts +70 -0
  248. package/dist/redact.js +212 -0
  249. package/dist/registration.d.ts +30 -0
  250. package/dist/registration.js +5 -5
  251. package/dist/risk.d.ts +380 -0
  252. package/dist/risk.js +206 -0
  253. package/dist/run-log.d.ts +78 -0
  254. package/dist/run-log.js +301 -0
  255. package/dist/s3/listing.d.ts +47 -0
  256. package/dist/s3/multipart.d.ts +21 -0
  257. package/dist/s3/response-sink.d.ts +8 -0
  258. package/dist/s3/same-file.d.ts +54 -0
  259. package/dist/s3/server.d.ts +58 -0
  260. package/dist/s3/server.js +2 -2
  261. package/dist/s3/sigv4.d.ts +46 -0
  262. package/dist/s3/sigv4.js +1 -1
  263. package/dist/s3/staging.d.ts +10 -0
  264. package/dist/s3/xml.d.ts +28 -0
  265. package/dist/safe-path.d.ts +41 -0
  266. package/dist/seal.d.ts +120 -0
  267. package/dist/secret-reader.d.ts +28 -0
  268. package/dist/server.d.ts +9 -0
  269. package/dist/session.d.ts +32 -0
  270. package/dist/session.js +1 -1
  271. package/dist/setup-questions.d.ts +7 -0
  272. package/dist/share.d.ts +108 -0
  273. package/dist/share.js +1 -1
  274. package/dist/shared/lib/crypto/size-padding.d.ts +55 -0
  275. package/dist/shared/lib/crypto/size-padding.js +5 -0
  276. package/dist/shared/lib/drive/manifest-chunks.d.ts +95 -0
  277. package/dist/shared/lib/drive/manifest-chunks.js +252 -0
  278. package/dist/shared/lib/drive/manifest-codec.d.ts +214 -0
  279. package/dist/shared/lib/drive/manifest-codec.js +7 -7
  280. package/dist/shared/lib/drive/manifest-index.d.ts +98 -0
  281. package/dist/shared/lib/drive/manifest-ops.d.ts +167 -0
  282. package/dist/shared/lib/drive/manifest-ops.js +9 -4
  283. package/dist/shared/lib/drive/manifest-pack.d.ts +65 -0
  284. package/dist/shared/lib/drive/manifest-pack.js +287 -0
  285. package/dist/shared/lib/drive/manifest-settings.d.ts +113 -0
  286. package/dist/shared/lib/drive/manifest-settings.js +87 -6
  287. package/dist/shared/lib/drive/name-conflict.d.ts +76 -0
  288. package/dist/shared/lib/drive/rebuild-verify.d.ts +73 -0
  289. package/dist/shared/lib/drive/rebuild-verify.js +112 -0
  290. package/dist/shared/lib/drive/unique-name.d.ts +9 -0
  291. package/dist/shared/lib/drive/zstd.d.ts +27 -0
  292. package/dist/shared/lib/drive/zstd.js +74 -0
  293. package/dist/shared/lib/extend/epochs.d.ts +205 -0
  294. package/dist/shared/lib/net/retry-budget.d.ts +79 -0
  295. package/dist/shared/lib/share/shared-file-info.d.ts +21 -0
  296. package/dist/shared/lib/storage-control/chain.d.ts +57 -0
  297. package/dist/shared/lib/storage-control/chain.js +82 -0
  298. package/dist/shared/lib/storage-control/plan.d.ts +40 -0
  299. package/dist/shared/lib/storage-control/plan.js +72 -0
  300. package/dist/shared/lib/storage-control/reuse.d.ts +72 -0
  301. package/dist/shared/lib/storage-control/reuse.js +95 -0
  302. package/dist/shared/lib/storage-network.d.ts +25 -0
  303. package/dist/shared/lib/upload/part-plan.d.ts +24 -0
  304. package/dist/shared/lib/wallet/activity.d.ts +138 -0
  305. package/dist/shared/lib/wallet/activity.js +208 -0
  306. package/dist/shared/lib/wallet/send-rules.d.ts +68 -0
  307. package/dist/shared/lib/wallet/send-rules.js +116 -0
  308. package/dist/shared/lib/wallet/swap-rules.d.ts +115 -0
  309. package/dist/shared/lib/wallet/swap-rules.js +199 -0
  310. package/dist/shared/lib/wallet/tip.d.ts +14 -0
  311. package/dist/shared/lib/wallet/tip.js +34 -0
  312. package/dist/shared/lib/wallet/venue-ids.d.ts +23 -0
  313. package/dist/shared/lib/wallet/venue-ids.js +53 -0
  314. package/dist/standing-tip.d.ts +24 -0
  315. package/dist/standing-tip.js +52 -0
  316. package/dist/stdout.d.ts +38 -0
  317. package/dist/storage-control-chain.d.ts +38 -0
  318. package/dist/storage-control-chain.js +78 -0
  319. package/dist/sui-rpc.d.ts +15 -0
  320. package/dist/sui-rpc.js +59 -0
  321. package/dist/support-attach.d.ts +24 -0
  322. package/dist/support-attach.js +72 -0
  323. package/dist/support-copy.d.ts +42 -0
  324. package/dist/support-copy.js +109 -0
  325. package/dist/support-wire.d.ts +49 -0
  326. package/dist/support-wire.js +194 -0
  327. package/dist/trash-sweep.d.ts +55 -0
  328. package/dist/units.d.ts +2 -0
  329. package/dist/update-check.d.ts +50 -0
  330. package/dist/update-source.d.ts +63 -0
  331. package/dist/upload-api.d.ts +3 -0
  332. package/dist/upload-file.d.ts +97 -0
  333. package/dist/upload-file.js +3 -2
  334. package/dist/upload-price.d.ts +50 -0
  335. package/dist/upload-steps.d.ts +26 -0
  336. package/dist/upload-steps.js +29 -9
  337. package/dist/upload-store.d.ts +182 -0
  338. package/dist/upload-wallet-chain.d.ts +54 -0
  339. package/dist/upload-wallet-chain.js +203 -0
  340. package/dist/upload-wallet-plan.d.ts +128 -0
  341. package/dist/upload-wallet-plan.js +184 -0
  342. package/dist/upload-wallet.d.ts +24 -0
  343. package/dist/upload-wallet.js +208 -0
  344. package/dist/upload-wire.d.ts +244 -0
  345. package/dist/upload.d.ts +18 -0
  346. package/dist/upload.js +10 -0
  347. package/dist/usage-report.d.ts +35 -0
  348. package/dist/wallet-activity-chain.d.ts +5 -0
  349. package/dist/wallet-activity-chain.js +31 -0
  350. package/dist/wallet-chain.d.ts +19 -0
  351. package/dist/wallet-chain.js +2 -2
  352. package/dist/wallet-grant.d.ts +50 -0
  353. package/dist/wallet-grant.js +218 -0
  354. package/dist/wallet-send-chain.d.ts +24 -0
  355. package/dist/wallet-send-chain.js +49 -0
  356. package/dist/wallet-sign.d.ts +133 -0
  357. package/dist/wallet-sign.js +317 -0
  358. package/dist/wallet-storage-chain.d.ts +3 -0
  359. package/dist/wallet-storage-chain.js +20 -0
  360. package/dist/wallet-swap-chain.d.ts +52 -0
  361. package/dist/wallet-swap-chain.js +186 -0
  362. package/dist/wallet-swap-quote.d.ts +22 -0
  363. package/dist/wallet-swap-quote.js +126 -0
  364. package/dist/wallet.d.ts +135 -0
  365. package/dist/wallet.js +5 -5
  366. package/dist/walrus-write.d.ts +56 -0
  367. package/dist/walrus-write.js +5 -4
  368. package/dist/walrus.d.ts +86 -0
  369. package/dist/walrus.js +48 -10
  370. package/dist/zstd-node.d.ts +11 -0
  371. package/dist/zstd-node.js +71 -0
  372. package/docs/commands/accept-terms.md +15 -0
  373. package/docs/commands/create.md +17 -0
  374. package/docs/commands/credits.md +34 -0
  375. package/docs/commands/delete-account.md +14 -0
  376. package/docs/commands/deposit.md +27 -0
  377. package/docs/commands/devices.md +9 -0
  378. package/docs/commands/documents.md +10 -0
  379. package/docs/commands/env.md +21 -0
  380. package/docs/commands/extend.md +27 -0
  381. package/docs/commands/folders.md +10 -0
  382. package/docs/commands/get.md +14 -0
  383. package/docs/commands/key.md +14 -0
  384. package/docs/commands/login.md +23 -0
  385. package/docs/commands/logout.md +11 -0
  386. package/docs/commands/losses.md +13 -0
  387. package/docs/commands/ls.md +16 -0
  388. package/docs/commands/marks.md +9 -0
  389. package/docs/commands/mcp.md +33 -0
  390. package/docs/commands/mode.md +29 -0
  391. package/docs/commands/on-collision.md +13 -0
  392. package/docs/commands/padding.md +13 -0
  393. package/docs/commands/public-code.md +9 -0
  394. package/docs/commands/pull.md +9 -0
  395. package/docs/commands/push.md +12 -0
  396. package/docs/commands/put.md +36 -0
  397. package/docs/commands/rebuild.md +13 -0
  398. package/docs/commands/recovery.md +18 -0
  399. package/docs/commands/s3.md +17 -0
  400. package/docs/commands/share.md +15 -0
  401. package/docs/commands/support.md +16 -0
  402. package/docs/commands/tip.md +21 -0
  403. package/docs/commands/trash.md +25 -0
  404. package/docs/commands/trial.md +12 -0
  405. package/docs/commands/unlock.md +25 -0
  406. package/docs/commands/update.md +14 -0
  407. package/docs/commands/usage.md +14 -0
  408. package/docs/commands/verify.md +18 -0
  409. package/docs/commands/wallet.md +67 -0
  410. package/docs/commands/whoami.md +12 -0
  411. package/package.json +67 -8
  412. package/server.json +28 -0
  413. package/vendor/nmts-crypto/nmts_crypto_wasm.d.ts +23 -2
  414. package/vendor/nmts-crypto/nmts_crypto_wasm.js +44 -2
  415. package/vendor/nmts-crypto/nmts_crypto_wasm_bg.wasm +0 -0
  416. package/vendor/nmts-crypto/nmts_crypto_wasm_bg.wasm.d.ts +1 -0
  417. package/vendor/nmts-crypto/package.json +1 -1
  418. package/dist/commands/consent.js +0 -77
  419. package/dist/extend-sign.js +0 -130
@@ -0,0 +1,40 @@
1
+ import type { CryptoGlue } from "./crypto.ts";
2
+ import { type ReadOptions } from "./walrus.ts";
3
+ export interface PartView {
4
+ part_index: number;
5
+ storage_kind: number;
6
+ network?: number;
7
+ blob_id: string;
8
+ patch_id?: string;
9
+ }
10
+ export interface PartsResponse {
11
+ size: number;
12
+ parts: PartView[];
13
+ }
14
+ export declare function asParts(value: unknown): PartsResponse;
15
+ /**
16
+ * Fetch one part's sealed bytes.
17
+ *
18
+ * ⛔ Refuse before reading, not after. A part on a storage network this build has no reader for
19
+ * would otherwise be fetched from a Walrus aggregator, 404, and be reported as missing bytes —
20
+ * which is a different thing and sends somebody looking for the wrong one.
21
+ */
22
+ export declare function fetchPart(part: PartView, chain: string, read: ReadOptions | undefined): Promise<Uint8Array>;
23
+ /**
24
+ * Open ONE part and pass its contribution on, a chunk at a time. Returns how much of the file it
25
+ * contributed.
26
+ *
27
+ * ⛔ THE SEALED BYTES ARE FED IN ONE CHUNK AT A TIME, not all at once. Handing the engine the whole
28
+ * part would make it hand back the whole part's plaintext in one array, which is the ceiling
29
+ * this path exists to remove; feeding it a chunk's worth means at most one chunk of plaintext
30
+ * exists at a time. The size fed is the format's own chunk plus its tag, so a well-formed
31
+ * stream yields exactly one chunk per push — and a stream whose header declares a different
32
+ * chunk size still works, because the engine buffers what it has not finished.
33
+ *
34
+ * ⛔ `finish()` IS WHAT CATCHES A PART CUT SHORT. Every chunk that arrived authenticates; only the
35
+ * end-of-stream check knows the rest is missing. Skipping it would accept a truncated part.
36
+ *
37
+ * ⛔ THE ENGINE-SIDE SESSION IS FREED ON EVERY PATH OUT, including a failure: it holds the file
38
+ * key until it is, and a download that failed is exactly when nobody comes back to tidy up.
39
+ */
40
+ export declare function openPart(crypt: CryptoGlue, dek: Uint8Array, part: PartView, sealed: Uint8Array, isLast: boolean, remaining: number, emit: (body: Uint8Array) => Promise<void>): Promise<number>;
@@ -0,0 +1,76 @@
1
+ import { type ByteDestination } from "./stdout.ts";
2
+ /**
3
+ * Somewhere a file's plaintext is delivered in order, and made visible only once.
4
+ *
5
+ * The shape is three-part on purpose: `write` moves bytes, `commit` is the only thing that may
6
+ * make them readable under the name somebody asked for, and `abandon` must leave nothing behind.
7
+ * A destination that cannot separate those three cannot hold the integrity promise above.
8
+ */
9
+ export interface PlaintextSink {
10
+ /**
11
+ * The file's real length, from the sealed list, BEFORE a single stored part is fetched.
12
+ *
13
+ * ⛔ A destination that cannot take a file this size refuses HERE, where nothing has been read
14
+ * from the network and nothing has been written. Discovering it half way through means the
15
+ * refusal costs a download that was never going to be delivered.
16
+ */
17
+ expect(size: number): void;
18
+ /** Take the next run of plaintext, in order. Resolves when the bytes are no longer needed. */
19
+ write(bytes: Uint8Array): Promise<void>;
20
+ /**
21
+ * Everything checked: make the file visible, or hand it over.
22
+ *
23
+ * False means the reader closed the pipe before the file was done — see `handOver`. Every other
24
+ * failure throws: a caller must not be able to mistake "it stopped half way" for "delivered".
25
+ */
26
+ commit(): Promise<boolean>;
27
+ /** Something did not check out: leave nothing behind. Never throws. */
28
+ abandon(): Promise<void>;
29
+ }
30
+ /**
31
+ * Write to a file, through a temporary name beside it, renamed into place only when the whole
32
+ * file has been proved.
33
+ *
34
+ * ⛔ THE TEMPORARY FILE IS IN THE SAME DIRECTORY AS THE DESTINATION, not in a system temporary
35
+ * directory, and that is the whole mechanism: `rename` is atomic only within one filesystem,
36
+ * and only an atomic rename guarantees that a reader either sees nothing under the real name or
37
+ * sees the finished file. A temporary directory can be — and on the machines this runs on
38
+ * usually is — a different filesystem, where the same call becomes copy-then-delete and a
39
+ * reader can catch the copy half done.
40
+ *
41
+ * ⛔ IT IS CREATED 0600 AND THE RENAME KEEPS THAT. The file is somebody's plaintext; it must not
42
+ * be readable by other accounts on the machine for the seconds it takes to download, any more
43
+ * than it may be afterwards.
44
+ */
45
+ export declare function fileSink(destination: string, options: {
46
+ force: boolean;
47
+ }): PlaintextSink;
48
+ /**
49
+ * How much plaintext `--out -` will hold before it hands anything over. One part's worth.
50
+ *
51
+ * ⛔ NOT AN ARBITRARY NUMBER: it is the upload path's default part size, which is the most memory
52
+ * this tool has ever asked for. Keeping the stdout ceiling there means the whole tool's bound
53
+ * is one part plus one chunk whichever direction the bytes are going.
54
+ */
55
+ export declare const STDOUT_HOLD_LIMIT: number;
56
+ /**
57
+ * Hand the whole file to whatever is reading stdout — after it has been proved, not during.
58
+ *
59
+ * ⛔ THERE IS NO RENAME ON A PIPE, so the trick the file path uses is not available: a byte handed
60
+ * to a reader cannot be taken back, and a reader that has already consumed half a file cannot
61
+ * be told afterwards that the half was wrong. An exit code does not fix that — `nmts get x
62
+ * --out - > y` leaves the truncated bytes in `y` whatever the exit code says, and an agent
63
+ * reading a pipe usually acts on what it read. So this branch keeps the ORIGINAL guarantee
64
+ * rather than the original size: the file is held, checked, and only then handed over, exactly
65
+ * as before streaming existed.
66
+ *
67
+ * ⛔ WHICH MEANS IT HAS TO REFUSE SOMEWHERE, AND IT REFUSES OUT LOUD AND EARLY. Above the ceiling
68
+ * the answer is a refusal naming `--out <name>`, which streams and is checked before the file
69
+ * appears — not a silent trade of the guarantee for the size, and not the out-of-memory crash
70
+ * that this used to be. `put` already refuses this way rather than discovering a limit halfway.
71
+ *
72
+ * ⚠ Every protection this branch already had is still here and still applies to the whole file:
73
+ * bytes a terminal would act on are refused (`readableOnATerminal`), a reader that closed the
74
+ * pipe first is an ordinary end and not a failure, and any other write failure throws.
75
+ */
76
+ export declare function stdoutSink(to: ByteDestination, limit?: number): PlaintextSink;
@@ -0,0 +1,79 @@
1
+ import type { PlaintextSink } from "./download-sink.ts";
2
+ import type { ReadOptions } from "./walrus.ts";
3
+ export interface FetchedFile {
4
+ /**
5
+ * How many plaintext bytes were delivered — the file's real length.
6
+ *
7
+ * ⚠ A COUNT, NOT THE BYTES. There is deliberately nothing here to read the file out of: the
8
+ * plaintext went to the sink as it was produced and was zeroed behind it, and a field holding
9
+ * it would put the ceiling this module exists to remove straight back.
10
+ */
11
+ byteCount: number;
12
+ /** How many stored objects it came from. */
13
+ partCount: number;
14
+ /** Whether the file's own sealed hash was there to check against, and matched. */
15
+ contentHashChecked: boolean;
16
+ /**
17
+ * Whether the whole file reached its destination.
18
+ *
19
+ * False has exactly one meaning: the program reading `--out -` closed the pipe before the file
20
+ * was done, which is an ordinary end and not a failure (`handOver`). Anything else throws.
21
+ */
22
+ delivered: boolean;
23
+ }
24
+ export interface FetchInput {
25
+ base: string;
26
+ apiKey: string;
27
+ accountCode: string;
28
+ itemId: string;
29
+ /** The file's real length, from the account's sealed file list. */
30
+ size: number;
31
+ /** Wrapped file key from the sealed file list. Without it nothing can be opened. */
32
+ dekWrapped: string;
33
+ /** Sealed whole-file hash from the sealed file list, when the account recorded one. */
34
+ contentHashCt?: string | undefined;
35
+ /**
36
+ * Which CHAIN this account's storage lives on — `mainnet` or `testnet`.
37
+ *
38
+ * ⛔ NOT the same question as a part's `network` field. That one says which STORAGE NETWORK holds
39
+ * the bytes (Walrus, and so far only Walrus); this one picks which of that network's
40
+ * aggregators to ask, because a blob id is meaningful on exactly one chain.
41
+ */
42
+ chain: string;
43
+ read?: ReadOptions;
44
+ /** Where the plaintext goes as it is decrypted. Committed only after the whole file checks out. */
45
+ sink: PlaintextSink;
46
+ }
47
+ /**
48
+ * Fetch, decrypt and verify one file.
49
+ *
50
+ * The NMTS key is used and not kept: the data key is derived, unwrapped keys are zeroed, and
51
+ * the derivation output — which holds every other key in the account — never outlives this call.
52
+ */
53
+ /**
54
+ * Fetch, decrypt and verify one file whose key is ALREADY OPEN.
55
+ *
56
+ * ⛔ SPLIT OUT BECAUSE THERE ARE TWO WAYS TO GET THAT KEY, and only one of them belongs to the
57
+ * account holding it. A file this account owns has its key wrapped in its own sealed list; a
58
+ * file somebody SHARED has its key inside an envelope only this account can open, sealed under
59
+ * a different separator, and its real length comes from what the sender sealed rather than from
60
+ * the account's own list. Everything after the key is identical — and writing it twice is how
61
+ * one copy comes to check the hash and the other does not.
62
+ */
63
+ export declare function fetchWithKey(input: {
64
+ base: string;
65
+ apiKey: string;
66
+ /** Where the server describes the stored parts. Different for an owned and a shared file. */
67
+ descriptorPath: string;
68
+ /** The file's REAL plaintext length. */
69
+ size: number;
70
+ /** The file's own key, already unwrapped. Wiped here. */
71
+ dek: Uint8Array;
72
+ /** The whole-plaintext digest to check against, or null when none was recorded. */
73
+ expected: Uint8Array | null;
74
+ chain: string;
75
+ read?: ReadOptions;
76
+ /** Where the plaintext goes as it is decrypted. Committed only after the whole file checks out. */
77
+ sink: PlaintextSink;
78
+ }): Promise<FetchedFile>;
79
+ export declare function fetchFile(input: FetchInput): Promise<FetchedFile>;
package/dist/download.js CHANGED
@@ -2,7 +2,7 @@
2
2
  //
3
3
  // ⛔ THE SERVER NEVER SEES THE FILE, AND NOTHING HERE TRUSTS IT WITH ONE. It says which stored
4
4
  // objects a file is made of and how big the file is; every byte that becomes the file is
5
- // decrypted here under a key derived from the account code, and the whole thing is checked
5
+ // decrypted here under a key derived from the NMTS key, and the whole thing is checked
6
6
  // against a hash the account sealed for itself. A server that lies about the parts, or an
7
7
  // aggregator that returns the wrong bytes, produces a refusal — never a quietly wrong file.
8
8
  //
@@ -34,7 +34,7 @@ import { NmtsError } from "./errors.js";
34
34
  /**
35
35
  * Fetch, decrypt and verify one file.
36
36
  *
37
- * The account code is used and not kept: the data key is derived, unwrapped keys are zeroed, and
37
+ * The NMTS key is used and not kept: the data key is derived, unwrapped keys are zeroed, and
38
38
  * the derivation output — which holds every other key in the account — never outlives this call.
39
39
  */
40
40
  /**
@@ -74,7 +74,7 @@ export async function fetchFile(input) {
74
74
  catch {
75
75
  dataKey.fill(0);
76
76
  throw new NmtsError("This file's key did not open with this account's key.", {
77
- nextStep: "Either the account code belongs to somebody else, or the file list has been altered.",
77
+ nextStep: "Either the NMTS key belongs to somebody else, or the file list has been altered.",
78
78
  });
79
79
  }
80
80
  let expected = null;
@@ -0,0 +1,73 @@
1
+ import type { ManifestEntry } from "./shared/lib/drive/manifest-codec.ts";
2
+ import { buildIndex, isLive, type ManifestIndex, trashedAt } from "./shared/lib/drive/manifest-index.ts";
3
+ /** Folder. The same numeric codes the items API uses. */
4
+ export declare const KIND_FOLDER = 0;
5
+ /** File. */
6
+ export declare const KIND_FILE = 1;
7
+ export { buildIndex, isLive, trashedAt };
8
+ export type { ManifestIndex };
9
+ /**
10
+ * The full path of one entry, marked when the walk could not reach the root.
11
+ *
12
+ * ⚠ The `seen` set is not defensive tidiness: a list where two folders are each other's parent
13
+ * would loop forever, and a list is a file that can arrive from anywhere.
14
+ */
15
+ export declare function fullPathOf(index: ManifestIndex, entry: ManifestEntry): string;
16
+ /**
17
+ * `/photos/2026/` and `./photos/2026` and `photos/2026` are one path.
18
+ *
19
+ * ⛔ AND SO ARE THE TWO SPELLINGS OF `café`. Unicode gives the same visible name more than one
20
+ * byte sequence — macOS hands back the decomposed form from the shell and the filesystem while
21
+ * a browser typically wrote the composed one. Comparing raw bytes meant `nmts rm café` could
22
+ * address a DIFFERENT entry from the one on screen. Both sides of every comparison here are
23
+ * folded to one form; what gets STORED is untouched, because the name belongs to whoever wrote
24
+ * it.
25
+ */
26
+ /**
27
+ * Strip a folder's own path off one of its descendants, in DRIVE terms.
28
+ *
29
+ * ⛔ IT IS STRING ARITHMETIC AND NOT `node:path`. A drive path always uses `/`, whatever separator
30
+ * the machine reading it happens to use, and `path.relative` answers in the MACHINE's
31
+ * separator. On Windows that turned `deep/under.txt` into `deep\under.txt`, which the
32
+ * containment check downstream then refused as a name trying to leave its directory — so
33
+ * fetching a folder failed outright on one of the three platforms this tool ships for, and
34
+ * every test passed, because on the other two the two separators are the same character.
35
+ * ⚠ That is the whole class: a drive path and a path on this disk are different kinds of thing,
36
+ * and `node:path` is only ever right about the second.
37
+ *
38
+ * A path that is not under the prefix comes back unchanged — the caller decides what that means.
39
+ */
40
+ export declare function underPrefix(prefix: string, drivePath: string): string;
41
+ export declare function normalisePath(input: string): string;
42
+ /** The same folding, for one name rather than a path. */
43
+ export declare function normaliseName(name: string): string;
44
+ export interface FindOptions {
45
+ /** Include entries in the trash. Off by default — `rm` twice must not find its own work. */
46
+ includeTrashed?: boolean;
47
+ /** Only entries of this kind. */
48
+ kind?: number;
49
+ /** What the caller is about to do, for the refusal's second line. */
50
+ nothingHappened?: string;
51
+ }
52
+ /**
53
+ * The one entry at this path, or a refusal saying which of the two ways it failed.
54
+ *
55
+ * ⛔ EXIT CODE 4, NOT 1: the command exists and could not do it, which is a different thing from
56
+ * the command being wrong. An agent is told to stop rather than to retry.
57
+ */
58
+ export declare function entryAt(entries: readonly ManifestEntry[], path: string, options?: FindOptions): ManifestEntry;
59
+ /**
60
+ * The folder id a destination names, or null for the top of the drive.
61
+ *
62
+ * ⚠ An empty destination is the ROOT, and that is not the same as "no destination given" being an
63
+ * error: `--to ""` and `--to /` both mean the top, which is what somebody types to move
64
+ * something back out of a folder.
65
+ */
66
+ export declare function folderIdFor(wanted: string | undefined, entries: readonly ManifestEntry[], nothingHappened?: string): string | null;
67
+ /**
68
+ * The names already used in one folder — what a new or renamed entry must not collide with.
69
+ *
70
+ * ⚠ Folded the same way paths are, so the two spellings of one visible name count as one taken
71
+ * name. Two entries a person cannot tell apart are worse than a refusal they can act on.
72
+ */
73
+ export declare function namesIn(entries: readonly ManifestEntry[], parentId: string | null): Set<string>;
@@ -0,0 +1,62 @@
1
+ import { type HostSighting } from "./agent-host.ts";
2
+ /** How this process is contained, as far as it can tell. */
3
+ export type Containment = "docker" | "podman" | "container" | "none" | "unknown";
4
+ export interface Environment {
5
+ /** `linux`, `darwin`, `win32`, … — what Node reports, not a guess. */
6
+ os: NodeJS.Platform;
7
+ osRelease: string;
8
+ /** Node's own version. An agent choosing between behaviours may care. */
9
+ node: string;
10
+ containment: Containment;
11
+ /**
12
+ * Is root here somebody else on the host?
13
+ *
14
+ * ⚠ NOT THE SAME QUESTION AS `uid`. A rootless container is uid 0 inside and an ordinary user
15
+ * outside; a rootful one is root in both places. `null` where it cannot be measured.
16
+ */
17
+ rootMapped: boolean | null;
18
+ /** The effective user id INSIDE this process's namespace, where the platform has one. */
19
+ uid: number | null;
20
+ /** Can a file here be kept private? MEASURED — see `codeStorageIsPrivate`. */
21
+ privateStorage: boolean;
22
+ /** Where anything this tool keeps would go. */
23
+ configDir: string;
24
+ /** Is there a person at a keyboard? A prompt is impossible without one. */
25
+ interactive: boolean;
26
+ /** Could a browser be opened here — needed for anything behind a human check. */
27
+ browserReachable: boolean;
28
+ /**
29
+ * Which agent hosts left a marker in this environment.
30
+ *
31
+ * ⚠ EVERY ONE OF THESE IS AN ANCESTOR, NOT NECESSARILY THE PARENT — markers are inherited, so a
32
+ * tool started by an agent that was itself started by another agent sees both. The direct
33
+ * parent is only knowable over the protocol, and that lives in the MCP server, not here.
34
+ * Empty means no marker was found, which includes every host that clears the environment.
35
+ */
36
+ agentHosts: HostSighting[];
37
+ }
38
+ /**
39
+ * Is this a container, and which kind?
40
+ *
41
+ * The three signals, in order of how much they actually prove:
42
+ * · `/run/.containerenv` — Podman writes it, and it names its own settings inside.
43
+ * · `/.dockerenv` — Docker writes it and has for a decade.
44
+ * · the process's own cgroup line naming a runtime.
45
+ * On a platform where none of those files can exist the answer is `unknown`, not `none`.
46
+ */
47
+ export declare function detectContainment(): Containment;
48
+ export declare function readEnvironment(): Environment;
49
+ /** One fact worth acting on, and what to do about it. */
50
+ export interface Advice {
51
+ /** `warn` is something to tell the person about. `note` is context. */
52
+ level: "warn" | "note";
53
+ text: string;
54
+ }
55
+ /**
56
+ * What this environment means, in the terms somebody has to decide in.
57
+ *
58
+ * ⛔ WRITTEN FOR AN AGENT TO REPEAT TO A PERSON. Each line is a complete sentence about a fact
59
+ * that was measured here, so passing it along loses nothing. None of it is an instruction
60
+ * aimed past the reader.
61
+ */
62
+ export declare function adviseFor(env: Environment, hasStoredCode: boolean): Advice[];
@@ -1,4 +1,4 @@
1
- // Working out where this tool is running, and what that means for the account code.
1
+ // Working out where this tool is running, and what that means for the NMTS key.
2
2
  //
3
3
  // ⛔ IT IS FOR THE AGENT, AND THE AGENT IS FOR THE PERSON. A program driving this tool cannot see
4
4
  // what a person can — whether it is inside a container, whether the home directory survives the
@@ -16,6 +16,8 @@
16
16
  import { existsSync, readFileSync } from "node:fs";
17
17
  import { platform, release, tmpdir, userInfo } from "node:os";
18
18
  import { configDir, codeStorageIsPrivate, modesAreEnforced } from "./credentials.js";
19
+ import { HOST_NAMES, hostsInEnvironment, washingHosts } from "./agent-host.js";
20
+ import { BINARY_NAME } from "./product.js";
19
21
  /**
20
22
  * Is this a container, and which kind?
21
23
  *
@@ -104,6 +106,7 @@ export function readEnvironment() {
104
106
  configDir: configDir(),
105
107
  interactive: process.stdin.isTTY === true,
106
108
  browserReachable: canOpenBrowser(),
109
+ agentHosts: hostsInEnvironment(),
107
110
  };
108
111
  }
109
112
  /**
@@ -118,8 +121,8 @@ export function adviseFor(env, hasStoredCode) {
118
121
  if (!env.privateStorage) {
119
122
  out.push({
120
123
  level: "warn",
121
- text: `This filesystem does not keep the mode a file is written with, so a stored account code ` +
122
- `could be read by anything else that can reach ${env.configDir}. Supplying the code for ` +
124
+ text: `This filesystem does not keep the mode a file is written with, so a stored NMTS key ` +
125
+ `could be read by anything else that can reach ${env.configDir}. Supplying the NMTS key for ` +
123
126
  `each run instead of storing it avoids that.`,
124
127
  });
125
128
  }
@@ -127,13 +130,13 @@ export function adviseFor(env, hasStoredCode) {
127
130
  out.push({
128
131
  level: "note",
129
132
  text: `This is a ${env.containment} container. Anything written to ${env.configDir} is lost when ` +
130
- `it is removed unless that path is a volume, so a stored account code will not be there ` +
133
+ `it is removed unless that path is a volume, so a stored NMTS key will not be there ` +
131
134
  `next time.`,
132
135
  });
133
136
  out.push({
134
137
  level: "warn",
135
- text: `Do not pass the account code as an environment variable in a container: the whole ` +
136
- `environment is visible to anybody who can inspect it. Put the code in a file and name ` +
138
+ text: `Do not pass the NMTS key as an environment variable in a container: the whole ` +
139
+ `environment is visible to anybody who can inspect it. Put the NMTS key in a file and name ` +
137
140
  `that file in NMTS_ACCOUNT_CODE_FILE, or pipe it in.`,
138
141
  });
139
142
  // ⛔ TWO DIFFERENT FACTS, and conflating them is how "rootless" gets reported backwards. What
@@ -162,7 +165,7 @@ export function adviseFor(env, hasStoredCode) {
162
165
  if (!env.interactive && !hasStoredCode) {
163
166
  out.push({
164
167
  level: "warn",
165
- text: `There is no terminal here, so this tool cannot ask for the account code. It has to ` +
168
+ text: `There is no terminal here, so this tool cannot ask for the NMTS key. It has to ` +
166
169
  `arrive in the environment or in a file named by NMTS_ACCOUNT_CODE_FILE.`,
167
170
  });
168
171
  }
@@ -170,13 +173,13 @@ export function adviseFor(env, hasStoredCode) {
170
173
  out.push({
171
174
  level: "note",
172
175
  text: `No browser can be opened here. Anything that needs a human check — making an account, ` +
173
- `applying for the free trial — has to be done on a machine that has one.`,
176
+ `renewing the account's four-week check — has to be done on a machine that has one.`,
174
177
  });
175
178
  }
176
179
  if (env.os === "win32") {
177
180
  out.push({
178
181
  level: "note",
179
- text: `Windows applies no POSIX file mode, so a stored account code inherits the folder's ` +
182
+ text: `Windows applies no POSIX file mode, so a stored NMTS key inherits the folder's ` +
180
183
  `permissions rather than being restricted to one user.`,
181
184
  });
182
185
  }
@@ -186,5 +189,22 @@ export function adviseFor(env, hasStoredCode) {
186
189
  text: `The configuration directory is inside the temporary directory and may be cleared at any time.`,
187
190
  });
188
191
  }
192
+ // ⛔ THE ONE THING THAT SURPRISES PEOPLE. Three of the five agents this tool knows clear the
193
+ // environment before starting an MCP server and put back a fixed list of names — none of
194
+ // which is ours. So a person who exported the NMTS key, attached the tool, and watched
195
+ // it say "not found" did everything right; the value was dropped between the two. Saying so
196
+ // while the marker is still visible (in the shell, where nothing has been cleared yet) is the
197
+ // only moment it can be said before the failure rather than after it.
198
+ const washing = washingHosts(env.agentHosts);
199
+ if (washing.length > 0) {
200
+ const names = washing.map((id) => HOST_NAMES[id]).join(" and ");
201
+ out.push({
202
+ level: "warn",
203
+ text: `${names} clears the environment before starting an MCP server and restores only a fixed ` +
204
+ `list of names, which does not include NMTS_ACCOUNT_CODE or NMTS_ACCOUNT_CODE_FILE. Those ` +
205
+ `work in a terminal here and will not reach the tool once it is attached. Sign in once ` +
206
+ `with \`${BINARY_NAME} login\` so the NMTS key is in this tool's own file instead.`,
207
+ });
208
+ }
189
209
  return out;
190
210
  }
@@ -0,0 +1,22 @@
1
+ /** A failure this tool understood, with an exit code and something the caller can do. */
2
+ export declare class NmtsError extends Error {
3
+ readonly exitCode: number;
4
+ /** One line naming the next action, or null when there is nothing useful to suggest. */
5
+ readonly nextStep: string | null;
6
+ constructor(message: string, options?: {
7
+ exitCode?: number;
8
+ nextStep?: string | null;
9
+ });
10
+ }
11
+ /** Nothing is signed in on this machine and no code was supplied. */
12
+ export declare class NotLoggedInError extends NmtsError {
13
+ constructor(binary: string, envVar: string);
14
+ }
15
+ /** The command exists but is not built yet. Said plainly rather than failing as if it broke. */
16
+ export declare class NotBuiltYetError extends NmtsError {
17
+ constructor(what: string);
18
+ }
19
+ /** Render a failure for a terminal an agent is reading. */
20
+ export declare function renderError(error: unknown, binary: string): string;
21
+ /** Exit code for an unknown failure, kept distinct from the ones above. */
22
+ export declare const UNKNOWN_FAILURE_EXIT = 1;
package/dist/errors.js CHANGED
@@ -5,7 +5,7 @@
5
5
  // tells an agent nothing it can use; "your API key was revoked — issue a new one at
6
6
  // nmts.me/account" tells it whether to retry, ask, or stop.
7
7
  //
8
- // ⛔ NOTHING SECRET IS EVER INTERPOLATED. Not the account code, not the API key, not a session
8
+ // ⛔ NOTHING SECRET IS EVER INTERPOLATED. Not the NMTS key, not the API key, not a session
9
9
  // token. An error string is the one place a secret escapes without anybody choosing to print
10
10
  // it, and agents copy error strings into logs and prompts by default.
11
11
  //
@@ -13,7 +13,7 @@
13
13
  // unknown error's `message` goes out verbatim, which is right (a swallowed cause is a debug
14
14
  // session nobody can start) and is also a hole: an adversarial review made `JSON.parse` fail on
15
15
  // the credentials file, and V8's own message quotes about thirty characters of the input —
16
- // nine symbols of a real account code reached stderr. The fix is not here. It is that anything
16
+ // nine symbols of a real NMTS key reached stderr. The fix is not here. It is that anything
17
17
  // reading a file the code is in must catch its own parser and throw a message of its own
18
18
  // (`credentials.ts`, `unusable`). ▶ Any NEW code that parses a secret-bearing file owes the
19
19
  // same, and this paragraph is the reason why.
@@ -32,7 +32,7 @@ export class NmtsError extends Error {
32
32
  /** Nothing is signed in on this machine and no code was supplied. */
33
33
  export class NotLoggedInError extends NmtsError {
34
34
  constructor(binary, envVar) {
35
- super(`No NMTS account code on this machine.`, {
35
+ super(`No NMTS key on this machine.`, {
36
36
  exitCode: 3,
37
37
  nextStep: `Run \`${binary} login\`, or set ${envVar} in the environment.`,
38
38
  });
package/dist/exit.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ /** The exit code a failure asks for, or the generic one. */
2
+ export declare function exitCodeFor(error: unknown): number;
3
+ /**
4
+ * Stop a closed pipe from becoming a crash.
5
+ *
6
+ * ⛔ `nmts ls | head` IS AN ORDINARY THING TO DO, and without this it prints a ten-line stack
7
+ * trace instead of the answer. `head` closes the pipe once it has its lines; the next write
8
+ * raises EPIPE, and Node turns an unhandled stream error into a fatal one. Every shell tool is
9
+ * expected to end quietly there — that is what SIGPIPE does for programs that do not intercept
10
+ * it — and an agent piping this into anything would otherwise read a crash and conclude the
11
+ * tool is broken.
12
+ *
13
+ * ⚠ ONLY EPIPE. A write that fails for any other reason is still a real failure and still throws;
14
+ * swallowing all stream errors would hide a full disk behind silence.
15
+ */
16
+ export declare function endQuietlyOnClosedPipe(): void;
17
+ /**
18
+ * Is the module at `moduleFilename` the program, or is something importing it?
19
+ *
20
+ * ⛔ THE FILENAME IS PASSED IN AND NOT READ HERE. `import.meta.filename` inside this module
21
+ * would name THIS file, which is never the program; the caller's own is the question.
22
+ *
23
+ * ⛔ THE COMPARISON IS BETWEEN REAL PATHS, AND THAT IS THE WHOLE POINT. `npm install -g` does not
24
+ * copy the command onto your PATH — it puts a SYMLINK there, pointing at `dist/main.js` inside
25
+ * the installed package. Node then loads the module by its real
26
+ * path, so the module's own name is `.../dist/main.js` while `process.argv[1]` is
27
+ * `.../bin/nmts`. Comparing those two directly is never true for an installed command: `nmts --version` printed NOTHING and exited 0, and
28
+ * so did every other command. The whole tool did nothing at all, silently, and only when
29
+ * installed — which is the one way a person who is not us runs it.
30
+ *
31
+ * ⚠ `realpathSync` THROWS on a path that is not there. `process.argv[1]` normally exists, but a
32
+ * caller is free to hand Node something else, and a crash before the first line of output would
33
+ * be a worse answer than not running. Not resolving is treated as "not the program", which is
34
+ * the same answer this was giving before symlinks were considered at all.
35
+ */
36
+ export declare function invokedDirectly(moduleFilename: string): boolean;
37
+ /**
38
+ * Say so if a newer release is already known about, and refresh what is known for next time.
39
+ *
40
+ * ⛔ AFTER THE COMMAND, NOT BEFORE IT. Whatever was asked for has already been printed and the
41
+ * exit code is already decided; nothing here can change either. ⛔ AND ONLY FROM `main`: the
42
+ * tests drive `run` directly, so no test and no embedded caller ever reaches a network.
43
+ */
44
+ export declare function noteUpdateAfter(argv: readonly string[], version: string): Promise<void>;
@@ -0,0 +1,58 @@
1
+ import { NOTICE_DAYS, NOTICE_EPOCHS, URGENT_DAYS, URGENT_EPOCHS, type DaysLeft } from "./shared/lib/extend/epochs.ts";
2
+ export { NOTICE_DAYS, NOTICE_EPOCHS, URGENT_DAYS, URGENT_EPOCHS };
3
+ export type { DaysLeft };
4
+ /** Where the storage network's clock stands. Built by `epochClock`, never assembled by hand. */
5
+ export interface EpochClock {
6
+ /** The epoch the network is in. */
7
+ readonly current: number;
8
+ /** One epoch's length in milliseconds — read from the network, never assumed. */
9
+ readonly durationMs: number;
10
+ /** When the current epoch began, or null when the network did not say. */
11
+ readonly startedMs: number | null;
12
+ }
13
+ /**
14
+ * A clock, or null when what the network answered cannot be counted with.
15
+ *
16
+ * ⛔ THE INVARIANT LIVES IN THE TYPE, so every function below can divide by `durationMs` without
17
+ * asking again. A zero or a NaN out of a chain read would otherwise become an Infinity printed
18
+ * as a number of days, and there would be no single place to have caught it.
19
+ */
20
+ export declare function epochClock(current: number, durationMs: number, startedMs: number | null): EpochClock | null;
21
+ /**
22
+ * How far ahead a warning stage reaches, in epochs: a floor in days and a floor in epochs, wider
23
+ * one wins.
24
+ *
25
+ * The day count rounds UP, because arriving a tick late is the quiet failure the whole surface
26
+ * exists to prevent.
27
+ */
28
+ export declare function warningEpochs(clock: EpochClock, days: number, floorEpochs: number): number;
29
+ /**
30
+ * Whole days from `nowMs` until `epoch` is reached, by the network's own clock.
31
+ *
32
+ * With an anchor both ends collapse onto one moment. Without one, the honest answer is the
33
+ * earliest the epoch can arrive — see the header for why the other edge is never used.
34
+ */
35
+ export declare function daysLeftUntilEpoch(clock: EpochClock, epoch: number, nowMs: number): DaysLeft;
36
+ /**
37
+ * How much trouble one file's storage term is in.
38
+ *
39
+ * `lapsed` is not a prediction: the term ran out and the bytes may already be unreadable. It is
40
+ * kept separate from `urgent` because the action differs — an urgent file can still be extended,
41
+ * a lapsed one usually cannot.
42
+ */
43
+ export type ExpiryStage = "unrecorded" | "lapsed" | "urgent" | "soon" | "later";
44
+ export declare function stageOf(clock: EpochClock, expiryEpoch: number, nowMs: number): ExpiryStage;
45
+ /**
46
+ * The epoch to ask the server about: everything ending before this is inside the warning window.
47
+ *
48
+ * The cutoff is computed HERE and sent as an absolute number because the server does not read the
49
+ * chain and cannot work it out — `GET /v1/items/expiring` takes the answer, not the question.
50
+ */
51
+ export declare function warningCutoffEpoch(clock: EpochClock): number;
52
+ /**
53
+ * How long is left, said the way a person reads it.
54
+ *
55
+ * ⚠ "or more" is not hedging: it is the difference between a measurement and a floor, and dropping
56
+ * it would turn a lower bound into a promise about a deletion date.
57
+ */
58
+ export declare function daysLeftInWords(left: DaysLeft): string;
@@ -0,0 +1,35 @@
1
+ import type { ExtendReads } from "./extend-plan.ts";
2
+ export interface Budget {
3
+ /** The address that would sign — the one `nmts wallet` prints and the one somebody funds. */
4
+ readonly address: string;
5
+ /** What the extension costs, in FROST. */
6
+ readonly priceFrost: bigint;
7
+ /** Held now, in base units — or null when the chain could not answer. */
8
+ readonly walFrost: bigint | null;
9
+ readonly suiMist: bigint | null;
10
+ /** The chain fee the dry run measured, in MIST — or null when it could not be measured. */
11
+ readonly feeMist: bigint | null;
12
+ /** Why each unread balance could not be read, in the words the chain gave. */
13
+ readonly unread: readonly string[];
14
+ /** What the wallet is known to be short of, or null when nothing known says it is short. */
15
+ readonly shortfall: string | null;
16
+ }
17
+ /** Read the wallet and measure the fee, then say whether the known numbers cover the purchase. */
18
+ export declare function readBudget(reads: ExtendReads, input: {
19
+ address: string;
20
+ objectIds: readonly string[];
21
+ epochs: number;
22
+ priceFrost: bigint;
23
+ }): Promise<Budget>;
24
+ /** The budget as the machine-readable answer carries it. ⚠ Base units are strings — see `Facts`. */
25
+ export declare function budgetFacts(b: Budget): {
26
+ wallet: string;
27
+ walletWal: string | null;
28
+ walletSui: string | null;
29
+ feeMist: string | null;
30
+ feeSui: string | null;
31
+ };
32
+ /** The next step when the wallet is short: where to send what, said once. */
33
+ export declare function shortfallNextStep(b: Budget): string;
34
+ /** The fee and the wallet, for a person, after the price. */
35
+ export declare function describeBudget(say: (line: string) => void, b: Budget): void;