shinjuku-shield 0.3.92 → 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 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.92. The npm packages `shinjuku-shield` and
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.92 setup
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.92
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.92 mcp
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.92", "mcp"] } } }
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": "afa037c8868c722838c0642335b1767af4bcc0040878ae441e83cb94dd9aeea2",
5
- "bytes": 12692822,
6
- "sourceCommit": "3b6e926704a348088fa33d114ed7913e2d610033",
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-24T02:20:31.413Z"
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.92",
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": "afa037c8",
7
- "shinjukuSha256": "afa037c8868c722838c0642335b1767af4bcc0040878ae441e83cb94dd9aeea2",
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",
@@ -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 reexec(args, mode, plainProxy) {
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 = spawn(process.execPath, [...proxiedExecArgv(process.execArgv), process.argv[1], ...args], { env, stdio: "inherit" });
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
- 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, TUNNEL_LINE, TOR_INSTALL, 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;
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 this app must restart to use it. Restart this app, then try again.";
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 restart this app.`;
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: "no Tor: the facilitator, the RPC provider and each seller see this computer's IP address; start the MCP with --tor (or run setup --prefer-tor) to hide it" } };
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 });
@@ -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 from a --tor or --proxy run, where they see the proxy's exit and not this machine's IP. This MCP server was started without --tor or --proxy; nothing was sent or paid",
132577
- // The exact npm version when this wallet knows it (npmVersion: stdioServer.mjs walletVersion().npm; the owner's pin, 2026-10-23).
132578
- `Tell the user to add --tor to this MCP server's launch line in the host (for example \`npx -y --no-audit --no-fund ${npxPackageWord(npmVersion)} mcp --tor\`, with Tor's HTTPTunnelPort 127.0.0.1:9080 on), or --proxy http://host:port for an HTTP proxy they trust, then restart the server and call inference_chat again`
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
- "Tell the user to restart this MCP server in the host (or restart the host app); the wallet tools start then",
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.` + (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)." : "")
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. Optional: tick "Use private inference for your AI now". ${PRIVATE_INFERENCE_WHY} It records Tor for this server (Tor must run with HTTPTunnelPort 127.0.0.1:9080).`;
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
- privateInference: { type: "boolean", title: "Use private inference for your AI now", description: PRIVATE_INFERENCE_WHY, default: false }
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
- return { ok, privateInference: answer?.content?.privateInference === true, unshown: !ok && elicitUnshown(askedAt, answer) };
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("MCP_SETUP_STARTED");
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 in place (Tor, or the wallet did not open) keeps every money tool refused.
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
- "Tell the user to restart this MCP server in the host (or restart the host app); the wallet tools start then",
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
- return { tools: [setupTool, statusTool, ...MCP_TOOL_NAMES.map((name) => name === "x402_discover" ? discoverTool(discoverCacheDir) : notSetUp(name))], doneTool };
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, 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, PRIVATE_INFERENCE_NEXT;
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";
@@ -134081,10 +134132,13 @@ var init_tools = __esm({
134081
134132
  "inference_models",
134082
134133
  "wallet_receive_shielded"
134083
134134
  ]);
134084
- setupTerminalNext = () => `Tell the user to run \`${terminalCommand("setup")}\` in a terminal on this machine, then restart this MCP server in the host`;
134135
+ setupTerminalNext = () => `Tell the user to run \`${terminalCommand("setup")}\` in a terminal on this machine, then reconnect the wallet (${RESTART_STEPS})`;
134085
134136
  SETUP_POLL_NEXT = `call shinjuku_setup again in ${POLL_SECONDS3} s for the status (it never creates a second wallet)`;
134086
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.";
134087
- PRIVATE_INFERENCE_NEXT = " Private inference is on: config.json records Tor, so restart this MCP server in the host now; it then runs behind Tor (Tor must run with HTTPTunnelPort 127.0.0.1:9080), and until then every wallet tool and inference_chat stay refused. After the restart: fund the wallet with wallet_add_funds (it gives a one-time address; after the user sends USDC there from any wallet, 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), then call inference_chat (with no prompt it lists the models; a short qwen3-8-flash answer costs about 0.001 USDC, 0.011 USDC when the AI provider offers only its standard payment). For another agent app, call inference_server: it starts the local AI address and gives its base_url and api key.";
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.";
134088
134142
  }
134089
134143
  });
134090
134144
 
@@ -134203,7 +134257,7 @@ function createMcpDispatcher({ tools, instructions: instructions2 = INSTRUCTIONS
134203
134257
  };
134204
134258
  }
134205
134259
  function serveStdio({ input, output: output2, dispatch, log = () => {
134206
- }, client }) {
134260
+ }, client, forward = () => false }) {
134207
134261
  const inFlight = /* @__PURE__ */ new Set();
134208
134262
  const write = (message) => {
134209
134263
  if (message === void 0) return;
@@ -134249,6 +134303,7 @@ function serveStdio({ input, output: output2, dispatch, log = () => {
134249
134303
  write(parseError);
134250
134304
  return;
134251
134305
  }
134306
+ if (forward(text3, message)) return;
134252
134307
  if (takeResponse(message)) return;
134253
134308
  const task = (async () => {
134254
134309
  if (Array.isArray(message)) {
@@ -135100,6 +135155,70 @@ function startProofToolsRefresh({
135100
135155
  clearTimeout(retry);
135101
135156
  };
135102
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
+ }
135103
135222
  async function runSetupModeServer({
135104
135223
  setupTools,
135105
135224
  startNormal,
@@ -135107,13 +135226,13 @@ async function runSetupModeServer({
135107
135226
  output: output2 = process.stdout,
135108
135227
  errorOutput = process.stderr,
135109
135228
  updateCheck,
135110
- discoverCacheDir,
135111
135229
  launchNotice
135112
135230
  }) {
135113
135231
  const log = (line) => errorOutput.write(`${line}
135114
135232
  `);
135115
135233
  const client = createClientBridge();
135116
- const notice = startUpdateNotice({ log, ...updateCheck !== void 0 ? { check: updateCheck } : {} });
135234
+ const startNotice = (facilitator) => startUpdateNotice({ facilitator, log, ...updateCheck !== void 0 ? { check: updateCheck } : {} });
135235
+ let notice = startUpdateNotice({ log, check: false });
135117
135236
  const saved = { log: console.log, info: console.info, debug: console.debug };
135118
135237
  const toStderr = (...parts) => console.error(...parts);
135119
135238
  console.log = toStderr;
@@ -135123,11 +135242,48 @@ async function runSetupModeServer({
135123
135242
  let doneTool;
135124
135243
  let current;
135125
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
+ };
135126
135270
  const stopKeepWarm = startOnionKeepWarm();
135127
135271
  const activate = async () => {
135128
- if (wallet) return;
135272
+ if (wallet || relay) return;
135129
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
+ }
135130
135285
  wallet = await openWalletServer({ ...options, client, log });
135286
+ notice = startNotice(options.memoServiceUrl);
135131
135287
  current = createMcpDispatcher({
135132
135288
  tools: withLaunchNotice(notice.wrapTools([...wallet.tools, ...doneTool ? [doneTool] : []], UPDATE_NOTICE_TOOLS), launchNotice),
135133
135289
  instructions: withLaunchLine(notice.instructions(INSTRUCTIONS), launchNotice),
@@ -135141,8 +135297,6 @@ async function runSetupModeServer({
135141
135297
  };
135142
135298
  try {
135143
135299
  const setup = setupTools({ client, log, activate });
135144
- if (discoverCacheDir) loadX402Listings({ cacheDir: discoverCacheDir }).catch(() => {
135145
- });
135146
135300
  doneTool = setup.doneTool;
135147
135301
  if (launchNotice) log(`MCP_LAUNCH_OLD_FORM ${launchNotice}`);
135148
135302
  current = createMcpDispatcher({
@@ -135154,15 +135308,30 @@ async function runSetupModeServer({
135154
135308
  listChanged: true
135155
135309
  });
135156
135310
  log("MCP_READY setup-mode: the wallet is not set up; tools: shinjuku_setup, wallet_status");
135157
- await serveStdio({ input, output: output2, dispatch: (entry) => current(entry), log, client });
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]);
135158
135323
  } finally {
135159
135324
  stopKeepWarm();
135325
+ if (relay) {
135326
+ relay.end();
135327
+ await relay.exited;
135328
+ }
135160
135329
  ended = wallet ? await closeWithin(wallet.close(), { moving: wallet.moving, movingWork: wallet.movingWork, historyBusy: closeHistoryBusy(wallet), log }) : true;
135161
135330
  Object.assign(console, saved);
135162
135331
  }
135163
135332
  return { closed: ended };
135164
135333
  }
135165
- 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;
135166
135335
  var init_stdioServer = __esm({
135167
135336
  "wallet/src/mcp/stdioServer.mjs"() {
135168
135337
  "use strict";
@@ -135222,6 +135391,8 @@ var init_stdioServer = __esm({
135222
135391
  MCP_CLOSE_POLL_MS = 500;
135223
135392
  closeHistoryBusy = (server) => () => compactHistoryReadsRunning() > 0 || memoReadsAheadRunning() > 0 || server.refreshOpen?.() === true;
135224
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";
135225
135396
  }
135226
135397
  });
135227
135398
 
@@ -135596,7 +135767,7 @@ async function serveTorMissingMcp({ message, recheck = async () => false, input
135596
135767
  ready = false;
135597
135768
  }
135598
135769
  const body = ready ? {
135599
- say: `Tor runs on this machine now, but this wallet started before it did. ${RESTART}.`,
135770
+ say: "Tor runs now. Reconnect the wallet once (the steps are below), then ask again. Nothing was paid.",
135600
135771
  ok: false,
135601
135772
  error: "mcp_restart_needed",
135602
135773
  next: `Tell the user: ${RESTART}. Nothing was paid.`
@@ -135635,7 +135806,7 @@ var init_torMissingMcp = __esm({
135635
135806
  "use strict";
135636
135807
  init_stdioServer();
135637
135808
  init_tools();
135638
- RESTART = "Restart this MCP server in your app (or restart the app), then ask again";
135809
+ RESTART = `Reconnect the wallet once (${RESTART_STEPS}), then ask again`;
135639
135810
  }
135640
135811
  });
135641
135812
 
@@ -161961,6 +162132,7 @@ async function runInferStop(values, deps) {
161961
162132
  var CHAT_RAW_ARGS = /* @__PURE__ */ Symbol("chat raw args");
161962
162133
  var WALLET_FROM_SETUP = /* @__PURE__ */ Symbol("wallet from setup");
161963
162134
  var RAN_BEHIND_TOR = /* @__PURE__ */ Symbol("ran behind tor");
162135
+ var SETUP_RERUN = /* @__PURE__ */ Symbol("setup rerun");
161964
162136
  var INFER_CAP_FLAGS = Object.freeze(["--max-payment", "--max-session"]);
161965
162137
  var RanBehindTorFailed = class extends Error {
161966
162138
  constructor(code2) {
@@ -162219,15 +162391,7 @@ function withProofToolsRefresh(options, fromConfig) {
162219
162391
  var inProxiedRun = (env) => childRunProxy(env).args.length > 0;
162220
162392
  var terminalQuiet = (values, deps) => deps.stdoutIsTTY?.() === true && !values.has("--json") && !values.has("--verbose");
162221
162393
  var TOR_RUN_STARTED_ENV2 = "SHINJUKU_WALLET_TOR_RUN_STARTED_FILE";
162222
- var TOR_DOWN_DETAIL = "Your private connection (Tor) is not running, so no payment was made. Start Tor, then restart this MCP server in your agent host and try again.";
162223
- var recordedTunnelHost = (configPath2) => {
162224
- try {
162225
- const tunnel = readSetupConfig(dirname33(configPath2))?.torTunnel;
162226
- return tunnel ? new URL(tunnel).host : "127.0.0.1:9080";
162227
- } catch {
162228
- return "127.0.0.1:9080";
162229
- }
162230
- };
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.";
162231
162395
  var recordedTunnelUrl = (configPath2) => {
162232
162396
  try {
162233
162397
  return readSetupConfig(dirname33(configPath2))?.torTunnel ?? TOR_HTTP_TUNNEL;
@@ -162235,11 +162399,18 @@ var recordedTunnelUrl = (configPath2) => {
162235
162399
  return TOR_HTTP_TUNNEL;
162236
162400
  }
162237
162401
  };
162238
- var torDownNext = (configPath2) => `Tell the user: start Tor (its torrc needs HTTPTunnelPort ${recordedTunnelHost(configPath2)}), then restart this MCP server in the agent host (or restart the host app); the wallet tools start behind Tor then. Setup recorded Tor in ${configPath2}; a setup rerun keeps it. Nothing falls back to a direct connection. If Tor is not installed: ${torInstallText()}`;
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}.)`;
162239
162403
  async function runMcpTorDown({ exitCode, configPath: configPath2, input = process.stdin, output: output2 = process.stdout, errorOutput = process.stderr }) {
162240
162404
  const log = (line) => errorOutput.write(`${line}
162241
162405
  `);
162242
- const unavailable = JSON.stringify({ ok: false, error: "mcp_tor_unavailable", detail: TOR_DOWN_DETAIL, next: torDownNext(configPath2) }, null, 2);
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);
162243
162414
  const tunnel = recordedTunnelUrl(configPath2);
162244
162415
  const answer = async () => {
162245
162416
  let ready = false;
@@ -162249,7 +162420,7 @@ async function runMcpTorDown({ exitCode, configPath: configPath2, input = proces
162249
162420
  ready = false;
162250
162421
  }
162251
162422
  const restart = ready ? {
162252
- say: `Tor runs on this machine now, but this wallet started before it did. ${RESTART}.`,
162423
+ say: "Tor runs now. Reconnect the wallet once (the steps are below), then ask again. Nothing was paid.",
162253
162424
  ok: false,
162254
162425
  error: "mcp_restart_needed",
162255
162426
  next: `Tell the user: ${RESTART}. Nothing was paid.`
@@ -162381,11 +162552,12 @@ async function runMcpFirstRun(values, deps) {
162381
162552
  discoverCacheDir: join40(home, "discover-cache"),
162382
162553
  npmVersion: deps.walletVersion().npm
162383
162554
  }),
162384
- discoverCacheDir: join40(home, "discover-cache"),
162385
162555
  startNormal: async () => {
162386
162556
  const after = mcpValuesAfterSetup(values, home, deps);
162387
- if (after.values.get(MCP_FROM_CONFIG).config.tor === true && !after.values.has("--no-tor") && !inProxiedRun(deps.env)) {
162388
- throw new Error("setup_tor_needs_restart: config.json asks for Tor, and this MCP server started without Tor, so it does not switch to the wallet tools in place; every money tool stays refused. Restart this MCP server in the host: it then starts behind Tor (Tor must run with HTTPTunnelPort 127.0.0.1:9080)");
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"]) };
162389
162561
  }
162390
162562
  const options = withProofToolsRefresh(mcpServerOptions(after.values, after.deps), after.values.get(MCP_FROM_CONFIG));
162391
162563
  warm = options.proofToolsPath ? deps.startKeepWarm(options, deps.env) : void 0;
@@ -162413,14 +162585,45 @@ function mcpSetupAdapter(values, home, deps) {
162413
162585
  },
162414
162586
  missing: () => missingPieces(home, readSetupConfig(home)),
162415
162587
  // privateInference: the human ticked "Use private inference for your AI now" (a yes, as setup --private-inference);
162416
- // no tick keeps what config.json records.
162417
- run: async (onStage, { privateInference } = {}) => runSetupRecorded(
162418
- { ...setupOptionsOf(values, home), onStage },
162419
- setupDeps,
162420
- inferenceRecordOf(readSetupConfig(home), privateInference === true ? true : void 0)
162421
- )
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
+ }
162422
162598
  };
162423
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
+ }
162424
162627
  function inferenceRecordOf(old, answer) {
162425
162628
  const recorded = typeof old?.inference?.enabled === "boolean" ? old.inference.enabled : void 0;
162426
162629
  if (answer === true) return true;
@@ -162717,13 +162920,14 @@ async function runSetupCommand(values, deps) {
162717
162920
  let ownAddress = values.get("--own-address");
162718
162921
  const old = setupConfigOf(home);
162719
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");
162720
162925
  if (!interactive && behindTor(values.has("--prefer-tor") || values.has("--private-inference") || old?.tor === true)) {
162721
162926
  await setupBehindTor(setupArgvOf(values), deps);
162722
162927
  if (ownAddress) io.out(`${recordOwnAddress(home, ownAddress, deps).join("\n")}
162723
162928
  `);
162724
162929
  return void 0;
162725
162930
  }
162726
- const missing = missingPieces(home, old);
162727
162931
  const npmVersion = deps.walletVersion().npm;
162728
162932
  const introduced = values.has("--yes") && inProxiedRun(deps.env);
162729
162933
  const asksOwnFirst = interactive && Boolean(old) && terminal && !ownAddress;
@@ -162745,7 +162949,7 @@ async function runSetupCommand(values, deps) {
162745
162949
  ...values.has("--max-shield") ? { maxShield: values.get("--max-shield") } : {},
162746
162950
  ...values.has("--max-unshield") ? { maxUnshield: values.get("--max-unshield") } : {},
162747
162951
  ...values.has("--prefer-tor") || torRunRecords ? { tor: true } : {},
162748
- // This --tor run's own local tunnel when it is not 127.0.0.1:9080 (setup --tor --proxy http://127.0.0.1:9150): mcp uses it.
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.
162749
162953
  ...torRunRecords && childRunProxy(deps.env).args[1] === "--proxy" ? { torTunnel: childRunProxy(deps.env).args[2] } : {},
162750
162954
  ...values.has("--passphrase-file") ? { passphraseFile: values.get("--passphrase-file") } : {},
162751
162955
  ...values.has("--facilitator") ? { facilitator: values.get("--facilitator") } : {},
@@ -162778,6 +162982,7 @@ async function runSetupCommand(values, deps) {
162778
162982
  if (/^setup_own_address_[a-z_]+: /.test(String(error?.message))) throw new PublicFailure(error.message);
162779
162983
  throw error;
162780
162984
  }
162985
+ values.set(SETUP_RERUN, "own-address");
162781
162986
  io.out([
162782
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).`,
162783
162988
  ...saved.dropped.length ? [`config.json keeps ${MAX_OWN_ADDRESSES} own addresses: the oldest (${saved.dropped.join(", ")}) now ask before each send.`] : [],
@@ -162859,25 +163064,33 @@ Copy it to two offline places now; it is the only way to restore this wallet.
162859
163064
  lines.push("");
162860
163065
  io.out(`${lines.join("\n")}
162861
163066
  `);
163067
+ const rerun = values.get(SETUP_RERUN) === "settings";
162862
163068
  const targets = values.get("--add-to") ?? [];
162863
163069
  if (targets.length) addToHosts(targets, home, deps, { force: values.has("--force"), npmVersion });
162864
- io.out(`${targets.length ? "Or add it by hand" : "Add it to your agent host"}:
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"}:
162865
163074
  ${hostConfigText({ home, env: deps.env, platform: deps.platform ?? process.platform, npmVersion })}
162866
163075
  `);
162867
- io.out(`
163076
+ io.out(`
162868
163077
  ${terminalUseLines(npmVersion).join("\n")}
162869
163078
  `);
163079
+ }
162870
163080
  const config = setupConfigOf(home);
163081
+ const inferenceNow = summary.privateInference === true && (!rerun || old?.inference?.enabled !== true);
162871
163082
  let apiKey;
162872
- if (summary.privateInference === true && config?.pool) {
163083
+ if (inferenceNow && config?.pool) {
162873
163084
  try {
162874
163085
  apiKey = localAiServerApiKey(home, { walletPath: homeWalletPath(home, config.pool) });
162875
163086
  } catch {
162876
163087
  apiKey = void 0;
162877
163088
  }
162878
163089
  }
162879
- io.out(`
162880
- ${summary.privateInference === true ? privateInferencePath(config, { apiKey }).text : fundingStepText(config?.tor === true)}`);
163090
+ if (inferenceNow) io.out(`
163091
+ ${privateInferencePath(config, { apiKey }).text}`);
163092
+ else if (!rerun) io.out(`
163093
+ ${fundingStepText(config?.tor === true)}`);
162881
163094
  if (interactive) await offerFundNow(deps, { tor: config?.tor === true });
162882
163095
  }
162883
163096
  function validateAddFunds(values) {
@@ -163738,8 +163951,9 @@ var COMMANDS = [
163738
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."
163739
163952
  ],
163740
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"`,
163741
- // After a run: the same line as the host config setup printed (this npm version, when the wallet knows it).
163742
- nextAfterRun: (values, deps) => `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"`,
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"`,
163743
163957
  run: (args, values, deps, io) => deps.setupMain(values, { ...deps, io })
163744
163958
  },
163745
163959
  {
@@ -166250,6 +166464,8 @@ function defaultDependencies() {
166250
166464
  else process.env[TOR_RUN_STARTED_ENV2] = before;
166251
166465
  }
166252
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),
166253
166469
  // No command calls these (the v0b and laneb families are retired, RETIRED_FAMILIES). They stay only because
166254
166470
  // wallet/scripts/bundle.mjs still requires the V0b zk-sdk WASM in the bundle; drop both together.
166255
166471
  v0bMain: async (...args) => (await Promise.resolve().then(() => (init_cli4(), cli_exports))).v0bMain(...args),