@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.
- package/AGENTS.md +125 -517
- package/CHANGELOG.md +104 -0
- package/README.ko.md +377 -469
- package/README.md +394 -474
- package/dist/account-proof.d.ts +29 -0
- package/dist/account-proof.js +6 -6
- package/dist/account.d.ts +18 -0
- package/dist/account.js +5 -5
- package/dist/agent-host.d.ts +71 -0
- package/dist/agent-host.js +169 -0
- package/dist/api-advice.d.ts +2 -0
- package/dist/api-advice.js +210 -0
- package/dist/api-key.d.ts +79 -0
- package/dist/api-key.js +7 -7
- package/dist/api-refusal.d.ts +14 -0
- package/dist/api-refusal.js +8 -0
- package/dist/api.d.ts +114 -0
- package/dist/api.js +59 -162
- package/dist/args.d.ts +160 -0
- package/dist/args.js +118 -30
- package/dist/artifact-about.d.ts +49 -0
- package/dist/autonomy.d.ts +39 -0
- package/dist/autonomy.js +110 -32
- package/dist/code-access.d.ts +29 -0
- package/dist/code-access.js +3 -3
- package/dist/code-vault.d.ts +38 -0
- package/dist/code-vault.js +8 -8
- package/dist/collision.d.ts +67 -0
- package/dist/collision.js +1 -1
- package/dist/commands/accept-terms.d.ts +11 -0
- package/dist/commands/accept-terms.js +106 -0
- package/dist/commands/balance.d.ts +7 -0
- package/dist/commands/balance.js +54 -1
- package/dist/commands/create-code-file.d.ts +24 -0
- package/dist/commands/create-code-file.js +93 -0
- package/dist/commands/create-link.d.ts +10 -0
- package/dist/commands/create-link.js +232 -0
- package/dist/commands/create.d.ts +20 -0
- package/dist/commands/create.js +43 -102
- package/dist/commands/credits.d.ts +9 -0
- package/dist/commands/credits.js +110 -0
- package/dist/commands/delete-account.d.ts +11 -0
- package/dist/commands/delete-account.js +63 -0
- package/dist/commands/deposit.d.ts +7 -0
- package/dist/commands/deposit.js +85 -0
- package/dist/commands/devices.d.ts +12 -0
- package/dist/commands/devices.js +144 -0
- package/dist/commands/documents.d.ts +35 -0
- package/dist/commands/documents.js +212 -0
- package/dist/commands/env.d.ts +5 -0
- package/dist/commands/env.js +10 -2
- package/dist/commands/erase.d.ts +13 -0
- package/dist/commands/erase.js +193 -0
- package/dist/commands/expiring.d.ts +19 -0
- package/dist/commands/extend.d.ts +33 -0
- package/dist/commands/extend.js +54 -15
- package/dist/commands/get.d.ts +18 -0
- package/dist/commands/key-manage.d.ts +11 -0
- package/dist/commands/key-manage.js +162 -0
- package/dist/commands/key.d.ts +28 -0
- package/dist/commands/key.js +249 -0
- package/dist/commands/kit.d.ts +11 -0
- package/dist/commands/kit.js +7 -7
- package/dist/commands/listfile.d.ts +13 -0
- package/dist/commands/listfile.js +12 -5
- package/dist/commands/login.d.ts +18 -0
- package/dist/commands/login.js +19 -19
- package/dist/commands/logout.d.ts +1 -0
- package/dist/commands/logout.js +1 -1
- package/dist/commands/losses.d.ts +12 -0
- package/dist/commands/losses.js +180 -0
- package/dist/commands/ls.d.ts +23 -0
- package/dist/commands/marks-dispatch.d.ts +2 -0
- package/dist/commands/marks-dispatch.js +51 -0
- package/dist/commands/marks.d.ts +46 -0
- package/dist/commands/marks.js +80 -0
- package/dist/commands/mcp.d.ts +24 -0
- package/dist/commands/mcp.js +70 -5
- package/dist/commands/mode.d.ts +8 -0
- package/dist/commands/mode.js +60 -24
- package/dist/commands/on-collision.d.ts +6 -0
- package/dist/commands/organise.d.ts +46 -0
- package/dist/commands/padding.d.ts +7 -0
- package/dist/commands/padding.js +114 -0
- package/dist/commands/public-code.d.ts +9 -0
- package/dist/commands/public-code.js +8 -8
- package/dist/commands/pull.d.ts +27 -0
- package/dist/commands/push-wallet.d.ts +19 -0
- package/dist/commands/push-wallet.js +69 -0
- package/dist/commands/push.d.ts +47 -0
- package/dist/commands/push.js +37 -7
- package/dist/commands/put-wallet.d.ts +77 -0
- package/dist/commands/put-wallet.js +316 -0
- package/dist/commands/put.d.ts +56 -0
- package/dist/commands/put.js +53 -6
- package/dist/commands/rebuild.d.ts +18 -0
- package/dist/commands/rebuild.js +108 -10
- package/dist/commands/receive.d.ts +24 -0
- package/dist/commands/recovery-dispatch.d.ts +2 -0
- package/dist/commands/recovery-dispatch.js +34 -0
- package/dist/commands/recovery-list.d.ts +11 -0
- package/dist/commands/recovery-list.js +6 -6
- package/dist/commands/recovery.d.ts +25 -0
- package/dist/commands/recovery.js +2 -2
- package/dist/commands/rollback.d.ts +9 -0
- package/dist/commands/rollback.js +118 -0
- package/dist/commands/s3.d.ts +23 -0
- package/dist/commands/s3.js +6 -6
- package/dist/commands/settings.d.ts +5 -0
- package/dist/commands/settings.js +21 -6
- package/dist/commands/share-dispatch.d.ts +2 -0
- package/dist/commands/share-dispatch.js +46 -0
- package/dist/commands/share.d.ts +14 -0
- package/dist/commands/share.js +13 -3
- package/dist/commands/shares-sent.d.ts +18 -0
- package/dist/commands/shares-sent.js +95 -0
- package/dist/commands/support.d.ts +24 -0
- package/dist/commands/support.js +321 -0
- package/dist/commands/sweep.d.ts +11 -0
- package/dist/commands/tip.d.ts +11 -0
- package/dist/commands/tip.js +86 -0
- package/dist/commands/trash.d.ts +17 -0
- package/dist/commands/trash.js +1 -1
- package/dist/commands/trial.d.ts +7 -0
- package/dist/commands/trial.js +16 -18
- package/dist/commands/unlock.d.ts +16 -0
- package/dist/commands/unlock.js +159 -0
- package/dist/commands/update.d.ts +42 -0
- package/dist/commands/update.js +1 -1
- package/dist/commands/usage.d.ts +8 -0
- package/dist/commands/verify.d.ts +18 -0
- package/dist/commands/verify.js +10 -6
- package/dist/commands/wallet-activity.d.ts +26 -0
- package/dist/commands/wallet-activity.js +117 -0
- package/dist/commands/wallet-donate.d.ts +26 -0
- package/dist/commands/wallet-donate.js +163 -0
- package/dist/commands/wallet-hall.d.ts +35 -0
- package/dist/commands/wallet-hall.js +214 -0
- package/dist/commands/wallet-send.d.ts +22 -0
- package/dist/commands/wallet-send.js +153 -0
- package/dist/commands/wallet-storage-ops.d.ts +24 -0
- package/dist/commands/wallet-storage-ops.js +215 -0
- package/dist/commands/wallet-storage.d.ts +18 -0
- package/dist/commands/wallet-storage.js +95 -0
- package/dist/commands/wallet-swap.d.ts +32 -0
- package/dist/commands/wallet-swap.js +287 -0
- package/dist/commands/wallet.d.ts +36 -0
- package/dist/commands/wallet.js +57 -15
- package/dist/commands/whoami.d.ts +10 -0
- package/dist/commands/whoami.js +24 -6
- package/dist/consent.d.ts +140 -0
- package/dist/consent.js +89 -30
- package/dist/credentials.d.ts +146 -0
- package/dist/credentials.js +10 -10
- package/dist/crypto-surface.d.ts +197 -0
- package/dist/crypto.d.ts +81 -0
- package/dist/crypto.js +13 -0
- package/dist/deposit.d.ts +25 -0
- package/dist/deposit.js +78 -0
- package/dist/download-part.d.ts +40 -0
- package/dist/download-sink.d.ts +76 -0
- package/dist/download.d.ts +79 -0
- package/dist/download.js +3 -3
- package/dist/drive-paths.d.ts +73 -0
- package/dist/environment.d.ts +62 -0
- package/dist/environment.js +29 -9
- package/dist/errors.d.ts +22 -0
- package/dist/errors.js +3 -3
- package/dist/exit.d.ts +44 -0
- package/dist/expiry.d.ts +58 -0
- package/dist/extend-budget.d.ts +35 -0
- package/dist/extend-budget.js +81 -0
- package/dist/extend-chain.d.ts +43 -0
- package/dist/extend-chain.js +40 -3
- package/dist/extend-plan.d.ts +148 -0
- package/dist/extend-plan.js +1 -1
- package/dist/gate.d.ts +18 -0
- package/dist/gate.js +100 -0
- package/dist/guards.d.ts +2 -0
- package/dist/help.d.ts +20 -0
- package/dist/help.js +199 -33
- package/dist/human-check.d.ts +23 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +49 -0
- package/dist/item-trash.d.ts +1 -0
- package/dist/kit-file.d.ts +56 -0
- package/dist/kit-file.js +10 -10
- package/dist/list-file.d.ts +88 -0
- package/dist/list-file.js +90 -7
- package/dist/list-view-find.d.ts +15 -0
- package/dist/list-view-order.d.ts +32 -0
- package/dist/main.d.ts +12 -0
- package/dist/main.js +112 -113
- package/dist/manifest-chunk-cache.d.ts +14 -0
- package/dist/manifest-chunk-cache.js +103 -0
- package/dist/manifest-chunk-flow.d.ts +81 -0
- package/dist/manifest-chunk-flow.js +307 -0
- package/dist/manifest-create.d.ts +23 -0
- package/dist/manifest-create.js +26 -30
- package/dist/manifest-write.d.ts +161 -0
- package/dist/manifest-write.js +42 -33
- package/dist/manifest.d.ts +82 -0
- package/dist/manifest.js +69 -21
- package/dist/mark-render.d.ts +26 -0
- package/dist/mcp-args.d.ts +17 -0
- package/dist/mcp-ask.d.ts +43 -0
- package/dist/mcp-ask.js +100 -0
- package/dist/mcp-tools/context.d.ts +46 -0
- package/dist/mcp-tools/credits.d.ts +3 -0
- package/dist/mcp-tools/credits.js +61 -0
- package/dist/mcp-tools/files.d.ts +3 -0
- package/dist/mcp-tools/files.js +34 -0
- package/dist/mcp-tools/organise.d.ts +3 -0
- package/dist/mcp-tools/organise.js +82 -2
- package/dist/mcp-tools/reads.d.ts +3 -0
- package/dist/mcp-tools/reads.js +132 -4
- package/dist/mcp-tools/share.d.ts +3 -0
- package/dist/mcp-tools/share.js +26 -7
- package/dist/mcp-tools/support.d.ts +3 -0
- package/dist/mcp-tools/support.js +140 -0
- package/dist/mcp-tools/tiers.d.ts +31 -0
- package/dist/mcp-tools/tiers.js +147 -0
- package/dist/mcp.d.ts +80 -0
- package/dist/mcp.js +110 -9
- package/dist/net-retry.d.ts +38 -0
- package/dist/network.d.ts +10 -0
- package/dist/notice.d.ts +7 -0
- package/dist/notice.js +7 -7
- package/dist/product.d.ts +29 -0
- package/dist/product.js +1 -1
- package/dist/progress.d.ts +37 -0
- package/dist/prompt.d.ts +31 -0
- package/dist/prompt.js +1 -1
- package/dist/rebuild-key-check.d.ts +26 -0
- package/dist/rebuild-key-check.js +90 -0
- package/dist/rebuild.d.ts +87 -0
- package/dist/rebuild.js +26 -4
- package/dist/recovery-assemble.d.ts +40 -0
- package/dist/recovery-assemble.js +1 -1
- package/dist/recovery-build.d.ts +40 -0
- package/dist/recovery-map-file.d.ts +53 -0
- package/dist/recovery-map-file.js +4 -4
- package/dist/recovery-map.d.ts +197 -0
- package/dist/recovery-release.d.ts +104 -0
- package/dist/recovery-seq.d.ts +10 -0
- package/dist/recovery-source.d.ts +50 -0
- package/dist/redact.d.ts +70 -0
- package/dist/redact.js +212 -0
- package/dist/registration.d.ts +30 -0
- package/dist/registration.js +5 -5
- package/dist/risk.d.ts +380 -0
- package/dist/risk.js +206 -0
- package/dist/run-log.d.ts +78 -0
- package/dist/run-log.js +301 -0
- package/dist/s3/listing.d.ts +47 -0
- package/dist/s3/multipart.d.ts +21 -0
- package/dist/s3/response-sink.d.ts +8 -0
- package/dist/s3/same-file.d.ts +54 -0
- package/dist/s3/server.d.ts +58 -0
- package/dist/s3/server.js +2 -2
- package/dist/s3/sigv4.d.ts +46 -0
- package/dist/s3/sigv4.js +1 -1
- package/dist/s3/staging.d.ts +10 -0
- package/dist/s3/xml.d.ts +28 -0
- package/dist/safe-path.d.ts +41 -0
- package/dist/seal.d.ts +120 -0
- package/dist/secret-reader.d.ts +28 -0
- package/dist/server.d.ts +9 -0
- package/dist/session.d.ts +32 -0
- package/dist/session.js +1 -1
- package/dist/setup-questions.d.ts +7 -0
- package/dist/share.d.ts +108 -0
- package/dist/share.js +1 -1
- package/dist/shared/lib/crypto/size-padding.d.ts +55 -0
- package/dist/shared/lib/crypto/size-padding.js +5 -0
- package/dist/shared/lib/drive/manifest-chunks.d.ts +95 -0
- package/dist/shared/lib/drive/manifest-chunks.js +252 -0
- package/dist/shared/lib/drive/manifest-codec.d.ts +214 -0
- package/dist/shared/lib/drive/manifest-codec.js +7 -7
- package/dist/shared/lib/drive/manifest-index.d.ts +98 -0
- package/dist/shared/lib/drive/manifest-ops.d.ts +167 -0
- package/dist/shared/lib/drive/manifest-ops.js +9 -4
- package/dist/shared/lib/drive/manifest-pack.d.ts +65 -0
- package/dist/shared/lib/drive/manifest-pack.js +287 -0
- package/dist/shared/lib/drive/manifest-settings.d.ts +113 -0
- package/dist/shared/lib/drive/manifest-settings.js +87 -6
- package/dist/shared/lib/drive/name-conflict.d.ts +76 -0
- package/dist/shared/lib/drive/rebuild-verify.d.ts +73 -0
- package/dist/shared/lib/drive/rebuild-verify.js +112 -0
- package/dist/shared/lib/drive/unique-name.d.ts +9 -0
- package/dist/shared/lib/drive/zstd.d.ts +27 -0
- package/dist/shared/lib/drive/zstd.js +74 -0
- package/dist/shared/lib/extend/epochs.d.ts +205 -0
- package/dist/shared/lib/net/retry-budget.d.ts +79 -0
- package/dist/shared/lib/share/shared-file-info.d.ts +21 -0
- package/dist/shared/lib/storage-control/chain.d.ts +57 -0
- package/dist/shared/lib/storage-control/chain.js +82 -0
- package/dist/shared/lib/storage-control/plan.d.ts +40 -0
- package/dist/shared/lib/storage-control/plan.js +72 -0
- package/dist/shared/lib/storage-control/reuse.d.ts +72 -0
- package/dist/shared/lib/storage-control/reuse.js +95 -0
- package/dist/shared/lib/storage-network.d.ts +25 -0
- package/dist/shared/lib/upload/part-plan.d.ts +24 -0
- package/dist/shared/lib/wallet/activity.d.ts +138 -0
- package/dist/shared/lib/wallet/activity.js +208 -0
- package/dist/shared/lib/wallet/send-rules.d.ts +68 -0
- package/dist/shared/lib/wallet/send-rules.js +116 -0
- package/dist/shared/lib/wallet/swap-rules.d.ts +115 -0
- package/dist/shared/lib/wallet/swap-rules.js +199 -0
- package/dist/shared/lib/wallet/tip.d.ts +14 -0
- package/dist/shared/lib/wallet/tip.js +34 -0
- package/dist/shared/lib/wallet/venue-ids.d.ts +23 -0
- package/dist/shared/lib/wallet/venue-ids.js +53 -0
- package/dist/standing-tip.d.ts +24 -0
- package/dist/standing-tip.js +52 -0
- package/dist/stdout.d.ts +38 -0
- package/dist/storage-control-chain.d.ts +38 -0
- package/dist/storage-control-chain.js +78 -0
- package/dist/sui-rpc.d.ts +15 -0
- package/dist/sui-rpc.js +59 -0
- package/dist/support-attach.d.ts +24 -0
- package/dist/support-attach.js +72 -0
- package/dist/support-copy.d.ts +42 -0
- package/dist/support-copy.js +109 -0
- package/dist/support-wire.d.ts +49 -0
- package/dist/support-wire.js +194 -0
- package/dist/trash-sweep.d.ts +55 -0
- package/dist/units.d.ts +2 -0
- package/dist/update-check.d.ts +50 -0
- package/dist/update-source.d.ts +63 -0
- package/dist/upload-api.d.ts +3 -0
- package/dist/upload-file.d.ts +97 -0
- package/dist/upload-file.js +3 -2
- package/dist/upload-price.d.ts +50 -0
- package/dist/upload-steps.d.ts +26 -0
- package/dist/upload-steps.js +29 -9
- package/dist/upload-store.d.ts +182 -0
- package/dist/upload-wallet-chain.d.ts +54 -0
- package/dist/upload-wallet-chain.js +203 -0
- package/dist/upload-wallet-plan.d.ts +128 -0
- package/dist/upload-wallet-plan.js +184 -0
- package/dist/upload-wallet.d.ts +24 -0
- package/dist/upload-wallet.js +208 -0
- package/dist/upload-wire.d.ts +244 -0
- package/dist/upload.d.ts +18 -0
- package/dist/upload.js +10 -0
- package/dist/usage-report.d.ts +35 -0
- package/dist/wallet-activity-chain.d.ts +5 -0
- package/dist/wallet-activity-chain.js +31 -0
- package/dist/wallet-chain.d.ts +19 -0
- package/dist/wallet-chain.js +2 -2
- package/dist/wallet-grant.d.ts +50 -0
- package/dist/wallet-grant.js +218 -0
- package/dist/wallet-send-chain.d.ts +24 -0
- package/dist/wallet-send-chain.js +49 -0
- package/dist/wallet-sign.d.ts +133 -0
- package/dist/wallet-sign.js +317 -0
- package/dist/wallet-storage-chain.d.ts +3 -0
- package/dist/wallet-storage-chain.js +20 -0
- package/dist/wallet-swap-chain.d.ts +52 -0
- package/dist/wallet-swap-chain.js +186 -0
- package/dist/wallet-swap-quote.d.ts +22 -0
- package/dist/wallet-swap-quote.js +126 -0
- package/dist/wallet.d.ts +135 -0
- package/dist/wallet.js +5 -5
- package/dist/walrus-write.d.ts +56 -0
- package/dist/walrus-write.js +5 -4
- package/dist/walrus.d.ts +86 -0
- package/dist/walrus.js +48 -10
- package/dist/zstd-node.d.ts +11 -0
- package/dist/zstd-node.js +71 -0
- package/docs/commands/accept-terms.md +15 -0
- package/docs/commands/create.md +17 -0
- package/docs/commands/credits.md +34 -0
- package/docs/commands/delete-account.md +14 -0
- package/docs/commands/deposit.md +27 -0
- package/docs/commands/devices.md +9 -0
- package/docs/commands/documents.md +10 -0
- package/docs/commands/env.md +21 -0
- package/docs/commands/extend.md +27 -0
- package/docs/commands/folders.md +10 -0
- package/docs/commands/get.md +14 -0
- package/docs/commands/key.md +14 -0
- package/docs/commands/login.md +23 -0
- package/docs/commands/logout.md +11 -0
- package/docs/commands/losses.md +13 -0
- package/docs/commands/ls.md +16 -0
- package/docs/commands/marks.md +9 -0
- package/docs/commands/mcp.md +33 -0
- package/docs/commands/mode.md +29 -0
- package/docs/commands/on-collision.md +13 -0
- package/docs/commands/padding.md +13 -0
- package/docs/commands/public-code.md +9 -0
- package/docs/commands/pull.md +9 -0
- package/docs/commands/push.md +12 -0
- package/docs/commands/put.md +36 -0
- package/docs/commands/rebuild.md +13 -0
- package/docs/commands/recovery.md +18 -0
- package/docs/commands/s3.md +17 -0
- package/docs/commands/share.md +15 -0
- package/docs/commands/support.md +16 -0
- package/docs/commands/tip.md +21 -0
- package/docs/commands/trash.md +25 -0
- package/docs/commands/trial.md +12 -0
- package/docs/commands/unlock.md +25 -0
- package/docs/commands/update.md +14 -0
- package/docs/commands/usage.md +14 -0
- package/docs/commands/verify.md +18 -0
- package/docs/commands/wallet.md +67 -0
- package/docs/commands/whoami.md +12 -0
- package/package.json +67 -8
- package/server.json +28 -0
- package/vendor/nmts-crypto/nmts_crypto_wasm.d.ts +23 -2
- package/vendor/nmts-crypto/nmts_crypto_wasm.js +44 -2
- package/vendor/nmts-crypto/nmts_crypto_wasm_bg.wasm +0 -0
- package/vendor/nmts-crypto/nmts_crypto_wasm_bg.wasm.d.ts +1 -0
- package/vendor/nmts-crypto/package.json +1 -1
- package/dist/commands/consent.js +0 -77
- package/dist/extend-sign.js +0 -130
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface SweepOptions {
|
|
2
|
+
server?: string | undefined;
|
|
3
|
+
network?: string | undefined;
|
|
4
|
+
json?: boolean;
|
|
5
|
+
/** Go ahead and drop them. Without this the run reports and changes nothing. */
|
|
6
|
+
yes?: boolean;
|
|
7
|
+
write?: (line: string) => void;
|
|
8
|
+
/** The instant to measure the thirty days against. Passed in so one run means one moment. */
|
|
9
|
+
now?: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function sweep(options?: SweepOptions): Promise<number>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface TipOptions {
|
|
2
|
+
server?: string | undefined;
|
|
3
|
+
network?: string | undefined;
|
|
4
|
+
json?: boolean;
|
|
5
|
+
yes?: boolean;
|
|
6
|
+
write?: (line: string) => void;
|
|
7
|
+
/** Injected in tests: answers the one confirmation above the dial's end. */
|
|
8
|
+
readLine?: ((question: string) => Promise<string>) | undefined;
|
|
9
|
+
now?: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function tip(wanted: string | undefined, options?: TipOptions): Promise<number>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// `nmts tip [percent | off]` — the standing share of every storage payment sent to the developer
|
|
2
|
+
// as a gift (owner 2026-09-06). Read with no argument; set with a percent; `off` is 0.
|
|
3
|
+
//
|
|
4
|
+
// ⛔ IT LIVES IN THE SEALED FILE LIST, like `padding`: the server must not learn it, and it follows
|
|
5
|
+
// the account, so the browser and every machine send the same share. 0 is spelled as absence.
|
|
6
|
+
//
|
|
7
|
+
// ⛔ THE AGREEMENT IS ASKED ONCE, AND ONLY WHEN RAISING FROM 0. Setting any share above 0 needs the
|
|
8
|
+
// `donate` unlock — that unlock's text IS the gift terms (voluntary · nothing in return · not
|
|
9
|
+
// refundable · the published address · visible on the chain) — and the first such setting
|
|
10
|
+
// writes the agreement's instant into the list, which the browser reads as the same agreement.
|
|
11
|
+
// After that, changing the share asks nothing. Above 10 % the run confirms once more, in words,
|
|
12
|
+
// that this share of EVERY payment is meant, permanently: at a terminal, or with `--yes`.
|
|
13
|
+
//
|
|
14
|
+
// ⛔ NOTHING IS SENT HERE. The sending happens after each payment (`standing-tip.ts`), without a
|
|
15
|
+
// question, because this is the person's standing choice.
|
|
16
|
+
import { requireConsent } from "../consent.js";
|
|
17
|
+
import { NmtsError } from "../errors.js";
|
|
18
|
+
import { readFileList } from "../manifest.js";
|
|
19
|
+
import { applyManyToList } from "../manifest-write.js";
|
|
20
|
+
import { BINARY_NAME } from "../product.js";
|
|
21
|
+
import { promptLine, stdinIsATerminal } from "../prompt.js";
|
|
22
|
+
import { openSession } from "../session.js";
|
|
23
|
+
import { TIP_DIAL_MAX_TENTHS, needsExtraConfirm, percentText, tenthsFromPercent } from "../shared/lib/wallet/tip.js";
|
|
24
|
+
export async function tip(wanted, options = {}) {
|
|
25
|
+
const say = options.write ?? ((line) => process.stdout.write(`${line}\n`));
|
|
26
|
+
const session = await openSession({ server: options.server, network: options.network });
|
|
27
|
+
const list = await readFileList(session.server, session.apiKey, session.code, session.accountId);
|
|
28
|
+
const current = list.manifest?.settings?.tipTenths ?? 0;
|
|
29
|
+
const consentAt = list.manifest?.settings?.tipConsentAt;
|
|
30
|
+
if (wanted === undefined || wanted === "") {
|
|
31
|
+
if (options.json === true) {
|
|
32
|
+
say(JSON.stringify({ tipPercent: Number(percentText(current)), tipTenths: current, agreedAt: consentAt === undefined ? null : new Date(consentAt).toISOString() }));
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
say(current > 0
|
|
36
|
+
? `Every storage payment sends ${percentText(current)} % of what it paid to the developer, as a gift, in WAL — without asking.`
|
|
37
|
+
: `No standing gift: 0 % of each storage payment goes to the developer.`);
|
|
38
|
+
say(` Set one: \`${BINARY_NAME} tip 2.5\` (in steps of 0.1 %, the dial ends at 10 %). Stop it: \`${BINARY_NAME} tip off\`.`);
|
|
39
|
+
if (consentAt !== undefined)
|
|
40
|
+
say(` The gift terms were agreed to on ${new Date(consentAt).toISOString().slice(0, 10)}.`);
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
const tenths = wanted === "off" || wanted === "0" ? 0 : tenthsFromPercent(Number(wanted));
|
|
44
|
+
if (wanted !== "off" && !/^\d+(\.\d+)?$/.test(wanted)) {
|
|
45
|
+
throw new NmtsError(`\`${BINARY_NAME} tip\` takes a percent (2.5) or off.`, { exitCode: 2 });
|
|
46
|
+
}
|
|
47
|
+
if (list.manifest === null) {
|
|
48
|
+
throw new NmtsError(`This account has no file list yet; the setting lives in the list, and there is nothing to write it into.`, {
|
|
49
|
+
exitCode: 4,
|
|
50
|
+
nextStep: `Upload once (\`${BINARY_NAME} put\`) and set it after.`,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
// ⛔ THE AGREEMENT — the `donate` unlock — stands between 0 and anything above it, once per machine.
|
|
54
|
+
if (tenths > 0)
|
|
55
|
+
requireConsent("donate");
|
|
56
|
+
if (needsExtraConfirm(tenths) && options.yes !== true) {
|
|
57
|
+
const ask = options.readLine ?? promptLine;
|
|
58
|
+
if (options.readLine === undefined && !stdinIsATerminal()) {
|
|
59
|
+
throw new NmtsError(`A share above ${percentText(TIP_DIAL_MAX_TENTHS)} % is confirmed by a person.`, {
|
|
60
|
+
exitCode: 5,
|
|
61
|
+
nextStep: `Ask them, then run the same command with --yes.`,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
const answer = (await ask(`Send ${percentText(tenths)} % of EVERY storage payment to the developer, permanently, until you change it? [y/N] `)).trim();
|
|
65
|
+
if (answer !== "y" && answer !== "Y") {
|
|
66
|
+
say(`Nothing changed.`);
|
|
67
|
+
return 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const patch = { tipTenths: tenths };
|
|
71
|
+
if (tenths > 0 && consentAt === undefined)
|
|
72
|
+
patch.tipConsentAt = options.now ?? Date.now();
|
|
73
|
+
const result = await applyManyToList(session, () => [], patch);
|
|
74
|
+
if (options.json === true) {
|
|
75
|
+
say(JSON.stringify({ tipPercent: Number(percentText(tenths)), tipTenths: tenths, changed: result.changed }));
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
if (!result.changed)
|
|
79
|
+
say(`Already ${tenths === 0 ? "off" : `${percentText(tenths)} %`}. Nothing changed.`);
|
|
80
|
+
else if (tenths === 0)
|
|
81
|
+
say(`Standing gift set to 0 %: nothing more is sent after a payment.`);
|
|
82
|
+
else
|
|
83
|
+
say(`Standing gift set: every storage payment now sends ${percentText(tenths)} % of what it paid to the developer, in WAL, without asking.`);
|
|
84
|
+
say(` Thank you.`);
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ManifestEntry } from "../shared/lib/drive/manifest-codec.ts";
|
|
2
|
+
export interface TrashOptions {
|
|
3
|
+
server?: string | undefined;
|
|
4
|
+
network?: string | undefined;
|
|
5
|
+
json?: boolean;
|
|
6
|
+
write?: (line: string) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function rm(paths: readonly string[], options?: TrashOptions): Promise<number>;
|
|
9
|
+
export declare function restore(paths: readonly string[], options?: TrashOptions): Promise<number>;
|
|
10
|
+
/**
|
|
11
|
+
* Every file at or under one entry.
|
|
12
|
+
*
|
|
13
|
+
* ⚠ Trashed descendants are INCLUDED HERE, and the CALLER filters. Somebody who trashed one file
|
|
14
|
+
* last week and then trashes its folder expects the folder to be gone from the server too — so
|
|
15
|
+
* `rm` takes this set whole. `restore` cannot: see the note at the call site.
|
|
16
|
+
*/
|
|
17
|
+
export declare function filesUnder(entries: readonly ManifestEntry[], rootId: string): ManifestEntry[];
|
package/dist/commands/trash.js
CHANGED
|
@@ -249,7 +249,7 @@ function uniqueById(files) {
|
|
|
249
249
|
* last week and then trashes its folder expects the folder to be gone from the server too — so
|
|
250
250
|
* `rm` takes this set whole. `restore` cannot: see the note at the call site.
|
|
251
251
|
*/
|
|
252
|
-
function filesUnder(entries, rootId) {
|
|
252
|
+
export function filesUnder(entries, rootId) {
|
|
253
253
|
const root = entries.find((e) => e.id === rootId);
|
|
254
254
|
if (root === undefined)
|
|
255
255
|
return [];
|
package/dist/commands/trial.js
CHANGED
|
@@ -17,13 +17,13 @@
|
|
|
17
17
|
// person — which sends an agent to make another key, the one thing that cannot help. So the
|
|
18
18
|
// standing check is asked about first, and the answer names `nmts verify`.
|
|
19
19
|
//
|
|
20
|
-
// ⛔ AND APPLYING ASKS FOR
|
|
21
|
-
// fresh browser check
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
20
|
+
// ⛔ AND APPLYING ASKS FOR NO BROWSER TOKEN OF ITS OWN (2026-09-06). `POST
|
|
21
|
+
// /v1/trial/apply` used to run a fresh browser check on every application, which closed the
|
|
22
|
+
// route to this tool completely: a command line has no browser, so the application was refused
|
|
23
|
+
// however good the credentials were. The server now reads the account's four-week check as the
|
|
24
|
+
// human evidence a key carries, so applying works exactly while that check is live — the same
|
|
25
|
+
// condition the pre-check above already asks about, and the one `nmts verify` renews. Nothing
|
|
26
|
+
// here produces a token, and nothing here needs to.
|
|
27
27
|
import { request, ServerError } from "../api.js";
|
|
28
28
|
import { readCredentialsFile } from "../credentials.js";
|
|
29
29
|
import { NmtsError } from "../errors.js";
|
|
@@ -134,18 +134,16 @@ function explain(error, week) {
|
|
|
134
134
|
// screen that is refusing for the same reason.
|
|
135
135
|
case "TURNSTILE_FAILED":
|
|
136
136
|
// ⛔ THE ADVICE `api.ts` CARRIES FOR THIS CODE IS THE WRONG ONE HERE, and that is why this
|
|
137
|
-
// case exists. It says
|
|
138
|
-
//
|
|
139
|
-
// credential
|
|
140
|
-
|
|
141
|
-
return new NmtsError("This server asks every application for a browser check, and a command line has none.", {
|
|
137
|
+
// case exists. It says a machine credential is what waives the check; on this route what
|
|
138
|
+
// waives it is the account's four-week check, and a caller sent to make another
|
|
139
|
+
// credential would make one and be refused again.
|
|
140
|
+
return new NmtsError("This server asked this application for a browser check of its own.", {
|
|
142
141
|
exitCode: 4,
|
|
143
|
-
nextStep: `Nothing was taken and this account's place for week ${week.round} is untouched.
|
|
144
|
-
`
|
|
145
|
-
`
|
|
146
|
-
`
|
|
147
|
-
|
|
148
|
-
`in for this one.`,
|
|
142
|
+
nextStep: `Nothing was taken and this account's place for week ${week.round} is untouched. ` +
|
|
143
|
+
`Applying needs the account's four-week check to be live, and \`${BINARY_NAME} verify\` ` +
|
|
144
|
+
`is what renews it: it prints a short code for a person to type at a browser. A server ` +
|
|
145
|
+
`that asks for a check on every application is an older build than this expects — ` +
|
|
146
|
+
`there, a person applies on the account screen at ${HOME_URL}.`,
|
|
149
147
|
});
|
|
150
148
|
case "TRIAL_FULL":
|
|
151
149
|
return new NmtsError("Every place in this week is taken.", {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface UnlockOptions {
|
|
2
|
+
json?: boolean;
|
|
3
|
+
write?: (line: string) => void;
|
|
4
|
+
/** The clock. Injected so a test asserts a real timestamp rather than tolerating any string. */
|
|
5
|
+
now?: () => Date;
|
|
6
|
+
/** Injected in tests: answers the one question. Its presence also stands in for a terminal. */
|
|
7
|
+
readLine?: ((question: string) => Promise<string>) | undefined;
|
|
8
|
+
/** `unlock wallet` only — see `wallet-grant.ts`. */
|
|
9
|
+
days?: string | undefined;
|
|
10
|
+
until?: string | undefined;
|
|
11
|
+
scope?: string | undefined;
|
|
12
|
+
capWal?: string | undefined;
|
|
13
|
+
capSui?: string | undefined;
|
|
14
|
+
}
|
|
15
|
+
/** `unlock` · `lock` · the list. `action` is already normalised by the caller (`grant` → `unlock`). */
|
|
16
|
+
export declare function unlock(action: string | undefined, target: string | undefined, options?: UnlockOptions): Promise<number>;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// `nmts unlock` — what this machine's owner has opened, and the one way to open more.
|
|
2
|
+
//
|
|
3
|
+
// ⛔ IT IS A COMMAND AND NOT A PROMPT. A yes/no question in the middle of another command cannot be
|
|
4
|
+
// answered by anything that is not a terminal, which is most of the places this tool runs: a
|
|
5
|
+
// container, a build step, an agent's subprocess. Making the unlock its own command means the
|
|
6
|
+
// same answer works everywhere, is recorded with a date, and can be looked at afterwards.
|
|
7
|
+
//
|
|
8
|
+
// ⛔ A PERSON UNLOCKS, AT A TERMINAL. Opening a lock refuses when stdin is not a terminal — the way
|
|
9
|
+
// an agent's subprocess usually arrives — and prints what the lock guards before it asks. The one
|
|
10
|
+
// mode that may unlock without a terminal is skip-permissions: the person who turned it on said
|
|
11
|
+
// nothing is to ask them. Locking again is one line from anywhere: the safe direction is never
|
|
12
|
+
// harder than the risky one.
|
|
13
|
+
//
|
|
14
|
+
// `nmts consent` is the older name for the same thing and still works: `grant` is `unlock`, `revoke`
|
|
15
|
+
// is `lock`.
|
|
16
|
+
import { currentMode } from "../autonomy.js";
|
|
17
|
+
import { CONSENTS, CONSENT_KEYS, grant, grantedAt, revoke } from "../consent.js";
|
|
18
|
+
import { NmtsError } from "../errors.js";
|
|
19
|
+
import { BINARY_NAME, SUPPORT_EMAIL, VERSION } from "../product.js";
|
|
20
|
+
import { promptLine, stdinIsATerminal } from "../prompt.js";
|
|
21
|
+
import { coinAmount } from "../wallet.js";
|
|
22
|
+
import { parseWalletGrant, readWalletGrant, walletGrantState, writeWalletGrant } from "../wallet-grant.js";
|
|
23
|
+
function isKey(value) {
|
|
24
|
+
return CONSENT_KEYS.includes(value);
|
|
25
|
+
}
|
|
26
|
+
function keyOrFail(raw) {
|
|
27
|
+
if (raw === undefined || raw === "") {
|
|
28
|
+
throw new NmtsError("Say which one.", { exitCode: 2, nextStep: `One of: ${CONSENT_KEYS.join(" · ")}` });
|
|
29
|
+
}
|
|
30
|
+
if (!isKey(raw)) {
|
|
31
|
+
throw new NmtsError(`There is nothing called "${raw}" to unlock.`, {
|
|
32
|
+
exitCode: 2,
|
|
33
|
+
nextStep: `One of: ${CONSENT_KEYS.join(" · ")}`,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return raw;
|
|
37
|
+
}
|
|
38
|
+
/** `unlock` · `lock` · the list. `action` is already normalised by the caller (`grant` → `unlock`). */
|
|
39
|
+
export async function unlock(action, target, options = {}) {
|
|
40
|
+
const say = options.write ?? ((line) => process.stdout.write(`${line}\n`));
|
|
41
|
+
const now = options.now ?? (() => new Date());
|
|
42
|
+
if (action === undefined || action === "" || action === "list") {
|
|
43
|
+
if (options.json) {
|
|
44
|
+
say(JSON.stringify(CONSENT_KEYS.map((key) => row(key, now()))));
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
for (const key of CONSENT_KEYS) {
|
|
48
|
+
if (key === "wallet") {
|
|
49
|
+
for (const line of walletLines(now()))
|
|
50
|
+
say(line);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const at = grantedAt(key);
|
|
54
|
+
say(`${at === null ? " locked " : " unlocked "} ${key}`);
|
|
55
|
+
say(` ${CONSENTS[key].what}`);
|
|
56
|
+
if (at !== null)
|
|
57
|
+
say(` unlocked on this machine ${at}`);
|
|
58
|
+
say(``);
|
|
59
|
+
}
|
|
60
|
+
say(` ${BINARY_NAME} unlock <name> open one, at a terminal, once`);
|
|
61
|
+
say(` ${BINARY_NAME} lock <name> close it again`);
|
|
62
|
+
say(``);
|
|
63
|
+
say(` Unlocking here does not change what the published Terms say. NMTS is not responsible`);
|
|
64
|
+
say(` for what any program on this machine does with this account, an AI agent included.`);
|
|
65
|
+
say(` Something wrong or confusing? ${SUPPORT_EMAIL}`);
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
if (action === "unlock") {
|
|
69
|
+
const key = keyOrFail(target);
|
|
70
|
+
if (options.readLine === undefined && !stdinIsATerminal() && currentMode() !== "skip-permissions") {
|
|
71
|
+
throw new NmtsError(`A person unlocks, at a terminal — stdin here is not one.`, {
|
|
72
|
+
exitCode: 5,
|
|
73
|
+
nextStep: `If you are an agent: do not unlock things. Show the person what \`${BINARY_NAME} unlock\` ` +
|
|
74
|
+
`prints for "${key}" and let them decide.`,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const c = CONSENTS[key];
|
|
78
|
+
// ⚠ A wrong command line is refused BEFORE the question, so nobody answers y to nothing.
|
|
79
|
+
const wallet = key === "wallet" ? parseWalletGrant(options, now(), VERSION) : null;
|
|
80
|
+
say(c.what);
|
|
81
|
+
say(` ${c.risk}`);
|
|
82
|
+
say(` ${c.limit}`);
|
|
83
|
+
if (currentMode() !== "skip-permissions") {
|
|
84
|
+
const ask = options.readLine ?? promptLine;
|
|
85
|
+
const answer = (await ask(`Unlock ${key} on this machine? [y/N] `)).trim();
|
|
86
|
+
if (answer !== "y" && answer !== "Y") {
|
|
87
|
+
say(`Nothing was unlocked.`);
|
|
88
|
+
return 1;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (wallet !== null) {
|
|
92
|
+
// ⛔ Not a bare date: scope, expiry and ceilings.
|
|
93
|
+
writeWalletGrant(wallet);
|
|
94
|
+
say(`unlocked: wallet — scope ${wallet.scope}, until ${wallet.expiresAt}`);
|
|
95
|
+
say(` ${ceilingWords(wallet.capWalFrost, wallet.capSuiMist)}`);
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
98
|
+
grant(key, VERSION, now());
|
|
99
|
+
say(`unlocked: ${key}`);
|
|
100
|
+
return 0;
|
|
101
|
+
}
|
|
102
|
+
if (action === "lock") {
|
|
103
|
+
const key = keyOrFail(target);
|
|
104
|
+
revoke(key);
|
|
105
|
+
say(`locked: ${key}`);
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
108
|
+
throw new NmtsError(`Unknown: ${BINARY_NAME} unlock ${action}`, {
|
|
109
|
+
exitCode: 2,
|
|
110
|
+
nextStep: `Try \`${BINARY_NAME} unlock\`, \`${BINARY_NAME} unlock <name>\`, or \`${BINARY_NAME} lock <name>\`.`,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function row(key, now) {
|
|
114
|
+
if (key === "wallet") {
|
|
115
|
+
const g = readWalletGrant();
|
|
116
|
+
const state = walletGrantState(g, now);
|
|
117
|
+
return {
|
|
118
|
+
key,
|
|
119
|
+
unlocked: state === "active",
|
|
120
|
+
state,
|
|
121
|
+
unlockedAt: g?.grantedAt ?? null,
|
|
122
|
+
expiresAt: g?.expiresAt ?? null,
|
|
123
|
+
scope: g?.scope ?? null,
|
|
124
|
+
capWalFrost: g?.capWalFrost ?? null,
|
|
125
|
+
capSuiMist: g?.capSuiMist ?? null,
|
|
126
|
+
spentWalFrost: g?.spentWalFrost ?? null,
|
|
127
|
+
spentSuiMist: g?.spentSuiMist ?? null,
|
|
128
|
+
what: CONSENTS[key].what,
|
|
129
|
+
risk: CONSENTS[key].risk,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return { key, unlocked: grantedAt(key) !== null, unlockedAt: grantedAt(key), what: CONSENTS[key].what, risk: CONSENTS[key].risk };
|
|
133
|
+
}
|
|
134
|
+
/** The wallet row of the list: state, scope, expiry, ceilings and what was signed under it. */
|
|
135
|
+
function walletLines(now) {
|
|
136
|
+
const g = readWalletGrant();
|
|
137
|
+
const state = walletGrantState(g, now);
|
|
138
|
+
const head = state === "active" ? " unlocked " : state === "expired" ? " ran out " : " locked ";
|
|
139
|
+
const out = [`${head} wallet`, ` ${CONSENTS.wallet.what}`];
|
|
140
|
+
if (g !== null) {
|
|
141
|
+
out.push(` scope ${g.scope} · unlocked ${g.grantedAt} · ${state === "expired" ? "ran out" : "until"} ${g.expiresAt}`);
|
|
142
|
+
out.push(` ${ceilingWords(g.capWalFrost, g.capSuiMist)} · signed away so far ${coinAmount(BigInt(g.spentWalFrost))} WAL, ${coinAmount(BigInt(g.spentSuiMist))} SUI in fees`);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
out.push(` ${BINARY_NAME} unlock wallet --days <1..30> [--scope storage|all] [--cap-wal <coins> --cap-sui <coins>]`);
|
|
146
|
+
}
|
|
147
|
+
out.push(``);
|
|
148
|
+
return out;
|
|
149
|
+
}
|
|
150
|
+
function ceilingWords(capWal, capSui) {
|
|
151
|
+
if (capWal === null && capSui === null)
|
|
152
|
+
return "no ceiling on what this tool may sign away";
|
|
153
|
+
const parts = [];
|
|
154
|
+
if (capWal !== null)
|
|
155
|
+
parts.push(`${coinAmount(BigInt(capWal))} WAL`);
|
|
156
|
+
if (capSui !== null)
|
|
157
|
+
parts.push(`${coinAmount(BigInt(capSui))} SUI`);
|
|
158
|
+
return `ceiling ${parts.join(" and ")}`;
|
|
159
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { lookupLatest } from "../update-check.ts";
|
|
2
|
+
export interface UpdateOptions {
|
|
3
|
+
json?: boolean;
|
|
4
|
+
/** Say what it would install, and stop. */
|
|
5
|
+
dryRun?: boolean;
|
|
6
|
+
write?: (line: string) => void;
|
|
7
|
+
/** Injected in tests, so the whole command can run without a host. */
|
|
8
|
+
lookup?: typeof lookupLatest;
|
|
9
|
+
/** Injected in tests. What is running now. */
|
|
10
|
+
running?: string;
|
|
11
|
+
/**
|
|
12
|
+
* The file this module was loaded from — the basis for "was this copy installed".
|
|
13
|
+
*
|
|
14
|
+
* ⚠ Injected rather than read straight from `import.meta` so both answers can be tested on one
|
|
15
|
+
* machine. Nothing on a command line reaches it.
|
|
16
|
+
*/
|
|
17
|
+
moduleFile?: string;
|
|
18
|
+
/** Injected in tests. Runs the installer and reports how it went. */
|
|
19
|
+
install?: (command: readonly string[], json: boolean) => InstallOutcome;
|
|
20
|
+
}
|
|
21
|
+
/** What running the installer produced. */
|
|
22
|
+
export interface InstallOutcome {
|
|
23
|
+
code: number;
|
|
24
|
+
/** What it said, when its output was captured rather than passed through. */
|
|
25
|
+
output?: string;
|
|
26
|
+
/** Why it could not be started at all. */
|
|
27
|
+
unstartable?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Was this copy put here by the installer that would replace it?
|
|
31
|
+
*
|
|
32
|
+
* The test is the one thing that is actually true of every such copy and of nothing else: it
|
|
33
|
+
* lives in a directory named for the package, inside a `node_modules`.
|
|
34
|
+
*
|
|
35
|
+
* ⛔ BOTH SEPARATORS, AND THAT IS NOT DEFENSIVENESS. Windows accepts either, and Node hands out
|
|
36
|
+
* either: a path that came through a file URL arrives as `D:/a/…` while `import.meta.filename`
|
|
37
|
+
* gives `D:\a\…`. Splitting on the platform's own separator found nothing in the first shape,
|
|
38
|
+
* so an installed copy on Windows was told it was not installed and `update` refused to run —
|
|
39
|
+
* green on Linux and macOS, red only on the platform this repository tests last.
|
|
40
|
+
*/
|
|
41
|
+
export declare function installedAsPackage(moduleFile: string): boolean;
|
|
42
|
+
export declare function update(options?: UpdateOptions): Promise<number>;
|
package/dist/commands/update.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// directories in an environment variable. That is the kind of confusion somebody debugs for an
|
|
19
19
|
// hour, so it is a refusal that says what to run instead.
|
|
20
20
|
//
|
|
21
|
-
// ⛔ IT ASKS THE SOURCE-HOSTING SITE, NOT NMTS. No
|
|
21
|
+
// ⛔ IT ASKS THE SOURCE-HOSTING SITE, NOT NMTS. No NMTS key, no API key, no session; the
|
|
22
22
|
// command works signed out, and it is one of the two places in this tool that talk to a host
|
|
23
23
|
// other than the NMTS server and the storage network. The other is `nmts recovery`.
|
|
24
24
|
import { spawnSync } from "node:child_process";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface UsageOptions {
|
|
2
|
+
server?: string | undefined;
|
|
3
|
+
network?: string | undefined;
|
|
4
|
+
/** Machine-readable output. For an agent this is the shape to parse; the table is for a person. */
|
|
5
|
+
json?: boolean;
|
|
6
|
+
write?: (line: string) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function usage(options?: UsageOptions): Promise<number>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface VerifyOptions {
|
|
2
|
+
server?: string | undefined;
|
|
3
|
+
json?: boolean;
|
|
4
|
+
/** Ask whether the check is live, print the answer, and mint nothing. */
|
|
5
|
+
status?: boolean;
|
|
6
|
+
write?: (line: string) => void;
|
|
7
|
+
/**
|
|
8
|
+
* The wait between asks. Injected by tests so they do not spend the real interval.
|
|
9
|
+
*
|
|
10
|
+
* ⚠ It resolves rather than rejects when the wait is cut short. What cancelling MEANS is decided
|
|
11
|
+
* in one place below, after the wait, so that an abort during a request and an abort during a
|
|
12
|
+
* wait end the same way.
|
|
13
|
+
*/
|
|
14
|
+
sleep?: (ms: number, signal: AbortSignal) => Promise<void>;
|
|
15
|
+
/** A caller's own reason to stop waiting. Joined with the interrupt key. */
|
|
16
|
+
signal?: AbortSignal | undefined;
|
|
17
|
+
}
|
|
18
|
+
export declare function verify(options?: VerifyOptions): Promise<number>;
|
package/dist/commands/verify.js
CHANGED
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
// the doing is theirs, the waiting is ours, and saying it any other way would be a lie about
|
|
10
10
|
// what a program can do.
|
|
11
11
|
//
|
|
12
|
-
// ⛔ THE CODE IS PRINTED ON PURPOSE, AND IT IS NOT THE
|
|
12
|
+
// ⛔ THE CODE IS PRINTED ON PURPOSE, AND IT IS NOT THE NMTS KEY. Everything else in this tool
|
|
13
13
|
// refuses to put a credential on the screen. This one is minted to be read out: it is single
|
|
14
14
|
// use, it stops working within minutes, the server keeps only a hash of it, and by itself it
|
|
15
|
-
// opens nothing — a person still has to pass the check on the page. The
|
|
15
|
+
// opens nothing — a person still has to pass the check on the page. The NMTS key is a
|
|
16
16
|
// different thing entirely and still never appears here, which the text says out loud so that
|
|
17
17
|
// nobody reads "type this code" and reaches for the wrong one.
|
|
18
18
|
//
|
|
@@ -23,8 +23,11 @@
|
|
|
23
23
|
// two answers to one question start. The honest thing is the absolute moment, and then whoever
|
|
24
24
|
// is reading decides.
|
|
25
25
|
//
|
|
26
|
-
// ⚠ IT NEEDS THE API KEY AND NOT THE
|
|
27
|
-
// code would refuse a run over a credential the command never uses.
|
|
26
|
+
// ⚠ IT NEEDS THE API KEY AND NOT THE NMTS KEY. Nothing here opens a file, so demanding the
|
|
27
|
+
// code would refuse a run over a credential the command never uses. The PAGE, since 2026-09-05,
|
|
28
|
+
// does want the account's holder — signed in there, or typing the NMTS key there — because
|
|
29
|
+
// a check anybody could pass for anybody was a check that could be bought; that is said to the
|
|
30
|
+
// person in the printed text, and it changes nothing about what this command holds.
|
|
28
31
|
import { request } from "../api.js";
|
|
29
32
|
import { readCredentialsFile } from "../credentials.js";
|
|
30
33
|
import { NmtsError } from "../errors.js";
|
|
@@ -92,8 +95,9 @@ export async function verify(options = {}) {
|
|
|
92
95
|
human(` Ask the person to open ${minted.verifyUrl}`);
|
|
93
96
|
human(` and to type this code ${minted.code}`);
|
|
94
97
|
human(``);
|
|
95
|
-
human(`
|
|
96
|
-
human(
|
|
98
|
+
human(`Only this account's holder can confirm: signed in to it in that browser, or`);
|
|
99
|
+
human(`typing its NMTS key there. The code above is not the NMTS key. It works`);
|
|
100
|
+
human(`once, and it stops working at ${minted.expiresAt.iso} (${inWords(minted.expiresAt.ms - Date.now())}).`);
|
|
97
101
|
human(``);
|
|
98
102
|
human(`Waiting here until it is used. Ctrl-C stops the waiting, not the code.`);
|
|
99
103
|
const wait = options.sleep ?? waitFor;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type Network } from "../network.ts";
|
|
2
|
+
import { type ActivityContext, type RpcTransaction } from "../shared/lib/wallet/activity.ts";
|
|
3
|
+
/** How many to ask for in each direction, and how many to print after the merge. */
|
|
4
|
+
export declare const FETCH_PER_DIRECTION = 25;
|
|
5
|
+
export declare const SHOW = 20;
|
|
6
|
+
/** The two lists the chain answers with. */
|
|
7
|
+
export interface ActivityFetch {
|
|
8
|
+
sent: readonly RpcTransaction[];
|
|
9
|
+
received: readonly RpcTransaction[];
|
|
10
|
+
}
|
|
11
|
+
export interface WalletActivityOptions {
|
|
12
|
+
server?: string | undefined;
|
|
13
|
+
network?: string | undefined;
|
|
14
|
+
json?: boolean;
|
|
15
|
+
write?: (line: string) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Where the transactions come from.
|
|
18
|
+
*
|
|
19
|
+
* ⚠ A SEAM, NOT AN OPTION: no flag reaches it. A test that talked to a live chain could not run
|
|
20
|
+
* offline and could never be asked to fail on purpose.
|
|
21
|
+
*/
|
|
22
|
+
queryChain?: (network: Network, address: string) => Promise<ActivityFetch>;
|
|
23
|
+
}
|
|
24
|
+
/** What the judgement compares against on this network. Donation and pool addresses: unknown here. */
|
|
25
|
+
export declare function activityContext(network: Network, address: string): ActivityContext;
|
|
26
|
+
export declare function walletActivity(options?: WalletActivityOptions): Promise<number>;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// `nmts wallet activity` — the recent transactions of the wallet this NMTS key derives.
|
|
2
|
+
//
|
|
3
|
+
// ⛔ IT READS. The chain is asked twice (sent, received — the RPC filter has no OR), the rows are
|
|
4
|
+
// named by the SAME judgement the browser uses (`shared/lib/wallet/activity.ts`, copied
|
|
5
|
+
// byte-for-byte), and nothing here signs or spends.
|
|
6
|
+
//
|
|
7
|
+
// ⛔ A NAME IS PUT ONLY WHERE A CONSTANT PROVES IT. What this tool cannot prove it prints as
|
|
8
|
+
// "other" — with the time, the balance changes and the chain link still there. Two things the
|
|
9
|
+
// browser knows and this tool does not: the developer's donation address and the free-trial
|
|
10
|
+
// pool's, which the server keeps to itself. So here a gift shows as a plain send, and a fee the
|
|
11
|
+
// pool paid shows as paid by "another address". Both are said below the list, once.
|
|
12
|
+
//
|
|
13
|
+
// ⛔ AN UNANSWERED CHAIN IS NOT AN EMPTY LIST. A read that fails exits non-zero and says so; the
|
|
14
|
+
// empty list is printed only when the chain answered and had nothing.
|
|
15
|
+
import { MAINNET_WALRUS_PACKAGE_CONFIG, TESTNET_WALRUS_PACKAGE_CONFIG } from "@mysten/walrus";
|
|
16
|
+
import { requireAccountCode } from "../code-access.js";
|
|
17
|
+
import { readCredentialsFile } from "../credentials.js";
|
|
18
|
+
import { NmtsError } from "../errors.js";
|
|
19
|
+
import { resolveNetwork } from "../network.js";
|
|
20
|
+
import { BINARY_NAME } from "../product.js";
|
|
21
|
+
import { resolveServer } from "../server.js";
|
|
22
|
+
import { mergeActivity, toActivityRow, } from "../shared/lib/wallet/activity.js";
|
|
23
|
+
import { BLUEFIN_PACKAGE_IDS, DEEPBOOK_PACKAGE_IDS } from "../shared/lib/wallet/venue-ids.js";
|
|
24
|
+
import { coinAmount, walCoinType, walletAddress } from "../wallet.js";
|
|
25
|
+
/** How many to ask for in each direction, and how many to print after the merge. */
|
|
26
|
+
export const FETCH_PER_DIRECTION = 25;
|
|
27
|
+
export const SHOW = 20;
|
|
28
|
+
/** What the judgement compares against on this network. Donation and pool addresses: unknown here. */
|
|
29
|
+
export function activityContext(network, address) {
|
|
30
|
+
const walrus = network === "mainnet" ? MAINNET_WALRUS_PACKAGE_CONFIG : TESTNET_WALRUS_PACKAGE_CONFIG;
|
|
31
|
+
return {
|
|
32
|
+
address,
|
|
33
|
+
donationAddresses: [],
|
|
34
|
+
poolAddress: "",
|
|
35
|
+
walCoinType: walCoinType(network),
|
|
36
|
+
walrusSystemObjectId: walrus.systemObjectId,
|
|
37
|
+
deepbookPackageId: DEEPBOOK_PACKAGE_IDS[network],
|
|
38
|
+
bluefinPackageId: BLUEFIN_PACKAGE_IDS[network],
|
|
39
|
+
exchangeObjectId: network === "testnet" ? (TESTNET_WALRUS_PACKAGE_CONFIG.exchangeIds[0] ?? null) : null,
|
|
40
|
+
network,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export async function walletActivity(options = {}) {
|
|
44
|
+
const say = options.write ?? ((line) => process.stdout.write(`${line}\n`));
|
|
45
|
+
const resolved = await requireAccountCode();
|
|
46
|
+
const address = await walletAddress(resolved.code);
|
|
47
|
+
const stored = resolved.source === "file" || resolved.source === "file-locked" ? readCredentialsFile() : null;
|
|
48
|
+
const server = resolveServer(options.server ?? stored?.server);
|
|
49
|
+
const network = resolveNetwork(server, options.network ?? stored?.network);
|
|
50
|
+
const query = options.queryChain ?? (async (net, addr) => (await import("../wallet-activity-chain.js")).queryActivity(net, addr));
|
|
51
|
+
let fetched;
|
|
52
|
+
try {
|
|
53
|
+
fetched = await query(network, address);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
throw new NmtsError("The wallet's transactions could not be read from the chain.", {
|
|
57
|
+
exitCode: 1,
|
|
58
|
+
nextStep: `Nothing is known about this wallet's activity from here — that is not the same as there ` +
|
|
59
|
+
`being none. \`${BINARY_NAME} env\` says which network was asked. ` +
|
|
60
|
+
`Cause: ${error instanceof Error ? error.message : String(error)}`,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const ctx = activityContext(network, address);
|
|
64
|
+
const rows = mergeActivity([fetched.sent.map((tx) => toActivityRow(tx, ctx)), fetched.received.map((tx) => toActivityRow(tx, ctx))], SHOW);
|
|
65
|
+
if (options.json) {
|
|
66
|
+
say(JSON.stringify({ address, network, shown: rows.length, rows: rows.map(asJson) }));
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
say(`Address ${address}`);
|
|
70
|
+
say(`Network ${network}`);
|
|
71
|
+
say(``);
|
|
72
|
+
if (rows.length === 0) {
|
|
73
|
+
say(` The chain answered and lists no transaction for this wallet.`);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
for (const row of rows)
|
|
77
|
+
say(` ${inWords(row)}`);
|
|
78
|
+
}
|
|
79
|
+
say(``);
|
|
80
|
+
say(` The newest ${SHOW} at most; the chain link on each line shows the rest. A name is put only`);
|
|
81
|
+
say(` where the transaction proves it — the storage network's own calls, the two exchanges, a`);
|
|
82
|
+
say(` plain transfer. Anything else is "other". Gifts to the developer show here as sends, and a`);
|
|
83
|
+
say(` fee the free-trial pool paid shows as paid by another address: this tool does not know`);
|
|
84
|
+
say(` those two addresses.`);
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
87
|
+
/** An amount with its sign — `coinAmount` formats magnitudes, and a balance change has a direction. */
|
|
88
|
+
function signed(amount) {
|
|
89
|
+
return amount < 0n ? `-${coinAmount(-amount)}` : `+${coinAmount(amount)}`;
|
|
90
|
+
}
|
|
91
|
+
/** One row, for a person: when · what · how much of which coin · who paid the fee · the link. */
|
|
92
|
+
function inWords(row) {
|
|
93
|
+
const when = row.atMs === null ? "time unknown " : new Date(row.atMs).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
94
|
+
const changes = row.changes.length === 0
|
|
95
|
+
? "no balance change"
|
|
96
|
+
: row.changes.map((c) => `${signed(c.amount)} ${c.coin ?? c.coinType}`).join(", ");
|
|
97
|
+
const fee = row.gasPayer === "self" ? "" : " fee paid by another address";
|
|
98
|
+
const failed = row.failed ? " ⛔ FAILED on chain" : "";
|
|
99
|
+
return `${when} ${row.kind.padEnd(8)} ${changes}${fee}${failed}\n ${row.explorerUrl}`;
|
|
100
|
+
}
|
|
101
|
+
/** One row, for a program. ⚠ Amounts are strings: base units run past what a JSON number keeps. */
|
|
102
|
+
function asJson(row) {
|
|
103
|
+
return {
|
|
104
|
+
digest: row.digest,
|
|
105
|
+
at: row.atMs === null ? null : new Date(row.atMs).toISOString(),
|
|
106
|
+
kind: row.kind,
|
|
107
|
+
failed: row.failed,
|
|
108
|
+
gasPayer: row.gasPayer,
|
|
109
|
+
changes: row.changes.map((c) => ({
|
|
110
|
+
coin: c.coin,
|
|
111
|
+
coinType: c.coinType,
|
|
112
|
+
baseUnits: c.amount.toString(),
|
|
113
|
+
amount: signed(c.amount),
|
|
114
|
+
})),
|
|
115
|
+
explorerUrl: row.explorerUrl,
|
|
116
|
+
};
|
|
117
|
+
}
|