@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,180 @@
|
|
|
1
|
+
// `nmts losses` — the storage bought with this account's credits that the chain no longer knows.
|
|
2
|
+
//
|
|
3
|
+
// ⛔ IT REPORTS, IT DOES NOT REPAIR. Once the chain has stopped serving a storage object nothing
|
|
4
|
+
// this tool or the server does brings the bytes back, and the row is the record of a purchase
|
|
5
|
+
// that produced nothing. What the command is for is that somebody finds out from us rather
|
|
6
|
+
// than from a download that stops coming back.
|
|
7
|
+
//
|
|
8
|
+
// ⛔ THERE IS NO FILE NAME AND THERE CANNOT BE ONE. The answer names on-chain STORAGE OBJECTS; the
|
|
9
|
+
// pairing that would resolve one to a file is server-side, has no route, and the drive's own
|
|
10
|
+
// list is sealed with a key the server never sees. Printing a guessed name would be worse than
|
|
11
|
+
// printing none, so the line prints the public object id and says why that is all there is.
|
|
12
|
+
//
|
|
13
|
+
// ⚠ AN EMPTY LIST IS NOT "NOTHING IS GONE". The daily round samples fifty objects at random, so an
|
|
14
|
+
// object nobody has drawn yet has not been asked about. The route's own note says a client must
|
|
15
|
+
// not print the second sentence, and the wording here does not.
|
|
16
|
+
//
|
|
17
|
+
// ⛔ THE THREE ACTS ARE ONE COMMAND BECAUSE THEY ARE ONE SUBJECT, and exactly one of them runs per
|
|
18
|
+
// call. Re-checking asks the chain the same question the daily round asks, now. Dismissing is a
|
|
19
|
+
// person saying they have read the line — see the mode check below, which is the reason this
|
|
20
|
+
// command imports the autonomy module at all.
|
|
21
|
+
import { request, ServerError } from "../api.js";
|
|
22
|
+
import { NmtsError } from "../errors.js";
|
|
23
|
+
import { isRecord } from "../guards.js";
|
|
24
|
+
import { BINARY_NAME } from "../product.js";
|
|
25
|
+
import { openSession } from "../session.js";
|
|
26
|
+
/**
|
|
27
|
+
* The refusal for an id this account holds no line for.
|
|
28
|
+
*
|
|
29
|
+
* ⛔ ONE TEXT FOR BOTH ARMS. The server answers 404 to a re-check and to a dismiss for the same
|
|
30
|
+
* reason — the account does not hold that loss — and two wordings for one cause is how a caller
|
|
31
|
+
* ends up branching on which command it happened to run.
|
|
32
|
+
*/
|
|
33
|
+
function noSuchLine(id) {
|
|
34
|
+
return new NmtsError(`NMTS holds no loss line for ${id} on this account.`, {
|
|
35
|
+
exitCode: 4,
|
|
36
|
+
nextStep: `Run \`${BINARY_NAME} losses\` to see the lines that exist.`,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/** `unknown` off the wire, read as the rows the route declares. */
|
|
40
|
+
function rowsOf(answer) {
|
|
41
|
+
const list = isRecord(answer) ? answer["losses"] : undefined;
|
|
42
|
+
if (!Array.isArray(list)) {
|
|
43
|
+
throw new NmtsError(`The server's answer did not carry a list of losses.`, {
|
|
44
|
+
exitCode: 1,
|
|
45
|
+
nextStep: `Nothing was changed. Report it rather than retrying — the shape, not the network, is wrong.`,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return list.map((row) => {
|
|
49
|
+
const id = isRecord(row) ? row["blob_object_id"] : undefined;
|
|
50
|
+
const seen = isRecord(row) ? row["first_seen"] : undefined;
|
|
51
|
+
const notice = isRecord(row) ? row["required_notice"] : undefined;
|
|
52
|
+
const restricted = isRecord(row) ? row["restricted"] : undefined;
|
|
53
|
+
if (typeof id !== "string" || typeof seen !== "string") {
|
|
54
|
+
throw new NmtsError(`The server listed a loss this version cannot read.`, {
|
|
55
|
+
exitCode: 1,
|
|
56
|
+
nextStep: `Nothing was changed. A newer version of this tool may understand it.`,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// ⚠ A flag that did not arrive as a boolean is read as false, and that is the only place here
|
|
60
|
+
// where a missing field is filled in: both mean "this line carries no extra sentence", and
|
|
61
|
+
// the sentences they add are additions to a line that is already correct without them.
|
|
62
|
+
return {
|
|
63
|
+
blob_object_id: id,
|
|
64
|
+
first_seen: seen,
|
|
65
|
+
required_notice: notice === true,
|
|
66
|
+
restricted: restricted === true,
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/** The UTC day of an RFC 3339 instant, `YYYY-MM-DD`. */
|
|
71
|
+
function utcDay(instant) {
|
|
72
|
+
const at = new Date(instant);
|
|
73
|
+
if (Number.isNaN(at.getTime())) {
|
|
74
|
+
throw new NmtsError(`The server dated a loss with something that is not a time.`, {
|
|
75
|
+
exitCode: 1,
|
|
76
|
+
nextStep: `Nothing was changed. Report it rather than retrying.`,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return at.toISOString().slice(0, 10);
|
|
80
|
+
}
|
|
81
|
+
export async function losses(options = {}) {
|
|
82
|
+
const say = options.write ?? ((line) => process.stdout.write(`${line}\n`));
|
|
83
|
+
if (options.recheck !== undefined && options.dismiss !== undefined) {
|
|
84
|
+
throw new NmtsError(`--recheck and --dismiss are two different acts, and one run does one.`, {
|
|
85
|
+
exitCode: 2,
|
|
86
|
+
nextStep: `Run one, read what it says, then run the other.`,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
const session = await openSession({ server: options.server, network: options.network });
|
|
90
|
+
if (options.recheck !== undefined) {
|
|
91
|
+
const id = options.recheck;
|
|
92
|
+
let answer;
|
|
93
|
+
try {
|
|
94
|
+
answer = await request(session.server, "/v1/storage-loss/recheck", {
|
|
95
|
+
token: session.apiKey,
|
|
96
|
+
method: "POST",
|
|
97
|
+
body: { blob_object_id: id },
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
if (error instanceof ServerError && error.status === 404)
|
|
102
|
+
throw noSuchLine(id);
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
const result = isRecord(answer) ? answer["result"] : undefined;
|
|
106
|
+
if (result !== "found" && result !== "still_missing" && result !== "unread") {
|
|
107
|
+
throw new NmtsError(`The server answered the re-check with something this version cannot read.`, {
|
|
108
|
+
exitCode: 1,
|
|
109
|
+
nextStep: `Nothing was decided about the storage. A newer version of this tool may understand it.`,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
const said = result;
|
|
113
|
+
if (options.json === true) {
|
|
114
|
+
say(JSON.stringify({ blob_object_id: id, result: said }));
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
if (said === "found")
|
|
118
|
+
say(`The chain knows ${id} again. Its line came off.`);
|
|
119
|
+
else if (said === "still_missing")
|
|
120
|
+
say(`The chain still does not know ${id}. The line stays.`);
|
|
121
|
+
else
|
|
122
|
+
say(`The chain could not be read just now. Nothing changed.`);
|
|
123
|
+
return 0;
|
|
124
|
+
}
|
|
125
|
+
if (options.dismiss !== undefined) {
|
|
126
|
+
const id = options.dismiss;
|
|
127
|
+
try {
|
|
128
|
+
await request(session.server, `/v1/storage-loss/${encodeURIComponent(id)}`, {
|
|
129
|
+
token: session.apiKey,
|
|
130
|
+
method: "DELETE",
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
if (error instanceof ServerError && error.status === 404)
|
|
135
|
+
throw noSuchLine(id);
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
if (options.json === true) {
|
|
139
|
+
say(JSON.stringify({ blob_object_id: id, dismissed: true }));
|
|
140
|
+
return 0;
|
|
141
|
+
}
|
|
142
|
+
say(`Took the line for ${id} off. The incident stays in a record that names nobody; if the same ` +
|
|
143
|
+
`storage is found and lost again, it is shown again.`);
|
|
144
|
+
return 0;
|
|
145
|
+
}
|
|
146
|
+
const answer = await request(session.server, "/v1/storage-loss", { token: session.apiKey });
|
|
147
|
+
if (options.json === true) {
|
|
148
|
+
// ⛔ THE SERVER'S OBJECT, UNCHANGED. A reader of this arm is reading the route, and a shape
|
|
149
|
+
// rewritten here would be a second wire to keep in step with the first.
|
|
150
|
+
say(JSON.stringify(answer));
|
|
151
|
+
return 0;
|
|
152
|
+
}
|
|
153
|
+
const rows = rowsOf(answer);
|
|
154
|
+
if (rows.length === 0) {
|
|
155
|
+
say(`The daily check has found nothing missing for this account.`);
|
|
156
|
+
say(`It samples the storage NMTS bought with your credits once a day and asks the chain whether ` +
|
|
157
|
+
`it is still there.`);
|
|
158
|
+
return 0;
|
|
159
|
+
}
|
|
160
|
+
say(rows.length === 1
|
|
161
|
+
? `The chain no longer knows one storage object your credits paid for. That is what the ` +
|
|
162
|
+
`check measured; it did not try the download. The file may no longer come back, and ` +
|
|
163
|
+
`NMTS cannot restore it.`
|
|
164
|
+
: `The chain no longer knows ${rows.length} storage objects your credits paid for. That is ` +
|
|
165
|
+
`what the check measured; it did not try the download. Those files may no longer come ` +
|
|
166
|
+
`back, and NMTS cannot restore them.`);
|
|
167
|
+
say(``);
|
|
168
|
+
for (const row of rows) {
|
|
169
|
+
say(`${row.blob_object_id} first missed ${utcDay(row.first_seen)}` +
|
|
170
|
+
(row.required_notice ? ` · shown because the law requires it` : ``) +
|
|
171
|
+
(row.restricted ? ` · kept but not used while you contest it` : ``));
|
|
172
|
+
}
|
|
173
|
+
say(``);
|
|
174
|
+
say(`The date is when a check first could not find it, not when the storage went. There is no ` +
|
|
175
|
+
`file name: the server cannot pair the object with a file, and NMTS cannot see inside files.`);
|
|
176
|
+
say(`\`${BINARY_NAME} losses --recheck <id>\` asks the chain again now. \`${BINARY_NAME} losses ` +
|
|
177
|
+
`--dismiss <id>\` takes a line off once you have read it; the incident stays in a record ` +
|
|
178
|
+
`that names nobody.`);
|
|
179
|
+
return 0;
|
|
180
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface LsOptions {
|
|
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
|
+
/** Include entries that are in the trash. */
|
|
7
|
+
all?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Keep only files whose name contains this text, case-insensitively.
|
|
10
|
+
*
|
|
11
|
+
* Taken as plain text rather than a parsed key so this command owns the refusal for a query that
|
|
12
|
+
* cannot mean anything — see `list-view-find.ts` for what a query does and does not match.
|
|
13
|
+
*/
|
|
14
|
+
find?: string | undefined;
|
|
15
|
+
/** `name`, `size` or `date`. Absent = the path order this command has always printed. */
|
|
16
|
+
sort?: string | undefined;
|
|
17
|
+
/** Reverse whichever order is in effect. */
|
|
18
|
+
desc?: boolean;
|
|
19
|
+
write?: (line: string) => void;
|
|
20
|
+
/** The instant the trash countdown is measured against. Passed in so one listing means one moment. */
|
|
21
|
+
now?: number;
|
|
22
|
+
}
|
|
23
|
+
export declare function ls(options?: LsOptions): Promise<number>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// The six mark verbs, dispatched here rather than in `main.ts`.
|
|
2
|
+
//
|
|
3
|
+
// ⛔ WHY A SECOND SWITCH. `main.ts` is measured (`check:size`) and had no room for `nmts support`;
|
|
4
|
+
// these six cases were the one contiguous block that shares a file, an option shape and a
|
|
5
|
+
// reason to be read together — `label --rename` and `unlabel --all` are sweeps over the whole
|
|
6
|
+
// account wearing the verbs of a per-file mark, and the guard that keeps them from being
|
|
7
|
+
// reached by accident is the comment below, which moved with them.
|
|
8
|
+
export async function runMarks(command, args) {
|
|
9
|
+
switch (command) {
|
|
10
|
+
case "star": {
|
|
11
|
+
const { star } = await import("./marks.js");
|
|
12
|
+
return await star(args.operands, { server: args.server, network: args.network, json: args.json });
|
|
13
|
+
}
|
|
14
|
+
case "unstar": {
|
|
15
|
+
const { unstar } = await import("./marks.js");
|
|
16
|
+
return await unstar(args.operands, { server: args.server, network: args.network, json: args.json });
|
|
17
|
+
}
|
|
18
|
+
case "pin": {
|
|
19
|
+
const { pin } = await import("./marks.js");
|
|
20
|
+
return await pin(args.operands, { server: args.server, network: args.network, json: args.json });
|
|
21
|
+
}
|
|
22
|
+
case "unpin": {
|
|
23
|
+
const { unpin } = await import("./marks.js");
|
|
24
|
+
return await unpin(args.operands, { server: args.server, network: args.network, json: args.json });
|
|
25
|
+
}
|
|
26
|
+
case "label": {
|
|
27
|
+
const options = { server: args.server, network: args.network, json: args.json };
|
|
28
|
+
// ⛔ `--rename` IS A DIFFERENT COMMAND WEARING THE SAME VERB, and it is dispatched here so
|
|
29
|
+
// that the label sweep cannot be reached by accident: `label <name> <files>` puts a mark
|
|
30
|
+
// on the files it names, and `label --rename <old> <new>` touches every file in the
|
|
31
|
+
// account. One takes paths and the other refuses them.
|
|
32
|
+
if (args.rename !== undefined) {
|
|
33
|
+
const { labelRename } = await import("./marks.js");
|
|
34
|
+
return await labelRename(args.rename, args.operands[0], options);
|
|
35
|
+
}
|
|
36
|
+
const { label } = await import("./marks.js");
|
|
37
|
+
return await label(args.operands[0], args.operands.slice(1), options);
|
|
38
|
+
}
|
|
39
|
+
case "unlabel": {
|
|
40
|
+
const options = { server: args.server, network: args.network, json: args.json };
|
|
41
|
+
if (args.all) {
|
|
42
|
+
const { unlabelAll } = await import("./marks.js");
|
|
43
|
+
return await unlabelAll(args.operands[0], options);
|
|
44
|
+
}
|
|
45
|
+
const { unlabel } = await import("./marks.js");
|
|
46
|
+
return await unlabel(args.operands[0], args.operands.slice(1), options);
|
|
47
|
+
}
|
|
48
|
+
default:
|
|
49
|
+
throw new Error(`not a mark verb: ${command}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export interface MarkOptions {
|
|
2
|
+
server?: string | undefined;
|
|
3
|
+
network?: string | undefined;
|
|
4
|
+
json?: boolean;
|
|
5
|
+
write?: (line: string) => void;
|
|
6
|
+
}
|
|
7
|
+
/** Star one or more files: they show in the drive's favourites as well as in their own folder. */
|
|
8
|
+
export declare function star(paths: readonly string[], options?: MarkOptions): Promise<number>;
|
|
9
|
+
/** Take the star off. */
|
|
10
|
+
export declare function unstar(paths: readonly string[], options?: MarkOptions): Promise<number>;
|
|
11
|
+
/** Hold one or more files at the top of the folder they are in. */
|
|
12
|
+
export declare function pin(paths: readonly string[], options?: MarkOptions): Promise<number>;
|
|
13
|
+
/** Let them fall back into the ordinary order. */
|
|
14
|
+
export declare function unpin(paths: readonly string[], options?: MarkOptions): Promise<number>;
|
|
15
|
+
/**
|
|
16
|
+
* Put one label on one or more files.
|
|
17
|
+
*
|
|
18
|
+
* ⚠ A LABEL EXISTS EXACTLY AS LONG AS SOME FILE WEARS IT. There is no registry to add it to and
|
|
19
|
+
* none to clean up: two devices inventing the same label converge on it instead of colliding,
|
|
20
|
+
* and the last `unlabel` is what makes it stop existing.
|
|
21
|
+
*/
|
|
22
|
+
export declare function label(name: string | undefined, paths: readonly string[], options?: MarkOptions): Promise<number>;
|
|
23
|
+
/** Take one label off one or more files. */
|
|
24
|
+
export declare function unlabel(name: string | undefined, paths: readonly string[], options?: MarkOptions): Promise<number>;
|
|
25
|
+
/**
|
|
26
|
+
* `nmts label --rename <old> <new>` — one label's name, changed on every file that wears it.
|
|
27
|
+
*
|
|
28
|
+
* ⛔ IT IS A SWEEP, AND IT NAMES NO PATHS. A label has no registry to rename it in (see `label`
|
|
29
|
+
* above): it exists on the files, so renaming it means touching every file that wears it. That
|
|
30
|
+
* is why this is a different entry point rather than a switch on `label` — one takes the files
|
|
31
|
+
* it is given, and this one takes whatever the account holds.
|
|
32
|
+
*
|
|
33
|
+
* ⛔ RENAMING ONTO A LABEL THAT ALREADY EXISTS MERGES THE TWO. A file wearing both would otherwise
|
|
34
|
+
* end up wearing one label twice, which shows a doubled row and counts the file twice. The
|
|
35
|
+
* intent does that; it is written down here because it is the behaviour somebody has to be able
|
|
36
|
+
* to predict before typing this.
|
|
37
|
+
*/
|
|
38
|
+
export declare function labelRename(from: string | undefined, to: string | undefined, options?: MarkOptions): Promise<number>;
|
|
39
|
+
/**
|
|
40
|
+
* `nmts unlabel <name> --all` — one label, taken off every file that wears it.
|
|
41
|
+
*
|
|
42
|
+
* ⛔ THIS IS WHAT MAKES A LABEL STOP EXISTING, and it is the whole reason the sweep is worth a
|
|
43
|
+
* flag: a label with no registry can only be removed by finding every file wearing it, and
|
|
44
|
+
* doing that by hand is how one file keeps a label nobody can see any more.
|
|
45
|
+
*/
|
|
46
|
+
export declare function unlabelAll(name: string | undefined, options?: MarkOptions): Promise<number>;
|
package/dist/commands/marks.js
CHANGED
|
@@ -50,6 +50,86 @@ export async function label(name, paths, options = {}) {
|
|
|
50
50
|
export async function unlabel(name, paths, options = {}) {
|
|
51
51
|
return run("unlabel", paths, name, options);
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* `nmts label --rename <old> <new>` — one label's name, changed on every file that wears it.
|
|
55
|
+
*
|
|
56
|
+
* ⛔ IT IS A SWEEP, AND IT NAMES NO PATHS. A label has no registry to rename it in (see `label`
|
|
57
|
+
* above): it exists on the files, so renaming it means touching every file that wears it. That
|
|
58
|
+
* is why this is a different entry point rather than a switch on `label` — one takes the files
|
|
59
|
+
* it is given, and this one takes whatever the account holds.
|
|
60
|
+
*
|
|
61
|
+
* ⛔ RENAMING ONTO A LABEL THAT ALREADY EXISTS MERGES THE TWO. A file wearing both would otherwise
|
|
62
|
+
* end up wearing one label twice, which shows a doubled row and counts the file twice. The
|
|
63
|
+
* intent does that; it is written down here because it is the behaviour somebody has to be able
|
|
64
|
+
* to predict before typing this.
|
|
65
|
+
*/
|
|
66
|
+
export async function labelRename(from, to, options = {}) {
|
|
67
|
+
const say = options.write ?? ((line) => process.stdout.write(`${line}\n`));
|
|
68
|
+
// ⚠ Trimmed here as well as inside the intent, so the text compared against what a file wears
|
|
69
|
+
// is the same text that gets stored. ` work ` and `work` are one label.
|
|
70
|
+
const old = from === undefined ? "" : from.trim();
|
|
71
|
+
const fresh = to === undefined ? "" : to.trim();
|
|
72
|
+
if (old === "" || fresh === "") {
|
|
73
|
+
throw new NmtsError("`nmts label --rename` needs the label to rename, then its new name.", {
|
|
74
|
+
exitCode: 2,
|
|
75
|
+
nextStep: "For example: nmts label --rename work archive",
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
const session = await openSession(options);
|
|
79
|
+
const at = Date.now();
|
|
80
|
+
let files = 0;
|
|
81
|
+
// ⛔ COUNTED INSIDE THE ATTEMPT, like every other question about the list. On a lost
|
|
82
|
+
// compare-and-swap the list is read again, and how many files wear a label is a fact about
|
|
83
|
+
// the version that was read — another device may have added one since.
|
|
84
|
+
await applyToList(session, (now) => {
|
|
85
|
+
files = now.filter((e) => (e.labels ?? []).includes(old)).length;
|
|
86
|
+
return { op: "labelRename", from: old, to: fresh, at };
|
|
87
|
+
});
|
|
88
|
+
if (options.json) {
|
|
89
|
+
say(JSON.stringify({ label: old, renamed_to: fresh, files }));
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
92
|
+
if (files === 0) {
|
|
93
|
+
say(`No file carries the label "${old}".`);
|
|
94
|
+
return 0;
|
|
95
|
+
}
|
|
96
|
+
say(`Renamed the label "${old}" to "${fresh}" on ${files} ${files === 1 ? "file" : "files"}.`);
|
|
97
|
+
return 0;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* `nmts unlabel <name> --all` — one label, taken off every file that wears it.
|
|
101
|
+
*
|
|
102
|
+
* ⛔ THIS IS WHAT MAKES A LABEL STOP EXISTING, and it is the whole reason the sweep is worth a
|
|
103
|
+
* flag: a label with no registry can only be removed by finding every file wearing it, and
|
|
104
|
+
* doing that by hand is how one file keeps a label nobody can see any more.
|
|
105
|
+
*/
|
|
106
|
+
export async function unlabelAll(name, options = {}) {
|
|
107
|
+
const say = options.write ?? ((line) => process.stdout.write(`${line}\n`));
|
|
108
|
+
const text = name === undefined ? "" : name.trim();
|
|
109
|
+
if (text === "") {
|
|
110
|
+
throw new NmtsError("`nmts unlabel --all` needs the label to take off.", {
|
|
111
|
+
exitCode: 2,
|
|
112
|
+
nextStep: "For example: nmts unlabel work --all",
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
const session = await openSession(options);
|
|
116
|
+
const at = Date.now();
|
|
117
|
+
let files = 0;
|
|
118
|
+
await applyToList(session, (now) => {
|
|
119
|
+
files = now.filter((e) => (e.labels ?? []).includes(text)).length;
|
|
120
|
+
return { op: "labelDelete", label: text, at };
|
|
121
|
+
});
|
|
122
|
+
if (options.json) {
|
|
123
|
+
say(JSON.stringify({ label: text, removed_from: files }));
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
if (files === 0) {
|
|
127
|
+
say(`No file carries the label "${text}".`);
|
|
128
|
+
return 0;
|
|
129
|
+
}
|
|
130
|
+
say(`Took the label "${text}" off ${files} ${files === 1 ? "file" : "files"}.`);
|
|
131
|
+
return 0;
|
|
132
|
+
}
|
|
53
133
|
async function run(verb, paths, name, options) {
|
|
54
134
|
const say = options.write ?? ((line) => process.stdout.write(`${line}\n`));
|
|
55
135
|
const on = !verb.startsWith("un");
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { destinationFor } from "../safe-path.ts";
|
|
2
|
+
export { destinationFor };
|
|
3
|
+
export interface McpOptions {
|
|
4
|
+
server?: string | undefined;
|
|
5
|
+
network?: string | undefined;
|
|
6
|
+
/** Where fetched files land. Defaults to the working directory the person started this in. */
|
|
7
|
+
out?: string | undefined;
|
|
8
|
+
/** Overridable so a test can drive both ends without pipes. */
|
|
9
|
+
input?: NodeJS.ReadableStream;
|
|
10
|
+
output?: (line: string) => void;
|
|
11
|
+
note?: (line: string) => void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Every schema this program actually serves, for the gate that checks they can be enforced.
|
|
15
|
+
*
|
|
16
|
+
* ⛔ IT BUILDS THE REAL TABLE rather than restating it. A hand-kept list of tool names in a test is
|
|
17
|
+
* a list that goes stale the day somebody adds a tool, and the failure is a tool nobody checks.
|
|
18
|
+
* The context here is a placeholder — no tool reads it while its schema is being looked at.
|
|
19
|
+
*/
|
|
20
|
+
export declare function mcpToolSchemas(): {
|
|
21
|
+
name: string;
|
|
22
|
+
inputSchema: Record<string, unknown>;
|
|
23
|
+
}[];
|
|
24
|
+
export declare function mcp(options?: McpOptions): Promise<number>;
|
package/dist/commands/mcp.js
CHANGED
|
@@ -35,16 +35,21 @@ import { requireAccountCode } from "../code-access.js";
|
|
|
35
35
|
import { API_KEY_ENV_VAR, CODE_ENV_VAR, readCredentialsFile, resolveApiKey } from "../credentials.js";
|
|
36
36
|
import { NmtsError } from "../errors.js";
|
|
37
37
|
import { serve } from "../mcp.js";
|
|
38
|
+
import { describeSighting } from "../agent-host.js";
|
|
38
39
|
// ⚠ Re-exported so callers that knew it here keep working; the rule itself lives one level up now.
|
|
39
40
|
import { destinationFor } from "../safe-path.js";
|
|
40
41
|
export { destinationFor };
|
|
41
42
|
import { BINARY_NAME, PRODUCT_NAME, VERSION } from "../product.js";
|
|
42
43
|
import { resolveNetwork } from "../network.js";
|
|
43
44
|
import { resolveServer } from "../server.js";
|
|
45
|
+
import { creditTools } from "../mcp-tools/credits.js";
|
|
44
46
|
import { fileTools } from "../mcp-tools/files.js";
|
|
45
47
|
import { organiseTools } from "../mcp-tools/organise.js";
|
|
46
48
|
import { readTools } from "../mcp-tools/reads.js";
|
|
47
49
|
import { shareTools } from "../mcp-tools/share.js";
|
|
50
|
+
import { withTiers } from "../mcp-tools/tiers.js";
|
|
51
|
+
import { supportTools } from "../mcp-tools/support.js";
|
|
52
|
+
import { currentMode } from "../autonomy.js";
|
|
48
53
|
/**
|
|
49
54
|
* Which account this server is holding, answered without asking anything.
|
|
50
55
|
*
|
|
@@ -56,7 +61,7 @@ import { shareTools } from "../mcp-tools/share.js";
|
|
|
56
61
|
function whoami(ctx) {
|
|
57
62
|
return {
|
|
58
63
|
name: "nmts_whoami",
|
|
59
|
-
description: "Which NMTS account this machine holds the
|
|
64
|
+
description: "Which NMTS account this machine holds the NMTS key for. Derived here, offline: it says " +
|
|
60
65
|
"nothing about whether that account exists on the server or has credits.",
|
|
61
66
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
62
67
|
async run() {
|
|
@@ -77,8 +82,22 @@ function whoami(ctx) {
|
|
|
77
82
|
* The context here is a placeholder — no tool reads it while its schema is being looked at.
|
|
78
83
|
*/
|
|
79
84
|
export function mcpToolSchemas() {
|
|
80
|
-
const ctx = {
|
|
81
|
-
|
|
85
|
+
const ctx = {
|
|
86
|
+
server: "https://example.invalid",
|
|
87
|
+
network: "testnet",
|
|
88
|
+
outDir: "/",
|
|
89
|
+
accountId: "-",
|
|
90
|
+
asker: () => null,
|
|
91
|
+
};
|
|
92
|
+
const all = [
|
|
93
|
+
whoami(ctx),
|
|
94
|
+
...readTools(ctx),
|
|
95
|
+
...fileTools(ctx),
|
|
96
|
+
...organiseTools(ctx),
|
|
97
|
+
...creditTools(ctx),
|
|
98
|
+
...shareTools(ctx),
|
|
99
|
+
...supportTools(ctx),
|
|
100
|
+
];
|
|
82
101
|
return all.map((t) => ({ name: t.name, inputSchema: t.inputSchema }));
|
|
83
102
|
}
|
|
84
103
|
export async function mcp(options = {}) {
|
|
@@ -109,7 +128,21 @@ export async function mcp(options = {}) {
|
|
|
109
128
|
if (!statSync(outDir).isDirectory()) {
|
|
110
129
|
throw new NmtsError(`${outDir} is not a directory.`, { exitCode: 2 });
|
|
111
130
|
}
|
|
112
|
-
|
|
131
|
+
/**
|
|
132
|
+
* How this session asks the person a question, filled in when the client says whether it can.
|
|
133
|
+
*
|
|
134
|
+
* ⛔ IT STARTS AS "NO WAY TO ASK" AND THAT IS THE RIGHT STARTING POINT. A tool call cannot
|
|
135
|
+
* arrive before `initialize`, so this is only ever read after the client has spoken; if a
|
|
136
|
+
* client somehow skipped that, the tools that need an answer refuse rather than assume one.
|
|
137
|
+
*/
|
|
138
|
+
let asker = null;
|
|
139
|
+
const ctx = {
|
|
140
|
+
server,
|
|
141
|
+
network,
|
|
142
|
+
outDir,
|
|
143
|
+
accountId: identity.accountId,
|
|
144
|
+
asker: () => asker,
|
|
145
|
+
};
|
|
113
146
|
/**
|
|
114
147
|
* The whole surface, in one place.
|
|
115
148
|
*
|
|
@@ -123,8 +156,17 @@ export async function mcp(options = {}) {
|
|
|
123
156
|
...readTools(ctx),
|
|
124
157
|
...fileTools(ctx),
|
|
125
158
|
...organiseTools(ctx),
|
|
159
|
+
...creditTools(ctx),
|
|
126
160
|
...shareTools(ctx),
|
|
161
|
+
// ⛔ LAST, AND NOT BECAUSE IT MATTERS LEAST. The order is the order a client shows them in,
|
|
162
|
+
// and writing to the developer is the one thing here that is not about this account's
|
|
163
|
+
// files at all — a model scanning the list should meet it after everything the work
|
|
164
|
+
// itself needs.
|
|
165
|
+
...supportTools(ctx),
|
|
127
166
|
];
|
|
167
|
+
// ⛔ THE TIER GATE, AROUND EVERY TOOL (`mcp-tools/tiers.ts`): the same table the command line
|
|
168
|
+
// reads, asked over elicitation instead of a terminal.
|
|
169
|
+
const gated = withTiers(tools, ctx.asker);
|
|
128
170
|
// ⛔ To stderr, deliberately. A person starting this by hand should see what it is; a client
|
|
129
171
|
// reading stdout must see nothing but protocol.
|
|
130
172
|
note(`${PRODUCT_NAME} · ${identity.accountId} · ${network} · files land in ${outDir}`);
|
|
@@ -132,8 +174,31 @@ export async function mcp(options = {}) {
|
|
|
132
174
|
await serve({
|
|
133
175
|
input: options.input ?? process.stdin,
|
|
134
176
|
output: options.output ?? ((line) => process.stdout.write(`${line}\n`)),
|
|
135
|
-
tools,
|
|
177
|
+
tools: gated,
|
|
136
178
|
info: { name: BINARY_NAME, version: VERSION },
|
|
179
|
+
// ⛔ WHO CONNECTED, SAID ONCE, TO STDERR. It is the only moment this is knowable: the name
|
|
180
|
+
// travels in `initialize` rather than in the environment, which is why it survives the
|
|
181
|
+
// three hosts that clear the environment before starting a server. A person reading the
|
|
182
|
+
// log of a server they did not start themselves has nowhere else to learn it.
|
|
183
|
+
onClient: (client) => {
|
|
184
|
+
if (client.host !== null)
|
|
185
|
+
note(`Client: ${describeSighting(client.host)}`);
|
|
186
|
+
else if (client.name !== null)
|
|
187
|
+
note(`Client: ${client.name} — not an agent this version knows by name`);
|
|
188
|
+
},
|
|
189
|
+
// ⛔ AND WHETHER IT CAN BE ASKED ANYTHING, said once for the same reason. A person watching
|
|
190
|
+
// this log needs to know before the first share, not when it is refused.
|
|
191
|
+
onAsker: (built) => {
|
|
192
|
+
asker = built;
|
|
193
|
+
// ⚠ A MODE THAT IS ON DECIDES THIS, so it is read here rather than assumed. Saying "every
|
|
194
|
+
// share will ask you" to somebody who turned a mode on would be telling them the opposite
|
|
195
|
+
// of what their own setting does.
|
|
196
|
+
if (currentMode() !== "default")
|
|
197
|
+
return;
|
|
198
|
+
note(built === null
|
|
199
|
+
? "This client cannot show you a question, so sharing is refused here. Share from a terminal."
|
|
200
|
+
: "This client can show you a question; every share will ask you first.");
|
|
201
|
+
},
|
|
137
202
|
});
|
|
138
203
|
return 0;
|
|
139
204
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface ModeOptions {
|
|
2
|
+
json?: boolean;
|
|
3
|
+
write?: (line: string) => void;
|
|
4
|
+
now?: () => Date;
|
|
5
|
+
/** Injected in tests: answers the one question. Its presence also stands in for a terminal. */
|
|
6
|
+
readLine?: ((question: string) => Promise<string>) | undefined;
|
|
7
|
+
}
|
|
8
|
+
export declare function mode(wanted: string | undefined, target: string | undefined, options?: ModeOptions): Promise<number>;
|