@needmoretruth/nmts-cli 0.34.4 → 0.35.0

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 (63) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.ko.md +15 -15
  3. package/README.md +1 -1
  4. package/dist/arg-options.d.ts +167 -0
  5. package/dist/arg-options.js +10 -0
  6. package/dist/args.d.ts +2 -157
  7. package/dist/args.js +2 -0
  8. package/dist/artifact-about.d.ts +1 -1
  9. package/dist/commands/extend.d.ts +2 -0
  10. package/dist/commands/extend.js +8 -1
  11. package/dist/commands/push-wallet.js +6 -0
  12. package/dist/commands/push.d.ts +2 -0
  13. package/dist/commands/put-payer.d.ts +8 -0
  14. package/dist/commands/put-payer.js +41 -0
  15. package/dist/commands/put-wallet.d.ts +9 -3
  16. package/dist/commands/put-wallet.js +105 -185
  17. package/dist/commands/put.d.ts +5 -7
  18. package/dist/commands/put.js +3 -26
  19. package/dist/commands/wallet-donate.d.ts +3 -0
  20. package/dist/commands/wallet-donate.js +6 -2
  21. package/dist/commands/wallet-list.d.ts +18 -0
  22. package/dist/commands/wallet-list.js +116 -0
  23. package/dist/commands/wallet-send.d.ts +4 -0
  24. package/dist/commands/wallet-send.js +6 -2
  25. package/dist/commands/wallet-use.d.ts +7 -0
  26. package/dist/commands/wallet-use.js +55 -0
  27. package/dist/commands/wallet.d.ts +4 -0
  28. package/dist/commands/wallet.js +20 -8
  29. package/dist/extend-plan.d.ts +2 -0
  30. package/dist/help.js +3 -1
  31. package/dist/index.d.ts +10 -1
  32. package/dist/index.js +14 -1
  33. package/dist/main.js +4 -4
  34. package/dist/product.d.ts +1 -1
  35. package/dist/product.js +1 -1
  36. package/dist/risk.d.ts +4 -0
  37. package/dist/risk.js +6 -0
  38. package/dist/shared/lib/drive/manifest-ops.d.ts +8 -30
  39. package/dist/shared/lib/drive/manifest-ops.js +7 -39
  40. package/dist/shared/lib/drive/manifest-settings-patch.d.ts +52 -0
  41. package/dist/shared/lib/drive/manifest-settings-patch.js +110 -0
  42. package/dist/shared/lib/drive/manifest-settings.d.ts +55 -4
  43. package/dist/shared/lib/drive/manifest-settings.js +66 -28
  44. package/dist/shared/lib/wallet/discover.d.ts +54 -0
  45. package/dist/shared/lib/wallet/discover.js +66 -0
  46. package/dist/standing-tip.d.ts +3 -0
  47. package/dist/standing-tip.js +1 -0
  48. package/dist/upload-wallet-put.d.ts +118 -0
  49. package/dist/upload-wallet-put.js +221 -0
  50. package/dist/upload-wallet.d.ts +3 -0
  51. package/dist/upload-wallet.js +2 -0
  52. package/dist/wallet-list-chain.d.ts +4 -0
  53. package/dist/wallet-list-chain.js +21 -0
  54. package/dist/wallet-pay-index.d.ts +21 -0
  55. package/dist/wallet-pay-index.js +68 -0
  56. package/dist/wallet-sign-seams.d.ts +57 -0
  57. package/dist/wallet-sign-seams.js +16 -0
  58. package/dist/wallet-sign.d.ts +3 -53
  59. package/dist/wallet-sign.js +22 -15
  60. package/dist/wallet.d.ts +13 -13
  61. package/dist/wallet.js +15 -15
  62. package/docs/commands/wallet.md +18 -4
  63. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,23 @@
3
3
  Each version's entry is what changed for the person or the program using `nmts`. The product's own
4
4
  update history, which covers the site and the server too, is at https://nmts.me/updates.
5
5
 
6
+ ## 0.35.0 — 2026-09-16
7
+
8
+ - Many wallets from one NMTS key. The key derives a wallet at every number from 0 upwards, and one
9
+ of them pays. `wallet list` scans the numbers in order, shows each wallet's address and balances,
10
+ marks the one that pays, and stops after twenty unused wallets in a row. `wallet use <number>`
11
+ moves which one pays; the number is kept inside your sealed file list, so the browser, this tool
12
+ and every other device agree on it. `wallet address --index <number>` derives any of them offline.
13
+ - Paying commands (`put --pay wallet`, `push --pay wallet`, `wallet send`, `extend`, `wallet donate`)
14
+ sign from the wallet that pays, and `--wallet <number>` pays from another one for that run only.
15
+ If the file list cannot be read they refuse rather than falling back to wallet 0.
16
+ - Library: `walletPut` — the wallet-paid upload without the terminal (plan, quote, dry-run the fee,
17
+ read both balances, refuse a shortfall before any signature, sign, upload, record) — plus
18
+ `discoverWallets`, `activeWalletOf`, `walletCountOf`, `hasHistory` and `walCoinType`, for the SDK
19
+ and other programs built on this package.
20
+ - Not yet on the paying wallet: `wallet swap`, `wallet storage split|merge|transfer` and `wallet hall`
21
+ still sign from wallet 0; a later version moves them together with the review they print.
22
+
6
23
  ## 0.34.4 — 2026-09-07
7
24
 
8
25
  - The advice for `SPONSORED_IDEM_MISMATCH`: the server now refuses a credit reservation repeated
package/README.ko.md CHANGED
@@ -16,7 +16,7 @@
16
16
 
17
17
  ## NMTS가 무엇인가
18
18
 
19
- **암호화가 내 기계에서 일어나고 열쇠가 기기 밖으로 나가지 않는** 저장소입니다. 서버는 암호화된
19
+ **암호화가 내 기계에서 일어나고 키가 기기 밖으로 나가지 않는** 저장소입니다. 서버는 암호화된
20
20
  바이트를 받을 뿐 열지 못합니다. 파일 내용도, 이름도, 폴더도 전부 NMTS 키만이 여는 암호화된
21
21
  목록 안에 있습니다.
22
22
 
@@ -51,7 +51,7 @@ nmts --help
51
51
 
52
52
  ```sh
53
53
  npm install -g github:needmoretruth/nmts-cli # 기본 브랜치
54
- npm install -g github:needmoretruth/nmts-cli#v0.34.4 # 버전을 고정할 때
54
+ npm install -g github:needmoretruth/nmts-cli#v0.35.0 # 버전을 고정할 때
55
55
  npm install -g https://github.com/needmoretruth/nmts-cli/releases/latest/download/nmts.tgz
56
56
  ```
57
57
 
@@ -92,7 +92,7 @@ nmts get x # 파일 하나 다운로드
92
92
 
93
93
  | | 하는 일 | 건네는 법 |
94
94
  |---|---|---|
95
- | **NMTS 키** | 파일을 엽니다. 계정의 모든 열쇠가 여기서 나옵니다. 서버로 가지 않습니다. | `NMTS_ACCOUNT_CODE_FILE=/path`(권장) · `nmts login` · `NMTS_ACCOUNT_CODE` |
95
+ | **NMTS 키** | 파일을 엽니다. 계정의 모든 키가 여기서 나옵니다. 서버로 가지 않습니다. | `NMTS_ACCOUNT_CODE_FILE=/path`(권장) · `nmts login` · `NMTS_ACCOUNT_CODE` |
96
96
  | **API 키** | 서버가 답하게 합니다. nmts.me의 계정 화면에서 만듭니다. 파일은 열지 못합니다. | `NMTS_API_KEY_FILE=/path`(권장) · `NMTS_API_KEY` · `nmts login` |
97
97
 
98
98
  `nmts ls`는 둘 다 필요합니다 — 서버가 답하게 하는 API 키와, 그 답을 열 수 있게 하는 NMTS 키.
@@ -101,14 +101,14 @@ nmts get x # 파일 하나 다운로드
101
101
  변수(`NMTS_ACCOUNT_CODE`·`NMTS_ACCOUNT_CODE_FILE`), 설정 키, MCP 도구와 인자 이름, 오류 코드,
102
102
  파일 형식은 모두 쓰던 이름 그대로입니다. 이미 짜 두신 스크립트는 그대로 돕니다.
103
103
 
104
- `nmts login`은 API 키를 적어 두기 전에 서버에 확인하고, 그 키의 공개된 손잡이만 찍고 키 자체는
104
+ `nmts login`은 API 키를 적어 두기 전에 서버에 확인하고, 그 키의 공개된 핸들만 찍고 키 자체는
105
105
  찍지 않으며, 그렇게 하라고 하지 않은 실행은 이미 저장된 API 키를 덮어쓰지 않습니다. `nmts logout`이 저장된
106
106
  것을 지웁니다.
107
107
 
108
108
  `nmts whoami --reveal`은 NMTS 키 자체를 찍습니다. `nmts unlock reveal`로 한 번 열기 전에는 잠겨
109
109
  있고 실행마다 다시 묻습니다. 터미널을 기록하는 무엇이든 그때부터 NMTS 키를 갖게 됩니다.
110
110
 
111
- **어느 자격도 명령줄 인자로는 받지 않습니다.** 어떤 프로세스든 다른 프로세스의 명령줄을 읽을 수
111
+ **어느 자격도 명령행 인자로는 받지 않습니다.** 어떤 프로세스든 다른 프로세스의 명령행 인자를 읽을 수
112
112
  있고, 셸은 그것을 기록에 남깁니다. 둘 다 그런 옵션이 없습니다.
113
113
 
114
114
  ### NMTS 키를 둘 수 있는 자리
@@ -158,7 +158,7 @@ NMTS 키는 한 번에 전부입니다. 그것을 가진 프로그램은 모든
158
158
  | `nmts rm <paths>` | 휴지통으로 옮깁니다 — 30일 동안 되살릴 수 있습니다 |
159
159
  | `nmts restore <paths>` | 휴지통에서 도로 꺼냅니다 |
160
160
  | `nmts sweep` | 30일이 지난 휴지통 항목을 버립니다. **되돌릴 수 없어** 실행마다 묻습니다 |
161
- | `nmts erase <paths>` | 파일을 완전히 지웁니다 — 서버 기록과 이 계정의 열쇠, 휴지통 안팎 가리지 않고. 문장 입력, API 키 옆에 NMTS 키 증명. `--release-storage`는 크레딧으로 산 저장까지 파기(`nmts unlock release-storage`로 열기 전에는 잠김) |
161
+ | `nmts erase <paths>` | 파일을 완전히 지웁니다 — 서버 기록과 이 계정의 키, 휴지통 안팎 가리지 않고. 문장 입력, API 키 옆에 NMTS 키 증명. `--release-storage`는 크레딧으로 산 저장까지 파기(`nmts unlock release-storage`로 열기 전에는 잠김) |
162
162
  | `nmts mkdir <path>` | 폴더를 만듭니다. 위에 없는 폴더도 함께 |
163
163
  | `nmts mv <paths> <folder>` | 폴더로 옮깁니다. `/`는 드라이브의 맨 위입니다 |
164
164
  | `nmts rename <path> <name>` | 하나에 새 이름을 줍니다 |
@@ -193,11 +193,11 @@ NMTS 키는 한 번에 전부입니다. 그것을 가진 프로그램은 모든
193
193
  | `nmts listfile` | 이 기계가 가진 암호화된 파일 목록을 파일로 씁니다 |
194
194
  | `nmts recovery-list` | NMTS 없이 이 계정의 바이트를 찾아내는 파일을 씁니다 |
195
195
  | `nmts kit` | 복구 키트: 그 목록**과 NMTS 키**를 한 파일에 |
196
- | `nmts recovery` | NMTS 없이 파일을 되읽는 독립 프로그램을 내려받습니다 |
196
+ | `nmts recovery` | NMTS 없이 파일을 되읽는 독립 프로그램을 다운로드합니다 |
197
197
  | `nmts unlock` / `nmts lock` | 이 기계가 무엇을 열어 두었는지. `unlock <열쇠>`가 하나를 엽니다(사람이, 터미널에서), `lock <열쇠>`가 닫습니다. `consent`는 옛 이름 |
198
198
  | `nmts mode` | 이 도구를 모는 에이전트가 묻지 않고 얼마나 정할 수 있는가 |
199
199
  | `nmts support send` | 개발자에게 제보를 보냅니다 — 버그·오류·아이디어·질문. `--attach-log`는 최근 실행 기록을 가려서 붙입니다 |
200
- | `nmts support list` / `show <코드>` / `reply <코드>` | 답장을 읽고, 같은 글타래에 다시 씁니다 |
200
+ | `nmts support list` / `show <코드>` / `reply <코드>` | 답장을 읽고, 같은 스레드에 다시 씁니다 |
201
201
  | `nmts update` | 이 도구의 가장 새 릴리스를 설치합니다 |
202
202
  | `nmts notices` | NMTS가 올린 공지 — 중단·장애·새 약관이 시행되기 전의 예고. `notices <id>`는 하나를 찍고, `--save <id>`는 날짜 붙은 파일로 보관합니다 |
203
203
  | `nmts terms` | 지금 시행 중인 이용약관. `--lang ko`는 한국어, `--board`는 게시판 약관, `--save`는 사본 보관 |
@@ -303,7 +303,7 @@ nmts restore photos/2026
303
303
  `extend`는 저장된 파일의 기간을 **NMTS 키가 만드는 지갑에서** 공개 체인 위에서 더 삽니다.
304
304
  `wallet` 잠금을 열 때 범위(`storage`, 또는 교환·보내기까지 `all`)와 기한(최대 30일), 원하면 이 도구가 서명해
305
305
  내보낼 수 있는 상한을 함께 정합니다 — `nmts unlock wallet --days 7 [--scope all] [--cap-wal 10
306
- --cap-sui 0.1]`. `--dry-run`을 받으며 그때는 열쇠를 건드리지 않습니다.
306
+ --cap-sui 0.1]`. `--dry-run`을 받으며 그때는 키를 건드리지 않습니다.
307
307
  동의를 묻기 전에 지갑을 읽고 그 거래를 체인에 미리 돌려 봅니다: 값, 체인 수수료(SUI), 두 잔액이
308
308
  찍히고, 모자란 것이 확인된 지갑은 서명 대신 두 수를 말하며 거절됩니다.
309
309
  `wallet`은 읽기만 합니다. 주소는 이 기계에서 만들고, 못 읽은 잔액은 0이 아니라 「못 읽음」으로
@@ -350,9 +350,9 @@ nmts restore photos/2026
350
350
 
351
351
  `recovery-list`는 저장 네트워크에서 내 바이트가 어디 있는지 찾아내는 암호화된 파일을 씁니다.
352
352
  NMTS 키는 들어 있지 않습니다. `kit`은 그 목록과 NMTS 키를 한 파일에 쓰므로, 키트를 가진
353
- 사람이 계정을 가집니다. `recovery`는 이 기계에 맞는 독립 복구 프로그램을 내려받아 릴리스의
353
+ 사람이 계정을 가집니다. `recovery`는 이 기계에 맞는 독립 복구 프로그램을 다운로드해 릴리스의
354
354
  체크섬 파일과 대조한 뒤에야 실행 가능하게 만들고, PATH에는 아무것도 넣지 않습니다. `rebuild`는
355
- 목록을 잃은 계정의 파일 목록을 서버의 줄로 다시 짓습니다. 열쇠·해시·날짜·크기는 돌아오고 이름과
355
+ 목록을 잃은 계정의 파일 목록을 서버의 줄로 다시 짓습니다. 키·해시·날짜·크기는 돌아오고 이름과
356
356
  폴더는 돌아오지 않습니다.
357
357
 
358
358
  `nmts rollback`은 파일 목록의 이전 버전을 현재 버전으로 되돌립니다 — 현재 목록이 열리지 않을
@@ -382,7 +382,7 @@ nmts verify # 계정 주인이 nmts.me에 칠 짧은 코드를 찍고
382
382
  **medium**(업로드·공개 코드 게시·새 키)은 실행마다 한 번 묻습니다 — 터미널에서 y/N, 또는 `--yes`. **high**
383
383
  (지갑 서명·다른 계정에 파일 주기·NMTS 키 노출·잠그지 않은 저장)는 이 기계에서 `nmts unlock <열쇠>`로 한 번 열기
384
384
  전에는 잠겨 있고, 연 뒤에도 실행마다 묻습니다. **ultra-high**(계정 삭제)는 문장을 입력합니다. `nmts unlock`이
385
- 열쇠 목록을 보여 주고, 각 열쇠는 묻기 전에 무엇을 여는지, 무엇이 잘못될 수 있는지, 무엇을 덮지 않는지를
385
+ 목록을 보여 주고, 각 키는 묻기 전에 무엇을 여는지, 무엇이 잘못될 수 있는지, 무엇을 덮지 않는지를
386
386
  찍습니다. `nmts help <명령>`이 어느 명령이든 그 문서를 등급과 함께 찍습니다.
387
387
 
388
388
  ## 컨테이너
@@ -420,7 +420,7 @@ docker run --rm \
420
420
  ## S3 도구에 드라이브 내주기
421
421
 
422
422
  `nmts s3`는 이 기계에서 S3 프로토콜을 말하는 서버를 띄웁니다. rclone, AWS CLI, S3를 아는 어떤
423
- 백업 프로그램이든 이 계정의 파일을 목록으로 보고 내려받을 수 있습니다.
423
+ 백업 프로그램이든 이 계정의 파일을 목록으로 보고 다운로드할 수 있습니다.
424
424
 
425
425
  ```
426
426
  $ nmts s3
@@ -457,7 +457,7 @@ $ rclone copy --size-only ./somewhere drive:drive
457
457
 
458
458
  ## MCP를 말하는 에이전트에게
459
459
 
460
- `nmts mcp`는 stdin과 stdout 위의 로컬 MCP 서버입니다. 먼저 로그인하십시오(`nmts login`). 명령줄로
460
+ `nmts mcp`는 stdin과 stdout 위의 로컬 MCP 서버입니다. 먼저 로그인하십시오(`nmts login`). CLI로
461
461
  NMTS 키를 받지 않고, 묻지도 않으므로, 잠가 둔 NMTS 키에 `NMTS_PASSPHRASE`가 없으면 시작하자마자 종료
462
462
  코드 3으로 끝납니다.
463
463
 
@@ -520,7 +520,7 @@ auto 모드 둘에서 거절됩니다. 모드가 켜져 있는 동안 모든 명
520
520
  ## 뭔가 잘못됐다면
521
521
 
522
522
  도구에서 바로 보내십시오: `nmts support send --category bug --message "…" --attach-log`. NMTS를
523
- 만드는 한 사람에게 앱의 문의함과 같은 곳으로 닿고, 답장은 같은 글타래로 옵니다(`nmts support list`,
523
+ 만드는 한 사람에게 앱의 문의함과 같은 곳으로 닿고, 답장은 같은 스레드로 옵니다(`nmts support list`,
524
524
  그다음 `nmts support show <코드>`). 보내기 전에 무엇이 갈지 그대로 보여 주고, NMTS 키·API 키·
525
525
  암호 구절·파일 내용은 이 기계에서 먼저 지우며, `--omit <글자>`로 무엇이든 더 지울 수 있습니다.
526
526
  영어를 권하지만 한국어도 읽습니다. 아이디어도 고장만큼 값어치가 있고, 확신이 없는 것도 그렇습니다.
package/README.md CHANGED
@@ -53,7 +53,7 @@ default branch, from a pinned version, or from the tarball attached to the
53
53
 
54
54
  ```sh
55
55
  npm install -g github:needmoretruth/nmts-cli # the default branch
56
- npm install -g github:needmoretruth/nmts-cli#v0.34.4 # a pinned version
56
+ npm install -g github:needmoretruth/nmts-cli#v0.35.0 # a pinned version
57
57
  npm install -g https://github.com/needmoretruth/nmts-cli/releases/latest/download/nmts.tgz
58
58
  ```
59
59
 
@@ -0,0 +1,167 @@
1
+ export interface ParsedArgs {
2
+ command: string | null;
3
+ /** Positional arguments after the command. */
4
+ operands: string[];
5
+ server?: string;
6
+ network?: string;
7
+ help: boolean;
8
+ version: boolean;
9
+ /** Machine-readable output where a command has one. */
10
+ json: boolean;
11
+ /** Include what is in the trash. */
12
+ all: boolean;
13
+ /** Where to write a fetched file. */
14
+ out?: string;
15
+ /** Replace a file that is already there. */
16
+ force: boolean;
17
+ /** The name an uploaded file gets in the drive. */
18
+ name?: string;
19
+ /** The destination folder for an upload. */
20
+ to?: string;
21
+ /** Say what an upload would cost and stop. */
22
+ dryRun: boolean;
23
+ /** `put`: how much of a file goes into one part. A byte count, optionally with a unit. */
24
+ partSize?: string;
25
+ /** `put`/`push`: what THIS run does about a name already in use. Absent = this machine's setting. */
26
+ onCollision?: string;
27
+ /** `put`/`push`: credits THIS upload sets aside per file, 0 to 64. Absent = the account's default. */
28
+ deposit?: string;
29
+ /** Answer yes to a warning this run would otherwise stop on. */
30
+ yes: boolean;
31
+ /** `public-code`: publish this account's public code on the server. Permanent. */
32
+ publish: boolean;
33
+ /** `login`: store the NMTS key unsealed rather than under a passphrase. */
34
+ plain: boolean;
35
+ /** `login`: store nothing; print the environment variable to set. */
36
+ env: boolean;
37
+ /** `verify`: report whether the human check is live and stop, asking for no new code. */
38
+ status: boolean;
39
+ /** `create`: print the registration address and stop, rather than waiting for a person. */
40
+ noWait?: boolean;
41
+ /** `ls`: keep only files whose name contains this text, case-insensitively. */
42
+ find?: string;
43
+ /** `ls`: which order to list in — `name`, `size` or `date`. Absent = the path order. */
44
+ sort?: string;
45
+ /** `ls`: reverse whichever order is in effect. */
46
+ desc: boolean;
47
+ /** `push`: include entries whose name begins with a dot. */
48
+ hidden: boolean;
49
+ /** `extend`: how many of the storage network's epochs to add; `put`/`push --pay wallet`: how many to buy. */
50
+ epochs?: string;
51
+ /** `put`/`push`: who pays for the storage — `credits` (the default) or `wallet`. */
52
+ pay?: string;
53
+ /** `put --pay wallet`: `fit`, `whole`, or a held storage resource's object id. */
54
+ storage?: string;
55
+ /** `consent grant wallet`: how long the grant lasts (days, at most 30), or until a date.
56
+ * `key new`: how many days the new API key lasts. The server clamps at its own ceiling. */
57
+ days?: string;
58
+ until?: string;
59
+ /** `consent grant wallet`: `storage` or `all`. */
60
+ scope?: string;
61
+ /** `key new`: which permissions the key carries — `read`, `write`, `spend`, comma-separated. */
62
+ scopes?: string;
63
+ /** `consent grant wallet`: ceilings in coins. */
64
+ capWal?: string;
65
+ capSui?: string;
66
+ /** `wallet send` · `wallet swap`: a ceiling on the chain fee, in SUI. */
67
+ feeCap?: string;
68
+ /** `wallet swap`: which venue, deepbook or bluefin. Without it both are quoted and the run stops. */
69
+ venue?: string;
70
+ /** `wallet swap`: the slippage allowance in whole bps (1 bps = 0.01%). */
71
+ slippageBps?: string;
72
+ /** `wallet swap`: a person's say past the extremes gate. Refused while a mode is on. */
73
+ acceptExtremes: boolean;
74
+ /** `wallet address`: which of this key's wallets to print. Absent = the first one, offline. */
75
+ index?: string;
76
+ /**
77
+ * `put`/`push`/`extend`/`wallet send`/`wallet donate`: which wallet pays, THIS RUN ONLY.
78
+ *
79
+ * ⛔ IT DOES NOT SAVE. Which wallet pays is the account's own setting (`nmts wallet use N`), read
80
+ * from the sealed file list so every device agrees; a flag that quietly rewrote it would make
81
+ * one hurried command change where the money comes from for every later one, everywhere.
82
+ */
83
+ wallet?: string;
84
+ /** `s3`: which loopback port the gateway listens on. */
85
+ port?: string;
86
+ /**
87
+ * `create`: the version of the Terms of Service a PERSON read and accepts for the new account.
88
+ *
89
+ * ⛔ IT IS A VALUE AND NOT A FLAG, so that what was accepted is on the command line rather than
90
+ * implied by it. A tool that could accept "whatever is current" would be agreeing on behalf
91
+ * of somebody who never saw a version number.
92
+ */
93
+ acceptTerms?: string;
94
+ /** `create`: the version of the Privacy Policy accepted in the same act. */
95
+ acceptPrivacy?: string;
96
+ /** `losses`: ask the chain about ONE listed storage object now, instead of listing. */
97
+ recheck?: string;
98
+ /** `losses`: take ONE line off this account's own drive, instead of listing. ⛔ A VALUE AND NOT
99
+ * A FLAG, so the line put down is named on the command line: a person reads one and puts it down. */
100
+ dismiss?: string;
101
+ /** `shares`: who ONE file was shared with, instead of what was shared with this account. */
102
+ sent?: string;
103
+ /** ultra-high acts under skip-permissions: why this is right to do now. Kept in the run log. */
104
+ reason?: string;
105
+ releaseStorage: boolean;
106
+ size?: string;
107
+ /** `devices`: sign ONE device out by id, or `all` — a person's act, proved by the NMTS key. */
108
+ signOut?: string;
109
+ /**
110
+ * `label`: the label to rename. The NEW name follows as the operand.
111
+ *
112
+ * ⛔ ONE VALUE, NOT TWO, because the table above gives every option exactly one — and a second
113
+ * spelling of "how many values does this take" is how an option ends up parsed one way and
114
+ * tested another. What a person types is still `label --rename <old> <new>`: the new name is
115
+ * read from the operands, which is where `label <name> <files>` already reads a name from.
116
+ */
117
+ rename?: string;
118
+ /** `support send`: what the report is about, and optionally which part of that. */
119
+ category?: string;
120
+ sub?: string;
121
+ /** `support`: the message itself, or the file holding it. */
122
+ message?: string;
123
+ messageFile?: string;
124
+ /**
125
+ * `support send`: attach the run log, and how many runs of it.
126
+ * ⛔ THE EMPTY STRING IS "GIVEN WITH NO NUMBER", which is different from absent. A boolean
127
+ * beside a count would be two fields answering one question, and the pair can disagree.
128
+ */
129
+ attachLog?: string;
130
+ /**
131
+ * `support`: values that must not travel, replaced wherever they appear.
132
+ *
133
+ * ⛔ THE ONLY REPEATABLE OPTION, and it is repeatable because what it names is one value at a
134
+ * time. A comma-separated list would make a comma impossible to omit.
135
+ */
136
+ omit?: string[];
137
+ /**
138
+ * `whoami`: print the NMTS key itself.
139
+ *
140
+ * ⛔ A FLAG AND NOT A VALUE — it names no secret, it asks for the one this machine already
141
+ * holds. The option table is checked for names that look like credentials; this one carries
142
+ * nothing and says what it does.
143
+ */
144
+ reveal: boolean;
145
+ /**
146
+ * `key new`: put the new key on the screen once, as well as storing it. A flag and not a value
147
+ * for the reason above: it names no secret, it asks for the one this run was just handed.
148
+ */
149
+ print: boolean;
150
+ /** `nmts wallet address --qr` — the address as a QR code in the terminal as well. */
151
+ qr: boolean;
152
+ /** `wallet hall --remove`: be listed by a shortened address again. Never with `--name`. */
153
+ remove: boolean;
154
+ /** `terms`/`privacy`: which language to fetch — `en` or `ko`. Absent = English. */
155
+ lang?: string;
156
+ /** `terms`: the message board's terms rather than the service's. */
157
+ board: boolean;
158
+ /**
159
+ * `notices`/`terms`/`privacy`: keep the document as a file instead of printing it.
160
+ *
161
+ * ⛔ A FLAG, AND THE NOTICE'S ID IS STILL THE OPERAND. `notices --save <id>` reads exactly like
162
+ * `notices <id>`, which is the point: one way to name a notice, whichever of the two things
163
+ * is being done with it. The file's NAME is never an option — it is the server's, so that a
164
+ * copy kept here and a copy kept from the browser are the same file.
165
+ */
166
+ save: boolean;
167
+ }
@@ -0,0 +1,10 @@
1
+ // What a command line can say — every option this tool accepts, in one place.
2
+ //
3
+ // ⛔ THE FIELDS ARE THE VOCABULARY, and the parser beside them (`args.ts`) is the only thing that
4
+ // fills them. They moved out of that file on 2026-09-16 because the two are different jobs and
5
+ // the parser's file had a ceiling: this is what the options MEAN, that is how a line is read.
6
+ //
7
+ // ⛔ NO SECRET IS EVER AN OPTION. There is no --code and no --api-key: on Linux any process can
8
+ // read another's command line, and the shell records it. A test asserts no option name looks
9
+ // like one.
10
+ export {};
package/dist/args.d.ts CHANGED
@@ -1,160 +1,5 @@
1
- export interface ParsedArgs {
2
- command: string | null;
3
- /** Positional arguments after the command. */
4
- operands: string[];
5
- server?: string;
6
- network?: string;
7
- help: boolean;
8
- version: boolean;
9
- /** Machine-readable output where a command has one. */
10
- json: boolean;
11
- /** Include what is in the trash. */
12
- all: boolean;
13
- /** Where to write a fetched file. */
14
- out?: string;
15
- /** Replace a file that is already there. */
16
- force: boolean;
17
- /** The name an uploaded file gets in the drive. */
18
- name?: string;
19
- /** The destination folder for an upload. */
20
- to?: string;
21
- /** Say what an upload would cost and stop. */
22
- dryRun: boolean;
23
- /** `put`: how much of a file goes into one part. A byte count, optionally with a unit. */
24
- partSize?: string;
25
- /** `put`/`push`: what THIS run does about a name already in use. Absent = this machine's setting. */
26
- onCollision?: string;
27
- /** `put`/`push`: credits THIS upload sets aside per file, 0 to 64. Absent = the account's default. */
28
- deposit?: string;
29
- /** Answer yes to a warning this run would otherwise stop on. */
30
- yes: boolean;
31
- /** `public-code`: publish this account's public code on the server. Permanent. */
32
- publish: boolean;
33
- /** `login`: store the NMTS key unsealed rather than under a passphrase. */
34
- plain: boolean;
35
- /** `login`: store nothing; print the environment variable to set. */
36
- env: boolean;
37
- /** `verify`: report whether the human check is live and stop, asking for no new code. */
38
- status: boolean;
39
- /** `create`: print the registration address and stop, rather than waiting for a person. */
40
- noWait?: boolean;
41
- /** `ls`: keep only files whose name contains this text, case-insensitively. */
42
- find?: string;
43
- /** `ls`: which order to list in — `name`, `size` or `date`. Absent = the path order. */
44
- sort?: string;
45
- /** `ls`: reverse whichever order is in effect. */
46
- desc: boolean;
47
- /** `push`: include entries whose name begins with a dot. */
48
- hidden: boolean;
49
- /** `extend`: how many of the storage network's epochs to add; `put`/`push --pay wallet`: how many to buy. */
50
- epochs?: string;
51
- /** `put`/`push`: who pays for the storage — `credits` (the default) or `wallet`. */
52
- pay?: string;
53
- /** `put --pay wallet`: `fit`, `whole`, or a held storage resource's object id. */
54
- storage?: string;
55
- /** `consent grant wallet`: how long the grant lasts (days, at most 30), or until a date.
56
- * `key new`: how many days the new API key lasts. The server clamps at its own ceiling. */
57
- days?: string;
58
- until?: string;
59
- /** `consent grant wallet`: `storage` or `all`. */
60
- scope?: string;
61
- /** `key new`: which permissions the key carries — `read`, `write`, `spend`, comma-separated. */
62
- scopes?: string;
63
- /** `consent grant wallet`: ceilings in coins. */
64
- capWal?: string;
65
- capSui?: string;
66
- /** `wallet send` · `wallet swap`: a ceiling on the chain fee, in SUI. */
67
- feeCap?: string;
68
- /** `wallet swap`: which venue, deepbook or bluefin. Without it both are quoted and the run stops. */
69
- venue?: string;
70
- /** `wallet swap`: the slippage allowance in whole bps (1 bps = 0.01%). */
71
- slippageBps?: string;
72
- /** `wallet swap`: a person's say past the extremes gate. Refused while a mode is on. */
73
- acceptExtremes: boolean;
74
- /** `s3`: which loopback port the gateway listens on. */
75
- port?: string;
76
- /**
77
- * `create`: the version of the Terms of Service a PERSON read and accepts for the new account.
78
- *
79
- * ⛔ IT IS A VALUE AND NOT A FLAG, so that what was accepted is on the command line rather than
80
- * implied by it. A tool that could accept "whatever is current" would be agreeing on behalf
81
- * of somebody who never saw a version number.
82
- */
83
- acceptTerms?: string;
84
- /** `create`: the version of the Privacy Policy accepted in the same act. */
85
- acceptPrivacy?: string;
86
- /** `losses`: ask the chain about ONE listed storage object now, instead of listing. */
87
- recheck?: string;
88
- /** `losses`: take ONE line off this account's own drive, instead of listing. ⛔ A VALUE AND NOT
89
- * A FLAG, so the line put down is named on the command line: a person reads one and puts it down. */
90
- dismiss?: string;
91
- /** `shares`: who ONE file was shared with, instead of what was shared with this account. */
92
- sent?: string;
93
- /** ultra-high acts under skip-permissions: why this is right to do now. Kept in the run log. */
94
- reason?: string;
95
- releaseStorage: boolean;
96
- size?: string;
97
- /** `devices`: sign ONE device out by id, or `all` — a person's act, proved by the NMTS key. */
98
- signOut?: string;
99
- /**
100
- * `label`: the label to rename. The NEW name follows as the operand.
101
- *
102
- * ⛔ ONE VALUE, NOT TWO, because the table above gives every option exactly one — and a second
103
- * spelling of "how many values does this take" is how an option ends up parsed one way and
104
- * tested another. What a person types is still `label --rename <old> <new>`: the new name is
105
- * read from the operands, which is where `label <name> <files>` already reads a name from.
106
- */
107
- rename?: string;
108
- /** `support send`: what the report is about, and optionally which part of that. */
109
- category?: string;
110
- sub?: string;
111
- /** `support`: the message itself, or the file holding it. */
112
- message?: string;
113
- messageFile?: string;
114
- /**
115
- * `support send`: attach the run log, and how many runs of it.
116
- * ⛔ THE EMPTY STRING IS "GIVEN WITH NO NUMBER", which is different from absent. A boolean
117
- * beside a count would be two fields answering one question, and the pair can disagree.
118
- */
119
- attachLog?: string;
120
- /**
121
- * `support`: values that must not travel, replaced wherever they appear.
122
- *
123
- * ⛔ THE ONLY REPEATABLE OPTION, and it is repeatable because what it names is one value at a
124
- * time. A comma-separated list would make a comma impossible to omit.
125
- */
126
- omit?: string[];
127
- /**
128
- * `whoami`: print the NMTS key itself.
129
- *
130
- * ⛔ A FLAG AND NOT A VALUE — it names no secret, it asks for the one this machine already
131
- * holds. The option table is checked for names that look like credentials; this one carries
132
- * nothing and says what it does.
133
- */
134
- reveal: boolean;
135
- /**
136
- * `key new`: put the new key on the screen once, as well as storing it. A flag and not a value
137
- * for the reason above: it names no secret, it asks for the one this run was just handed.
138
- */
139
- print: boolean;
140
- /** `nmts wallet address --qr` — the address as a QR code in the terminal as well. */
141
- qr: boolean;
142
- /** `wallet hall --remove`: be listed by a shortened address again. Never with `--name`. */
143
- remove: boolean;
144
- /** `terms`/`privacy`: which language to fetch — `en` or `ko`. Absent = English. */
145
- lang?: string;
146
- /** `terms`: the message board's terms rather than the service's. */
147
- board: boolean;
148
- /**
149
- * `notices`/`terms`/`privacy`: keep the document as a file instead of printing it.
150
- *
151
- * ⛔ A FLAG, AND THE NOTICE'S ID IS STILL THE OPERAND. `notices --save <id>` reads exactly like
152
- * `notices <id>`, which is the point: one way to name a notice, whichever of the two things
153
- * is being done with it. The file's NAME is never an option — it is the server's, so that a
154
- * copy kept here and a copy kept from the browser are the same file.
155
- */
156
- save: boolean;
157
- }
1
+ import type { ParsedArgs } from "./arg-options.ts";
2
+ export type { ParsedArgs } from "./arg-options.ts";
158
3
  export declare const OPTIONS_TAKING_A_VALUE: string[];
159
4
  export declare const FLAGS: string[];
160
5
  export declare function parseArgs(argv: readonly string[]): ParsedArgs;
package/dist/args.js CHANGED
@@ -32,6 +32,8 @@ const VALUE_OPTIONS = {
32
32
  "--fee-cap": "feeCap",
33
33
  "--venue": "venue",
34
34
  "--slippage-bps": "slippageBps",
35
+ "--index": "index",
36
+ "--wallet": "wallet",
35
37
  "--port": "port",
36
38
  "--accept-terms": "acceptTerms",
37
39
  "--accept-privacy": "acceptPrivacy",
@@ -11,7 +11,7 @@ export declare const CRYPTO_SPEC_URL = "https://github.com/needmoretruth/nmts-re
11
11
  * is the field's own contract — what the writer says about itself — and a person holding two
12
12
  * copies of one account's artefacts can then tell which program made each.
13
13
  */
14
- export declare const WRITTEN_BY = "nmts-cli 0.34.4";
14
+ export declare const WRITTEN_BY = "nmts-cli 0.35.0";
15
15
  /** Which of the three artefacts a wrapper is. A reader holding several can sort them. */
16
16
  export type ArtifactKind = "recovery-list" | "file-list" | "recovery-kit";
17
17
  /**
@@ -29,5 +29,7 @@ export interface ExtendOptions {
29
29
  now?: number;
30
30
  /** ⚠ SEAMS, NOT OPTIONS — the standing tip's own read and signature. No flag reaches them. */
31
31
  tip?: Pick<StandingTipInput, "readDonation" | "sign">;
32
+ /** `--wallet N`: which wallet pays, this run only. Absent = the account's own number. */
33
+ wallet?: string | undefined;
32
34
  }
33
35
  export declare function extend(target: string | undefined, options?: ExtendOptions): Promise<number>;
@@ -31,6 +31,8 @@ import { resolveNetwork } from "../network.js";
31
31
  import { BINARY_NAME } from "../product.js";
32
32
  import { openSession } from "../session.js";
33
33
  import { coinAmount, walletAddress } from "../wallet.js";
34
+ import { payingWalletIndex } from "../wallet-pay-index.js";
35
+ import { activeWalletOf } from "../shared/lib/drive/manifest-settings.js";
34
36
  import { budgetFacts, describeBudget, readBudget, shortfallNextStep } from "../extend-budget.js";
35
37
  export async function extend(target, options = {}) {
36
38
  const say = options.write ?? ((line) => process.stdout.write(`${line}\n`));
@@ -110,7 +112,10 @@ export async function extend(target, options = {}) {
110
112
  const cohort = Math.max(0, ...preview.targets.map((t) => t.sharedItems));
111
113
  const unreachable = preview.treasuryParts + preview.untrackedParts;
112
114
  // What the wallet holds and what the chain would charge — read, never assumed (`extend-budget.ts`).
113
- const address = await walletAddress(session.code);
115
+ // WHICH WALLET PAYS comes out of the list this run already read, before the price is measured
116
+ // against a balance: the address below is the one that will sign (`wallet-pay-index.ts`).
117
+ const wallet = await payingWalletIndex({ ...options, readActiveWallet: async () => activeWalletOf(settings) });
118
+ const address = await walletAddress(session.code, wallet);
114
119
  const budget = await readBudget(reads, {
115
120
  address,
116
121
  objectIds: preview.targets.map((t) => t.objectId),
@@ -182,6 +187,7 @@ export async function extend(target, options = {}) {
182
187
  const digest = await sign({
183
188
  network: session.network,
184
189
  code: session.code,
190
+ wallet,
185
191
  objectIds: preview.targets.map((t) => t.objectId),
186
192
  epochs,
187
193
  });
@@ -227,6 +233,7 @@ export async function extend(target, options = {}) {
227
233
  network: resolveNetwork(session.server, session.network),
228
234
  code: session.code,
229
235
  settings,
236
+ wallet,
230
237
  paidWalFrost: frost,
231
238
  say: options.json === true ? (line) => void process.stderr.write(`${line}\n`) : say,
232
239
  ...(options.tip ?? {}),
@@ -3,6 +3,8 @@
3
3
  //
4
4
  // ⛔ SPLIT OUT OF `push.ts` FOR THE LENGTH GATE, and along the one seam that was already there:
5
5
  // `push.ts` decides WHICH files go and where; this decides how the wallet pays for each.
6
+ import { payingWalletIndex } from "../wallet-pay-index.js";
7
+ import { activeWalletOf } from "../shared/lib/drive/manifest-settings.js";
6
8
  import { loadCrypto } from "../crypto.js";
7
9
  import { NmtsError } from "../errors.js";
8
10
  import { resolveNetwork } from "../network.js";
@@ -24,6 +26,10 @@ export async function pushWithWallet(session, options, run) {
24
26
  rule: run.rule,
25
27
  onCollision: run.asked,
26
28
  settings: run.settings,
29
+ wallet: await payingWalletIndex({
30
+ ...options,
31
+ readActiveWallet: async () => activeWalletOf(run.settings),
32
+ }),
27
33
  progress: new Progress(options.json === true ? silentSink() : stderrSink(), "uploading"),
28
34
  say,
29
35
  json: options.json === true,
@@ -19,6 +19,8 @@ export interface PushOptions {
19
19
  epochs?: string | number | undefined;
20
20
  /** ⛔ Refused here: a held resource holds ONE blob, and a directory is many. */
21
21
  storage?: string | undefined;
22
+ /** `--pay wallet`: which of this key's wallets pays, this run only. Absent = the account's own. */
23
+ wallet?: string | undefined;
22
24
  json?: boolean;
23
25
  write?: (line: string) => void;
24
26
  /**
@@ -0,0 +1,8 @@
1
+ /** Who pays, or a refusal for a payer this tool does not know. */
2
+ export declare function payerOf(pay: string | undefined): "credits" | "wallet";
3
+ /** The two options that only mean something when the wallet pays, refused when it does not. */
4
+ export declare function refuseWalletOnlyOptions(options: {
5
+ epochs?: string | number | undefined;
6
+ storage?: string | undefined;
7
+ wallet?: string | undefined;
8
+ }): void;
@@ -0,0 +1,41 @@
1
+ // WHO PAYS FOR AN UPLOAD, and which options mean anything once that is answered.
2
+ //
3
+ // ⛔ THE OPTIONS ARE REFUSED, NOT IGNORED. `--epochs 12 --pay credits` is somebody asking for a
4
+ // term credits do not sell; accepting it silently would upload for a different length than the
5
+ // person typed and charge them for it. Every refusal here happens before a file is measured.
6
+ //
7
+ // ⚠ They moved out of `put.ts` on 2026-09-16 (`--wallet` joined them and that file has a ceiling).
8
+ // `put.ts` re-exports them, so `push.ts` and the tests spell the same path they always did.
9
+ import { NmtsError } from "../errors.js";
10
+ /** Who pays, or a refusal for a payer this tool does not know. */
11
+ export function payerOf(pay) {
12
+ if (pay === undefined || pay === "credits")
13
+ return "credits";
14
+ if (pay === "wallet")
15
+ return "wallet";
16
+ throw new NmtsError(`--pay takes credits or wallet, not "${pay}".`, {
17
+ exitCode: 2,
18
+ nextStep: `Nothing was sent. --pay wallet buys the storage from the wallet this NMTS key derives; without it credits pay.`,
19
+ });
20
+ }
21
+ /** The two options that only mean something when the wallet pays, refused when it does not. */
22
+ export function refuseWalletOnlyOptions(options) {
23
+ if (options.wallet !== undefined) {
24
+ throw new NmtsError("--wallet only applies with --pay wallet: credits are not held in a wallet.", {
25
+ exitCode: 2,
26
+ nextStep: `Nothing was sent. Add --pay wallet to pay from one of this key's wallets.`,
27
+ });
28
+ }
29
+ if (options.epochs !== undefined) {
30
+ throw new NmtsError("--epochs only applies with --pay wallet: one credit buys a fixed term.", {
31
+ exitCode: 2,
32
+ nextStep: `Nothing was sent. Add --pay wallet to choose the term, or leave --epochs off to pay with credits.`,
33
+ });
34
+ }
35
+ if (options.storage !== undefined) {
36
+ throw new NmtsError("--storage only applies with --pay wallet: credits buy storage from the treasury.", {
37
+ exitCode: 2,
38
+ nextStep: `Nothing was sent. Add --pay wallet to use a storage resource this wallet holds.`,
39
+ });
40
+ }
41
+ }