@needmoretruth/nmts-cli 0.34.4 → 0.36.1

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 (156) hide show
  1. package/AGENTS.md +11 -12
  2. package/CHANGELOG.md +43 -0
  3. package/README.ko.md +33 -35
  4. package/README.md +21 -22
  5. package/dist/account.js +2 -1
  6. package/dist/arg-options.d.ts +169 -0
  7. package/dist/arg-options.js +10 -0
  8. package/dist/args.d.ts +2 -157
  9. package/dist/args.js +2 -0
  10. package/dist/artifact-about.d.ts +1 -1
  11. package/dist/autonomy.d.ts +3 -10
  12. package/dist/autonomy.js +15 -17
  13. package/dist/bytes.d.ts +15 -0
  14. package/dist/bytes.js +63 -0
  15. package/dist/collision.d.ts +5 -5
  16. package/dist/collision.js +19 -22
  17. package/dist/commands/delete-account.js +1 -1
  18. package/dist/commands/erase.js +1 -1
  19. package/dist/commands/extend.d.ts +2 -0
  20. package/dist/commands/extend.js +8 -1
  21. package/dist/commands/get.js +1 -1
  22. package/dist/commands/listfile.js +1 -1
  23. package/dist/commands/mcp.js +5 -1
  24. package/dist/commands/mode.js +2 -2
  25. package/dist/commands/on-collision.d.ts +1 -1
  26. package/dist/commands/on-collision.js +3 -3
  27. package/dist/commands/platform.d.ts +9 -0
  28. package/dist/commands/platform.js +124 -0
  29. package/dist/commands/pull.js +1 -1
  30. package/dist/commands/push-wallet.js +8 -1
  31. package/dist/commands/push.d.ts +2 -0
  32. package/dist/commands/push.js +6 -4
  33. package/dist/commands/put-payer.d.ts +8 -0
  34. package/dist/commands/put-payer.js +41 -0
  35. package/dist/commands/put-wallet.d.ts +9 -3
  36. package/dist/commands/put-wallet.js +108 -186
  37. package/dist/commands/put.d.ts +5 -7
  38. package/dist/commands/put.js +11 -31
  39. package/dist/commands/receive.js +1 -1
  40. package/dist/commands/settings.js +1 -1
  41. package/dist/commands/support.js +3 -3
  42. package/dist/commands/unlock.js +2 -2
  43. package/dist/commands/wallet-donate.d.ts +3 -0
  44. package/dist/commands/wallet-donate.js +6 -2
  45. package/dist/commands/wallet-hall.d.ts +4 -1
  46. package/dist/commands/wallet-hall.js +16 -8
  47. package/dist/commands/wallet-list.d.ts +18 -0
  48. package/dist/commands/wallet-list.js +116 -0
  49. package/dist/commands/wallet-send.d.ts +4 -0
  50. package/dist/commands/wallet-send.js +6 -2
  51. package/dist/commands/wallet-storage-ops.d.ts +4 -1
  52. package/dist/commands/wallet-storage-ops.js +7 -2
  53. package/dist/commands/wallet-swap.d.ts +3 -0
  54. package/dist/commands/wallet-swap.js +8 -4
  55. package/dist/commands/wallet-use.d.ts +7 -0
  56. package/dist/commands/wallet-use.js +55 -0
  57. package/dist/commands/wallet.d.ts +4 -0
  58. package/dist/commands/wallet.js +20 -8
  59. package/dist/crypto.d.ts +8 -5
  60. package/dist/crypto.js +15 -61
  61. package/dist/download-sink-node.d.ts +49 -0
  62. package/dist/download-sink-node.js +204 -0
  63. package/dist/download-sink.d.ts +0 -48
  64. package/dist/download-sink.js +6 -199
  65. package/dist/download.js +5 -4
  66. package/dist/engine-node.d.ts +19 -0
  67. package/dist/engine-node.js +77 -0
  68. package/dist/env-vars.d.ts +20 -0
  69. package/dist/env-vars.js +27 -0
  70. package/dist/extend-plan.d.ts +2 -0
  71. package/dist/gate.js +1 -1
  72. package/dist/help.js +12 -5
  73. package/dist/host-contract.d.ts +7 -0
  74. package/dist/host-contract.js +95 -0
  75. package/dist/host-node.d.ts +27 -0
  76. package/dist/host-node.js +192 -0
  77. package/dist/host.d.ts +99 -0
  78. package/dist/host.js +59 -0
  79. package/dist/index.d.ts +6 -40
  80. package/dist/index.js +20 -32
  81. package/dist/main.js +11 -10
  82. package/dist/manifest-chunk-cache.d.ts +3 -3
  83. package/dist/manifest-chunk-cache.js +39 -44
  84. package/dist/manifest-chunk-flow.js +15 -14
  85. package/dist/manifest-write.js +1 -1
  86. package/dist/manifest.d.ts +2 -2
  87. package/dist/manifest.js +37 -34
  88. package/dist/mcp-tools/tiers.js +1 -1
  89. package/dist/network.d.ts +1 -1
  90. package/dist/network.js +6 -2
  91. package/dist/platform-sign.d.ts +143 -0
  92. package/dist/platform-sign.js +220 -0
  93. package/dist/portable.d.ts +59 -0
  94. package/dist/portable.js +82 -0
  95. package/dist/product.d.ts +1 -1
  96. package/dist/product.js +1 -1
  97. package/dist/progress-node.d.ts +2 -0
  98. package/dist/progress-node.js +14 -0
  99. package/dist/progress.d.ts +0 -1
  100. package/dist/progress.js +4 -8
  101. package/dist/redact.js +3 -2
  102. package/dist/registration.js +5 -2
  103. package/dist/risk.d.ts +11 -0
  104. package/dist/risk.js +16 -0
  105. package/dist/run-log.d.ts +4 -4
  106. package/dist/run-log.js +29 -36
  107. package/dist/seal.js +5 -4
  108. package/dist/server.d.ts +1 -1
  109. package/dist/server.js +6 -2
  110. package/dist/setup-questions.js +2 -2
  111. package/dist/shared/lib/drive/manifest-ops.d.ts +8 -30
  112. package/dist/shared/lib/drive/manifest-ops.js +7 -39
  113. package/dist/shared/lib/drive/manifest-settings-patch.d.ts +52 -0
  114. package/dist/shared/lib/drive/manifest-settings-patch.js +110 -0
  115. package/dist/shared/lib/drive/manifest-settings.d.ts +55 -4
  116. package/dist/shared/lib/drive/manifest-settings.js +66 -28
  117. package/dist/shared/lib/wallet/discover.d.ts +54 -0
  118. package/dist/shared/lib/wallet/discover.js +66 -0
  119. package/dist/standing-tip.d.ts +3 -0
  120. package/dist/standing-tip.js +1 -0
  121. package/dist/upload-file-node.d.ts +3 -0
  122. package/dist/upload-file-node.js +38 -0
  123. package/dist/upload-file.d.ts +2 -2
  124. package/dist/upload-file.js +15 -45
  125. package/dist/upload-price-node.d.ts +8 -0
  126. package/dist/upload-price-node.js +37 -0
  127. package/dist/upload-price.d.ts +0 -8
  128. package/dist/upload-price.js +4 -33
  129. package/dist/upload-steps.js +3 -3
  130. package/dist/upload-store.d.ts +14 -14
  131. package/dist/upload-store.js +68 -75
  132. package/dist/upload-wallet-chain.js +3 -2
  133. package/dist/upload-wallet-put.d.ts +118 -0
  134. package/dist/upload-wallet-put.js +221 -0
  135. package/dist/upload-wallet.d.ts +3 -0
  136. package/dist/upload-wallet.js +18 -15
  137. package/dist/upload.js +16 -15
  138. package/dist/wallet-list-chain.d.ts +4 -0
  139. package/dist/wallet-list-chain.js +21 -0
  140. package/dist/wallet-pay-index.d.ts +21 -0
  141. package/dist/wallet-pay-index.js +68 -0
  142. package/dist/wallet-sign-seams.d.ts +69 -0
  143. package/dist/wallet-sign-seams.js +16 -0
  144. package/dist/wallet-sign.d.ts +3 -53
  145. package/dist/wallet-sign.js +22 -18
  146. package/dist/wallet.d.ts +13 -13
  147. package/dist/wallet.js +15 -15
  148. package/dist/walrus-write.js +3 -2
  149. package/dist/walrus.d.ts +1 -16
  150. package/dist/walrus.js +11 -22
  151. package/docs/commands/credits.md +1 -1
  152. package/docs/commands/platform.md +14 -0
  153. package/docs/commands/support.md +1 -1
  154. package/docs/commands/trash.md +1 -1
  155. package/docs/commands/wallet.md +26 -8
  156. package/package.json +13 -2
@@ -0,0 +1,169 @@
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 — and
78
+ * `wallet swap`/`wallet storage split|merge|transfer`/`wallet hall --name`, which act on that
79
+ * same wallet without paying anybody.
80
+ *
81
+ * ⛔ IT DOES NOT SAVE. Which wallet pays is the account's own setting (`nmts wallet use N`), read
82
+ * from the sealed file list so every device agrees; a flag that quietly rewrote it would make
83
+ * one hurried command change where the money comes from for every later one, everywhere.
84
+ */
85
+ wallet?: string;
86
+ /** `s3`: which loopback port the gateway listens on. */
87
+ port?: string;
88
+ /**
89
+ * `create`: the version of the Terms of Service a PERSON read and accepts for the new account.
90
+ *
91
+ * ⛔ IT IS A VALUE AND NOT A FLAG, so that what was accepted is on the command line rather than
92
+ * implied by it. A tool that could accept "whatever is current" would be agreeing on behalf
93
+ * of somebody who never saw a version number.
94
+ */
95
+ acceptTerms?: string;
96
+ /** `create`: the version of the Privacy Policy accepted in the same act. */
97
+ acceptPrivacy?: string;
98
+ /** `losses`: ask the chain about ONE listed storage object now, instead of listing. */
99
+ recheck?: string;
100
+ /** `losses`: take ONE line off this account's own drive, instead of listing. ⛔ A VALUE AND NOT
101
+ * A FLAG, so the line put down is named on the command line: a person reads one and puts it down. */
102
+ dismiss?: string;
103
+ /** `shares`: who ONE file was shared with, instead of what was shared with this account. */
104
+ sent?: string;
105
+ /** ultra-high acts under skip-permissions: why this is right to do now. Kept in the run log. */
106
+ reason?: string;
107
+ releaseStorage: boolean;
108
+ size?: string;
109
+ /** `devices`: sign ONE device out by id, or `all` — a person's act, proved by the NMTS key. */
110
+ signOut?: string;
111
+ /**
112
+ * `label`: the label to rename. The NEW name follows as the operand.
113
+ *
114
+ * ⛔ ONE VALUE, NOT TWO, because the table above gives every option exactly one — and a second
115
+ * spelling of "how many values does this take" is how an option ends up parsed one way and
116
+ * tested another. What a person types is still `label --rename <old> <new>`: the new name is
117
+ * read from the operands, which is where `label <name> <files>` already reads a name from.
118
+ */
119
+ rename?: string;
120
+ /** `support send`: what the report is about, and optionally which part of that. */
121
+ category?: string;
122
+ sub?: string;
123
+ /** `support`: the message itself, or the file holding it. */
124
+ message?: string;
125
+ messageFile?: string;
126
+ /**
127
+ * `support send`: attach the run log, and how many runs of it.
128
+ * ⛔ THE EMPTY STRING IS "GIVEN WITH NO NUMBER", which is different from absent. A boolean
129
+ * beside a count would be two fields answering one question, and the pair can disagree.
130
+ */
131
+ attachLog?: string;
132
+ /**
133
+ * `support`: values that must not travel, replaced wherever they appear.
134
+ *
135
+ * ⛔ THE ONLY REPEATABLE OPTION, and it is repeatable because what it names is one value at a
136
+ * time. A comma-separated list would make a comma impossible to omit.
137
+ */
138
+ omit?: string[];
139
+ /**
140
+ * `whoami`: print the NMTS key itself.
141
+ *
142
+ * ⛔ A FLAG AND NOT A VALUE — it names no secret, it asks for the one this machine already
143
+ * holds. The option table is checked for names that look like credentials; this one carries
144
+ * nothing and says what it does.
145
+ */
146
+ reveal: boolean;
147
+ /**
148
+ * `key new`: put the new key on the screen once, as well as storing it. A flag and not a value
149
+ * for the reason above: it names no secret, it asks for the one this run was just handed.
150
+ */
151
+ print: boolean;
152
+ /** `nmts wallet address --qr` — the address as a QR code in the terminal as well. */
153
+ qr: boolean;
154
+ /** `wallet hall --remove`: be listed by a shortened address again. Never with `--name`. */
155
+ remove: boolean;
156
+ /** `terms`/`privacy`: which language to fetch — `en` or `ko`. Absent = English. */
157
+ lang?: string;
158
+ /** `terms`: the message board's terms rather than the service's. */
159
+ board: boolean;
160
+ /**
161
+ * `notices`/`terms`/`privacy`: keep the document as a file instead of printing it.
162
+ *
163
+ * ⛔ A FLAG, AND THE NOTICE'S ID IS STILL THE OPERAND. `notices --save <id>` reads exactly like
164
+ * `notices <id>`, which is the point: one way to name a notice, whichever of the two things
165
+ * is being done with it. The file's NAME is never an option — it is the server's, so that a
166
+ * copy kept here and a copy kept from the browser are the same file.
167
+ */
168
+ save: boolean;
169
+ }
@@ -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.36.1";
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
  /**
@@ -17,18 +17,11 @@ export declare function isAgentMode(mode: Autonomy): boolean;
17
17
  * and `auto` is `auto-low`. Anything else counts as `default`.
18
18
  */
19
19
  export declare function modeFromStored(value: unknown): Autonomy;
20
- /**
21
- * What this machine is set to.
22
- *
23
- * ⛔ Unreadable counts as `default`. The fail-safe direction for "I do not know" is the one where
24
- * somebody is still asked -- a file that switches autonomy on when it cannot be parsed is worse
25
- * than no file at all.
26
- */
27
- export declare function currentMode(): Autonomy;
20
+ export declare function currentMode(): Promise<Autonomy>;
28
21
  /** When it was set, or null when it is default or unreadable. */
29
- export declare function setAt(): string | null;
22
+ export declare function setAt(): Promise<string | null>;
30
23
  /** Write the choice down, with the date and the version that was asked. */
31
- export declare function setMode(mode: Autonomy, version: string, now: Date): void;
24
+ export declare function setMode(mode: Autonomy, version: string, now: Date): Promise<void>;
32
25
  /**
33
26
  * The line every run prints when a mode is on.
34
27
  *
package/dist/autonomy.js CHANGED
@@ -30,9 +30,10 @@
30
30
  // ⚠ AND WHAT NO COMMAND-LINE TOOL CAN DO: tell whether a person or a program typed this. The
31
31
  // protection here is that the choice is explicit, written down, dated, and announced on every
32
32
  // run that uses it -- not that it cannot be automated.
33
- import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, chmodSync } from "node:fs";
34
- import { join } from "node:path";
35
- import { configDir, modesAreEnforced } from "./credentials.js";
33
+ import { fromUtf8, utf8 } from "./bytes.js";
34
+ import { host } from "./host.js";
35
+ /** The one key this mode lives under. On this machine that is `autonomy.json`. */
36
+ const KEY = "autonomy";
36
37
  export const AUTONOMY_MODES = ["default", "auto-low", "auto-high", "skip-permissions"];
37
38
  /** What each mode means, in the words the tool prints. One line each, no more. */
38
39
  export const MODE_MEANS = {
@@ -101,9 +102,6 @@ export const SKIP_SENTENCE = "NOTHING WILL ASK ME AND I ACCEPT THAT";
101
102
  export function isAgentMode(mode) {
102
103
  return mode !== "default";
103
104
  }
104
- function path() {
105
- return join(configDir(), "autonomy.json");
106
- }
107
105
  /**
108
106
  * Read a stored name, including the two this tool wrote before 2026-09-06: `off` is `default`
109
107
  * and `auto` is `auto-low`. Anything else counts as `default`.
@@ -124,9 +122,13 @@ export function modeFromStored(value) {
124
122
  * somebody is still asked -- a file that switches autonomy on when it cannot be parsed is worse
125
123
  * than no file at all.
126
124
  */
127
- export function currentMode() {
125
+ async function stored() {
126
+ const held = await host().state.read(KEY);
127
+ return held === undefined ? null : JSON.parse(fromUtf8(held));
128
+ }
129
+ export async function currentMode() {
128
130
  try {
129
- const parsed = JSON.parse(readFileSync(path(), "utf8"));
131
+ const parsed = await stored();
130
132
  if (typeof parsed !== "object" || parsed === null)
131
133
  return "default";
132
134
  return modeFromStored(Reflect.get(parsed, "mode"));
@@ -136,9 +138,9 @@ export function currentMode() {
136
138
  }
137
139
  }
138
140
  /** When it was set, or null when it is default or unreadable. */
139
- export function setAt() {
141
+ export async function setAt() {
140
142
  try {
141
- const parsed = JSON.parse(readFileSync(path(), "utf8"));
143
+ const parsed = await stored();
142
144
  if (typeof parsed !== "object" || parsed === null)
143
145
  return null;
144
146
  const at = Reflect.get(parsed, "setAt");
@@ -149,17 +151,13 @@ export function setAt() {
149
151
  }
150
152
  }
151
153
  /** Write the choice down, with the date and the version that was asked. */
152
- export function setMode(mode, version, now) {
154
+ export async function setMode(mode, version, now) {
153
155
  if (mode === "default") {
154
- if (existsSync(path()))
155
- rmSync(path(), { force: true });
156
+ await host().state.remove(KEY);
156
157
  return;
157
158
  }
158
159
  const body = { mode, setAt: now.toISOString(), byVersion: version };
159
- mkdirSync(configDir(), { recursive: true, mode: 0o700 });
160
- writeFileSync(path(), `${JSON.stringify(body, null, 2)}\n`, { mode: 0o600 });
161
- if (modesAreEnforced())
162
- chmodSync(path(), 0o600);
160
+ await host().state.write(KEY, utf8(`${JSON.stringify(body, null, 2)}\n`));
163
161
  }
164
162
  /**
165
163
  * The line every run prints when a mode is on.
@@ -0,0 +1,15 @@
1
+ /** These bytes as unpadded base64url. */
2
+ export declare function toBase64Url(bytes: Uint8Array): string;
3
+ /**
4
+ * Base64url back to bytes.
5
+ *
6
+ * ⚠ PLAIN BASE64 IS ACCEPTED TOO, and on purpose: `Buffer.from(text, "base64url")` accepted both,
7
+ * and a record written by an older version of this tool has to keep opening.
8
+ */
9
+ export declare function fromBase64Url(text: string): Uint8Array;
10
+ /** This text as UTF-8 bytes. */
11
+ export declare function utf8(text: string): Uint8Array;
12
+ /** These UTF-8 bytes as text. Malformed sequences become the replacement character. */
13
+ export declare function fromUtf8(bytes: Uint8Array): string;
14
+ /** One run of bytes from several, in order. */
15
+ export declare function concat(parts: readonly Uint8Array[]): Uint8Array;
package/dist/bytes.js ADDED
@@ -0,0 +1,63 @@
1
+ // Bytes to text and back, in the two spellings this format uses.
2
+ //
3
+ // ⛔ WHY NOT `Buffer`. It is Node's, it is the one global this package leaned on that a browser
4
+ // does not have, and every use of it was one of these five calls. A bundler shim would drag a
5
+ // polyfill of the whole class into a page to reach `toString("base64url")`; these are ten lines
6
+ // on top of what the chain library already carries.
7
+ //
8
+ // ⛔ BASE64URL IS THE FORMAT'S SPELLING (NCF-3), not a preference. Sealed blobs, wrapped keys and
9
+ // chunk names all travel unpadded with `-` and `_`, because they end up in URLs and file names.
10
+ // The alphabet swap and the padding live here, in one place, so that a second spelling cannot
11
+ // appear somewhere and produce a name that never matches.
12
+ //
13
+ // ⛔ `atob`/`btoa` RATHER THAN A LIBRARY, and that is not a reinvention: they are the runtime's own
14
+ // base64, present in Node and in every browser, and they are what the browser half of this
15
+ // product already decodes with (`web/src/lib/crypto/wasm-engine.ts`). A package would be a
16
+ // dependency in the chain of `nmts --help`, which `check:cli-startup` measures and refuses.
17
+ const encoder = new TextEncoder();
18
+ const decoder = new TextDecoder();
19
+ /** These bytes as unpadded base64url. */
20
+ export function toBase64Url(bytes) {
21
+ let binary = "";
22
+ // ⚠ In runs rather than one `String.fromCharCode(...bytes)`: spreading a multi-megabyte array
23
+ // into an argument list overflows the stack, and the sealed blobs here are exactly that big.
24
+ for (let at = 0; at < bytes.length; at += 0x8000) {
25
+ binary += String.fromCharCode(...bytes.subarray(at, Math.min(at + 0x8000, bytes.length)));
26
+ }
27
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
28
+ }
29
+ /**
30
+ * Base64url back to bytes.
31
+ *
32
+ * ⚠ PLAIN BASE64 IS ACCEPTED TOO, and on purpose: `Buffer.from(text, "base64url")` accepted both,
33
+ * and a record written by an older version of this tool has to keep opening.
34
+ */
35
+ export function fromBase64Url(text) {
36
+ const standard = text.replace(/-/g, "+").replace(/_/g, "/");
37
+ const binary = atob(standard.padEnd(standard.length + ((4 - (standard.length % 4)) % 4), "="));
38
+ const out = new Uint8Array(binary.length);
39
+ for (let at = 0; at < binary.length; at += 1)
40
+ out[at] = binary.charCodeAt(at);
41
+ return out;
42
+ }
43
+ /** This text as UTF-8 bytes. */
44
+ export function utf8(text) {
45
+ return encoder.encode(text);
46
+ }
47
+ /** These UTF-8 bytes as text. Malformed sequences become the replacement character. */
48
+ export function fromUtf8(bytes) {
49
+ return decoder.decode(bytes);
50
+ }
51
+ /** One run of bytes from several, in order. */
52
+ export function concat(parts) {
53
+ let total = 0;
54
+ for (const part of parts)
55
+ total += part.length;
56
+ const out = new Uint8Array(total);
57
+ let at = 0;
58
+ for (const part of parts) {
59
+ out.set(part, at);
60
+ at += part.length;
61
+ }
62
+ return out;
63
+ }
@@ -19,13 +19,13 @@ export declare const DEFAULT_COLLISION: OnCollision;
19
19
  * ⛔ Unreadable counts as `rename`, for the same reason autonomy unreadable counts as off: the
20
20
  * fail-safe direction for "I do not know" is the one that destroys nothing.
21
21
  */
22
- export declare function currentChoice(): OnCollision;
22
+ export declare function currentChoice(): Promise<OnCollision>;
23
23
  /** Has anybody answered on this machine? Used to know whether setup still has to ask. */
24
- export declare function hasChosen(): boolean;
24
+ export declare function hasChosen(): Promise<boolean>;
25
25
  /** Write the choice down, with the date and the version that asked. */
26
- export declare function setChoice(choice: OnCollision, version: string, now: Date): void;
26
+ export declare function setChoice(choice: OnCollision, version: string, now: Date): Promise<void>;
27
27
  /** Forget the answer, so setup asks again. */
28
- export declare function forgetChoice(): void;
28
+ export declare function forgetChoice(): Promise<void>;
29
29
  /** What decided, so the tool can say so rather than acting silently. */
30
30
  export interface Decision {
31
31
  readonly choice: OnCollision;
@@ -54,7 +54,7 @@ export interface Decision {
54
54
  */
55
55
  export declare function decide(
56
56
  /** What this run asked for, if anything. `undefined` means "use what this machine is set to". */
57
- askedFor?: OnCollision, setting?: OnCollision, mode?: Autonomy): Decision;
57
+ askedFor?: OnCollision, setting?: OnCollision, mode?: Autonomy): Promise<Decision>;
58
58
  /** How the two answers are numbered where setup asks. Kept here so the question and the reading agree. */
59
59
  export declare const ANSWER_NUMBER: Readonly<Record<OnCollision, string>>;
60
60
  /**
package/dist/collision.js CHANGED
@@ -23,12 +23,13 @@
23
23
  // ⚠ WHAT THIS CANNOT DO is tell an agent from a person. Nothing on a command line can. What it can
24
24
  // do is make the destructive answer require a setting that was turned on deliberately, and say
25
25
  // which setting decided.
26
- import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, chmodSync } from "node:fs";
27
- import { join } from "node:path";
28
26
  import { currentMode } from "./autonomy.js";
27
+ import { fromUtf8, utf8 } from "./bytes.js";
29
28
  import { NmtsError } from "./errors.js";
29
+ import { host } from "./host.js";
30
30
  import { BINARY_NAME } from "./product.js";
31
- import { configDir, modesAreEnforced } from "./credentials.js";
31
+ /** The one key this answer lives under. On this machine that is `collision.json`. */
32
+ const KEY = "collision";
32
33
  export const COLLISION_CHOICES = ["rename", "overwrite"];
33
34
  /** What each choice does, in the words the tool prints. One line each. */
34
35
  export const COLLISION_MEANS = {
@@ -53,9 +54,6 @@ export function parseAsked(typed) {
53
54
  }
54
55
  /** What is written down when nobody has chosen. */
55
56
  export const DEFAULT_COLLISION = "rename";
56
- function path() {
57
- return join(configDir(), "collision.json");
58
- }
59
57
  function isChoice(value) {
60
58
  return typeof value === "string" && COLLISION_CHOICES.includes(value);
61
59
  }
@@ -65,9 +63,12 @@ function isChoice(value) {
65
63
  * ⛔ Unreadable counts as `rename`, for the same reason autonomy unreadable counts as off: the
66
64
  * fail-safe direction for "I do not know" is the one that destroys nothing.
67
65
  */
68
- export function currentChoice() {
66
+ export async function currentChoice() {
69
67
  try {
70
- const parsed = JSON.parse(readFileSync(path(), "utf8"));
68
+ const held = await host().state.read(KEY);
69
+ if (held === undefined)
70
+ return DEFAULT_COLLISION;
71
+ const parsed = JSON.parse(fromUtf8(held));
71
72
  if (typeof parsed !== "object" || parsed === null)
72
73
  return DEFAULT_COLLISION;
73
74
  const choice = Reflect.get(parsed, "onCollision");
@@ -78,21 +79,17 @@ export function currentChoice() {
78
79
  }
79
80
  }
80
81
  /** Has anybody answered on this machine? Used to know whether setup still has to ask. */
81
- export function hasChosen() {
82
- return existsSync(path());
82
+ export async function hasChosen() {
83
+ return (await host().state.read(KEY)) !== undefined;
83
84
  }
84
85
  /** Write the choice down, with the date and the version that asked. */
85
- export function setChoice(choice, version, now) {
86
- mkdirSync(configDir(), { recursive: true, mode: 0o700 });
86
+ export async function setChoice(choice, version, now) {
87
87
  const body = { onCollision: choice, setAt: now.toISOString(), byVersion: version };
88
- writeFileSync(path(), `${JSON.stringify(body, null, 2)}\n`, { mode: 0o600 });
89
- if (modesAreEnforced())
90
- chmodSync(path(), 0o600);
88
+ await host().state.write(KEY, utf8(`${JSON.stringify(body, null, 2)}\n`));
91
89
  }
92
90
  /** Forget the answer, so setup asks again. */
93
- export function forgetChoice() {
94
- if (existsSync(path()))
95
- rmSync(path(), { force: true });
91
+ export async function forgetChoice() {
92
+ await host().state.remove(KEY);
96
93
  }
97
94
  /**
98
95
  * What to do with this collision, and what settled it.
@@ -108,14 +105,14 @@ export function forgetChoice() {
108
105
  * ⛔ THE OVERRIDE IS ONE-WAY. A mode can let `overwrite` through; nothing here turns a `rename`
109
106
  * into an `overwrite`.
110
107
  */
111
- export function decide(
108
+ export async function decide(
112
109
  /** What this run asked for, if anything. `undefined` means "use what this machine is set to". */
113
- askedFor, setting = currentChoice(), mode = currentMode()) {
110
+ askedFor, setting, mode) {
114
111
  if (askedFor === undefined)
115
- return { choice: setting, by: "setting" };
112
+ return { choice: setting ?? (await currentChoice()), by: "setting" };
116
113
  if (askedFor === "rename")
117
114
  return { choice: "rename", by: "asked-for" };
118
- if (mode === "default")
115
+ if ((mode ?? (await currentMode())) === "default")
119
116
  return { choice: "rename", by: "agent-refused" };
120
117
  return { choice: "overwrite", by: "asked-for" };
121
118
  }