shinjuku-shield 0.3.91 → 0.3.93
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/README.md +5 -5
- package/manifest.json +4 -4
- package/package.json +3 -3
- package/shinjuku-wallet.mjs +305 -86
package/README.md
CHANGED
|
@@ -6,13 +6,13 @@ answers privately, in a terminal chat or for your agent app. Its `mcp`
|
|
|
6
6
|
command runs a local MCP server (stdio) for your agent. Your keys never
|
|
7
7
|
leave your machine.
|
|
8
8
|
|
|
9
|
-
This is version 0.3.
|
|
9
|
+
This is version 0.3.93. The npm packages `shinjuku-shield` and
|
|
10
10
|
`shinjuku-shielded` hold the same files; `shinjuku` is the short command.
|
|
11
11
|
|
|
12
12
|
## Set up
|
|
13
13
|
|
|
14
14
|
```sh
|
|
15
|
-
npx -y --no-audit --no-fund shinjuku-shield@0.3.
|
|
15
|
+
npx -y --no-audit --no-fund shinjuku-shield@0.3.93 setup
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
Setup makes the wallet on this machine, a private passphrase file, and the
|
|
@@ -24,7 +24,7 @@ server to that host's config.
|
|
|
24
24
|
## The `shinjuku` command
|
|
25
25
|
|
|
26
26
|
```sh
|
|
27
|
-
npm install -g shinjuku@0.3.
|
|
27
|
+
npm install -g shinjuku@0.3.93
|
|
28
28
|
shinjuku help
|
|
29
29
|
```
|
|
30
30
|
|
|
@@ -36,13 +36,13 @@ Every wallet command works after `shinjuku`, for example `shinjuku balance`,
|
|
|
36
36
|
Claude Code:
|
|
37
37
|
|
|
38
38
|
```sh
|
|
39
|
-
claude mcp add --scope user shinjuku-shielded -- npx -y --no-audit --no-fund shinjuku-shield@0.3.
|
|
39
|
+
claude mcp add --scope user shinjuku-shielded -- npx -y --no-audit --no-fund shinjuku-shield@0.3.93 mcp
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
Claude Desktop (`claude_desktop_config.json`) or Cursor (`~/.cursor/mcp.json`):
|
|
43
43
|
|
|
44
44
|
```json
|
|
45
|
-
{ "mcpServers": { "shinjuku-shielded": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.
|
|
45
|
+
{ "mcpServers": { "shinjuku-shielded": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.93", "mcp"] } } }
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
On native Windows, if the host cannot find `npx`, use `"command": "cmd"` and
|
package/manifest.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "carbon-shielded-wallet/bundle-manifest/v1",
|
|
3
3
|
"file": "shinjuku-wallet.mjs",
|
|
4
|
-
"sha256": "
|
|
5
|
-
"bytes":
|
|
6
|
-
"sourceCommit": "
|
|
4
|
+
"sha256": "6048ca6123de12e425ab2f3575fa69838eb1ea93dbff3d2facab612e0004bf8a",
|
|
5
|
+
"bytes": 12704961,
|
|
6
|
+
"sourceCommit": "714b20d52346099009acced7d327566f239e8b7d",
|
|
7
7
|
"sourceDirty": false,
|
|
8
8
|
"installRecordMatchesLockfile": true,
|
|
9
9
|
"releaseRule": "valid only when two fresh npm ci --ignore-scripts builds on different OSes give the same sha256; installRecordMatchesLockfile true means every entry npm installed equals its package-lock.json entry and every entry not marked optional, devOptional included, is installed: an optional entry (a package for another platform) may be absent",
|
|
@@ -1297,5 +1297,5 @@
|
|
|
1297
1297
|
"version": "1.8.0"
|
|
1298
1298
|
}
|
|
1299
1299
|
],
|
|
1300
|
-
"publishedAt": "2026-10-
|
|
1300
|
+
"publishedAt": "2026-10-24T03:23:12.626Z"
|
|
1301
1301
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shinjuku-shield",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.93",
|
|
4
4
|
"mcpName": "io.github.ShinjukuStaition/shinjuku-mcp",
|
|
5
5
|
"description": "Shinjuku Shielded, the private x402 facilitator on Solana: the self-custody wallet CLI and its MCP server. Shield, pay, and unshield USDC from any MCP agent, under caps you set.",
|
|
6
|
-
"shinjukuRelease": "
|
|
7
|
-
"shinjukuSha256": "
|
|
6
|
+
"shinjukuRelease": "6048ca61",
|
|
7
|
+
"shinjukuSha256": "6048ca6123de12e425ab2f3575fa69838eb1ea93dbff3d2facab612e0004bf8a",
|
|
8
8
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
9
9
|
"author": "Shinjuku Shielded",
|
|
10
10
|
"homepage": "https://github.com/ShinjukuStaition/shinjuku-mcp#readme",
|
package/shinjuku-wallet.mjs
CHANGED
|
@@ -47225,7 +47225,7 @@ async function rpcFetch(input, init) {
|
|
|
47225
47225
|
rpcNotBefore.set(post.key, Math.max(rpcNotBefore.get(post.key) ?? 0, Date.now() + retryAfterMs(response)));
|
|
47226
47226
|
}
|
|
47227
47227
|
}
|
|
47228
|
-
function
|
|
47228
|
+
function proxiedChild(args, mode, plainProxy, stdio) {
|
|
47229
47229
|
const proxy = withRunTag(mode, plainProxy);
|
|
47230
47230
|
const env = {
|
|
47231
47231
|
...process.env,
|
|
@@ -47237,8 +47237,11 @@ function reexec(args, mode, plainProxy) {
|
|
|
47237
47237
|
delete env[QUIET_RUN_MARK];
|
|
47238
47238
|
const quiet = quietRun(args);
|
|
47239
47239
|
if (quiet) env[QUIET_RUN_MARK] = quiet;
|
|
47240
|
+
return spawn(process.execPath, [...proxiedExecArgv(process.execArgv), process.argv[1], ...args], { env, stdio });
|
|
47241
|
+
}
|
|
47242
|
+
function reexec(args, mode, plainProxy) {
|
|
47240
47243
|
return new Promise((resolvePromise) => {
|
|
47241
|
-
const child =
|
|
47244
|
+
const child = proxiedChild(args, mode, plainProxy, "inherit");
|
|
47242
47245
|
const ignore = () => {
|
|
47243
47246
|
};
|
|
47244
47247
|
const forward = () => child.kill("SIGTERM");
|
|
@@ -47314,7 +47317,12 @@ async function proxyEntry(argv2, run5, { err = (text3) => process.stderr.write(t
|
|
|
47314
47317
|
}
|
|
47315
47318
|
return reexec(options.args, options.mode, options.proxy);
|
|
47316
47319
|
}
|
|
47317
|
-
|
|
47320
|
+
function torChild(argv2, stdio) {
|
|
47321
|
+
const options = proxyOptions(argv2);
|
|
47322
|
+
if (!options.mode) throw new ProxyUsageError("torChild needs --tor or --proxy");
|
|
47323
|
+
return proxiedChild(options.args, options.mode, options.proxy, stdio);
|
|
47324
|
+
}
|
|
47325
|
+
var TOR_HTTP_TUNNEL, TOR_CHECK, PROOF_TIMEOUT_MS, LOCAL_PROOF_TIMEOUT_MS, LOCAL_PROOF_MAX_BYTES, torProvenAt, proxyProvenAt, MARK, TOR_RUN_STARTED_ENV, ownProxyRefused, ONION_V3, RETRY_AFTER_CAP_MS, RETRY_AFTER_FLOOR_MS, RETRY_AFTER_DEFAULT_MS, RPC_NO_ANSWER_LIMIT_MS, RPC_PACING_CAP_MS, PACING_NOTICE_EVERY_MS, PACING_RATE_WINDOW_MS, TOR_MAX_ROTATIONS, runStartedAt, rpcNotBefore, pacingWaiters, pacingSince, pacedMs, rpcAnswered, lastAnswerAt, readSteps, pacingNoticeAt, pacingSamples, torMoves, torCircuitId, torMovesRefused, pendingMove, inTorRun, runNetworkMode, isOnionOrigin, ProxyUsageError, isOnionHost, TOR_EXPERT_BUNDLE, TOR_EXPERT_BUNDLE_SHA256, TUNNEL_LINE, TOR_INSTALL, torStart, OS_NAMES, osKey, torNotRunningMessage, NOTICE, QUIET_RUN_MARK, QUIET_NOTICE, QUIET_TERMINAL_COMMANDS, INFER_SUBCOMMANDS, quietRun, TOR_TROUBLE_LINE, TOR_WAIT_PLAIN, TOR_TROUBLE_PLAIN, TOR_TROUBLE_SAID, quietTorErr, withRunTag, proxyEnv, pacedSoFar, RESENDABLE_METHOD, torCircuit, GLOBAL_DISPATCHER2, laneDispatchers, paymentWarmStop, PROXY_WARNING_FLAG, proxiedExecArgv, proxiedNodeOptions, TOR_FROM_CONFIG_ENV, TOR_FROM_CONFIG_HINT;
|
|
47318
47326
|
var init_proxy = __esm({
|
|
47319
47327
|
"wallet/src/net/proxy.mjs"() {
|
|
47320
47328
|
"use strict";
|
|
@@ -47361,12 +47369,14 @@ var init_proxy = __esm({
|
|
|
47361
47369
|
};
|
|
47362
47370
|
isOnionHost = (host) => /\.onion$/i.test(String(host ?? "").replace(/\.+$/, ""));
|
|
47363
47371
|
TOR_EXPERT_BUNDLE = "15.0.25";
|
|
47372
|
+
TOR_EXPERT_BUNDLE_SHA256 = "c1988c701de2f24f7d098d1d6d7f507b58f27740d097f29c246e0524d639b252";
|
|
47364
47373
|
TUNNEL_LINE = "HTTPTunnelPort 127.0.0.1:9080 IsolateDestAddr";
|
|
47365
47374
|
TOR_INSTALL = Object.freeze({
|
|
47366
|
-
windows: `iwr https://archive.torproject.org/tor-package-archive/torbrowser/${TOR_EXPERT_BUNDLE}/tor-expert-bundle-windows-x86_64-${TOR_EXPERT_BUNDLE}.tar.gz -OutFile $env:TEMP\\tor.tar.gz; mkdir -Force $env:LOCALAPPDATA\\tor | Out-Null; tar -xzf $env:TEMP\\tor.tar.gz -C $env:LOCALAPPDATA\\tor; & $env:LOCALAPPDATA\\tor\\tor\\tor.exe --HTTPTunnelPort '127.0.0.1:9080 IsolateDestAddr' --SocksPort 0`,
|
|
47375
|
+
windows: `iwr https://archive.torproject.org/tor-package-archive/torbrowser/${TOR_EXPERT_BUNDLE}/tor-expert-bundle-windows-x86_64-${TOR_EXPERT_BUNDLE}.tar.gz -OutFile $env:TEMP\\tor.tar.gz; if ((Get-FileHash $env:TEMP\\tor.tar.gz -Algorithm SHA256).Hash -ne '${TOR_EXPERT_BUNDLE_SHA256}') { Remove-Item $env:TEMP\\tor.tar.gz; throw 'The Tor download does not match its pinned sha256, so it was deleted and not run' }; mkdir -Force $env:LOCALAPPDATA\\tor | Out-Null; & $env:SystemRoot\\System32\\tar.exe -xzf $env:TEMP\\tor.tar.gz -C $env:LOCALAPPDATA\\tor; & $env:LOCALAPPDATA\\tor\\tor\\tor.exe --HTTPTunnelPort '127.0.0.1:9080 IsolateDestAddr' --SocksPort 0`,
|
|
47367
47376
|
macos: `brew install tor && echo '${TUNNEL_LINE}' >> "$(brew --prefix)/etc/tor/torrc" && brew services restart tor`,
|
|
47368
47377
|
linux: `sudo apt install -y tor && echo '${TUNNEL_LINE}' | sudo tee -a /etc/tor/torrc && sudo systemctl restart tor`
|
|
47369
47378
|
});
|
|
47379
|
+
torStart = (platform = process.platform) => platform === "win32" ? { where: "PowerShell (keep its window open while the wallet runs)", command: TOR_INSTALL.windows } : platform === "darwin" ? { where: "Terminal", command: TOR_INSTALL.macos } : { where: "a terminal", command: TOR_INSTALL.linux };
|
|
47370
47380
|
OS_NAMES = { windows: "Windows (PowerShell; keep its window open while the wallet runs)", macos: "macOS (Homebrew)", linux: "Linux (Debian or Ubuntu)" };
|
|
47371
47381
|
osKey = (platform) => platform === "win32" ? "windows" : platform === "darwin" ? "macos" : "linux";
|
|
47372
47382
|
torNotRunningMessage = (address5, platform = process.platform) => `tor_not_running: Tor is not running on this machine (nothing answers at ${address5}), so nothing was sent. ${torInstallText(platform)}`;
|
|
@@ -67280,6 +67290,9 @@ var init_errorCodes = __esm({
|
|
|
67280
67290
|
"mcp_setup_switch_failed",
|
|
67281
67291
|
"mcp_tor_unavailable",
|
|
67282
67292
|
"setup_tor_unavailable",
|
|
67293
|
+
// The wallet server behind Tor that the setup server starts after a Tor setup (stdioServer.mjs startTorRelay).
|
|
67294
|
+
"setup_tor_wallet_ended",
|
|
67295
|
+
"setup_tor_wallet_slow",
|
|
67283
67296
|
"wallet_not_set_up",
|
|
67284
67297
|
"shinjuku_setup",
|
|
67285
67298
|
"wallet_status",
|
|
@@ -109970,7 +109983,7 @@ function refusalSay(a, tool, again, npmVersion) {
|
|
|
109970
109983
|
}
|
|
109971
109984
|
if (code2 === "mcp_balance_unknown") return "Nothing was moved yet: the wallet is still reading its private balance. Try again in a minute.";
|
|
109972
109985
|
if (code2 === "mcp_payment_still_open") return "Not paid: a payment for this request is still open. Ask with its request_id for the result.";
|
|
109973
|
-
if (code2 === "mcp_setup_restart_needed") return "The wallet is set up, but
|
|
109986
|
+
if (code2 === "mcp_setup_restart_needed") return "The wallet is set up, but it must reconnect once. Follow the steps below, then try again. Nothing was paid.";
|
|
109974
109987
|
if (code2 === "mcp_restart_needed") return "Nothing was paid. Restart this app, then try again.";
|
|
109975
109988
|
if (/accounts_split/.test(code2) || /accounts_split/.test(detail)) {
|
|
109976
109989
|
return `Nothing was ${tool === "wallet_unshield" ? "sent" : "paid"}. The wallet is getting your balance ready to send; try again in about 1 minute, then once more 2 minutes later.`;
|
|
@@ -110063,10 +110076,13 @@ function refusalSay(a, tool, again, npmVersion) {
|
|
|
110063
110076
|
return str(a.ownAddressCommand) && words(own) <= SAY_MAX_WORDS ? own : head;
|
|
110064
110077
|
}
|
|
110065
110078
|
if (code2 === "mcp_unshield_declined") return "Not sent. The send was not confirmed.";
|
|
110066
|
-
if (code2 === "mcp_setup_declined" && unshown) {
|
|
110067
|
-
return `Not set up. This app cannot show the setup question. Run ${oneTimeCommandLine("setup", npmVersion)} in a terminal, then
|
|
110079
|
+
if (code2 === "mcp_setup_declined" && unshown || code2 === "mcp_setup_needs_terminal") {
|
|
110080
|
+
return `Not set up. This app cannot show the setup question. Run ${oneTimeCommandLine("setup", npmVersion)} in a terminal, then reconnect the wallet.`;
|
|
110068
110081
|
}
|
|
110069
110082
|
if (code2 === "mcp_setup_declined") return "Not set up. The setup was not confirmed; nothing was created.";
|
|
110083
|
+
if (code2 === "tor_not_running" && tool === "shinjuku_setup") return "Not set up: Tor is not running on this computer. Start it with the command below and ask again, or set up without Tor.";
|
|
110084
|
+
if (code2 === "wallet_not_set_up" && tool === "x402_discover") return "Not searched yet. Set up the wallet first: setup asks one question, whether to use Tor, which hides your IP address.";
|
|
110085
|
+
if (code2 === "wallet_not_set_up") return "The wallet is not set up yet, so nothing was paid. Ask to set up the wallet first.";
|
|
110070
110086
|
if (code2 === "mcp_tool_disabled") return "Nothing was paid or moved. This tool is off; only your owner can turn it on when starting the wallet.";
|
|
110071
110087
|
if (code2 === "mcp_unshield_to_invalid") {
|
|
110072
110088
|
return "Not sent. That address has no USDC account yet. Ask for a Solana address that already holds USDC, like a Phantom address.";
|
|
@@ -127172,7 +127188,7 @@ ${canonical5}`;
|
|
|
127172
127188
|
} catch {
|
|
127173
127189
|
onion = false;
|
|
127174
127190
|
}
|
|
127175
|
-
return { network: mode === "tor" ? { mode: "tor", detail: `every request of this wallet goes through Tor (checked at start)${onion ? "; the facilitator is reached over its onion service, so no Tor exit sees those requests" : ""}` } : mode === "proxy" ? { mode: "proxy", detail: "every request of this wallet goes through the proxy in its launch line (--proxy); it is not checked as Tor" } : { mode: "direct", detail:
|
|
127191
|
+
return { network: mode === "tor" ? { mode: "tor", detail: `every request of this wallet goes through Tor (checked at start)${onion ? "; the facilitator is reached over its onion service, so no Tor exit sees those requests" : ""}` } : mode === "proxy" ? { mode: "proxy", detail: "every request of this wallet goes through the proxy in its launch line (--proxy); it is not checked as Tor" } : { mode: "direct", detail: `no Tor: the facilitator, the RPC provider and each seller see this computer's IP address. To hide it, the user runs ${terminalCommand("setup --yes --prefer-tor")} once in a terminal (it records Tor and checks the wallet's files again; nothing else changes), then restarts this app` } };
|
|
127176
127192
|
}
|
|
127177
127193
|
function sayFirst(fields, tool, autoId) {
|
|
127178
127194
|
let say6 = sayFor(fields, { tool, npmVersion });
|
|
@@ -127591,7 +127607,7 @@ ${canonical5}`;
|
|
|
127591
127607
|
const balance = {
|
|
127592
127608
|
name: "wallet_balance",
|
|
127593
127609
|
title: "Balance",
|
|
127594
|
-
description: `Use this when the user asks "what is my balance" or "how much USDC do I have": it answers ONE balance (balanceAtomic, what x402_pay can spend) and the public (unshielded) USDC. Pays nothing and signs nothing. When the user asks to see the wallet ("show my wallet"), print \`card\` as it is
|
|
127610
|
+
description: `Use this when the user asks "what is my balance" or "how much USDC do I have": it answers ONE balance (balanceAtomic, what x402_pay can spend) and the public (unshielded) USDC. Pays nothing and signs nothing. When the user asks to see the wallet ("show my wallet"), print \`card\` as it is (at most 8 lines: balances, Tor, the last 3 payments, example requests). balanceParts (only above 1): a send of all of it first gets the balance ready to send (next says the minutes; never say parts or join to the user). balanceAtomic is one number; breakdown names its parts (breakdown.shieldedAtomic is what wallet_unshield can send; privateSendPendingAtomic is the part of a running private send (wallet_unshield with parts or max_delay_minutes) not sent yet, already taken off shieldedAtomic; refundsInFlightAtomic is a Shinjuku refund on its way back; setAsideAtomic (only when not 0) is value an older version of this wallet set aside to pay sellers; during a pool move, pools lists each pool's part and movingAtomic is value on its way from the old pool to the new one; the move field shows the move, poolSwitches each switch). UNSHIELDED (unshieldedAtomic) is the plain public USDC on the wallet's own Solana key (ownAddress), the USDC wallet_shield makes private; unshieldedSolLamports is that key's SOL, information only: wallet_shield needs none (the facilitator's relayer pays every fee and rent). When the local balance is stale (a new deposit, a received payment), it reads the chain by itself first; when that takes longer than about 20 s it answers the last balance with refreshing: true and finishes in the background (call wallet_balance again in 30 s). A balance with refreshing: true and refreshReason is exact (payment_settling: a payment settles and the number counts it; account_join: the wallet gets its own balance ready to send and the number counts all of it; pool_move: value from the old pool arrives and the number counts it; refund_check: a refund counted from an old read, which the wallet checks now (never tell the user it is still on its way); first_check: a new wallet's first history check, the number is its own landed deposits). status reading (balanceAtomic null): the first balance read of a wallet that may hold money is not done; call wallet_balance again in 30 s. If the public read fails, unshieldedAtomic is null with unshieldedReason; the rest still answers. ownKeyTokens (only when there are any): the other tokens on ownAddress (not its USDC), each { mint, amountAtomic, decimals, amount }, at most 10 (ownKeyTokensMore counts the rest); a token is its mint, never a name or symbol; wallet_transfer_token with that mint as token_mint sells one and sends the USDC privately. earlierDeposits (only when there are any): USDC found at a one-time deposit address of an earlier pool, each with a notice line to tell the user; the wallet moves it into the current pool by itself. addFunds (only when there are any): each wallet_add_funds address still open, with its state and the USDC known to wait there (heldAtomic; null with heldNote when the address was not checked yet). startsAtNextRequest true (old name): its deposit is not sent yet; once the wallet has seen USDC there, it sends it by itself in about startsInMinutes + 1 minutes, in every host, with no ask. landingAtomic (only when not 0): USDC you added whose deposit landed on chain and that balanceAtomic does not count yet; this call finishes it and waits about 20 s for it, past that it is being counted: call wallet_balance again as next says (at once in the same turn when this call waited its 20 s, else in 30 s). session: the spending limits (null or "none": no limit), what is left, and how to change them (session.summary, only when a limit is set). With no limit set, say nothing about limits or the session counters (limit bookkeeping; they may count earlier conversations). To add money, use wallet_add_funds. Amounts are atomic units (USDC: 1000000 = 1 USDC); say and usdc give them in USDC.`,
|
|
127595
127611
|
inputSchema: { type: "object", properties: {
|
|
127596
127612
|
verbose: { type: "boolean", description: "Optional. true adds `internal`: the engineering numbers (funded accounts, notes, payments without waiting, a 0 set-aside value). Default false." }
|
|
127597
127613
|
}, additionalProperties: false },
|
|
@@ -129812,7 +129828,7 @@ ${canonical5}`;
|
|
|
129812
129828
|
decimals = Number(session.openStore().state.decimals);
|
|
129813
129829
|
} catch {
|
|
129814
129830
|
}
|
|
129815
|
-
const amount =
|
|
129831
|
+
const amount = usdcText2(job.amountAtomic, decimals);
|
|
129816
129832
|
const askedAt = Date.now();
|
|
129817
129833
|
try {
|
|
129818
129834
|
const how = isSplitSend(job) ? job.parts === 1 ? ` after a random wait of up to ${job.maxDelayMinutes} min` : ` as ${job.parts} separate exits of unequal size, each after a random wait of up to ${job.maxDelayMinutes} min` : "";
|
|
@@ -130105,13 +130121,13 @@ ${canonical5}`;
|
|
|
130105
130121
|
}
|
|
130106
130122
|
if (checkInput) {
|
|
130107
130123
|
try {
|
|
130108
|
-
await recipientCheck(checkInput);
|
|
130124
|
+
await withTimeout(recipientCheck(checkInput), RECIPIENT_CHECK_TIMEOUT_MS);
|
|
130109
130125
|
} catch (error) {
|
|
130110
130126
|
if (errorCode2(error, "") === "mcp_unshield_to_invalid") {
|
|
130111
130127
|
log(`MCP_UNSHIELD_TO_REFUSED requestId=${request.requestId}`);
|
|
130112
130128
|
return refuse12("mcp_unshield_to_invalid", /has no USDC token account/.test(String(error?.message)) ? UNSHIELD_TO_NO_USDC_DETAIL : String(error.message).replace(/^mcp_unshield_to_invalid:\s*/, ""), UNSHIELD_TO_INVALID_NEXT, { requestId: request.requestId, to: request.to });
|
|
130113
130129
|
}
|
|
130114
|
-
log(`MCP_UNSHIELD_TO_CHECK_SKIPPED requestId=${request.requestId} ${errorCode2(error, "unknown")}`);
|
|
130130
|
+
log(`MCP_UNSHIELD_TO_CHECK_SKIPPED requestId=${request.requestId} ${error?.timedOut === true ? "timeout" : errorCode2(error, "unknown")}`);
|
|
130115
130131
|
}
|
|
130116
130132
|
}
|
|
130117
130133
|
}
|
|
@@ -131189,7 +131205,7 @@ ${canonical5}`;
|
|
|
131189
131205
|
const unshield = {
|
|
131190
131206
|
name: "wallet_unshield",
|
|
131191
131207
|
title: "Send USDC privately from the shielded balance",
|
|
131192
|
-
description: `Use this when the user says "send 2 USDC to <address>" or "withdraw to my wallet" (leave \`to\` out for the owner's own wallet when one is set): it sends amount (USDC, like "2"; or amount_atomic) from the SHIELDED balance as plain USDC to \`to\`, a public Solana address (the USDC goes to its USDC token account). BEFORE you call it to send all of the balance when wallet_balance showed balanceParts above 1, write to the user that it takes about joinMinutes minutes (the wallet first gets the balance ready to send; never say parts or join to the user; some apps show nothing until this call ends). Privately: the chain shows the pool paying the address, not which wallet paid. The wallet's own key (ownAddress in wallet_balance) is this wallet's public address: it holds the public USDC, wallet_shield deposits from it, and wallet_transfer_token sells from it. So it is refused as \`to\`: an exit there would show on chain that the private balance belongs to this wallet. This holds whether or not that key ever deposited: wallet_add_funds deposits come from one-time addresses, not from this key, so never tell the user the deposits came from it. The facilitator pays every network fee; no SOL is needed. The owner's --unshield-to addresses send at once. Any other address is sent only after the user confirms it in the MCP client (a confirmation dialog); a client that cannot ask is refused (mcp_unshield_to_not_allowed) and a decline sends nothing (mcp_unshield_declined). \`to\` must already hold USDC (have a USDC token account): an address without one is refused before any dialog (mcp_unshield_to_invalid). It takes minutes (one wait of up to 5 minutes is normal): the call answers within about 20 s with stage (confirming, queued, refreshing, self-pay = preparing, exit = sending, done; joining = the wallet first gets the balance ready to send, then sends; the answer says how many more asks and when (joinAsks, joinMinutes), ok: true); call wallet_unshield again with the SAME request_id, amount, and to for the status (each call answers within about 20 s, at once when the send ends; a confirmation dialog the user answers may take longer). When the balance is in several parts, the FIRST call answers at once with stage joining and joinTellFirst: true; write its say to the user, then call again with the same request_id at once. One exception: for a single send (no parts, no delay) whose balance is in several parts, when this MCP app sends a progress token with the call, that next call joins the parts and then sends, taking up to ${JOIN_CALL_MAX_MS / 6e4} minutes, with a progress line every ${JOIN_STEP_MS / 1e3} s ("getting your balance ready to send (about M min)"; some apps show none of them, so the time is said before the call, as above). Without a progress token it answers within about 20 s with stage joining and when to ask again. The same request_id never sends twice, also after a restart. request_id is optional: without it the answer names the id it made, and the same call again within 10 minutes after it ends reads that same send. When it lands, the wallet writes an encrypted backup (backupPath). x402_pay calls wait while it runs. An optional owner cap (--max-unshield) may bound each call and what this wallet sends in any 24 hours, from every MCP process (mcp_unshield_cap_exceeded: tell the owner). Other refusals: mcp_argument_invalid, mcp_request_id_reused, mcp_unshield_to_invalid, wallet_locked, mcp_tool_disabled, mcp_unshield_failed, and the unshield's own p03_* codes. PRIVATE SEND (optional): when the user says "send it in parts", "spread it out", or "do not send it all at once", pass parts (2-8) WITH max_delay_minutes (1-60;
|
|
131208
|
+
description: `Use this when the user says "send 2 USDC to <address>" or "withdraw to my wallet" (leave \`to\` out for the owner's own wallet when one is set): it sends amount (USDC, like "2"; or amount_atomic) from the SHIELDED balance as plain USDC to \`to\`, a public Solana address (the USDC goes to its USDC token account). BEFORE you call it to send all of the balance when wallet_balance showed balanceParts above 1, write to the user that it takes about joinMinutes minutes (the wallet first gets the balance ready to send; never say parts or join to the user; some apps show nothing until this call ends). Privately: the chain shows the pool paying the address, not which wallet paid. The wallet's own key (ownAddress in wallet_balance) is this wallet's public address: it holds the public USDC, wallet_shield deposits from it, and wallet_transfer_token sells from it. So it is refused as \`to\`: an exit there would show on chain that the private balance belongs to this wallet. This holds whether or not that key ever deposited: wallet_add_funds deposits come from one-time addresses, not from this key, so never tell the user the deposits came from it. The facilitator pays every network fee; no SOL is needed. The owner's --unshield-to addresses send at once. Any other address is sent only after the user confirms it in the MCP client (a confirmation dialog); a client that cannot ask is refused (mcp_unshield_to_not_allowed) and a decline sends nothing (mcp_unshield_declined). \`to\` must already hold USDC (have a USDC token account): an address without one is refused before any dialog (mcp_unshield_to_invalid). It takes minutes (one wait of up to 5 minutes is normal): the call answers within about 20 s with stage (confirming, queued, refreshing, self-pay = preparing, exit = sending, done; joining = the wallet first gets the balance ready to send, then sends; the answer says how many more asks and when (joinAsks, joinMinutes), ok: true); call wallet_unshield again with the SAME request_id, amount, and to for the status (each call answers within about 20 s, at once when the send ends; a confirmation dialog the user answers may take longer). When the balance is in several parts, the FIRST call answers at once with stage joining and joinTellFirst: true; write its say to the user, then call again with the same request_id at once. One exception: for a single send (no parts, no delay) whose balance is in several parts, when this MCP app sends a progress token with the call, that next call joins the parts and then sends, taking up to ${JOIN_CALL_MAX_MS / 6e4} minutes, with a progress line every ${JOIN_STEP_MS / 1e3} s ("getting your balance ready to send (about M min)"; some apps show none of them, so the time is said before the call, as above). Without a progress token it answers within about 20 s with stage joining and when to ask again. The same request_id never sends twice, also after a restart. request_id is optional: without it the answer names the id it made, and the same call again within 10 minutes after it ends reads that same send. When it lands, the wallet writes an encrypted backup (backupPath). x402_pay calls wait while it runs. An optional owner cap (--max-unshield) may bound each call and what this wallet sends in any 24 hours, from every MCP process (mcp_unshield_cap_exceeded: tell the owner). Other refusals: mcp_argument_invalid, mcp_request_id_reused, mcp_unshield_to_invalid, wallet_locked, mcp_tool_disabled, mcp_unshield_failed, and the unshield's own p03_* codes. PRIVATE SEND (optional): when the user says "send it in parts", "spread it out", or "do not send it all at once", pass parts (2-8) WITH max_delay_minutes (1-60); the parts argument says how it works, and its privacy limit, which you tell the user.`,
|
|
131193
131209
|
inputSchema: {
|
|
131194
131210
|
type: "object",
|
|
131195
131211
|
properties: {
|
|
@@ -131197,7 +131213,7 @@ ${canonical5}`;
|
|
|
131197
131213
|
amount_atomic: { type: "string", pattern: "^[1-9][0-9]*$", description: "USDC to send, in atomic units (1000000 = 1 USDC)." },
|
|
131198
131214
|
to: { type: "string", description: "The receiving Solana address (base58), exactly as the user gave it. Leave it out to send to the owner's own wallet when the owner set exactly one (wallet_balance session.unshield.to); with none or several set, pass it." },
|
|
131199
131215
|
request_id: { type: "string", pattern: "^[A-Za-z0-9._:-]{1,128}$", description: "Optional. Your stable name for this send, like send-1; pass it again to read the status." },
|
|
131200
|
-
parts: { type: "integer", minimum: 1, maximum: 8, description: "Optional, default 1: send the amount as this many separate exits of unequal size (a private send). Each part carries at least 10000 atomic (0.01 USDC). Above 1 it needs max_delay_minutes 1-60." },
|
|
131216
|
+
parts: { type: "integer", minimum: 1, maximum: 8, description: "Optional, default 1: send the amount as this many separate exits of unequal size (a private send). Each part carries at least 10000 atomic (0.01 USDC). Above 1 it needs max_delay_minutes 1-60 (parts with no wait are refused: they would leave together). Each part is sent after a random wait of up to max_delay_minutes (part 1 too), so the chain shows no single exit of this amount at this time; max_delay_minutes alone delays one exit. " + SEND_RUNS_ON + ` Late parts never go together. While parts are unsent, x402_pay may spend only the rest of the balance. The plan is saved in the wallet before part 1, so the same request_id (with the same parts and max_delay_minutes) continues after a restart and never sends a part twice; the answer's privateSend lists each part (state, amount, when it may go, transactions), sentAtomic, and remainingAtomic. The user confirms the whole send once. Each part is a full unshield, so it takes as long as one, and the facilitator pays the network fee of each. Privacy limit (tell the user): every part goes to the SAME \`to\`, so anyone who adds up that address's incoming transfers sees the total; the parts hide the time and the single amount of the exit, not the sum the address received. wallet_cancel with the same request_id stops the parts not sent yet (their value stays in the shielded balance); while a part is being sent, that call waits for the part to finish, up to about ${CALL_BUDGET_MS / 1e3} s.` },
|
|
131201
131217
|
max_delay_minutes: { type: "integer", minimum: 0, maximum: 60, description: "Optional, default 0: each part, part 1 included, is sent after a random wait of up to this many minutes (a private send)." }
|
|
131202
131218
|
},
|
|
131203
131219
|
additionalProperties: false
|
|
@@ -132164,7 +132180,7 @@ ${canonical5}`;
|
|
|
132164
132180
|
async function confirmTransfer(request, quote, decimals) {
|
|
132165
132181
|
const usdcOut = usdcText2(BigInt(quote.outAtomic));
|
|
132166
132182
|
const usdcMin = usdcText2(BigInt(quote.minOutAtomic));
|
|
132167
|
-
const amount =
|
|
132183
|
+
const amount = usdcText2(request.amountAtomic, decimals);
|
|
132168
132184
|
const message = `Sell ${amount} of token ${request.tokenMint} for about ${usdcOut} USDC (at least ${usdcMin}; price impact ${(Number(quote.priceImpactPct) * 100).toFixed(2)} %), shield it, and send it to ${request.to} as ${request.parts} parts, each after a random wait of up to ${request.maxDelayMinutes} min? The address receives USDC, not the token.`;
|
|
132169
132185
|
const askedAt = Date.now();
|
|
132170
132186
|
try {
|
|
@@ -132573,9 +132589,9 @@ ${canonical5}`;
|
|
|
132573
132589
|
const moreTokens = (maxTokens) => Math.max(1024, 2 * maxTokens);
|
|
132574
132590
|
const torRefusal = () => refuse12(
|
|
132575
132591
|
"inference_tor_required",
|
|
132576
|
-
"inference sends the prompt to the AI provider and the company that runs the model, so this wallet sends it only
|
|
132577
|
-
//
|
|
132578
|
-
`Tell the user
|
|
132592
|
+
"inference sends the prompt to the AI provider and the company that runs the model, so this wallet sends it only over Tor (or a proxy the user trusts), where they see the exit and not this machine's IP. This wallet runs without Tor; nothing was sent or paid",
|
|
132593
|
+
// docs/mcp/TOR.md: no flag name, port number or torrc in an agent-app answer outside the one command (here the setup line).
|
|
132594
|
+
`Tell the user: private AI runs only over Tor, and this wallet runs without Tor. To turn Tor on, the user runs ${terminalCommand("setup --yes --prefer-tor")} once in a terminal (it records Tor and checks the wallet's files again; nothing else changes), then reconnects the wallet (${RESTART_STEPS}), and asks again`
|
|
132579
132595
|
);
|
|
132580
132596
|
const inferenceModels = {
|
|
132581
132597
|
name: "inference_models",
|
|
@@ -133460,6 +133476,17 @@ function createSetupTools({
|
|
|
133460
133476
|
recoveryFile ? { recoveryFile } : void 0
|
|
133461
133477
|
);
|
|
133462
133478
|
}
|
|
133479
|
+
if (job.state === "no_tor") {
|
|
133480
|
+
const torBrowser = job.torBrowser === true;
|
|
133481
|
+
job = void 0;
|
|
133482
|
+
const start = torStart();
|
|
133483
|
+
return refuse12(
|
|
133484
|
+
"tor_not_running",
|
|
133485
|
+
`the user chose Tor in the setup question, and Tor is not running on this computer (nothing answers at the wallet's local Tor connection${torBrowser ? "; Tor Browser is open, but it does not give the kind of connection the wallet needs" : ""}); nothing was created or paid`,
|
|
133486
|
+
`Tell the user: ${torBrowser ? "Tor Browser is open, but the wallet needs its own Tor connection. Run the command below." : "Tor hides your IP address, and it is not running on this computer."} Show torStartCommand in one code block, to copy into ${start.where}: this command downloads Tor and starts it for the wallet (more about Tor: https://www.torproject.org). If you can run commands here, offer to run it for the user. Then the user asks again to set up the wallet: it then sets up over Tor and always runs over Tor. Or, to set up without Tor, the user asks again and unticks "${SETUP_TOR_TITLE}" in the question`,
|
|
133487
|
+
{ torStartCommand: start.command }
|
|
133488
|
+
);
|
|
133489
|
+
}
|
|
133463
133490
|
if (job.state === "declined") {
|
|
133464
133491
|
const unshown = job.unshown === true;
|
|
133465
133492
|
job = void 0;
|
|
@@ -133487,19 +133514,11 @@ function createSetupTools({
|
|
|
133487
133514
|
wallet: summary.wallet.status,
|
|
133488
133515
|
...summary.wallet.recoveryFile ? { recoveryFile: summary.wallet.recoveryFile, solanaFeePayer: summary.wallet.solanaFeePayer } : {}
|
|
133489
133516
|
});
|
|
133490
|
-
if (job.state === "restart" && privateInference && job.failure.error === "setup_tor_needs_restart") {
|
|
133491
|
-
return json3({
|
|
133492
|
-
...doneFacts(job.summary),
|
|
133493
|
-
privateInference: true,
|
|
133494
|
-
restartNeeded: true,
|
|
133495
|
-
next: `The wallet is ready.${recoveryNext(job.summary)}${PRIVATE_INFERENCE_NEXT}`
|
|
133496
|
-
});
|
|
133497
|
-
}
|
|
133498
133517
|
if (job.state === "restart") {
|
|
133499
133518
|
return refuse12(
|
|
133500
133519
|
"mcp_setup_restart_needed",
|
|
133501
133520
|
`the wallet is set up, but this MCP server could not start the wallet tools in place (reason: ${job.failure.detail}); nothing was paid or moved`,
|
|
133502
|
-
|
|
133521
|
+
`Tell the user: ${RESTART_STEPS}; the wallet tools start then`,
|
|
133503
133522
|
{ stage: "done" }
|
|
133504
133523
|
);
|
|
133505
133524
|
}
|
|
@@ -133507,15 +133526,16 @@ function createSetupTools({
|
|
|
133507
133526
|
const summary = job.summary;
|
|
133508
133527
|
return json3({
|
|
133509
133528
|
...doneFacts(summary),
|
|
133529
|
+
...summary.tor === true ? { tor: true } : {},
|
|
133510
133530
|
...privateInference ? { privateInference: true } : {},
|
|
133511
|
-
next: `The wallet tools are live in this server: call wallet_balance.${recoveryNext(summary)} To add funds, call wallet_shield after the user sends USDC to solanaFeePayer (no SOL needed), or call wallet_add_funds: it gives a one-time address for any amount from 0.01 USDC. After the user sends USDC there, ask for the balance once: the wallet then sees the USDC and makes it private by itself after a random privacy wait of a few minutes
|
|
133531
|
+
next: `The wallet tools are live in this server: call wallet_balance.${recoveryNext(summary)}` + (summary.tor === true ? " Setup ran over Tor, and the wallet runs over Tor: the servers it talks to do not see this computer's IP address." : "") + (summary.wallet.solanaFeePayer ? " To add funds, call wallet_shield after the user sends USDC to solanaFeePayer (no SOL needed), or call" : " To add funds, call") + " wallet_add_funds: it gives a one-time address for any amount from 0.01 USDC. After the user sends USDC there, ask for the balance once: the wallet then sees the USDC and makes it private by itself after a random privacy wait of a few minutes." + (privateInference ? " Private inference is on: after funding, call inference_chat (with no prompt it lists the models and prices); if this server was started with --no-tor, restart it without --no-tor so it runs behind Tor (inference_chat refuses until then)." : "")
|
|
133512
133532
|
});
|
|
133513
133533
|
}
|
|
133514
133534
|
return json3({ ok: true, stage: job.stage, ...job.progress ? { progress: job.progress } : {}, next: SETUP_POLL_NEXT });
|
|
133515
133535
|
}
|
|
133516
133536
|
async function confirm2(plan) {
|
|
133517
133537
|
const limit = (atomic4) => String(atomic4) === NO_LIMIT_ATOMIC2 ? "no limit" : `${usdc9(atomic4)} USDC`;
|
|
133518
|
-
const message = `Create a Shinjuku Shield wallet on this machine (spending limits: ${limit(plan.maxPaymentAtomic)} per payment, ${limit(plan.maxSessionAtomic)} in any 24 hours)? The keys and a random passphrase stay in private files on this machine
|
|
133538
|
+
const message = `Create a Shinjuku Shield wallet on this machine (spending limits: ${limit(plan.maxPaymentAtomic)} per payment, ${limit(plan.maxSessionAtomic)} in any 24 hours)? The keys and a random passphrase stay in private files on this machine.`;
|
|
133519
133539
|
const askedAt = Date.now();
|
|
133520
133540
|
try {
|
|
133521
133541
|
const answer = await client.elicit({
|
|
@@ -133524,15 +133544,17 @@ function createSetupTools({
|
|
|
133524
133544
|
type: "object",
|
|
133525
133545
|
properties: {
|
|
133526
133546
|
confirm: { type: "boolean", title: "Create the wallet", description: message, default: true },
|
|
133527
|
-
|
|
133547
|
+
tor: { type: "boolean", title: SETUP_TOR_TITLE, description: `${SETUP_TOR_WHY} Setup downloads the wallet's files over Tor too.`, default: true },
|
|
133548
|
+
privateInference: { type: "boolean", title: "Use private inference for your AI now", description: `${PRIVATE_INFERENCE_WHY} It needs Tor, so it turns Tor on.`, default: false }
|
|
133528
133549
|
},
|
|
133529
133550
|
required: ["confirm"]
|
|
133530
133551
|
}
|
|
133531
133552
|
}, elicitTimeoutMs);
|
|
133532
133553
|
const ok = answer?.action === "accept" && answer?.content?.confirm !== false;
|
|
133533
|
-
|
|
133554
|
+
const privateInference = answer?.content?.privateInference === true;
|
|
133555
|
+
return { ok, privateInference, tor: answer?.content?.tor !== false || privateInference, unshown: !ok && elicitUnshown(askedAt, answer) };
|
|
133534
133556
|
} catch (error) {
|
|
133535
|
-
return { ok: false, privateInference: false, unshown: error?.timedOut !== true && elicitUnshown(askedAt) };
|
|
133557
|
+
return { ok: false, privateInference: false, tor: false, unshown: error?.timedOut !== true && elicitUnshown(askedAt) };
|
|
133536
133558
|
}
|
|
133537
133559
|
}
|
|
133538
133560
|
async function begin() {
|
|
@@ -133555,10 +133577,16 @@ function createSetupTools({
|
|
|
133555
133577
|
log(`MCP_SETUP_DECLINED${answer.unshown ? " unshown=true" : ""}`);
|
|
133556
133578
|
return;
|
|
133557
133579
|
}
|
|
133580
|
+
if (answer.tor && !inTorRun() && await localTorProof(TOR_HTTP_TUNNEL) === "refused") {
|
|
133581
|
+
job.torBrowser = await localTorProof(TOR_BROWSER_PORT) !== "refused";
|
|
133582
|
+
job.state = "no_tor";
|
|
133583
|
+
log(`MCP_SETUP_NO_TOR${job.torBrowser ? " tor-browser=open" : ""}`);
|
|
133584
|
+
return;
|
|
133585
|
+
}
|
|
133558
133586
|
job.state = "running";
|
|
133559
133587
|
job.stage = "starting";
|
|
133560
133588
|
job.privateInference = answer.privateInference;
|
|
133561
|
-
log(
|
|
133589
|
+
log(`MCP_SETUP_STARTED tor=${answer.tor}`);
|
|
133562
133590
|
try {
|
|
133563
133591
|
job.summary = await setup.run((stage, progress3) => {
|
|
133564
133592
|
if (stage === "wallet-created" && progress3?.recoveryFile) {
|
|
@@ -133567,7 +133595,7 @@ function createSetupTools({
|
|
|
133567
133595
|
}
|
|
133568
133596
|
job.stage = stage;
|
|
133569
133597
|
job.progress = progress3;
|
|
133570
|
-
}, { privateInference: answer.privateInference });
|
|
133598
|
+
}, { privateInference: answer.privateInference, tor: answer.tor });
|
|
133571
133599
|
} catch (error) {
|
|
133572
133600
|
job.failure = failure2(error, "mcp_setup_failed");
|
|
133573
133601
|
job.state = "failed";
|
|
@@ -133593,7 +133621,7 @@ function createSetupTools({
|
|
|
133593
133621
|
const setupTool = {
|
|
133594
133622
|
name: "shinjuku_setup",
|
|
133595
133623
|
title: "Set up the Shinjuku Shield wallet",
|
|
133596
|
-
description: "The wallet is not set up on this machine yet. Call this when the user wants to pay an x402 URL, check a balance, or shield USDC. It asks the user to confirm in this client (with the spending caps), then creates a self-custody wallet on this machine (keys and a random passphrase in private local files; no tool takes or returns them), downloads and checks the proof tools (about 191 MB, minutes), and switches this server to the wallet tools. Takes no arguments. Call it again with no arguments as `next` says for the stage (confirming, platform, release, passphrase, wallet, proof-tools, config, done). A decline creates nothing (mcp_setup_declined). A client that cannot confirm is refused (mcp_setup_needs_terminal) with the terminal command; a client that declines at once without showing the dialog gets mcp_setup_declined with the same terminal command.",
|
|
133624
|
+
description: "The wallet is not set up on this machine yet. Call this when the user wants to pay an x402 URL, check a balance, or shield USDC. It asks the user to confirm in this client (with the spending caps), then creates a self-custody wallet on this machine (keys and a random passphrase in private local files; no tool takes or returns them), downloads and checks the proof tools (about 191 MB, minutes), and switches this server to the wallet tools. Takes no arguments. Call it again with no arguments as `next` says for the stage (confirming, tor, platform, release, passphrase, wallet, proof-tools, config, done). A decline creates nothing (mcp_setup_declined). A client that cannot confirm is refused (mcp_setup_needs_terminal) with the terminal command; a client that declines at once without showing the dialog gets mcp_setup_declined with the same terminal command.",
|
|
133597
133625
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
133598
133626
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
133599
133627
|
run: () => begin()
|
|
@@ -133628,11 +133656,11 @@ function createSetupTools({
|
|
|
133628
133656
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
133629
133657
|
// Hidden after setup are hidden here too (callable by name, not listed).
|
|
133630
133658
|
...MCP_HIDDEN_TOOL_NAMES.includes(name) ? { hidden: true } : {},
|
|
133631
|
-
// After setup, a switch that could not happen
|
|
133659
|
+
// After setup, a switch that could not happen (the wallet did not open, or its server behind Tor did not start) keeps every money tool refused.
|
|
133632
133660
|
run: async () => job?.state === "restart" ? refuse12(
|
|
133633
133661
|
"mcp_setup_restart_needed",
|
|
133634
133662
|
`the wallet is set up, but this MCP server could not start the wallet tools in place (reason: ${job.failure.detail}); nothing was paid or moved`,
|
|
133635
|
-
|
|
133663
|
+
`Tell the user: ${RESTART_STEPS}; the wallet tools start then`,
|
|
133636
133664
|
{ stage: "done" }
|
|
133637
133665
|
) : refuse12(
|
|
133638
133666
|
"wallet_not_set_up",
|
|
@@ -133646,9 +133674,32 @@ function createSetupTools({
|
|
|
133646
133674
|
description: "The wallet is set up and its tools are live. Answers the setup summary; it never creates a second wallet.",
|
|
133647
133675
|
run: async () => job ? status() : json3({ ok: true, stage: "done", walletReady: true, next: "call wallet_balance" })
|
|
133648
133676
|
};
|
|
133649
|
-
|
|
133677
|
+
const discoverNow = inTorRun();
|
|
133678
|
+
const discoverAfterSetup = () => {
|
|
133679
|
+
const tool = notSetUp("x402_discover");
|
|
133680
|
+
return {
|
|
133681
|
+
...tool,
|
|
133682
|
+
description: "Finds x402 sellers after setup. Before setup it sends nothing: setup first asks the user whether to use Tor, which hides this computer's IP address from the servers that list sellers. Call shinjuku_setup first.",
|
|
133683
|
+
run: async (args) => job?.state === "restart" ? tool.run(args) : refuse12(
|
|
133684
|
+
"wallet_not_set_up",
|
|
133685
|
+
"x402_discover asks Shinjuku and other servers for their seller lists, and they would see this computer's IP address before the user chose whether to use Tor; nothing was sent",
|
|
133686
|
+
"Tell the user: set up the wallet first; setup asks one question, whether to use Tor (it hides your IP address). Then call shinjuku_setup; after setup, call x402_discover again",
|
|
133687
|
+
...job ? [{ stage: job.stage }] : []
|
|
133688
|
+
)
|
|
133689
|
+
};
|
|
133690
|
+
};
|
|
133691
|
+
const sayOnRefusal = (tool) => ({ ...tool, run: async (args, ctx) => {
|
|
133692
|
+
const output2 = await tool.run(args, ctx);
|
|
133693
|
+
const text3 = typeof output2?.text === "string" ? output2.text : output2?.content?.[0]?.text;
|
|
133694
|
+
return typeof text3 === "string" && /^\s*\{\s*"ok"\s*:\s*false\b/.test(text3) ? addSay(output2, tool.name, { npmVersion }) : output2;
|
|
133695
|
+
} });
|
|
133696
|
+
const discover = discoverNow ? withSay(discoverTool(discoverCacheDir), { npmVersion }) : sayOnRefusal(discoverAfterSetup());
|
|
133697
|
+
return {
|
|
133698
|
+
tools: [sayOnRefusal(setupTool), statusTool, ...MCP_TOOL_NAMES.map((name) => name !== "x402_discover" ? sayOnRefusal(notSetUp(name)) : discover)],
|
|
133699
|
+
doneTool: sayOnRefusal(doneTool)
|
|
133700
|
+
};
|
|
133650
133701
|
}
|
|
133651
|
-
var import_web3133, shownCaps, RELEASE_RETRY_MS, STAGE_WORDS, stageWords, INTERNAL_BALANCE_DETAIL, shownBreakdown, sessionLeftShown, TOKEN_UNIT_TOOLS, RESOURCE_PAYMENT_WAL_PREFIX2, POOL_LAYOUT_CODE, POOL_LAYOUT_UPDATE, USEPOD_VIA_INFERENCE_CHAT, SEND_RUNS_ON, DEPOSIT_RUNS_ON, CLI_FUNDS_PLAN_PREFIX, CLI_FUNDS_SCHEMA, SELF_PAY_ORIGIN3, REQUEST_ID4, POSITIVE_ATOMIC6, PRIVATE_HOST3, FORBIDDEN_HEADERS3, MAX_BODY_BYTES2, PREVIEW_TIMEOUT_MS, PREVIEW_SELLER_READ_MS, CALL_BUDGET_MS, budgetLeft, MONEY_FIRST_ANSWER_MS, BALANCE_AFTER_LANDING_MS, JOIN_CALL_MAX_MS, JOIN_NUDGE_QUIET_MS, JOIN_STEP_MS, sleep2, PROGRESS_EVERY_MS2, READ_BUDGET_MS, UNPAID_TOR_TRY_MS, UNPAID_CLEAR_MS, READ_BUDGET_TOOLS, FLOAT_BUSY_CODES, RETRY_MARGIN_MS, ASK_PAY_CODES, runningNpmVersion, terminalCommand, capPlaceWords, capRaiseText, cheaperSellerText, limitNext, SAFE_TEXT, MCP_TOOL_ALIASES, POOL_SWITCH_WHY, POOL_SWITCH_NEXT, SWITCH_STATES, quietSwitch, switchKey, ATOMIC_TEXT, FLOAT_ID, ANSWERED_EXIT_RETRY_MS, ANSWERED_EXIT_UNCONFIRMED_MS, ANSWERED_EXIT_RETRY_WINDOW_MS, ANSWERED_EXIT_CLOSED, switchAmount, switchEta, switchRows, OWNER_CAP_CODES, JOIN_END_MCP, JOIN_END_TERMINAL_LIBRARY, JOIN_RETRY_BACKOFF_MS, WALLET_CAP_FIX, MCP_CAP_FIX, capFix, ownerOnlyNext, mcpNext, CONFIDENTIAL_RETIRED, json3, answerResult, discoverTool, refuse12, publicOffer, FLOAT_PAID_CODES, FLOAT_PRIVATE_LEG, floatStillSettling, MONEY_ID2, toRecordId, linkKindOf, moneyId, REFUSED_CODES, refusedCodeOf, PLAIN_REASONS, plainReason, KEPT_SEND_TRIES, shownId, isSplitSend, sendPartId, PROMISED_NEXT, PUBLIC_READ_TIMEOUT_MS, withTimeout, ownKey, readFailure, OWN_KEY_TOKENS_MAX, OWN_TOKENS_GRACE_MS, tokenAmountText, elsewhereId, AGENT_ID_SCHEMA, agentIdName, minutesText2, ageWords2, DEPOSIT_SENT_STATES, depositLanded, usdcText2, walkWalletHistory, REFRESH_LEASE_WALK_MS, HOME_MARKS_SETTLED_MS2, AUTO_BACKUPS_KEPT, AUTO_BACKUP_NAME, AUTO_BACKUP_VERIFIED, FRONTED_SETTLE_MARGIN_SLOTS, BALANCE_REFRESH_WAIT_MS, BALANCE_REFRESH_GRACE_MS, BALANCE_REFRESH_LONG_MS, INBOUND_REFRESH_AGE_MS, CAP_BALANCE_WAIT_MS, CAP_BALANCE_RETRY_MS, REFRESH_RETRY_MS, FINALITY_POLL_MS, FINALITY_WAIT_MS, FINALITY_REFRESH_LIMIT_MS, POOL_WATCH_MS, POOL_WATCH_POLL_MS, EARLY_BALANCE_DELAY_MS, FINALITY_SETTLE_WINDOW_SLOTS, PUBLIC_READ_ANSWER_MS, SWITCH_WAIT_MS, UNSHIELD_TO_NO_USDC_DETAIL, UNSHIELD_TO_INVALID_NEXT, INFERENCE_MIN_MAX_TOKENS, ELICIT_TIMEOUT_MS, ELICIT_UNSHOWN_MS, elicitUnshown, POLL_SECONDS3, TRANSFER_CHANGE_READ_MS, TEMP_CLEAN_DELAY_MS, KEPT_ON_DISK, MAX_SHIELDED_BALANCE_ATOMIC, receiveGenerator, MCP_TOOL_NAMES, MCP_HIDDEN_TOOL_NAMES, setupTerminalNext, SETUP_POLL_NEXT, PRIVATE_INFERENCE_WHY,
|
|
133702
|
+
var import_web3133, shownCaps, RELEASE_RETRY_MS, STAGE_WORDS, stageWords, INTERNAL_BALANCE_DETAIL, shownBreakdown, sessionLeftShown, TOKEN_UNIT_TOOLS, RESOURCE_PAYMENT_WAL_PREFIX2, POOL_LAYOUT_CODE, POOL_LAYOUT_UPDATE, USEPOD_VIA_INFERENCE_CHAT, SEND_RUNS_ON, DEPOSIT_RUNS_ON, CLI_FUNDS_PLAN_PREFIX, CLI_FUNDS_SCHEMA, SELF_PAY_ORIGIN3, REQUEST_ID4, POSITIVE_ATOMIC6, PRIVATE_HOST3, FORBIDDEN_HEADERS3, MAX_BODY_BYTES2, PREVIEW_TIMEOUT_MS, PREVIEW_SELLER_READ_MS, CALL_BUDGET_MS, budgetLeft, MONEY_FIRST_ANSWER_MS, BALANCE_AFTER_LANDING_MS, JOIN_CALL_MAX_MS, JOIN_NUDGE_QUIET_MS, JOIN_STEP_MS, sleep2, PROGRESS_EVERY_MS2, READ_BUDGET_MS, UNPAID_TOR_TRY_MS, UNPAID_CLEAR_MS, READ_BUDGET_TOOLS, FLOAT_BUSY_CODES, RETRY_MARGIN_MS, ASK_PAY_CODES, runningNpmVersion, terminalCommand, capPlaceWords, capRaiseText, cheaperSellerText, limitNext, SAFE_TEXT, MCP_TOOL_ALIASES, POOL_SWITCH_WHY, POOL_SWITCH_NEXT, SWITCH_STATES, quietSwitch, switchKey, ATOMIC_TEXT, FLOAT_ID, ANSWERED_EXIT_RETRY_MS, ANSWERED_EXIT_UNCONFIRMED_MS, ANSWERED_EXIT_RETRY_WINDOW_MS, ANSWERED_EXIT_CLOSED, switchAmount, switchEta, switchRows, OWNER_CAP_CODES, JOIN_END_MCP, JOIN_END_TERMINAL_LIBRARY, JOIN_RETRY_BACKOFF_MS, WALLET_CAP_FIX, MCP_CAP_FIX, capFix, ownerOnlyNext, mcpNext, CONFIDENTIAL_RETIRED, json3, answerResult, discoverTool, refuse12, publicOffer, FLOAT_PAID_CODES, FLOAT_PRIVATE_LEG, floatStillSettling, MONEY_ID2, toRecordId, linkKindOf, moneyId, REFUSED_CODES, refusedCodeOf, PLAIN_REASONS, plainReason, KEPT_SEND_TRIES, shownId, isSplitSend, sendPartId, PROMISED_NEXT, PUBLIC_READ_TIMEOUT_MS, RECIPIENT_CHECK_TIMEOUT_MS, withTimeout, ownKey, readFailure, OWN_KEY_TOKENS_MAX, OWN_TOKENS_GRACE_MS, tokenAmountText, elsewhereId, AGENT_ID_SCHEMA, agentIdName, minutesText2, ageWords2, DEPOSIT_SENT_STATES, depositLanded, usdcText2, walkWalletHistory, REFRESH_LEASE_WALK_MS, HOME_MARKS_SETTLED_MS2, AUTO_BACKUPS_KEPT, AUTO_BACKUP_NAME, AUTO_BACKUP_VERIFIED, FRONTED_SETTLE_MARGIN_SLOTS, BALANCE_REFRESH_WAIT_MS, BALANCE_REFRESH_GRACE_MS, BALANCE_REFRESH_LONG_MS, INBOUND_REFRESH_AGE_MS, CAP_BALANCE_WAIT_MS, CAP_BALANCE_RETRY_MS, REFRESH_RETRY_MS, FINALITY_POLL_MS, FINALITY_WAIT_MS, FINALITY_REFRESH_LIMIT_MS, POOL_WATCH_MS, POOL_WATCH_POLL_MS, EARLY_BALANCE_DELAY_MS, FINALITY_SETTLE_WINDOW_SLOTS, PUBLIC_READ_ANSWER_MS, SWITCH_WAIT_MS, UNSHIELD_TO_NO_USDC_DETAIL, UNSHIELD_TO_INVALID_NEXT, INFERENCE_MIN_MAX_TOKENS, ELICIT_TIMEOUT_MS, ELICIT_UNSHOWN_MS, elicitUnshown, POLL_SECONDS3, TRANSFER_CHANGE_READ_MS, TEMP_CLEAN_DELAY_MS, KEPT_ON_DISK, MAX_SHIELDED_BALANCE_ATOMIC, receiveGenerator, MCP_TOOL_NAMES, MCP_HIDDEN_TOOL_NAMES, setupTerminalNext, SETUP_POLL_NEXT, PRIVATE_INFERENCE_WHY, RESTART_STEPS, TOR_BROWSER_PORT, SETUP_TOR_TITLE, SETUP_TOR_WHY;
|
|
133652
133703
|
var init_tools = __esm({
|
|
133653
133704
|
"wallet/src/mcp/tools.mjs"() {
|
|
133654
133705
|
"use strict";
|
|
@@ -133976,6 +134027,7 @@ var init_tools = __esm({
|
|
|
133976
134027
|
sendPartId = (requestId) => (index) => `mp${index}-${toRecordId(requestId)}`;
|
|
133977
134028
|
PROMISED_NEXT = "Nothing was sent. Part of the shielded balance is promised to the unsent parts of a private send. Wait until that send is done (wallet_unshield with its request_id shows its parts), or stop its unsent parts with wallet_cancel and its request_id, then call wallet_unshield again with the same arguments; or send at most freeAtomic now with a NEW request_id";
|
|
133978
134029
|
PUBLIC_READ_TIMEOUT_MS = 3e4;
|
|
134030
|
+
RECIPIENT_CHECK_TIMEOUT_MS = 8e3;
|
|
133979
134031
|
withTimeout = (promise, ms) => Promise.race([
|
|
133980
134032
|
promise,
|
|
133981
134033
|
new Promise((_, reject) => {
|
|
@@ -134080,10 +134132,13 @@ var init_tools = __esm({
|
|
|
134080
134132
|
"inference_models",
|
|
134081
134133
|
"wallet_receive_shielded"
|
|
134082
134134
|
]);
|
|
134083
|
-
setupTerminalNext = () => `Tell the user to run \`${terminalCommand("setup")}\` in a terminal on this machine, then
|
|
134135
|
+
setupTerminalNext = () => `Tell the user to run \`${terminalCommand("setup")}\` in a terminal on this machine, then reconnect the wallet (${RESTART_STEPS})`;
|
|
134084
134136
|
SETUP_POLL_NEXT = `call shinjuku_setup again in ${POLL_SECONDS3} s for the status (it never creates a second wallet)`;
|
|
134085
134137
|
PRIVATE_INFERENCE_WHY = "Your agent then buys AI answers from an AI provider, paid from your private balance over Tor; the AI provider and the company that runs the model see the prompt, not who paid.";
|
|
134086
|
-
|
|
134138
|
+
RESTART_STEPS = "In Claude Code: type /mcp, pick shinjuku-shielded, and choose Reconnect. In Claude Desktop: quit it and open it again. In another app: restart it";
|
|
134139
|
+
TOR_BROWSER_PORT = "http://127.0.0.1:9150";
|
|
134140
|
+
SETUP_TOR_TITLE = "Use Tor?";
|
|
134141
|
+
SETUP_TOR_WHY = "It hides your IP address from the payment service and sellers.";
|
|
134087
134142
|
}
|
|
134088
134143
|
});
|
|
134089
134144
|
|
|
@@ -134202,7 +134257,7 @@ function createMcpDispatcher({ tools, instructions: instructions2 = INSTRUCTIONS
|
|
|
134202
134257
|
};
|
|
134203
134258
|
}
|
|
134204
134259
|
function serveStdio({ input, output: output2, dispatch, log = () => {
|
|
134205
|
-
}, client }) {
|
|
134260
|
+
}, client, forward = () => false }) {
|
|
134206
134261
|
const inFlight = /* @__PURE__ */ new Set();
|
|
134207
134262
|
const write = (message) => {
|
|
134208
134263
|
if (message === void 0) return;
|
|
@@ -134248,6 +134303,7 @@ function serveStdio({ input, output: output2, dispatch, log = () => {
|
|
|
134248
134303
|
write(parseError);
|
|
134249
134304
|
return;
|
|
134250
134305
|
}
|
|
134306
|
+
if (forward(text3, message)) return;
|
|
134251
134307
|
if (takeResponse(message)) return;
|
|
134252
134308
|
const task = (async () => {
|
|
134253
134309
|
if (Array.isArray(message)) {
|
|
@@ -135099,6 +135155,70 @@ function startProofToolsRefresh({
|
|
|
135099
135155
|
clearTimeout(retry);
|
|
135100
135156
|
};
|
|
135101
135157
|
}
|
|
135158
|
+
function startTorRelay({ spawn: spawn10, initParams, output: output2, log, rewrite = (line) => line, readyMs = TOR_RELAY_READY_MS }) {
|
|
135159
|
+
const child = spawn10();
|
|
135160
|
+
let ready = false;
|
|
135161
|
+
let settle;
|
|
135162
|
+
const answered2 = new Promise((resolvePromise, rejectPromise) => {
|
|
135163
|
+
settle = { resolve: resolvePromise, reject: rejectPromise };
|
|
135164
|
+
});
|
|
135165
|
+
const exited = new Promise((resolvePromise) => {
|
|
135166
|
+
child.on("error", (error) => {
|
|
135167
|
+
log(`MCP_TOR_RELAY_SPAWN_FAILED ${error?.code ?? error?.name ?? "Error"}`);
|
|
135168
|
+
resolvePromise(1);
|
|
135169
|
+
});
|
|
135170
|
+
child.on("exit", (code2, signal) => resolvePromise(code2 ?? (signal ? 1 : 0)));
|
|
135171
|
+
});
|
|
135172
|
+
exited.then((code2) => {
|
|
135173
|
+
if (!ready) settle.reject(new Error(`setup_tor_wallet_ended: the wallet server behind Tor ended (exit code ${code2}) before it answered; its own lines are in this server's log`));
|
|
135174
|
+
});
|
|
135175
|
+
const timer = setTimeout(() => settle.reject(new Error(`setup_tor_wallet_slow: the wallet server behind Tor gave no answer in ${readyMs / 1e3} s`)), readyMs);
|
|
135176
|
+
timer.unref?.();
|
|
135177
|
+
let buffer = "";
|
|
135178
|
+
child.stdout.setEncoding("utf8");
|
|
135179
|
+
child.stdout.on("data", (chunk) => {
|
|
135180
|
+
buffer += chunk;
|
|
135181
|
+
let newline;
|
|
135182
|
+
while ((newline = buffer.indexOf("\n")) !== -1) {
|
|
135183
|
+
const line = buffer.slice(0, newline);
|
|
135184
|
+
buffer = buffer.slice(newline + 1);
|
|
135185
|
+
if (!line.trim()) continue;
|
|
135186
|
+
if (!ready) {
|
|
135187
|
+
let message;
|
|
135188
|
+
try {
|
|
135189
|
+
message = JSON.parse(line);
|
|
135190
|
+
} catch {
|
|
135191
|
+
message = void 0;
|
|
135192
|
+
}
|
|
135193
|
+
if (message?.id === RELAY_INIT_ID) {
|
|
135194
|
+
ready = true;
|
|
135195
|
+
clearTimeout(timer);
|
|
135196
|
+
settle.resolve();
|
|
135197
|
+
continue;
|
|
135198
|
+
}
|
|
135199
|
+
}
|
|
135200
|
+
output2.write(`${rewrite(line)}
|
|
135201
|
+
`);
|
|
135202
|
+
}
|
|
135203
|
+
});
|
|
135204
|
+
child.stdin.on("error", () => {
|
|
135205
|
+
});
|
|
135206
|
+
const write = (line) => {
|
|
135207
|
+
if (child.stdin.writable) child.stdin.write(`${line}
|
|
135208
|
+
`);
|
|
135209
|
+
};
|
|
135210
|
+
write(JSON.stringify({
|
|
135211
|
+
jsonrpc: "2.0",
|
|
135212
|
+
id: RELAY_INIT_ID,
|
|
135213
|
+
method: "initialize",
|
|
135214
|
+
params: initParams ?? { protocolVersion: SUPPORTED_PROTOCOL_VERSIONS[0], capabilities: {}, clientInfo: { name: "shinjuku-setup-relay", version: "1" } }
|
|
135215
|
+
}));
|
|
135216
|
+
write(JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" }));
|
|
135217
|
+
return answered2.then(() => ({ write, end: () => child.stdin.end(), exited }), (error) => {
|
|
135218
|
+
child.kill("SIGTERM");
|
|
135219
|
+
throw error;
|
|
135220
|
+
});
|
|
135221
|
+
}
|
|
135102
135222
|
async function runSetupModeServer({
|
|
135103
135223
|
setupTools,
|
|
135104
135224
|
startNormal,
|
|
@@ -135106,13 +135226,13 @@ async function runSetupModeServer({
|
|
|
135106
135226
|
output: output2 = process.stdout,
|
|
135107
135227
|
errorOutput = process.stderr,
|
|
135108
135228
|
updateCheck,
|
|
135109
|
-
discoverCacheDir,
|
|
135110
135229
|
launchNotice
|
|
135111
135230
|
}) {
|
|
135112
135231
|
const log = (line) => errorOutput.write(`${line}
|
|
135113
135232
|
`);
|
|
135114
135233
|
const client = createClientBridge();
|
|
135115
|
-
const
|
|
135234
|
+
const startNotice = (facilitator) => startUpdateNotice({ facilitator, log, ...updateCheck !== void 0 ? { check: updateCheck } : {} });
|
|
135235
|
+
let notice = startUpdateNotice({ log, check: false });
|
|
135116
135236
|
const saved = { log: console.log, info: console.info, debug: console.debug };
|
|
135117
135237
|
const toStderr = (...parts) => console.error(...parts);
|
|
135118
135238
|
console.log = toStderr;
|
|
@@ -135122,11 +135242,48 @@ async function runSetupModeServer({
|
|
|
135122
135242
|
let doneTool;
|
|
135123
135243
|
let current;
|
|
135124
135244
|
let ended;
|
|
135245
|
+
let initParams;
|
|
135246
|
+
let relay;
|
|
135247
|
+
let relayStopped;
|
|
135248
|
+
const relayEnded = new Promise((resolvePromise) => {
|
|
135249
|
+
relayStopped = resolvePromise;
|
|
135250
|
+
});
|
|
135251
|
+
const listIds = /* @__PURE__ */ new Set();
|
|
135252
|
+
const withDoneTool = (line) => {
|
|
135253
|
+
if (!doneTool || !listIds.size) return line;
|
|
135254
|
+
let message;
|
|
135255
|
+
try {
|
|
135256
|
+
message = JSON.parse(line);
|
|
135257
|
+
} catch {
|
|
135258
|
+
return line;
|
|
135259
|
+
}
|
|
135260
|
+
if (!listIds.delete(message?.id) || !Array.isArray(message?.result?.tools)) return line;
|
|
135261
|
+
const listed = {
|
|
135262
|
+
name: doneTool.name,
|
|
135263
|
+
title: doneTool.title,
|
|
135264
|
+
description: doneTool.description,
|
|
135265
|
+
inputSchema: doneTool.inputSchema,
|
|
135266
|
+
annotations: { title: doneTool.title, ...doneTool.annotations }
|
|
135267
|
+
};
|
|
135268
|
+
return JSON.stringify({ ...message, result: { ...message.result, tools: [...message.result.tools.filter((tool) => tool?.name !== doneTool.name), listed] } });
|
|
135269
|
+
};
|
|
135125
135270
|
const stopKeepWarm = startOnionKeepWarm();
|
|
135126
135271
|
const activate = async () => {
|
|
135127
|
-
if (wallet) return;
|
|
135272
|
+
if (wallet || relay) return;
|
|
135128
135273
|
const options = await startNormal();
|
|
135274
|
+
if (options.relay) {
|
|
135275
|
+
relay = await startTorRelay({ spawn: options.relay, initParams, output: output2, log, rewrite: withDoneTool });
|
|
135276
|
+
relay.exited.then((code2) => {
|
|
135277
|
+
log(`MCP_TOR_RELAY_ENDED code=${code2}`);
|
|
135278
|
+
relayStopped();
|
|
135279
|
+
});
|
|
135280
|
+
current = createMcpDispatcher({ tools: doneTool ? [doneTool] : [], instructions: INSTRUCTIONS, log, client, listChanged: true });
|
|
135281
|
+
log("MCP_SETUP_SWITCHED to the wallet server behind Tor");
|
|
135282
|
+
client.notify?.("notifications/tools/list_changed");
|
|
135283
|
+
return;
|
|
135284
|
+
}
|
|
135129
135285
|
wallet = await openWalletServer({ ...options, client, log });
|
|
135286
|
+
notice = startNotice(options.memoServiceUrl);
|
|
135130
135287
|
current = createMcpDispatcher({
|
|
135131
135288
|
tools: withLaunchNotice(notice.wrapTools([...wallet.tools, ...doneTool ? [doneTool] : []], UPDATE_NOTICE_TOOLS), launchNotice),
|
|
135132
135289
|
instructions: withLaunchLine(notice.instructions(INSTRUCTIONS), launchNotice),
|
|
@@ -135140,8 +135297,6 @@ async function runSetupModeServer({
|
|
|
135140
135297
|
};
|
|
135141
135298
|
try {
|
|
135142
135299
|
const setup = setupTools({ client, log, activate });
|
|
135143
|
-
if (discoverCacheDir) loadX402Listings({ cacheDir: discoverCacheDir }).catch(() => {
|
|
135144
|
-
});
|
|
135145
135300
|
doneTool = setup.doneTool;
|
|
135146
135301
|
if (launchNotice) log(`MCP_LAUNCH_OLD_FORM ${launchNotice}`);
|
|
135147
135302
|
current = createMcpDispatcher({
|
|
@@ -135153,15 +135308,30 @@ async function runSetupModeServer({
|
|
|
135153
135308
|
listChanged: true
|
|
135154
135309
|
});
|
|
135155
135310
|
log("MCP_READY setup-mode: the wallet is not set up; tools: shinjuku_setup, wallet_status");
|
|
135156
|
-
|
|
135311
|
+
const forward = (text3, message) => {
|
|
135312
|
+
if (!relay) return false;
|
|
135313
|
+
if (message?.method === "tools/call" && message.params?.name === "shinjuku_setup") return false;
|
|
135314
|
+
if (message?.method === "tools/list" && validId(message.id)) listIds.add(message.id);
|
|
135315
|
+
relay.write(text3);
|
|
135316
|
+
return true;
|
|
135317
|
+
};
|
|
135318
|
+
const served = serveStdio({ input, output: output2, log, client, forward, dispatch: (entry) => {
|
|
135319
|
+
if (entry?.method === "initialize") initParams = entry.params;
|
|
135320
|
+
return current(entry);
|
|
135321
|
+
} });
|
|
135322
|
+
await Promise.race([served, relayEnded]);
|
|
135157
135323
|
} finally {
|
|
135158
135324
|
stopKeepWarm();
|
|
135325
|
+
if (relay) {
|
|
135326
|
+
relay.end();
|
|
135327
|
+
await relay.exited;
|
|
135328
|
+
}
|
|
135159
135329
|
ended = wallet ? await closeWithin(wallet.close(), { moving: wallet.moving, movingWork: wallet.movingWork, historyBusy: closeHistoryBusy(wallet), log }) : true;
|
|
135160
135330
|
Object.assign(console, saved);
|
|
135161
135331
|
}
|
|
135162
135332
|
return { closed: ended };
|
|
135163
135333
|
}
|
|
135164
|
-
var import_web3134, SUPPORTED_PROTOCOL_VERSIONS, MAX_LINE_BYTES, POSITIVE_ATOMIC7, INSTRUCTIONS, MCP_LOG_LEVELS, POOL_SWITCH_LOG_LEVEL, validId, BUNDLED_SOURCE_DIR, SHA256_HEX, UPDATE_NOTICE_TOOLS, UPDATE_NOTICE_MAX_TEXT, NPM_VERSION2, GIT_COMMIT, ownWalletVersion, mcpServerVersion, UPDATE_NOTICE_TEXT, updateNoticeLine, LAUNCH_NOTICE_TOOLS, withLaunchLine, capRequired, setupInvalid, TOOL_ROOTS_WAIT_MS, ROOTS_FREE_TOOLS, MCP_CLOSE_BOUND_MS, MCP_CLOSE_HISTORY_BOUND_MS, MCP_CLOSE_UNREADABLE_BOUND_MS, MCP_CLOSE_POLL_MS, closeHistoryBusy, SETUP_INSTRUCTIONS;
|
|
135334
|
+
var import_web3134, SUPPORTED_PROTOCOL_VERSIONS, MAX_LINE_BYTES, POSITIVE_ATOMIC7, INSTRUCTIONS, MCP_LOG_LEVELS, POOL_SWITCH_LOG_LEVEL, validId, BUNDLED_SOURCE_DIR, SHA256_HEX, UPDATE_NOTICE_TOOLS, UPDATE_NOTICE_MAX_TEXT, NPM_VERSION2, GIT_COMMIT, ownWalletVersion, mcpServerVersion, UPDATE_NOTICE_TEXT, updateNoticeLine, LAUNCH_NOTICE_TOOLS, withLaunchLine, capRequired, setupInvalid, TOOL_ROOTS_WAIT_MS, ROOTS_FREE_TOOLS, MCP_CLOSE_BOUND_MS, MCP_CLOSE_HISTORY_BOUND_MS, MCP_CLOSE_UNREADABLE_BOUND_MS, MCP_CLOSE_POLL_MS, closeHistoryBusy, SETUP_INSTRUCTIONS, TOR_RELAY_READY_MS, RELAY_INIT_ID;
|
|
135165
135335
|
var init_stdioServer = __esm({
|
|
135166
135336
|
"wallet/src/mcp/stdioServer.mjs"() {
|
|
135167
135337
|
"use strict";
|
|
@@ -135192,7 +135362,7 @@ var init_stdioServer = __esm({
|
|
|
135192
135362
|
SUPPORTED_PROTOCOL_VERSIONS = Object.freeze(["2025-06-18", "2025-03-26", "2024-11-05"]);
|
|
135193
135363
|
MAX_LINE_BYTES = 4 * 1024 * 1024;
|
|
135194
135364
|
POSITIVE_ATOMIC7 = /^[1-9][0-9]{0,30}$/;
|
|
135195
|
-
INSTRUCTIONS = `A self-custody Shinjuku Shield wallet on this machine; the keys and the passphrase stay in this process and no tool takes or returns them. Every tool answer starts with say: one plain sentence to tell the user; the other fields hold the exact numbers. Map the user's plain request to one tool: "what is my balance" -> wallet_balance; "add money" / "deposit" / "fund the wallet" / "move USDC in from Phantom, an exchange, or another wallet" -> wallet_add_funds (it answers a one-time
|
|
135365
|
+
INSTRUCTIONS = `A self-custody Shinjuku Shield wallet on this machine; the keys and the passphrase stay in this process and no tool takes or returns them. Every tool answer starts with say: one plain sentence to tell the user; the other fields hold the exact numbers. Map the user's plain request to one tool: "what is my balance" -> wallet_balance; "add money" / "deposit" / "fund the wallet" / "move USDC in from Phantom, an exchange, or another wallet" -> wallet_add_funds (it answers a one-time address; the money becomes private a few minutes after it arrives, at the next wallet call); "shield the USDC on this wallet's own address" -> wallet_shield (only public USDC already there); "stop" / "cancel" -> wallet_cancel with the request_id of what to stop; "pay this URL" -> x402_pay (call it directly, no preview is needed); "what does this URL cost" -> x402_preview (only when the user asks for the price); "find a paid API for X" -> x402_discover, then x402_pay on the url it found; "send 2 USDC to <address>" -> wallet_unshield. wallet_balance answers ONE balance (balanceAtomic), and x402_pay pays any x402 seller from it (through Shinjuku for a seller that cannot take a private payment: max_payment must cover the total amountAtomic, fee included; a refund comes back by itself within about 7 minutes). Fields ending in Atomic are atomic units (USDC: 1000000 = 1 USDC); tell the user amounts in USDC. The wallet does its upkeep by itself (chain reads, encrypted backups); the user never runs a CLI command for it. wallet_shield, wallet_add_funds, and wallet_unshield can run for minutes: call again with the SAME request_id as next says. Pass your own request_id to x402_pay: the same request_id never pays or moves money twice (on a code that ends in _retry_same_request, call again with it). wallet_unshield never sends to the wallet's own deposit address; a send to an address the owner did not approve ahead asks the user to confirm it in this client first. When the owner set limits, x402_pay never pays above them (one payment, and any 24 hours for this wallet across all MCP processes); with none, the balance is the only bound. Never claim a payment happened unless the answer has a transaction. Privacy: the chain does not show which wallet paid, but this MCP host and its model provider see every URL, body, price, and paid answer the agent handles. When an item of an answer's poolSwitch.items[] has tellUser true, tell the user its message once, in plain words; the wallet moves the balance by itself.`;
|
|
135196
135366
|
MCP_LOG_LEVELS = Object.freeze(["debug", "info", "notice", "warning", "error", "critical", "alert", "emergency"]);
|
|
135197
135367
|
POOL_SWITCH_LOG_LEVEL = "info";
|
|
135198
135368
|
validId = (id) => id === null || typeof id === "string" || typeof id === "number" && Number.isFinite(id);
|
|
@@ -135220,7 +135390,9 @@ var init_stdioServer = __esm({
|
|
|
135220
135390
|
MCP_CLOSE_UNREADABLE_BOUND_MS = 6e4;
|
|
135221
135391
|
MCP_CLOSE_POLL_MS = 500;
|
|
135222
135392
|
closeHistoryBusy = (server) => () => compactHistoryReadsRunning() > 0 || memoReadsAheadRunning() > 0 || server.refreshOpen?.() === true;
|
|
135223
|
-
SETUP_INSTRUCTIONS = `
|
|
135393
|
+
SETUP_INSTRUCTIONS = `This Shinjuku Shield wallet server is NOT SET UP on this machine yet: every money tool answers wallet_not_set_up. When the user wants to pay, check a balance, or add money, call shinjuku_setup: it asks the user to confirm in this client, creates the wallet here, and downloads the proof tools (minutes: call it again as its next says). At stage done the wallet tools are live in this same server. After setup: ${INSTRUCTIONS}`;
|
|
135394
|
+
TOR_RELAY_READY_MS = 18e4;
|
|
135395
|
+
RELAY_INIT_ID = "shinjuku-wallet-relay-initialize";
|
|
135224
135396
|
}
|
|
135225
135397
|
});
|
|
135226
135398
|
|
|
@@ -135595,7 +135767,7 @@ async function serveTorMissingMcp({ message, recheck = async () => false, input
|
|
|
135595
135767
|
ready = false;
|
|
135596
135768
|
}
|
|
135597
135769
|
const body = ready ? {
|
|
135598
|
-
say:
|
|
135770
|
+
say: "Tor runs now. Reconnect the wallet once (the steps are below), then ask again. Nothing was paid.",
|
|
135599
135771
|
ok: false,
|
|
135600
135772
|
error: "mcp_restart_needed",
|
|
135601
135773
|
next: `Tell the user: ${RESTART}. Nothing was paid.`
|
|
@@ -135634,7 +135806,7 @@ var init_torMissingMcp = __esm({
|
|
|
135634
135806
|
"use strict";
|
|
135635
135807
|
init_stdioServer();
|
|
135636
135808
|
init_tools();
|
|
135637
|
-
RESTART =
|
|
135809
|
+
RESTART = `Reconnect the wallet once (${RESTART_STEPS}), then ask again`;
|
|
135638
135810
|
}
|
|
135639
135811
|
});
|
|
135640
135812
|
|
|
@@ -159643,7 +159815,8 @@ var PublicFundsFailure = class extends Error {
|
|
|
159643
159815
|
};
|
|
159644
159816
|
var failure = (code2, text3) => new PublicFundsFailure(`p03_funds_${code2}: ${text3}`);
|
|
159645
159817
|
var iso2 = (ms) => new Date(ms).toISOString();
|
|
159646
|
-
var
|
|
159818
|
+
var plainUsdc = (text3) => text3.includes(".") ? text3.replace(/0+$/, "").replace(/\.$/, "") : text3;
|
|
159819
|
+
var usdc5 = (atomic4, decimals = 6) => plainUsdc(formatAtomic(BigInt(atomic4), decimals));
|
|
159647
159820
|
var usdcFlag = usdcFlagText;
|
|
159648
159821
|
var planName = (fundsId) => `${FUNDS_PLAN_PREFIX2}${fundsId}`;
|
|
159649
159822
|
var lockPath = (walletFile) => `${walletFile}.add-funds.lock`;
|
|
@@ -159862,7 +160035,7 @@ function fundsView(store, plan, { now = Date.now(), running } = {}) {
|
|
|
159862
160035
|
function fundsSummary(view2) {
|
|
159863
160036
|
const privacy = `. Privacy: ${view2.privacy}`;
|
|
159864
160037
|
const status = view2.status.endsWith(privacy) ? view2.status.slice(0, -privacy.length) : view2.status;
|
|
159865
|
-
const total = view2.balance?.total ? ` (your balance now: ${view2.balance.total} USDC)` : "";
|
|
160038
|
+
const total = view2.balance?.total ? ` (your balance now: ${plainUsdc(String(view2.balance.total))} USDC)` : "";
|
|
159866
160039
|
return [
|
|
159867
160040
|
view2.ready ? `add-funds ${view2.fundsId} is ready: ${view2.amount} was added to your shielded balance${total}.` : `add-funds ${view2.fundsId} is not ready yet: ${status}.`,
|
|
159868
160041
|
`Next: ${view2.next}.`
|
|
@@ -159894,6 +160067,7 @@ function fundsStatusSummary(view2) {
|
|
|
159894
160067
|
}
|
|
159895
160068
|
var HELD = /^(shinjuku(?:-wallet)?\b.*\bfailed: |shinjuku(?:-wallet)?\b.*: waiting for funds, nothing failed \(|hint: |Help: |next: |Examples?:|Every flag: | shinjuku(?:-wallet)? )/;
|
|
159896
160069
|
var STEP_TOR_LINE = /^(?:tor|proxy): /;
|
|
160070
|
+
var DENOMINATION_WARNING = /^warning: no pool denomination is configured\b/;
|
|
159897
160071
|
async function runStep(ctx, argv2) {
|
|
159898
160072
|
if (ctx.signal.aborted) return { exit: 1, held: [], codes: [], details: {}, aborted: true };
|
|
159899
160073
|
const file = join37(ctx.tempDir, `step-${randomBytes28(8).toString("hex")}.json`);
|
|
@@ -159919,7 +160093,7 @@ async function runStep(ctx, argv2) {
|
|
|
159919
160093
|
`);
|
|
159920
160094
|
return;
|
|
159921
160095
|
}
|
|
159922
|
-
if (ctx.quiet && isProgressLine(text3)) return;
|
|
160096
|
+
if (ctx.quiet && (isProgressLine(text3) || DENOMINATION_WARNING.test(text3))) return;
|
|
159923
160097
|
if (!text3.trim() || ctx.shown.has(text3)) return;
|
|
159924
160098
|
ctx.shown.add(text3);
|
|
159925
160099
|
ctx.io.err(` ${text3}
|
|
@@ -161958,6 +162132,7 @@ async function runInferStop(values, deps) {
|
|
|
161958
162132
|
var CHAT_RAW_ARGS = /* @__PURE__ */ Symbol("chat raw args");
|
|
161959
162133
|
var WALLET_FROM_SETUP = /* @__PURE__ */ Symbol("wallet from setup");
|
|
161960
162134
|
var RAN_BEHIND_TOR = /* @__PURE__ */ Symbol("ran behind tor");
|
|
162135
|
+
var SETUP_RERUN = /* @__PURE__ */ Symbol("setup rerun");
|
|
161961
162136
|
var INFER_CAP_FLAGS = Object.freeze(["--max-payment", "--max-session"]);
|
|
161962
162137
|
var RanBehindTorFailed = class extends Error {
|
|
161963
162138
|
constructor(code2) {
|
|
@@ -162216,15 +162391,7 @@ function withProofToolsRefresh(options, fromConfig) {
|
|
|
162216
162391
|
var inProxiedRun = (env) => childRunProxy(env).args.length > 0;
|
|
162217
162392
|
var terminalQuiet = (values, deps) => deps.stdoutIsTTY?.() === true && !values.has("--json") && !values.has("--verbose");
|
|
162218
162393
|
var TOR_RUN_STARTED_ENV2 = "SHINJUKU_WALLET_TOR_RUN_STARTED_FILE";
|
|
162219
|
-
var TOR_DOWN_DETAIL = "
|
|
162220
|
-
var recordedTunnelHost = (configPath2) => {
|
|
162221
|
-
try {
|
|
162222
|
-
const tunnel = readSetupConfig(dirname33(configPath2))?.torTunnel;
|
|
162223
|
-
return tunnel ? new URL(tunnel).host : "127.0.0.1:9080";
|
|
162224
|
-
} catch {
|
|
162225
|
-
return "127.0.0.1:9080";
|
|
162226
|
-
}
|
|
162227
|
-
};
|
|
162394
|
+
var TOR_DOWN_DETAIL = "The wallet runs only over Tor, and Tor is not running on this computer (after the computer restarts, Tor must be started again), so nothing was paid or sent.";
|
|
162228
162395
|
var recordedTunnelUrl = (configPath2) => {
|
|
162229
162396
|
try {
|
|
162230
162397
|
return readSetupConfig(dirname33(configPath2))?.torTunnel ?? TOR_HTTP_TUNNEL;
|
|
@@ -162232,11 +162399,18 @@ var recordedTunnelUrl = (configPath2) => {
|
|
|
162232
162399
|
return TOR_HTTP_TUNNEL;
|
|
162233
162400
|
}
|
|
162234
162401
|
};
|
|
162235
|
-
var torDownNext = (configPath2) => `Tell the user:
|
|
162402
|
+
var torDownNext = (configPath2) => `Tell the user why: Tor is not running, and the wallet never falls back to a direct connection. Show torStartCommand in one code block, to copy into ${torStart().where}: this command downloads Tor and starts it for the wallet. If you can run commands here, offer to run it for the user. When Tor runs: ${RESTART}. (Setup recorded Tor in ${configPath2}.)`;
|
|
162236
162403
|
async function runMcpTorDown({ exitCode, configPath: configPath2, input = process.stdin, output: output2 = process.stdout, errorOutput = process.stderr }) {
|
|
162237
162404
|
const log = (line) => errorOutput.write(`${line}
|
|
162238
162405
|
`);
|
|
162239
|
-
const unavailable = JSON.stringify({
|
|
162406
|
+
const unavailable = JSON.stringify({
|
|
162407
|
+
say: "Not paid: the wallet runs only over Tor, and Tor is not running on this computer. Start it with the command below.",
|
|
162408
|
+
ok: false,
|
|
162409
|
+
error: "mcp_tor_unavailable",
|
|
162410
|
+
detail: TOR_DOWN_DETAIL,
|
|
162411
|
+
next: torDownNext(configPath2),
|
|
162412
|
+
torStartCommand: torStart().command
|
|
162413
|
+
}, null, 2);
|
|
162240
162414
|
const tunnel = recordedTunnelUrl(configPath2);
|
|
162241
162415
|
const answer = async () => {
|
|
162242
162416
|
let ready = false;
|
|
@@ -162246,7 +162420,7 @@ async function runMcpTorDown({ exitCode, configPath: configPath2, input = proces
|
|
|
162246
162420
|
ready = false;
|
|
162247
162421
|
}
|
|
162248
162422
|
const restart = ready ? {
|
|
162249
|
-
say:
|
|
162423
|
+
say: "Tor runs now. Reconnect the wallet once (the steps are below), then ask again. Nothing was paid.",
|
|
162250
162424
|
ok: false,
|
|
162251
162425
|
error: "mcp_restart_needed",
|
|
162252
162426
|
next: `Tell the user: ${RESTART}. Nothing was paid.`
|
|
@@ -162378,11 +162552,12 @@ async function runMcpFirstRun(values, deps) {
|
|
|
162378
162552
|
discoverCacheDir: join40(home, "discover-cache"),
|
|
162379
162553
|
npmVersion: deps.walletVersion().npm
|
|
162380
162554
|
}),
|
|
162381
|
-
discoverCacheDir: join40(home, "discover-cache"),
|
|
162382
162555
|
startNormal: async () => {
|
|
162383
162556
|
const after = mcpValuesAfterSetup(values, home, deps);
|
|
162384
|
-
|
|
162385
|
-
|
|
162557
|
+
const config = after.values.get(MCP_FROM_CONFIG).config;
|
|
162558
|
+
if (config.tor === true && !after.values.has("--no-tor") && !inProxiedRun(deps.env)) {
|
|
162559
|
+
const args = ["--tor", "mcp", ...after.values.get(MCP_RAW_ARGS), ...config.torTunnel ? ["--proxy", config.torTunnel] : []];
|
|
162560
|
+
return { relay: () => deps.torChild(args, ["pipe", "pipe", "inherit"]) };
|
|
162386
162561
|
}
|
|
162387
162562
|
const options = withProofToolsRefresh(mcpServerOptions(after.values, after.deps), after.values.get(MCP_FROM_CONFIG));
|
|
162388
162563
|
warm = options.proofToolsPath ? deps.startKeepWarm(options, deps.env) : void 0;
|
|
@@ -162410,14 +162585,45 @@ function mcpSetupAdapter(values, home, deps) {
|
|
|
162410
162585
|
},
|
|
162411
162586
|
missing: () => missingPieces(home, readSetupConfig(home)),
|
|
162412
162587
|
// privateInference: the human ticked "Use private inference for your AI now" (a yes, as setup --private-inference);
|
|
162413
|
-
// no tick keeps what config.json records.
|
|
162414
|
-
|
|
162415
|
-
|
|
162416
|
-
|
|
162417
|
-
|
|
162418
|
-
|
|
162588
|
+
// no tick keeps what config.json records. tor: the answer to "Use Tor?" (private inference turns it on). A server
|
|
162589
|
+
// already behind Tor (or an old caller with no answer) sets up in place.
|
|
162590
|
+
run: async (onStage, { privateInference, tor } = {}) => {
|
|
162591
|
+
if (tor === true && !inProxiedRun(deps.env)) return mcpSetupBehindTor(values, home, deps, { privateInference: privateInference === true, onStage });
|
|
162592
|
+
return runSetupRecorded(
|
|
162593
|
+
{ ...setupOptionsOf(values, home), ...typeof tor === "boolean" ? { tor } : {}, onStage },
|
|
162594
|
+
setupDeps,
|
|
162595
|
+
inferenceRecordOf(readSetupConfig(home), privateInference === true ? true : void 0)
|
|
162596
|
+
);
|
|
162597
|
+
}
|
|
162419
162598
|
};
|
|
162420
162599
|
}
|
|
162600
|
+
async function mcpSetupBehindTor(values, home, deps, { privateInference, onStage }) {
|
|
162601
|
+
const caps = new Map(Object.entries(setupOptionsOf(values, home)).filter(([key]) => key !== "home").map(([key, value]) => [`--${key.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)}`, value]));
|
|
162602
|
+
onStage("tor", "setup runs over Tor: it makes the wallet and downloads its files (about 191 MB) over Tor, which takes a few minutes");
|
|
162603
|
+
const child = deps.torChild(
|
|
162604
|
+
["--tor", "setup", "--yes", "--prefer-tor", ...privateInference ? ["--private-inference"] : [], ...setupArgvOf(caps)],
|
|
162605
|
+
["ignore", 2, 2]
|
|
162606
|
+
);
|
|
162607
|
+
const code2 = await new Promise((resolvePromise) => {
|
|
162608
|
+
child.on("error", () => resolvePromise(1));
|
|
162609
|
+
child.on("exit", (exitCode, signal) => resolvePromise(exitCode ?? (signal ? 1 : 0)));
|
|
162610
|
+
});
|
|
162611
|
+
const config = code2 === 0 ? setupConfigOf(home) : void 0;
|
|
162612
|
+
if (!config) {
|
|
162613
|
+
const made = setupConfigOf(home)?.recoveryFile;
|
|
162614
|
+
if (made && existsSync(made)) onStage("wallet-created", { recoveryFile: made });
|
|
162615
|
+
throw new Error(`setup_tor_unavailable: setup ran behind Tor, and that run ended with exit code ${code2} (its lines are in this server's log); nothing was paid. It continues where it stopped when it runs again`);
|
|
162616
|
+
}
|
|
162617
|
+
onStage("tor", "the wallet is made; its server starts over Tor now (the first Tor connection can take a minute)");
|
|
162618
|
+
const recoveryFile = config.recoveryFile && existsSync(config.recoveryFile) ? config.recoveryFile : void 0;
|
|
162619
|
+
return Object.freeze({
|
|
162620
|
+
pool: config.pool,
|
|
162621
|
+
caps: config.caps,
|
|
162622
|
+
tor: true,
|
|
162623
|
+
wallet: { status: recoveryFile ? "created" : "existing", ...recoveryFile ? { recoveryFile } : {} },
|
|
162624
|
+
...privateInference ? { privateInference: true } : {}
|
|
162625
|
+
});
|
|
162626
|
+
}
|
|
162421
162627
|
function inferenceRecordOf(old, answer) {
|
|
162422
162628
|
const recorded = typeof old?.inference?.enabled === "boolean" ? old.inference.enabled : void 0;
|
|
162423
162629
|
if (answer === true) return true;
|
|
@@ -162714,13 +162920,14 @@ async function runSetupCommand(values, deps) {
|
|
|
162714
162920
|
let ownAddress = values.get("--own-address");
|
|
162715
162921
|
const old = setupConfigOf(home);
|
|
162716
162922
|
const behindTor = (wanted) => wanted && !values.has("--no-tor") && !inProxiedRun(deps.env);
|
|
162923
|
+
const missing = missingPieces(home, old);
|
|
162924
|
+
if (old && !missing.length) values.set(SETUP_RERUN, "settings");
|
|
162717
162925
|
if (!interactive && behindTor(values.has("--prefer-tor") || values.has("--private-inference") || old?.tor === true)) {
|
|
162718
162926
|
await setupBehindTor(setupArgvOf(values), deps);
|
|
162719
162927
|
if (ownAddress) io.out(`${recordOwnAddress(home, ownAddress, deps).join("\n")}
|
|
162720
162928
|
`);
|
|
162721
162929
|
return void 0;
|
|
162722
162930
|
}
|
|
162723
|
-
const missing = missingPieces(home, old);
|
|
162724
162931
|
const npmVersion = deps.walletVersion().npm;
|
|
162725
162932
|
const introduced = values.has("--yes") && inProxiedRun(deps.env);
|
|
162726
162933
|
const asksOwnFirst = interactive && Boolean(old) && terminal && !ownAddress;
|
|
@@ -162742,7 +162949,7 @@ async function runSetupCommand(values, deps) {
|
|
|
162742
162949
|
...values.has("--max-shield") ? { maxShield: values.get("--max-shield") } : {},
|
|
162743
162950
|
...values.has("--max-unshield") ? { maxUnshield: values.get("--max-unshield") } : {},
|
|
162744
162951
|
...values.has("--prefer-tor") || torRunRecords ? { tor: true } : {},
|
|
162745
|
-
// This --tor run's own local tunnel when it is not 127.0.0.1:9080 (setup --tor --proxy http://127.0.0.1:
|
|
162952
|
+
// This --tor run's own local tunnel when it is not 127.0.0.1:9080 (another local Tor HTTPTunnelPort, for example a second tor process: setup --tor --proxy http://127.0.0.1:9180): mcp uses it.
|
|
162746
162953
|
...torRunRecords && childRunProxy(deps.env).args[1] === "--proxy" ? { torTunnel: childRunProxy(deps.env).args[2] } : {},
|
|
162747
162954
|
...values.has("--passphrase-file") ? { passphraseFile: values.get("--passphrase-file") } : {},
|
|
162748
162955
|
...values.has("--facilitator") ? { facilitator: values.get("--facilitator") } : {},
|
|
@@ -162775,6 +162982,7 @@ async function runSetupCommand(values, deps) {
|
|
|
162775
162982
|
if (/^setup_own_address_[a-z_]+: /.test(String(error?.message))) throw new PublicFailure(error.message);
|
|
162776
162983
|
throw error;
|
|
162777
162984
|
}
|
|
162985
|
+
values.set(SETUP_RERUN, "own-address");
|
|
162778
162986
|
io.out([
|
|
162779
162987
|
`Saved: ${ownAddress} is your own address now, so your agent sends money back to you there without asking each time (no restart of your agent app needed).`,
|
|
162780
162988
|
...saved.dropped.length ? [`config.json keeps ${MAX_OWN_ADDRESSES} own addresses: the oldest (${saved.dropped.join(", ")}) now ask before each send.`] : [],
|
|
@@ -162856,25 +163064,33 @@ Copy it to two offline places now; it is the only way to restore this wallet.
|
|
|
162856
163064
|
lines.push("");
|
|
162857
163065
|
io.out(`${lines.join("\n")}
|
|
162858
163066
|
`);
|
|
163067
|
+
const rerun = values.get(SETUP_RERUN) === "settings";
|
|
162859
163068
|
const targets = values.get("--add-to") ?? [];
|
|
162860
163069
|
if (targets.length) addToHosts(targets, home, deps, { force: values.has("--force"), npmVersion });
|
|
162861
|
-
|
|
163070
|
+
if (rerun && !targets.length) {
|
|
163071
|
+
io.out("Your agent app keeps its MCP entry: restart this wallet's MCP server there (or restart the app) so it reads these settings. To add the wallet to another agent app, run setup again with --add-to claude-code, claude-desktop, or cursor.\n");
|
|
163072
|
+
} else {
|
|
163073
|
+
io.out(`${targets.length ? "Or add it by hand" : "Add it to your agent host"}:
|
|
162862
163074
|
${hostConfigText({ home, env: deps.env, platform: deps.platform ?? process.platform, npmVersion })}
|
|
162863
163075
|
`);
|
|
162864
|
-
|
|
163076
|
+
io.out(`
|
|
162865
163077
|
${terminalUseLines(npmVersion).join("\n")}
|
|
162866
163078
|
`);
|
|
163079
|
+
}
|
|
162867
163080
|
const config = setupConfigOf(home);
|
|
163081
|
+
const inferenceNow = summary.privateInference === true && (!rerun || old?.inference?.enabled !== true);
|
|
162868
163082
|
let apiKey;
|
|
162869
|
-
if (
|
|
163083
|
+
if (inferenceNow && config?.pool) {
|
|
162870
163084
|
try {
|
|
162871
163085
|
apiKey = localAiServerApiKey(home, { walletPath: homeWalletPath(home, config.pool) });
|
|
162872
163086
|
} catch {
|
|
162873
163087
|
apiKey = void 0;
|
|
162874
163088
|
}
|
|
162875
163089
|
}
|
|
162876
|
-
io.out(`
|
|
162877
|
-
${
|
|
163090
|
+
if (inferenceNow) io.out(`
|
|
163091
|
+
${privateInferencePath(config, { apiKey }).text}`);
|
|
163092
|
+
else if (!rerun) io.out(`
|
|
163093
|
+
${fundingStepText(config?.tor === true)}`);
|
|
162878
163094
|
if (interactive) await offerFundNow(deps, { tor: config?.tor === true });
|
|
162879
163095
|
}
|
|
162880
163096
|
function validateAddFunds(values) {
|
|
@@ -163735,8 +163951,9 @@ var COMMANDS = [
|
|
|
163735
163951
|
"A command that takes --pool (balance, recover, deposit, add-funds, and others) takes it, and the passphrase of this home's wallet, from config.json when you leave them out: shinjuku balance needs no flags. A pocket command (pocket list, scan, reshield, release, fill) takes this home's --wallet and passphrase file the same way, and --program, --proof-tools, --facilitator when it needs them. A flag or SHIELDED_WALLET_PASSPHRASE still wins; init and restore never use config.json, and move reads it itself."
|
|
163736
163952
|
],
|
|
163737
163953
|
next: `start it from your agent host with npx -y --no-audit --no-fund ${NPX_AT_VERSION} mcp (or ${CLI2} mcp), then ask your agent "what is my balance"`,
|
|
163738
|
-
// After a run: the same line as the host config setup printed (this npm version, when the wallet knows it).
|
|
163739
|
-
|
|
163954
|
+
// After a run: the same line as the host config setup printed (this npm version, when the wallet knows it). A rerun
|
|
163955
|
+
// of a complete setup (SETUP_RERUN): the agent app already has the entry.
|
|
163956
|
+
nextAfterRun: (values, deps) => values.get(SETUP_RERUN) === "settings" ? `restart this wallet's MCP server in your agent app (or restart the app) so it reads these settings, then ask your agent "what is my balance"` : values.get(SETUP_RERUN) === "own-address" ? "ask your agent to send money to your own address: it sends without asking you each time" : `start it from your agent host with npx -y --no-audit --no-fund ${npxPackageWord(deps.walletVersion().npm)} mcp (or ${CLI2} mcp), then ask your agent "what is my balance"`,
|
|
163740
163957
|
run: (args, values, deps, io) => deps.setupMain(values, { ...deps, io })
|
|
163741
163958
|
},
|
|
163742
163959
|
{
|
|
@@ -166247,6 +166464,8 @@ function defaultDependencies() {
|
|
|
166247
166464
|
else process.env[TOR_RUN_STARTED_ENV2] = before;
|
|
166248
166465
|
}
|
|
166249
166466
|
},
|
|
166467
|
+
/** One command line as a child behind Tor with the given stdio (the MCP setup server's Tor setup and Tor wallet server). */
|
|
166468
|
+
torChild: (argv2, stdio) => torChild(argv2, stdio),
|
|
166250
166469
|
// No command calls these (the v0b and laneb families are retired, RETIRED_FAMILIES). They stay only because
|
|
166251
166470
|
// wallet/scripts/bundle.mjs still requires the V0b zk-sdk WASM in the bundle; drop both together.
|
|
166252
166471
|
v0bMain: async (...args) => (await Promise.resolve().then(() => (init_cli4(), cli_exports))).v0bMain(...args),
|