shinjuku-shielded 0.3.57 → 0.3.59

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/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": "a5a9b7ddd7aa96aa7feb6470868cd662c20f0f412df665093e768c07c4cda23c",
5
- "bytes": 12153017,
6
- "sourceCommit": "114e9aff996b18aae17a35d0a2f7dd46b9dfc9d2",
4
+ "sha256": "a18f4dcc8553e48c173aa610e7b3632d8edb25dbe317dd1f820e44673dd0fa39",
5
+ "bytes": 12158087,
6
+ "sourceCommit": "4274f17fee017d2010ae9d1ca94c5c03d200effc",
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",
@@ -1282,5 +1282,5 @@
1282
1282
  "version": "1.8.0"
1283
1283
  }
1284
1284
  ],
1285
- "publishedAt": "2026-10-22T01:10:14.358Z"
1285
+ "publishedAt": "2026-10-22T04:38:17.814Z"
1286
1286
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "shinjuku-shielded",
3
- "version": "0.3.57",
3
+ "version": "0.3.59",
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": "a5a9b7dd",
7
- "shinjukuSha256": "a5a9b7ddd7aa96aa7feb6470868cd662c20f0f412df665093e768c07c4cda23c",
6
+ "shinjukuRelease": "a18f4dcc",
7
+ "shinjukuSha256": "a18f4dcc8553e48c173aa610e7b3632d8edb25dbe317dd1f820e44673dd0fa39",
8
8
  "license": "SEE LICENSE IN LICENSE.txt",
9
9
  "author": "Shinjuku Shielded",
10
10
  "homepage": "https://github.com/ShinjukuStaition/shinjuku-mcp#readme",
@@ -42691,7 +42691,8 @@ function untilAborted(promise, signal) {
42691
42691
  async function routeFacilitatorsOverOnion(argv2, {
42692
42692
  fetchImpl = globalThis.fetch,
42693
42693
  err = (text3) => process.stderr.write(text3),
42694
- raceTimeoutMs = RACE_TIMEOUT_MS
42694
+ raceTimeoutMs = RACE_TIMEOUT_MS,
42695
+ routeWaitMs = ROUTE_WAIT_MS
42695
42696
  } = {}) {
42696
42697
  const routes = /* @__PURE__ */ new Map();
42697
42698
  const groups = /* @__PURE__ */ new Map();
@@ -42701,7 +42702,10 @@ async function routeFacilitatorsOverOnion(argv2, {
42701
42702
  const onions = (pinned ?? [await publishedOnion(origin, fetchImpl)]).filter((onion) => onion && V3_ONION.test(onion));
42702
42703
  if (onions.length > 0) {
42703
42704
  const key = onions.join(" ");
42704
- if (!groups.has(key)) groups.set(key, { onions });
42705
+ if (!groups.has(key)) {
42706
+ groups.set(key, { onions, waitMs: routeWaitMs, onNone: () => err(`tor: no onion of ${origin} answered its start probe (${onions.length} tried); its requests go to its onions in turn and wait for them (Tor may still be building circuits)
42707
+ `) });
42708
+ }
42705
42709
  routes.set(origin, groups.get(key));
42706
42710
  routes.set(payHostOf(origin), groups.get(key));
42707
42711
  const hosts = onions.map((onion) => `${new URL(onion).host.slice(0, 8)}...`).join(", ");
@@ -42756,10 +42760,19 @@ async function routeFacilitatorsOverOnion(argv2, {
42756
42760
  const group = url && routes.get(url.origin);
42757
42761
  if (!group) return original(input, init);
42758
42762
  const send3 = (onion) => {
42763
+ if (onion === void 0) onion = group.onions[(group.sent = (group.sent ?? 0) + 1) % group.onions.length];
42759
42764
  const target = `${onion}${url.pathname}${url.search}`;
42760
42765
  return original(input instanceof Request ? new Request(target, input) : target, onionInit(init));
42761
42766
  };
42762
- return group.winner ? send3(group.winner) : untilAborted(group.pending, init?.signal ?? (input instanceof Request ? input.signal : void 0)).then(send3);
42767
+ if (group.winner) return send3(group.winner);
42768
+ const signal = init?.signal ?? (input instanceof Request ? input.signal : void 0);
42769
+ if (!group.waitMs) return untilAborted(group.pending, signal).then(send3);
42770
+ let timer;
42771
+ const bound = new Promise((resolve38) => {
42772
+ timer = setTimeout(resolve38, group.waitMs);
42773
+ timer.unref?.();
42774
+ });
42775
+ return untilAborted(Promise.race([group.pending, bound]), signal).finally(() => clearTimeout(timer)).then(send3);
42763
42776
  };
42764
42777
  return {
42765
42778
  routes: new Map([...routes].map(([origin, group]) => [origin, group.onions])),
@@ -42769,7 +42782,7 @@ async function routeFacilitatorsOverOnion(argv2, {
42769
42782
  }
42770
42783
  };
42771
42784
  }
42772
- var SITE_ONIONS, PINNED_FACILITATOR_ONIONS, HISTORY_ONIONS, PINNED_HISTORY_ONIONS, HISTORY_PROBE_PATH, FACILITATOR_FLAGS, V3_ONION, DISCOVERY_TIMEOUT_MS, WARM_TIMEOUT_MS, RACE_TIMEOUT_MS, routedGroups, routedOnions, routedOrigins, onionsOfOrigin, routesOverOnion, GLOBAL_DISPATCHER, onionDispatchers;
42785
+ var SITE_ONIONS, PINNED_FACILITATOR_ONIONS, HISTORY_ONIONS, PINNED_HISTORY_ONIONS, HISTORY_PROBE_PATH, FACILITATOR_FLAGS, V3_ONION, DISCOVERY_TIMEOUT_MS, WARM_TIMEOUT_MS, RACE_TIMEOUT_MS, ROUTE_WAIT_MS, routedGroups, routedOnions, routedOrigins, onionsOfOrigin, routesOverOnion, GLOBAL_DISPATCHER, onionDispatchers;
42773
42786
  var init_facilitatorOnion = __esm({
42774
42787
  "wallet/src/net/facilitatorOnion.mjs"() {
42775
42788
  "use strict";
@@ -42796,6 +42809,7 @@ var init_facilitatorOnion = __esm({
42796
42809
  DISCOVERY_TIMEOUT_MS = 2e4;
42797
42810
  WARM_TIMEOUT_MS = 3e4;
42798
42811
  RACE_TIMEOUT_MS = 9e4;
42812
+ ROUTE_WAIT_MS = 15e3;
42799
42813
  routedGroups = [];
42800
42814
  routedOnions = () => [...new Set(routedGroups.flatMap((group) => group.winner ? [group.winner] : group.onions))];
42801
42815
  routedOrigins = /* @__PURE__ */ new Map();
@@ -60944,8 +60958,18 @@ function settleFunder(transaction, id, intent) {
60944
60958
  }
60945
60959
  return void 0;
60946
60960
  }
60947
- async function landedReceipt({ connection, id, record, intent, loadHistory }) {
60948
- const context = landedDepositContext(await loadHistory(), record);
60961
+ async function landedReceipt({ connection, id, record, intent, loadHistory, walkMs = LANDED_WALK_MS }) {
60962
+ const walking = Promise.resolve().then(loadHistory);
60963
+ walking.catch(() => {
60964
+ });
60965
+ let timer;
60966
+ const slow = new Promise((resolve38) => {
60967
+ timer = setTimeout(() => resolve38(SLOW_WALK), walkMs);
60968
+ timer.unref?.();
60969
+ });
60970
+ const history = await Promise.race([walking, slow]).finally(() => clearTimeout(timer));
60971
+ if (history === SLOW_WALK) fail11("landed_history_walk_slow_retry_later");
60972
+ const context = landedDepositContext(history, record);
60949
60973
  const signature2 = context?.provenance?.signature;
60950
60974
  if (!signature2) fail11("landed_history_pending_retry_later");
60951
60975
  const transaction = await retryRpc2(() => connection.getTransaction(signature2, {
@@ -61652,7 +61676,15 @@ async function submitRelayedDepositLeased({ store, connection, programId, proofT
61652
61676
  };
61653
61677
  const intent = await readIntent(connection, id, record);
61654
61678
  if (intent.landed) {
61655
- const receipt = await relayReceipt({ connection, id, record, intent, loadHistory, transaction: reads.settle });
61679
+ const receipt = await relayReceipt({
61680
+ connection,
61681
+ id,
61682
+ record,
61683
+ intent,
61684
+ loadHistory,
61685
+ transaction: reads.settle,
61686
+ ...deps.landedWalkMs !== void 0 ? { walkMs: deps.landedWalkMs } : {}
61687
+ });
61656
61688
  if (receipt.source !== source.toBase58()) {
61657
61689
  record.state = "foreign_funded";
61658
61690
  record.foreignFunding = receipt;
@@ -61781,7 +61813,7 @@ function settleTransaction(connection, signature2) {
61781
61813
  maxSupportedTransactionVersion: 1
61782
61814
  }));
61783
61815
  }
61784
- async function relayReceipt({ connection, id, record, intent, loadHistory, transaction: read }) {
61816
+ async function relayReceipt({ connection, id, record, intent, loadHistory, transaction: read, walkMs }) {
61785
61817
  const signature2 = record.relay.result?.signature;
61786
61818
  if (signature2) {
61787
61819
  const transaction = (read ? await read : void 0) ?? await settleTransaction(connection, signature2);
@@ -61798,7 +61830,7 @@ async function relayReceipt({ connection, id, record, intent, loadHistory, trans
61798
61830
  };
61799
61831
  }
61800
61832
  }
61801
- return landedReceipt({ connection, id, record, intent, loadHistory });
61833
+ return landedReceipt({ connection, id, record, intent, loadHistory, ...walkMs !== void 0 ? { walkMs } : {} });
61802
61834
  }
61803
61835
  async function reclaimRelayedDeposit(input) {
61804
61836
  return withWalletLease(input.store, input.deps ?? {}, () => reclaimRelayedDepositLeased(input));
@@ -62178,7 +62210,7 @@ async function publishDepositMemo({ serviceUrl: serviceUrl2, record, fetchImpl =
62178
62210
  const stored = await fetchMemoFromService(serviceUrl2, record.memoDigest, { fetchImpl });
62179
62211
  if (!stored || !Buffer.from(stored).equals(bytes2)) fail11("memo_publish_readback_mismatch");
62180
62212
  }
62181
- var import_web3101, DEPOSIT_WAL_SCHEMA, P03_BINDING, BUFFER_SIZE, DEPOSIT_INTENT_LEN, DEPOSIT_RECORD_LEN, CLOSE_BUFFER, COMPACT_DEPOSIT_INTENT, BUFFER_LIFETIME_SLOTS, BUFFER_MIN_REMAINING_SLOTS, FEE_MARGIN_LAMPORTS, RESOLVED_STATES, LANDED_STATES, hex, field32, walName, delay, DEPOSIT_RELAY_SCHEMA, DEPOSIT_RECLAIM_SCHEMA, DEPOSIT_RELAY_CONFIG_SCHEMA, APPROVE_COMPUTE_UNITS, RECLAIM_COMPUTE_UNITS, RELAY_ROUNDS, RELAY_KEY_PROBES, MAX_SCAN_COUNT, RELAY_REQUEST_TIMEOUT_MS, RELAY_MAX_WAIT_SECONDS, RELAY_REFUSALS, RECLAIM_REFUSALS, relayHex, SPLIT_MAX, DEFAULT_SPLIT_PARTS, SPLIT_UNIT_ATOMIC, FUNDS_PLAN_SCHEMA, FUNDS_PLAN_PREFIX, relayKeyPool, __test;
62213
+ var import_web3101, DEPOSIT_WAL_SCHEMA, P03_BINDING, BUFFER_SIZE, DEPOSIT_INTENT_LEN, DEPOSIT_RECORD_LEN, CLOSE_BUFFER, COMPACT_DEPOSIT_INTENT, BUFFER_LIFETIME_SLOTS, BUFFER_MIN_REMAINING_SLOTS, FEE_MARGIN_LAMPORTS, RESOLVED_STATES, LANDED_STATES, hex, field32, walName, LANDED_WALK_MS, SLOW_WALK, delay, DEPOSIT_RELAY_SCHEMA, DEPOSIT_RECLAIM_SCHEMA, DEPOSIT_RELAY_CONFIG_SCHEMA, APPROVE_COMPUTE_UNITS, RECLAIM_COMPUTE_UNITS, RELAY_ROUNDS, RELAY_KEY_PROBES, MAX_SCAN_COUNT, RELAY_REQUEST_TIMEOUT_MS, RELAY_MAX_WAIT_SECONDS, RELAY_REFUSALS, RECLAIM_REFUSALS, relayHex, SPLIT_MAX, DEFAULT_SPLIT_PARTS, SPLIT_UNIT_ATOMIC, FUNDS_PLAN_SCHEMA, FUNDS_PLAN_PREFIX, relayKeyPool, __test;
62182
62214
  var init_deposit = __esm({
62183
62215
  "wallet/src/deposit/deposit.mjs"() {
62184
62216
  "use strict";
@@ -62213,6 +62245,8 @@ var init_deposit = __esm({
62213
62245
  hex = (value) => Buffer.from(String(value).replace(/^0x/, ""), "hex");
62214
62246
  field32 = (value) => Buffer.from(BigInt(value).toString(16).padStart(64, "0"), "hex");
62215
62247
  walName = (depositId) => `deposit-${depositId}`;
62248
+ LANDED_WALK_MS = 12e4;
62249
+ SLOW_WALK = /* @__PURE__ */ Symbol("slow landed walk");
62216
62250
  delay = (ms) => new Promise((resolve38) => setTimeout(resolve38, ms));
62217
62251
  DEPOSIT_RELAY_SCHEMA = "carbon-shielded-x402/p03-deposit-relay/v1";
62218
62252
  DEPOSIT_RECLAIM_SCHEMA = "carbon-shielded-x402/p03-deposit-reclaim/v1";
@@ -63832,6 +63866,7 @@ var init_errorCodes = __esm({
63832
63866
  "key_index_invalid",
63833
63867
  "key_probe_exhausted",
63834
63868
  "landed_history_pending_retry_later",
63869
+ "landed_history_walk_slow_retry_later",
63835
63870
  "leaf_range",
63836
63871
  "lock_missing",
63837
63872
  "mainnet_ack_invalid",
@@ -103035,6 +103070,17 @@ function checkConfig(value) {
103035
103070
  }
103036
103071
  if (BigInt(caps.maxSession) < BigInt(caps.maxPayment)) throw invalid3("caps.maxSession is below caps.maxPayment");
103037
103072
  if (value.tor !== void 0 && typeof value.tor !== "boolean") throw invalid3("tor is not true or false");
103073
+ if (value.torTunnel !== void 0) {
103074
+ let tunnel;
103075
+ try {
103076
+ tunnel = new URL(value.torTunnel);
103077
+ } catch {
103078
+ tunnel = void 0;
103079
+ }
103080
+ if (!tunnel || tunnel.protocol !== "http:" || !["127.0.0.1", "localhost", "[::1]"].includes(tunnel.hostname) || !tunnel.port || tunnel.pathname !== "/" || tunnel.search || tunnel.username || value.torTunnel !== tunnel.origin) {
103081
+ throw invalid3("torTunnel is not a local http://127.0.0.1:<port> Tor tunnel");
103082
+ }
103083
+ }
103038
103084
  if (value.previousPools !== void 0) {
103039
103085
  if (!Array.isArray(value.previousPools) || value.previousPools.length > 8) throw invalid3("previousPools is not a short list");
103040
103086
  for (const entry of value.previousPools) {
@@ -104650,33 +104696,54 @@ async function getBytes(fetchImpl, url, timeoutMs, label, maxBytes, budget, { la
104650
104696
  if (over) throw tooLarge();
104651
104697
  return Buffer.concat(chunks, total);
104652
104698
  }
104653
- function getSmall(fetchImpl, url, label, maxBytes) {
104699
+ function getSmall(fetchImpl, url, label, maxBytes, { patientMs = 0, progressLine, progressEveryMs = PROGRESS_EVERY_MS, laneMs = RELEASE_TIMEOUT_MS } = {}) {
104654
104700
  const stop3 = new AbortController();
104655
104701
  const timers = [];
104702
+ const startedAt = Date.now();
104656
104703
  let started = 0;
104657
104704
  let running = 0;
104658
104705
  let settled = false;
104659
104706
  let firstError;
104707
+ const mayRelaunch = () => patientMs > 0 && Date.now() - startedAt + laneMs <= patientMs;
104660
104708
  return new Promise((resolve38, reject) => {
104661
104709
  const done = (finish, value) => {
104662
104710
  if (settled) return;
104663
104711
  settled = true;
104664
- for (const timer of timers) clearTimeout(timer);
104712
+ for (const timer of timers) {
104713
+ clearTimeout(timer);
104714
+ clearInterval(timer);
104715
+ }
104665
104716
  stop3.abort();
104717
+ if (finish === reject && patientMs > 0 && LOST.test(String(value?.message))) {
104718
+ const seconds2 = Math.round((Date.now() - startedAt) / 1e3);
104719
+ value = fail26("setup_download_failed", inTorRun() ? `${label} could not be fetched from the facilitator over Tor (no answer in ${seconds2} s on ${started} Tor circuits). Tor runs but reached no path to the facilitator's onion service yet; a Tor that has just started can need a few minutes for that. Wait 1 minute and rerun setup: it keeps what it already checked` : `${label} could not be fetched from the facilitator (no answer in ${seconds2} s); check the network and rerun setup: it keeps what it already checked`);
104720
+ }
104666
104721
  finish(value);
104667
104722
  };
104723
+ if (progressLine) {
104724
+ const tick = setInterval(() => {
104725
+ const seconds2 = Math.round((Date.now() - startedAt) / 1e3);
104726
+ try {
104727
+ progressLine(`still waiting for ${label}: no answer after ${seconds2} s${inTorRun() ? " (over Tor the first onion connection can take a minute after Tor starts)" : ""}
104728
+ `);
104729
+ } catch {
104730
+ }
104731
+ }, progressEveryMs);
104732
+ tick.unref?.();
104733
+ timers.push(tick);
104734
+ }
104668
104735
  const launch = () => {
104669
- if (settled || started >= SMALL_LANES) return;
104736
+ if (settled || started >= SMALL_LANES && !mayRelaunch()) return;
104670
104737
  const lane = started;
104671
104738
  started += 1;
104672
104739
  running += 1;
104673
- getBytes(fetchImpl, url, RELEASE_TIMEOUT_MS, label, maxBytes, void 0, { lane, stop: stop3.signal }).then(
104740
+ getBytes(fetchImpl, url, laneMs, label, maxBytes, void 0, { lane, stop: stop3.signal }).then(
104674
104741
  (bytes2) => done(resolve38, bytes2),
104675
104742
  (error) => {
104676
104743
  running -= 1;
104677
104744
  firstError ??= error;
104678
104745
  if (!LOST.test(String(error?.message))) done(reject, error);
104679
- else if (started < SMALL_LANES) launch();
104746
+ else if (started < SMALL_LANES || mayRelaunch()) launch();
104680
104747
  else if (running === 0) done(reject, firstError);
104681
104748
  }
104682
104749
  );
@@ -104878,10 +104945,10 @@ async function downloadSet({ fetchImpl, base, entries, budget, onFile, onBytes =
104878
104945
  if (firstError) throw firstError;
104879
104946
  if (filesLeft > 0) throw fail26("setup_download_failed", "the proof-tool download stopped before every file arrived; rerun setup: it keeps what it already checked");
104880
104947
  }
104881
- async function fetchRelease(facilitator, { fetchImpl = fetch } = {}) {
104948
+ async function fetchRelease(facilitator, { fetchImpl = fetch, patientMs = 0, progressLine, progressEveryMs, laneMs } = {}) {
104882
104949
  const url = new URL("/api/wallet/release", facilitator).href;
104883
104950
  const label = "the release document (/api/wallet/release)";
104884
- const bytes2 = await getSmall(fetchImpl, url, label, LIMITS.release);
104951
+ const bytes2 = await getSmall(fetchImpl, url, label, LIMITS.release, { patientMs, ...progressLine ? { progressLine } : {}, ...progressEveryMs ? { progressEveryMs } : {}, ...laneMs ? { laneMs } : {} });
104885
104952
  let release;
104886
104953
  try {
104887
104954
  release = JSON.parse(bytes2.toString("utf8"));
@@ -105123,7 +105190,7 @@ async function refreshTrustedProofTools({ home, facilitator, pool: pool2, fetchI
105123
105190
  });
105124
105191
  return Object.freeze({ changed: true, dir: tools.dir, sumsSha256: tools.sumsSha256, downloaded: tools.downloaded });
105125
105192
  }
105126
- var PINNED_PROOF_TOOLS, UPDATE_NEXT, HEX643, DIR2, SUMS_LINE, MAX_FILES, LIMITS, RELEASE_TIMEOUT_MS, FILE_TIMEOUT_MS, DOWNLOAD_LANES, RANGE_BYTES, RANGE_TIMEOUT_MS, RANGE_STALL_MS, RANGE_FLOOR_BYTES, RANGE_ATTEMPTS, HEDGE_AFTER_MS, CONTENT_RANGE, PROGRESS_EVERY_MS, releasedBytes, megabytes, REQUIRED_FILES, sha2569, fail26, SMALL_HEDGE_MS, SMALL_LANES, LOST, passing, localPath, executable, toolPaths;
105193
+ var PINNED_PROOF_TOOLS, UPDATE_NEXT, HEX643, DIR2, SUMS_LINE, MAX_FILES, LIMITS, RELEASE_TIMEOUT_MS, FILE_TIMEOUT_MS, DOWNLOAD_LANES, RANGE_BYTES, RANGE_TIMEOUT_MS, RANGE_STALL_MS, RANGE_FLOOR_BYTES, RANGE_ATTEMPTS, HEDGE_AFTER_MS, CONTENT_RANGE, PROGRESS_EVERY_MS, releasedBytes, megabytes, REQUIRED_FILES, sha2569, fail26, SMALL_HEDGE_MS, SMALL_LANES, LOST, SETUP_RELEASE_PATIENCE_MS, passing, localPath, executable, toolPaths;
105127
105194
  var init_proofTools = __esm({
105128
105195
  "wallet/src/setup/proofTools.mjs"() {
105129
105196
  "use strict";
@@ -105163,6 +105230,7 @@ var init_proofTools = __esm({
105163
105230
  SMALL_HEDGE_MS = 1e4;
105164
105231
  SMALL_LANES = 3;
105165
105232
  LOST = /\(no answer\)|stopped before its end/;
105233
+ SETUP_RELEASE_PATIENCE_MS = 11e4;
105166
105234
  passing = (error) => Object.assign(error, { passing: true });
105167
105235
  localPath = (folder, path) => join21(folder, ...path.split("/"));
105168
105236
  executable = (path) => path.startsWith("bin/") || path.startsWith("house/bin/");
@@ -107886,10 +107954,10 @@ function addFundsHeldSay(entries, have = "") {
107886
107954
  const lead = (text3) => have ? `${have}; ${text3}` : `${text3[0].toUpperCase()}${text3.slice(1)}`;
107887
107955
  const now = !nowUnknown ? `${usdcText(nowHeld)} USDC is becoming private now` : nowHeld > 0n ? `${usdcText(nowHeld)} USDC and an amount still being read are becoming private now` : "an amount still being read is becoming private now";
107888
107956
  const later = startMinutes !== null ? `within about 1 minute of your next wallet request${startMinutes > 0 ? ` after about ${minutesText(startMinutes)}` : ""}` : minutesKnown && minutes !== null ? `in about ${minutesText(minutes)}` : "in a few minutes";
107889
- const askLater = startMinutes !== null && startMinutes > 0 ? `ask again in about ${minutesText(startMinutes)}, and it becomes private within about 1 minute of that request` : null;
107890
- if (nowAny && waiting > 0n) return askLater ? `${lead(`${now}; ${usdcText(waiting)} USDC more arrived: ask again in about ${minutesText(startMinutes)} for it`)}.` : `${lead(`${now}, and ${usdcText(waiting)} USDC more ${later}`)}.`;
107957
+ const askLater = startMinutes !== null && startMinutes > 0 ? `a random privacy wait ends in about ${minutesText(startMinutes)}: ask then; it is private 1 minute later` : null;
107958
+ if (nowAny && waiting > 0n) return askLater ? `${lead(`${now}; ${usdcText(waiting)} USDC more is in a random privacy wait: ask in about ${minutesText(startMinutes)}`)}.` : `${lead(`${now}, and ${usdcText(waiting)} USDC more ${later}`)}.`;
107891
107959
  if (nowAny) return `${lead(now)}. Nothing to do.`;
107892
- const arrived = askLater ? `${usdcText(waiting)} USDC arrived: ${askLater}` : `${usdcText(waiting)} USDC arrived and becomes private ${later === "in a few minutes" ? "within a few minutes of your next wallet request" : later}`;
107960
+ const arrived = askLater ? `${usdcText(waiting)} USDC arrived; ${askLater}` : `${usdcText(waiting)} USDC arrived and becomes private ${later === "in a few minutes" ? "within a few minutes of your next wallet request" : later}`;
107893
107961
  if (startMinutes !== null) return `${lead(arrived)}.`;
107894
107962
  if (!minutesKnown || minutes === null) {
107895
107963
  return have ? `${lead(arrived)}. Nothing to do.` : `${lead(arrived)}. A random wait hides the link to your deposit. Nothing to do.`;
@@ -108055,7 +108123,7 @@ function transferSay(a) {
108055
108123
  const head = `Done. ${to} received ${usdc8}, not the token.`;
108056
108124
  const left = a.leftover;
108057
108125
  if (!left || typeof left !== "object") return head;
108058
- if (typeof left.ownSol === "string" && left.ownSol) return `${head} ${left.ownSol} SOL stays on this wallet's key to pay fees of your next transfer.`;
108126
+ if (typeof left.ownSol === "string" && left.ownSol) return `${head} ${left.ownSol} SOL stays on this wallet's key for later fees; no tool moves it out yet.`;
108059
108127
  if (left.state === "closing") return `${head} An empty token account on this wallet's key is closing; its rent comes back there.`;
108060
108128
  return `${head} Some SOL stays on this wallet's key for fees; wallet_balance shows how much.`;
108061
108129
  }
@@ -114377,7 +114445,7 @@ function transferLeftoverView(plan) {
114377
114445
  ownSol: lamports === null ? null : solText(lamports),
114378
114446
  ...tidy.solReadAt ? { ownSolReadAt: tidy.solReadAt } : {},
114379
114447
  solUse: lamports === null ? "the SOL on the own key pays the network fee of a next wallet_transfer_token sell (at most about 0.00012 SOL each); wallet_balance shows it as unshieldedSolLamports" : enough ? `the ${solText(lamports)} SOL on the own key pays the network fee of a next wallet_transfer_token sell (at most about 0.00012 SOL each)` : `the ${solText(lamports)} SOL on the own key is less than the network fee of a next wallet_transfer_token sell (about 0.00012 SOL)`,
114380
- solExit: "this wallet cannot send SOL out privately yet (wallet_transfer_token sells tokens, not SOL), so the SOL stays on the own key for fees",
114448
+ solExit: "no tool of this wallet moves SOL off the own key, and no private route for that SOL exists yet (wallet_transfer_token sells tokens, not SOL), so the SOL stays on the own key and pays the fees of later sells; if the user asks to get it back, say exactly that",
114381
114449
  usdcAccount: "the own key's USDC account stays open on purpose: wallet_shield and the next transfer use it, so they do not pay its rent (about 0.00204 SOL) again"
114382
114450
  };
114383
114451
  }
@@ -116315,7 +116383,8 @@ async function runShield({ session, depositId, amountAtomic, onStage, steps = {}
116315
116383
  programId: session.programId,
116316
116384
  proofTools: session.proofTools,
116317
116385
  depositId,
116318
- serviceUrl: session.memoServiceUrl
116386
+ serviceUrl: session.memoServiceUrl,
116387
+ deps: { walkHistory: () => walkWalletHistory(session, store) }
116319
116388
  };
116320
116389
  if (!existing || existing.state === "awaiting_funds") {
116321
116390
  onStage("proving");
@@ -116370,7 +116439,8 @@ async function runShieldFromElsewhere({ session, depositId, amountAtomic, onStag
116370
116439
  programId: session.programId,
116371
116440
  proofTools: session.proofTools,
116372
116441
  depositId,
116373
- serviceUrl: session.memoServiceUrl
116442
+ serviceUrl: session.memoServiceUrl,
116443
+ deps: { walkHistory: () => walkWalletHistory(session, store) }
116374
116444
  };
116375
116445
  const before = store.readWal(`deposit-${depositId}`);
116376
116446
  if (!before || before.state === "awaiting_funds") {
@@ -121326,13 +121396,17 @@ ${canonical5}`;
121326
121396
  `call the same tool again with the same request_id in ${POLL_SECONDS3} s. If the same code repeats, tell your owner: ${code2}`
121327
121397
  );
121328
121398
  };
121329
- const payMeRun = () => ({
121330
- store: session.openStore(),
121331
- connection: session.connection,
121332
- programId: session.programId,
121333
- proofTools: session.proofTools,
121334
- serviceUrl: session.memoServiceUrl
121335
- });
121399
+ const payMeRun = () => {
121400
+ const store = session.openStore();
121401
+ return {
121402
+ store,
121403
+ connection: session.connection,
121404
+ programId: session.programId,
121405
+ proofTools: session.proofTools,
121406
+ serviceUrl: session.memoServiceUrl,
121407
+ deps: { walkHistory: () => walkWalletHistory(session, store) }
121408
+ };
121409
+ };
121336
121410
  const payMeRoundMax = () => {
121337
121411
  const max = capOf2(money.maxShieldAtomic);
121338
121412
  return max !== void 0 && max < MAX_SHIELDED_BALANCE_ATOMIC ? max : MAX_SHIELDED_BALANCE_ATOMIC;
@@ -145635,7 +145709,7 @@ init_walk();
145635
145709
  init_cli();
145636
145710
  init_floatPay();
145637
145711
  import { randomBytes as randomBytes33 } from "node:crypto";
145638
- import { join as join36, resolve as resolve37 } from "node:path";
145712
+ import { dirname as dirname29, join as join36, resolve as resolve37 } from "node:path";
145639
145713
  import { spawn as spawn6 } from "node:child_process";
145640
145714
  import { fileURLToPath as fileURLToPath22 } from "node:url";
145641
145715
 
@@ -145658,6 +145732,7 @@ init_secretFile();
145658
145732
  init_recoveryFile();
145659
145733
  init_config2();
145660
145734
  init_proofTools();
145735
+ init_proxy();
145661
145736
  init_migration();
145662
145737
  init_successions();
145663
145738
  init_chain2();
@@ -145803,7 +145878,10 @@ async function runSetup(options, deps = {}) {
145803
145878
  let movedFrom;
145804
145879
  let releasePools;
145805
145880
  try {
145806
- release = await fetchRelease(facilitator, { fetchImpl: deps.fetchImpl });
145881
+ release = await fetchRelease(facilitator, {
145882
+ fetchImpl: deps.fetchImpl,
145883
+ ...inTorRun() ? { patientMs: deps.releasePatienceMs ?? SETUP_RELEASE_PATIENCE_MS, progressLine: deps.progressLine ?? ((text3) => process.stderr.write(text3)) } : {}
145884
+ });
145807
145885
  } catch (error) {
145808
145886
  releaseError = error;
145809
145887
  }
@@ -145951,6 +146029,7 @@ async function runSetup(options, deps = {}) {
145951
146029
  let previousPools = movedFrom ? withPreviousPool(old) : old?.pool === identity.pool ? old.previousPools : void 0;
145952
146030
  const drainingHere = (releasePools?.migration?.from ?? []).filter((entry) => entry.pool !== identity.pool && existsSync(homeWalletPath(home, entry.pool)) && !(previousPools ?? []).some((known) => known.pool === entry.pool));
145953
146031
  if (drainingHere.length) previousPools = [...previousPools ?? [], ...drainingHere.map((entry) => ({ pool: entry.pool, program: entry.programId }))].slice(-8);
146032
+ const torTunnel = tor ? options.torTunnel ?? old?.torTunnel : void 0;
145954
146033
  const base = {
145955
146034
  schema: CONFIG_SCHEMA,
145956
146035
  ...identity,
@@ -145958,6 +146037,7 @@ async function runSetup(options, deps = {}) {
145958
146037
  passphraseFile,
145959
146038
  caps,
145960
146039
  tor,
146040
+ ...torTunnel ? { torTunnel } : {},
145961
146041
  ...wallet.recoveryFile ? { recoveryFile: wallet.recoveryFile } : {},
145962
146042
  ...previousPools?.length ? { previousPools } : {}
145963
146043
  };
@@ -150913,7 +150993,15 @@ function withProofToolsRefresh(options, fromConfig) {
150913
150993
  var inProxiedRun = (env) => childRunProxy(env).args.length > 0;
150914
150994
  var TOR_RUN_STARTED_ENV2 = "SHINJUKU_WALLET_TOR_RUN_STARTED_FILE";
150915
150995
  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.";
150916
- var torDownNext = (configPath2) => `Tell the user: start Tor (its torrc needs HTTPTunnelPort 127.0.0.1:9080), 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()}`;
150996
+ var recordedTunnelHost = (configPath2) => {
150997
+ try {
150998
+ const tunnel = readSetupConfig(dirname29(configPath2))?.torTunnel;
150999
+ return tunnel ? new URL(tunnel).host : "127.0.0.1:9080";
151000
+ } catch {
151001
+ return "127.0.0.1:9080";
151002
+ }
151003
+ };
151004
+ 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()}`;
150917
151005
  async function runMcpTorDown({ exitCode, configPath: configPath2, input = process.stdin, output: output2 = process.stdout, errorOutput = process.stderr }) {
150918
151006
  const log = (line) => errorOutput.write(`${line}
150919
151007
  `);
@@ -150965,7 +151053,8 @@ var mcpServerEndedHere = () => mcpServerEnded;
150965
151053
  async function runMcp(values, deps) {
150966
151054
  const torHome = mcpTorAheadHome(values, deps);
150967
151055
  if (torHome !== void 0) {
150968
- const { code: code2, started } = await torRunOf(["mcp", ...values.get(MCP_RAW_ARGS)], deps);
151056
+ const tunnel = setupConfigOf(torHome)?.torTunnel;
151057
+ const { code: code2, started } = await torRunOf(["mcp", ...values.get(MCP_RAW_ARGS), ...tunnel ? ["--proxy", tunnel] : []], deps);
150969
151058
  if (code2 === 0) return void 0;
150970
151059
  if (started) {
150971
151060
  throw new PublicFailure(`wallet_command_failed: the MCP server ran behind Tor and then ended with exit code ${code2}; its own message is above. Tor was running when it started, so this is not a Tor failure, and nothing fell back to a direct connection. Fix what that message says, then start mcp again`);
@@ -151345,6 +151434,8 @@ async function runSetupCommand(values, deps) {
151345
151434
  ...values.has("--max-shield") ? { maxShield: values.get("--max-shield") } : {},
151346
151435
  ...values.has("--max-unshield") ? { maxUnshield: values.get("--max-unshield") } : {},
151347
151436
  ...values.has("--prefer-tor") || torRunRecords ? { tor: true } : {},
151437
+ // 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.
151438
+ ...torRunRecords && childRunProxy(deps.env).args[1] === "--proxy" ? { torTunnel: childRunProxy(deps.env).args[2] } : {},
151348
151439
  ...values.has("--passphrase-file") ? { passphraseFile: values.get("--passphrase-file") } : {},
151349
151440
  ...values.has("--facilitator") ? { facilitator: values.get("--facilitator") } : {},
151350
151441
  ...values.has("--trust-proof-tools") ? { trustProofTools: values.get("--trust-proof-tools") } : {}
@@ -151368,7 +151459,9 @@ async function runSetupCommand(values, deps) {
151368
151459
  if (privateInference === true && (options.tor !== true || torRunRecords) && old?.tor !== true) {
151369
151460
  io.out('Private inference needs Tor, so setup records Tor for mcp (Tor must run with HTTPTunnelPort 127.0.0.1:9080), and the commands below use --tor. To turn both off later: set "tor": false and "inference": { "enabled": false } in config.json (mcp --no-tor skips Tor for one run).\n\n');
151370
151461
  } else if (torRunRecords && old?.tor !== true) {
151371
- io.out('Tor is recorded for mcp: this setup runs with --tor, so config.json gets "tor": true and the MCP runs behind Tor too (Tor must run with HTTPTunnelPort 127.0.0.1:9080; mcp --no-tor skips it for one run).\n\n');
151462
+ io.out(`Tor is recorded for mcp: this setup runs with --tor, so config.json gets "tor": true and the MCP runs behind Tor too (Tor must run with HTTPTunnelPort ${options.torTunnel ? `${new URL(options.torTunnel).host}; config.json records it as "torTunnel", so mcp uses that port` : "127.0.0.1:9080"}; mcp --no-tor skips it for one run).
151463
+
151464
+ `);
151372
151465
  }
151373
151466
  if (behindTor(options.tor === true || privateInference === true || options.tor === void 0 && old?.tor === true)) {
151374
151467
  io.out("Setup continues behind Tor: the release, the proof tools, and the RPC requests go over Tor.\n");