shinjuku-shielded 0.3.185 → 0.3.186

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.185. The npm packages `shinjuku-shield` and
9
+ This is version 0.3.186. The npm packages `shinjuku-shield` and
10
10
  `shinjuku-shielded` hold the same files. The command is `shinjuku`.
11
11
 
12
12
  ## Set up
13
13
 
14
14
  ```sh
15
- npx -y shinjuku@0.3.185 setup
15
+ npx -y shinjuku@0.3.186 setup
16
16
  ```
17
17
 
18
18
  Setup offers to install the `shinjuku` command and, on Windows, adds npm's
@@ -35,13 +35,13 @@ Every wallet command works after `shinjuku`, for example `shinjuku balance`,
35
35
  Claude Code:
36
36
 
37
37
  ```sh
38
- claude mcp add --scope user shinjuku -- npx -y --no-audit --no-fund shinjuku-shield@0.3.185 mcp
38
+ claude mcp add --scope user shinjuku -- npx -y --no-audit --no-fund shinjuku-shield@0.3.186 mcp
39
39
  ```
40
40
 
41
41
  Claude Desktop (`claude_desktop_config.json`) or Cursor (`~/.cursor/mcp.json`):
42
42
 
43
43
  ```json
44
- { "mcpServers": { "shinjuku": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.185", "mcp"] } } }
44
+ { "mcpServers": { "shinjuku": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.186", "mcp"] } } }
45
45
  ```
46
46
 
47
47
  On native Windows, if the host cannot find `npx`, use `"command": "cmd"` and
@@ -54,7 +54,7 @@ Codex (the Codex app and Codex CLI read the same file, `~/.codex/config.toml`):
54
54
  ```toml
55
55
  [mcp_servers.shinjuku]
56
56
  command = "npx"
57
- args = ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.185", "mcp"]
57
+ args = ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.186", "mcp"]
58
58
  startup_timeout_sec = 120
59
59
  tool_timeout_sec = 300
60
60
  ```
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": "cab378d1d911f907711de448e5c6525febcd0e73ff8988efcb4ae7d1fa82e961",
5
- "bytes": 9351549,
6
- "sourceCommit": "0e77401ed1e90cd6fa9035028ac5098ae6abbb6e",
4
+ "sha256": "80d2ed100a8e4a1f0c3926c4572c20f71ed5c333ff510dd0e291065480fe2d98",
5
+ "bytes": 9360488,
6
+ "sourceCommit": "cb04124afb5e7deb6c6e7132dcb0175a1bc0eb2c",
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",
@@ -1038,5 +1038,5 @@
1038
1038
  "version": "1.8.0"
1039
1039
  }
1040
1040
  ],
1041
- "publishedAt": "2026-11-06T17:17:10.158Z"
1041
+ "publishedAt": "2026-11-06T17:55:56.110Z"
1042
1042
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "shinjuku-shielded",
3
- "version": "0.3.185",
3
+ "version": "0.3.186",
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": "cab378d1",
7
- "shinjukuSha256": "cab378d1d911f907711de448e5c6525febcd0e73ff8988efcb4ae7d1fa82e961",
6
+ "shinjukuRelease": "80d2ed10",
7
+ "shinjukuSha256": "80d2ed100a8e4a1f0c3926c4572c20f71ed5c333ff510dd0e291065480fe2d98",
8
8
  "license": "SEE LICENSE IN LICENSE.txt",
9
9
  "author": "Shinjuku Shielded",
10
10
  "homepage": "https://github.com/ShinjukuStaition/shinjuku-shield#readme",
@@ -48786,6 +48786,15 @@ function torOwnCircuitInit(lane, init = {}) {
48786
48786
  const made = torLaneInit(lane, init);
48787
48787
  return made !== init && made?.dispatcher !== void 0 ? made : void 0;
48788
48788
  }
48789
+ function freshTorCircuitProxy() {
48790
+ if (!inTorRun() || runEnded()) return void 0;
48791
+ try {
48792
+ if (globalThis[GLOBAL_DISPATCHER4]?.constructor?.name !== "EnvHttpProxyAgent") return void 0;
48793
+ return withRunTag(`http://${new URL(process.env[MARK].split(" ")[1]).host}`);
48794
+ } catch {
48795
+ return void 0;
48796
+ }
48797
+ }
48789
48798
  function onCurrentCircuit(init) {
48790
48799
  const lane = laneOfDispatcher.get(init?.dispatcher);
48791
48800
  return lane === void 0 || laneDispatchers.get(lane) === init.dispatcher ? init : torLaneInit(lane, init);
@@ -104928,7 +104937,7 @@ function floatOutcomeWords(code2, error, t) {
104928
104937
  const why = code2 === "p03_float_paid_finishing_retry_same_request" ? `Shinjuku is still signing the transfer to ${p.the}` : error?.transferLanded === true ? `Shinjuku's transfer to ${p.the} landed (${p.the} has the payment), and ${answer}` : `${answer}. Not known yet whether ${p.the} takes it`;
104929
104938
  return [
104930
104939
  code2,
104931
- `PAID ${totalText(error)} to Shinjuku (${t.privateLeg}); ${why}`,
104940
+ `PAID ${totalText(error)} to Shinjuku (${t.privateLeg}); ${why}${stallResentWords(p, error)}`,
104932
104941
  `${t.again}: it resends the same payment and never pays twice`
104933
104942
  ];
104934
104943
  }
@@ -104998,7 +105007,7 @@ function floatOutcomeWords(code2, error, t) {
104998
105007
  case "p03_float_seller_unanswered_paid_retry_same_request":
104999
105008
  return [
105000
105009
  code2,
105001
- `PAID ${totalText(error)}: the transfer to ${p.the} landed${withTransaction(error)}, but ${p.the} did not answer` + (typeof error?.httpStatus === "number" ? ` (it answered HTTP ${error.httpStatus}${typeof error?.sellerReason === "string" ? `: ${JSON.stringify(error.sellerReason)}` : ""})` : ""),
105010
+ `PAID ${totalText(error)}: the transfer to ${p.the} landed${withTransaction(error)}, but ${p.the} did not answer` + (typeof error?.httpStatus === "number" ? ` (it answered HTTP ${error.httpStatus}${typeof error?.sellerReason === "string" ? `: ${JSON.stringify(error.sellerReason)}` : ""})` : "") + stallResentWords(p, error),
105002
105011
  `${t.again}: it resends the same proof of payment and never pays twice`
105003
105012
  ];
105004
105013
  case "p03_float_seller_kept_payment": {
@@ -105098,6 +105107,12 @@ function floatOutcomeWords(code2, error, t) {
105098
105107
  return void 0;
105099
105108
  }
105100
105109
  }
105110
+ function stallResentWords(p, error) {
105111
+ return error?.stallResent === true ? `; the Tor connection to ${p?.the ?? "the seller"} stalled, so the wallet sent this same payment once more on a new Tor route: it is still one payment, not a second one` : "";
105112
+ }
105113
+ function stallResentLine(payee = "the seller") {
105114
+ return `The Tor connection to ${payee} stalled, so the wallet sent this same payment once more on a new Tor route: it is still one payment, not a second one.`;
105115
+ }
105101
105116
  var ATOMIC4, TRANSFER_DEAD_WORDS, payeeOf, floatSellerCanBeFixed, withoutProviderText, floatSeller4xx, answeredInstead, floatStillSettling, floatChargeTooLate, amountText, withTransaction, PAID_SELLER_FAILED_CODE, stillWants, AI_SERVER_WRONG, QUOTE_REFUSED_WHY;
105102
105117
  var init_floatWords = __esm({
105103
105118
  "wallet/src/pay/floatWords.mjs"() {
@@ -106112,6 +106127,138 @@ function sellerAnswerInit(url, init, ms) {
106112
106127
  if (target() === void 0) return init;
106113
106128
  return { ...init, dispatcher: { dispatch: (options, handler) => target().dispatch({ ...options, headersTimeout: ms, bodyTimeout: ms }, handler) } };
106114
106129
  }
106130
+ async function sendWatchingStall(fetchImpl, url, init, waitMs, { mark = () => {
106131
+ }, onResend = () => {
106132
+ }, resentBefore = false } = {}) {
106133
+ const global2 = globalThis[GLOBAL_DISPATCHER5];
106134
+ const proxy = process.env.HTTPS_PROXY;
106135
+ const watched = !resentBefore && inTorRun() && init.dispatcher === void 0 && routeDispatcherOf(url) === void 0 && global2?.constructor?.name === "EnvHttpProxyAgent" && typeof proxy === "string" && proxy !== "";
106136
+ if (!watched) return { response: await fetchImpl(url, sellerAnswerInit(url, init, waitMs)), stallResent: false };
106137
+ const sameCircuit = () => {
106138
+ try {
106139
+ return proxyDispatcher(global2.constructor, proxy);
106140
+ } catch {
106141
+ return void 0;
106142
+ }
106143
+ };
106144
+ const first = new AbortController();
106145
+ let ended2 = false;
106146
+ let timer;
106147
+ let checkStop;
106148
+ const stalled = new Promise((resolve43) => {
106149
+ let misses = 0;
106150
+ const check = async () => {
106151
+ const startedAtMs = Date.now();
106152
+ mark("seller-stall-check");
106153
+ checkStop = new AbortController();
106154
+ const dispatcher = sameCircuit();
106155
+ let alive2 = false;
106156
+ try {
106157
+ if (dispatcher === void 0) throw new Error("no dispatcher");
106158
+ const answer = await fetchImpl(new URL(url).origin, {
106159
+ method: "HEAD",
106160
+ redirect: "manual",
106161
+ dispatcher,
106162
+ signal: AbortSignal.any([AbortSignal.timeout(SELLER_STALL_CHECK_TIMEOUT_MS), checkStop.signal, ...init.signal ? [init.signal] : []])
106163
+ });
106164
+ alive2 = true;
106165
+ answer.body?.cancel?.().catch?.(() => {
106166
+ });
106167
+ } catch {
106168
+ alive2 = false;
106169
+ }
106170
+ dispatcher?.destroy().catch(() => {
106171
+ });
106172
+ if (ended2) return;
106173
+ misses = alive2 ? 0 : misses + 1;
106174
+ mark("seller-stall-check-done", alive2 ? "answered" : `missed_${misses}`);
106175
+ if (misses >= SELLER_STALL_MISSES) {
106176
+ resolve43(true);
106177
+ return;
106178
+ }
106179
+ timer = setTimeout(check, Math.max(0, startedAtMs + SELLER_STALL_CHECK_EVERY_MS - Date.now()));
106180
+ };
106181
+ timer = setTimeout(check, SELLER_STALL_CHECK_AFTER_MS);
106182
+ });
106183
+ const firstSend = fetchImpl(url, sellerAnswerInit(url, { ...init, signal: AbortSignal.any([...init.signal ? [init.signal] : [], first.signal]) }, waitMs)).then((response) => ({ response }), (error) => ({ error }));
106184
+ let outcome;
106185
+ try {
106186
+ outcome = await Promise.race([firstSend, stalled.then(() => ({ stalled: true }))]);
106187
+ } finally {
106188
+ ended2 = true;
106189
+ clearTimeout(timer);
106190
+ checkStop?.abort();
106191
+ }
106192
+ if (outcome.stalled !== true) {
106193
+ if (outcome.error !== void 0) throw outcome.error;
106194
+ return { response: outcome.response, stallResent: false };
106195
+ }
106196
+ const replacementProxy = freshTorCircuitProxy();
106197
+ let fresh;
106198
+ try {
106199
+ fresh = replacementProxy === void 0 ? void 0 : proxyDispatcher(global2.constructor, replacementProxy);
106200
+ } catch {
106201
+ fresh = void 0;
106202
+ }
106203
+ if (fresh === void 0) {
106204
+ const kept3 = await firstSend;
106205
+ if (kept3.error !== void 0) throw kept3.error;
106206
+ return { response: kept3.response, stallResent: false };
106207
+ }
106208
+ onResend(replacementProxy);
106209
+ mark("seller-stall-resend");
106210
+ const second = new AbortController();
106211
+ const resend = fetchImpl(url, sellerAnswerInit(url, {
106212
+ ...init,
106213
+ dispatcher: fresh,
106214
+ signal: AbortSignal.any([...init.signal ? [init.signal] : [], second.signal])
106215
+ }, waitMs)).then((response) => ({ response, from: "resend" }), (error) => ({ error, from: "resend" }));
106216
+ const whole = (side) => side.then((one) => one.error !== void 0 ? one : wholeAnswer(one.response).then((response) => ({ response, from: one.from }), (error) => ({ error, from: one.from })));
106217
+ const firstWhole = whole(firstSend.then((one) => ({ ...one, from: "first" })));
106218
+ const resendWhole = whole(resend);
106219
+ const ok = (one) => one.response !== void 0 && one.response.status >= 200 && one.response.status <= 299;
106220
+ try {
106221
+ const earlier = await Promise.race([firstWhole, resendWhole]);
106222
+ let winner = earlier;
106223
+ if (!ok(earlier)) {
106224
+ const other = await (earlier.from === "first" ? resendWhole : firstWhole);
106225
+ winner = ok(other) ? other : earlier.response !== void 0 ? earlier : other.response !== void 0 ? other : void 0;
106226
+ if (winner === void 0) {
106227
+ if (init.signal?.aborted) throw init.signal.reason;
106228
+ throw (earlier.from === "resend" ? earlier : other).error;
106229
+ }
106230
+ }
106231
+ (winner.from === "first" ? second : first).abort();
106232
+ mark("seller-stall-answer", winner.from);
106233
+ return { response: winner.response, stallResent: true, replacementProxy };
106234
+ } finally {
106235
+ fresh.close().catch(() => {
106236
+ });
106237
+ }
106238
+ }
106239
+ async function wholeAnswer(response) {
106240
+ const nullBody = [101, 103, 204, 205, 304].includes(response.status);
106241
+ if (!response.body || nullBody) {
106242
+ await response.body?.cancel?.().catch?.(() => {
106243
+ });
106244
+ return new Response(null, { status: response.status, statusText: response.statusText, headers: response.headers });
106245
+ }
106246
+ const reader = response.body.getReader();
106247
+ const chunks = [];
106248
+ let size = 0;
106249
+ while (size <= RESULT_LIMIT_BYTES) {
106250
+ const { done, value: value2 } = await reader.read();
106251
+ if (done) break;
106252
+ size += value2.byteLength;
106253
+ chunks.push(Buffer.from(value2));
106254
+ }
106255
+ if (size > RESULT_LIMIT_BYTES) await reader.cancel().catch(() => {
106256
+ });
106257
+ return new Response(
106258
+ Buffer.concat(chunks).subarray(0, RESULT_LIMIT_BYTES + 1),
106259
+ { status: response.status, statusText: response.statusText, headers: response.headers }
106260
+ );
106261
+ }
106115
106262
  async function sellerRefusalText(response) {
106116
106263
  let text3 = "";
106117
106264
  let reader;
@@ -106167,9 +106314,10 @@ function x402HeaderText(response, name, field4) {
106167
106314
  const value2 = x402Header(response, name)?.[field4];
106168
106315
  return typeof value2 === "string" && value2.trim() !== "" ? value2 : void 0;
106169
106316
  }
106170
- function newConnectionDispatcher() {
106317
+ function newConnectionDispatcher(stallProxy) {
106171
106318
  try {
106172
106319
  const Dispatcher = globalThis[GLOBAL_DISPATCHER5]?.constructor;
106320
+ if (stallProxy !== void 0) return Dispatcher?.name === "EnvHttpProxyAgent" ? proxyDispatcher(Dispatcher, stallProxy) : void 0;
106173
106321
  if (Dispatcher?.name === "Agent") return new Dispatcher();
106174
106322
  const proxy = String(process.env.SHINJUKU_WALLET_PROXIED ?? "").startsWith("tor ") ? process.env.HTTPS_PROXY : void 0;
106175
106323
  return Dispatcher?.name === "EnvHttpProxyAgent" && proxy ? proxyDispatcher(Dispatcher, proxy) : void 0;
@@ -107518,6 +107666,10 @@ async function payViaFloat({
107518
107666
  for (const dispatcher of resendDispatchers) dispatcher.close().catch(() => {
107519
107667
  });
107520
107668
  }
107669
+ function stallResent() {
107670
+ record = { ...record, sellerStallResent: true };
107671
+ store.writeWal(walName2, record);
107672
+ }
107521
107673
  function unanswered2(error) {
107522
107674
  if (wasKept) keptAgain();
107523
107675
  const verdict = watch.verdict();
@@ -107535,6 +107687,7 @@ async function payViaFloat({
107535
107687
  refundPendingAnswer(record);
107536
107688
  }
107537
107689
  if (verdict?.state === "cancelled") byVerdict(verdict, {}, { cause: error });
107690
+ const resentNow = record.sellerStallResent === true ? { stallResent: true } : {};
107538
107691
  if (verdict?.state === "final") {
107539
107692
  fail22("p03_float_seller_unanswered_paid_retry_same_request", {
107540
107693
  cause: error,
@@ -107542,7 +107695,8 @@ async function payViaFloat({
107542
107695
  ...verdict.transaction ? { transaction: verdict.transaction } : {},
107543
107696
  paidAtomic: record.paidAtomic,
107544
107697
  priceAtomic: record.priceAtomic,
107545
- feeAtomic: record.feeAtomic
107698
+ feeAtomic: record.feeAtomic,
107699
+ ...resentNow
107546
107700
  });
107547
107701
  }
107548
107702
  fail22("p03_float_seller_unanswered_retry_same_request", {
@@ -107551,7 +107705,8 @@ async function payViaFloat({
107551
107705
  paidAtomic: record.paidAtomic,
107552
107706
  priceAtomic: record.priceAtomic,
107553
107707
  feeAtomic: record.feeAtomic,
107554
- ...verdict?.state === "landed" ? { transferLanded: true } : {}
107708
+ ...verdict?.state === "landed" ? { transferLanded: true } : {},
107709
+ ...resentNow
107555
107710
  });
107556
107711
  }
107557
107712
  async function finalAfterLanded() {
@@ -107578,6 +107733,7 @@ async function payViaFloat({
107578
107733
  let resendUntilMs;
107579
107734
  let answeredAtMs;
107580
107735
  let dispatcher;
107736
+ let stallProxy;
107581
107737
  const waitMs = sellerWaitMs(record);
107582
107738
  const sellerTimeout = AbortSignal.timeout(waitMs);
107583
107739
  const stopResends = () => Date.now() > resendUntilMs || ["landed", "dead", "final", "cancelled"].includes(watch.verdict()?.state);
@@ -107591,7 +107747,16 @@ async function payViaFloat({
107591
107747
  };
107592
107748
  const socketWatch = resend === 0 ? watchRequestSocket(record.url) : void 0;
107593
107749
  try {
107594
- response = await fetchImpl(record.url, sellerAnswerInit(record.url, dispatcher === void 0 ? keepAliveInit(init) : { ...init, dispatcher }, waitMs));
107750
+ ({ response } = await sendWatchingStall(
107751
+ fetchImpl,
107752
+ record.url,
107753
+ dispatcher === void 0 ? keepAliveInit(init) : { ...init, dispatcher },
107754
+ waitMs,
107755
+ { mark, resentBefore: record.sellerStallResent === true, onResend: (proxy) => {
107756
+ stallProxy ??= proxy;
107757
+ stallResent();
107758
+ } }
107759
+ ));
107595
107760
  } catch (error) {
107596
107761
  unanswered2(error);
107597
107762
  } finally {
@@ -107604,7 +107769,7 @@ async function payViaFloat({
107604
107769
  mark(resend === 0 ? "seller-answered" : `seller-answered-resend-${resend}`);
107605
107770
  resendUntilMs ??= Date.now() + FEE_PAYER_RESEND_MS;
107606
107771
  if (wasKept || resend >= FEE_PAYER_RESENDS || stopResends() || !(feePayerRotated(response, accepted) || feePayerNotManaged(response))) break;
107607
- dispatcher = newConnectionDispatcher();
107772
+ dispatcher = newConnectionDispatcher(stallProxy);
107608
107773
  if (dispatcher === void 0) break;
107609
107774
  resendDispatchers.push(dispatcher);
107610
107775
  await drainBody(response);
@@ -107877,6 +108042,8 @@ async function selfBroadcastLeg({ store, walName: walName2, record, sendRequest,
107877
108042
  fail22("p03_float_seller_kept_payment", landed);
107878
108043
  }
107879
108044
  let unanswered2 = 0;
108045
+ let stallProxy;
108046
+ let stallDeadline;
107880
108047
  const resendUnanswered = async () => {
107881
108048
  const wait2 = SELF_BROADCAST_UNANSWERED_RESEND_MS[unanswered2];
107882
108049
  if (wait2 === void 0 || Date.now() + wait2 >= record.selfBroadcast.expiresAtMs) return false;
@@ -107892,22 +108059,38 @@ async function selfBroadcastLeg({ store, walName: walName2, record, sendRequest,
107892
108059
  }
107893
108060
  mark("seller-sent");
107894
108061
  let response;
108062
+ const onStallTag = stallProxy === void 0 ? void 0 : newConnectionDispatcher(stallProxy);
108063
+ const sendDeadline = stallDeadline ?? AbortSignal.timeout(sellerWaitMs(record));
107895
108064
  try {
107896
- response = await fetchImpl(record.url, sellerAnswerInit(record.url, keepAliveInit({
108065
+ ({ response } = await sendWatchingStall(fetchImpl, record.url, keepAliveInit({
107897
108066
  method: sendRequest.method,
107898
108067
  headers: { ...Object.fromEntries(sendRequest.headers), "PAYMENT-SIGNATURE": header },
107899
108068
  ...sendRequest.method === "POST" ? { body: Buffer.from(sendRequest.bodyBase64, "base64") } : {},
107900
108069
  redirect: "error",
107901
- signal: AbortSignal.timeout(sellerWaitMs(record))
107902
- }), sellerWaitMs(record)));
108070
+ signal: sendDeadline,
108071
+ ...onStallTag !== void 0 ? { dispatcher: onStallTag } : {}
108072
+ }), sellerWaitMs(record), { mark, resentBefore: record.sellerStallResent === true, onResend: (proxy) => {
108073
+ stallProxy ??= proxy;
108074
+ stallDeadline ??= sendDeadline;
108075
+ record = { ...record, sellerStallResent: true };
108076
+ store.writeWal(walName2, record);
108077
+ } }));
107903
108078
  } catch (error) {
108079
+ onStallTag?.close().catch(() => {
108080
+ });
107904
108081
  const timedOut = error?.name === "TimeoutError" || error?.cause?.name === "TimeoutError";
107905
108082
  if (!timedOut && !proxyRefusedConnection(error) && await resendUnanswered()) {
107906
108083
  attempt -= 1;
107907
108084
  continue;
107908
108085
  }
107909
- fail22("p03_float_seller_unanswered_paid_retry_same_request", { cause: error, ...landed });
108086
+ fail22("p03_float_seller_unanswered_paid_retry_same_request", {
108087
+ cause: error,
108088
+ ...landed,
108089
+ ...record.sellerStallResent === true ? { stallResent: true } : {}
108090
+ });
107910
108091
  }
108092
+ onStallTag?.close().catch(() => {
108093
+ });
107911
108094
  mark("seller-answered");
107912
108095
  if (response.ok && response.status !== 202) {
107913
108096
  let settled;
@@ -108019,6 +108202,9 @@ function paidResult(record, replayed) {
108019
108202
  replayed,
108020
108203
  scheme: "exact",
108021
108204
  status: record.status ?? 200,
108205
+ // AB32: the paid request went once more on a new Tor circuit after a stall (sendWatchingStall); every paid line says
108206
+ // it is still one payment (Codex round 1 on aa3927fc item 3).
108207
+ ...!replayed && record.sellerStallResent === true ? { stallResent: true } : {},
108022
108208
  // A record written before headers were kept has none.
108023
108209
  sellerHeaders: Array.isArray(record.sellerHeaders) ? record.sellerHeaders : [],
108024
108210
  receipt: { ...record.receipt, float: { floatId: record.floatId, settleTransaction: record.floatSettleTransaction ?? null } },
@@ -108030,7 +108216,7 @@ function paidResult(record, replayed) {
108030
108216
  float: { floatId: record.floatId }
108031
108217
  };
108032
108218
  }
108033
- var import_web3115, FLOAT_PAYMENT_SCHEMA2, REGENERATE_CODES, FLOAT_PAYMENT_WAL_PREFIX2, FLOAT_CONFIG_SCHEMA, FLOAT_PAY_PATH, FLOAT_MEMO_PATH, FLOAT_STATUS_PATH, MAX_BODY_BYTES, FLOAT_REFUND_ETA_SECONDS, REFUND_READ_EARLY_MS, REFUND_ETA_MAX_SECONDS, refundDueOf, REFUND_SETTLED_AFTER_MS, REFUND_OUTCOME_NEWS_MS, FINISHING_POLL_MS, FINISHING_LIMIT_MS, SELLER_TIMEOUT_MS, SELLER_TIMEOUT_ABSURD_SECONDS, FLOAT_STATUS_START_MS, FLOAT_STATUS_POLL_MS, FLOAT_STATUS_TIMEOUT_MS, FLOAT_TRANSFER_DEAD, FLOAT_PAYMENT_REVERTED, VERDICT_POLL_MS, SELLER_ANSWER_VERDICT_MS, TRANSFER_MIN_BLOCKS_LEFT, TRANSFER_FRESH_MS, BLOCK_HEIGHT_TIMEOUT_MS, CONFIG_TIMEOUT_MS, MEMO_UPLOAD_TIMEOUT_MS, CONFIG_CACHE_MS, FLOAT_POOL_WARM_MS, DECIMAL3, POSITIVE, PENDING_CODES, FLOAT_FRONT_HEADER, hash7, fail22, GENERIC_REASON, SELLER_REASON_MAX, SELLER_REASON_READ_BYTES, FEE_PAYER_RESENDS, FEE_PAYER_RESEND_MS, GLOBAL_DISPATCHER5, sortedJson, MODEL_ID, floatPaymentWalName, floatRecordName, FLOAT_KEEP_BYTES_MS, memoryOnlyNeedsScrub, FLOAT_KEEP_OPEN_REQUEST_MS, configCache, configGeneration, configReadSequence, configReads, configRefreshes, SPECULATED_MAX_AGE_MS, speculatedQuotes, poolDomains, FLOAT_FACTS_SCHEMA, floatFacts, floatFactsKey, floatFactsMac, poolDomainReads, poolDomainWarmFailedAt, WARM_RETRY_MS, payerGenerator, etaEntry, loadPayerGenerator, plainText, BROADCAST_REFUSED, BROADCAST_REFUSED_STANDARD, BROADCAST_DEAD, TRANSFER_LANDING_WINDOW_MS, PROOF_DELIVERY_MS, SELF_BROADCAST_LEG1_LEFT_MS, BROADCAST_UNSIGNED, BROADCAST_NO_LOOKUP, BROADCAST_LANDED, BROADCAST_LIMIT_MS, BROADCAST_QUOTE_MARGIN_MS, SELF_BROADCAST_RESEND_MS, SELF_BROADCAST_UNANSWERED_RESEND_MS, SELLER_HEADERS_MAX_COUNT, SELLER_HEADERS_MAX_BYTES, FINAL_AFTER_202_MS, SELLER_HEADERS_KEPT;
108219
+ var import_web3115, FLOAT_PAYMENT_SCHEMA2, REGENERATE_CODES, FLOAT_PAYMENT_WAL_PREFIX2, FLOAT_CONFIG_SCHEMA, FLOAT_PAY_PATH, FLOAT_MEMO_PATH, FLOAT_STATUS_PATH, MAX_BODY_BYTES, FLOAT_REFUND_ETA_SECONDS, REFUND_READ_EARLY_MS, REFUND_ETA_MAX_SECONDS, refundDueOf, REFUND_SETTLED_AFTER_MS, REFUND_OUTCOME_NEWS_MS, FINISHING_POLL_MS, FINISHING_LIMIT_MS, SELLER_TIMEOUT_MS, SELLER_TIMEOUT_ABSURD_SECONDS, SELLER_STALL_CHECK_AFTER_MS, SELLER_STALL_CHECK_EVERY_MS, SELLER_STALL_CHECK_TIMEOUT_MS, SELLER_STALL_MISSES, RESULT_LIMIT_BYTES, FLOAT_STATUS_START_MS, FLOAT_STATUS_POLL_MS, FLOAT_STATUS_TIMEOUT_MS, FLOAT_TRANSFER_DEAD, FLOAT_PAYMENT_REVERTED, VERDICT_POLL_MS, SELLER_ANSWER_VERDICT_MS, TRANSFER_MIN_BLOCKS_LEFT, TRANSFER_FRESH_MS, BLOCK_HEIGHT_TIMEOUT_MS, CONFIG_TIMEOUT_MS, MEMO_UPLOAD_TIMEOUT_MS, CONFIG_CACHE_MS, FLOAT_POOL_WARM_MS, DECIMAL3, POSITIVE, PENDING_CODES, FLOAT_FRONT_HEADER, hash7, fail22, GENERIC_REASON, SELLER_REASON_MAX, SELLER_REASON_READ_BYTES, FEE_PAYER_RESENDS, FEE_PAYER_RESEND_MS, GLOBAL_DISPATCHER5, sortedJson, MODEL_ID, floatPaymentWalName, floatRecordName, FLOAT_KEEP_BYTES_MS, memoryOnlyNeedsScrub, FLOAT_KEEP_OPEN_REQUEST_MS, configCache, configGeneration, configReadSequence, configReads, configRefreshes, SPECULATED_MAX_AGE_MS, speculatedQuotes, poolDomains, FLOAT_FACTS_SCHEMA, floatFacts, floatFactsKey, floatFactsMac, poolDomainReads, poolDomainWarmFailedAt, WARM_RETRY_MS, payerGenerator, etaEntry, loadPayerGenerator, plainText, BROADCAST_REFUSED, BROADCAST_REFUSED_STANDARD, BROADCAST_DEAD, TRANSFER_LANDING_WINDOW_MS, PROOF_DELIVERY_MS, SELF_BROADCAST_LEG1_LEFT_MS, BROADCAST_UNSIGNED, BROADCAST_NO_LOOKUP, BROADCAST_LANDED, BROADCAST_LIMIT_MS, BROADCAST_QUOTE_MARGIN_MS, SELF_BROADCAST_RESEND_MS, SELF_BROADCAST_UNANSWERED_RESEND_MS, SELLER_HEADERS_MAX_COUNT, SELLER_HEADERS_MAX_BYTES, FINAL_AFTER_202_MS, SELLER_HEADERS_KEPT;
108034
108220
  var init_floatPay = __esm({
108035
108221
  "wallet/src/pay/floatPay.mjs"() {
108036
108222
  "use strict";
@@ -108078,6 +108264,11 @@ var init_floatPay = __esm({
108078
108264
  FINISHING_LIMIT_MS = 6e4;
108079
108265
  SELLER_TIMEOUT_MS = 12e4;
108080
108266
  SELLER_TIMEOUT_ABSURD_SECONDS = 86400;
108267
+ SELLER_STALL_CHECK_AFTER_MS = 3e4;
108268
+ SELLER_STALL_CHECK_EVERY_MS = 3e4;
108269
+ SELLER_STALL_CHECK_TIMEOUT_MS = 15e3;
108270
+ SELLER_STALL_MISSES = 2;
108271
+ RESULT_LIMIT_BYTES = 1024 * 1024;
108081
108272
  FLOAT_STATUS_START_MS = 45e3;
108082
108273
  FLOAT_STATUS_POLL_MS = 5e3;
108083
108274
  FLOAT_STATUS_TIMEOUT_MS = 5e3;
@@ -114454,7 +114645,9 @@ async function paidCall({ session, target, method, headers, body, cap, maxPrice,
114454
114645
  amountAtomic: amountAtomic ?? null,
114455
114646
  requestId,
114456
114647
  replayed: result.replayed === true,
114457
- receiptFinality: result.receiptFinality ?? null
114648
+ receiptFinality: result.receiptFinality ?? null,
114649
+ // AB32 (pay/floatPay.mjs sendWatchingStall): the paid request went once more on a new Tor circuit; still one payment.
114650
+ ...result.stallResent === true ? { stallResent: true } : {}
114458
114651
  };
114459
114652
  const status = Number.isInteger(result.status) && result.status >= 200 && result.status <= 299 ? result.status : 200;
114460
114653
  return new Response(
@@ -134744,7 +134937,7 @@ ${canonical5}`;
134744
134937
  ...floatPaid ? { via: "shinjuku", shinjukuTransaction } : {},
134745
134938
  ...balanceAnswer(one),
134746
134939
  ...notices,
134747
- next: (unpaid ? "nothing was paid: this request id's payment never landed (the pool's public history proves it), and the answer it got came back again; nothing new was paid. Tell the user nothing was paid for it" : receipt.replayed === true ? "this request id was already paid: the stored receipt came back and nothing new was paid" : floatPaid ? floatPaidNext({ transaction: unpaid ? null : transaction, shinjukuTransaction }) : "paid; tell the user what was paid (amountAtomic, transaction). wallet_receipts lists this payment, wallet_balance shows the new balance") + noticesStep(notices)
134940
+ next: (unpaid ? "nothing was paid: this request id's payment never landed (the pool's public history proves it), and the answer it got came back again; nothing new was paid. Tell the user nothing was paid for it" : receipt.replayed === true ? "this request id was already paid: the stored receipt came back and nothing new was paid" : floatPaid ? floatPaidNext({ transaction: unpaid ? null : transaction, shinjukuTransaction }) + (receipt.stallResent === true || float?.sellerStallResent === true ? `. Tell the user too: ${stallResentLine()}` : "") : "paid; tell the user what was paid (amountAtomic, transaction). wallet_receipts lists this payment, wallet_balance shows the new balance") + noticesStep(notices)
134748
134941
  }, "pay_for_service")
134749
134942
  }));
134750
134943
  }
@@ -135056,6 +135249,8 @@ ${canonical5}`;
135056
135249
  ...!ambiguous && floatSellerCanBeFixed(error) ? { sellerFixable: true } : {},
135057
135250
  ...error?.transferLanded === true ? { transferLanded: true } : {},
135058
135251
  ...error?.resent === true ? { resent: true } : {},
135252
+ // AB32: this payment went once more on a new Tor circuit after a stall (floatPay.mjs sendWatchingStall).
135253
+ ...error?.stallResent === true ? { stallResent: true } : {},
135059
135254
  ...error?.pruned === true ? { pruned: true } : {},
135060
135255
  ...typeof error?.floatCode === "string" ? { floatCode: error.floatCode } : {},
135061
135256
  // AB164: the seller's own code beside its error after it took the payment (floatWords.mjs PAID_SELLER_FAILED_CODE).
@@ -149470,6 +149665,7 @@ The next question uses it${state2.mode === "talk" ? ", with the conversation so
149470
149665
  else if (plainPaid && reader?.terminal && unsureAtomic() === 0n && !dayRoom2) {
149471
149666
  if (cut2) say2(cut2.trim());
149472
149667
  } else say2(`${cut2}${paidText}. ${tail}`);
149668
+ if (plainPaid && result.receipt?.stallResent === true) say2(stallResentLine("the AI provider"));
149473
149669
  if (state2.mode === "each" && !state2.eachHinted) {
149474
149670
  state2.eachHinted = true;
149475
149671
  say2(paint([["Each question goes alone: the AI does not see your earlier questions. For follow-ups, /mode 2 picks a conversation.", "mute"]], color));
@@ -159225,7 +159421,8 @@ async function curlOutput(response, values, deps, requestId) {
159225
159421
  const person = values.get(PERSON_LINK);
159226
159422
  const said = (text4) => person ? personWords(text4, { homeJob: person.homeJob }) : text4;
159227
159423
  io.err(said(unpaid ? `the same answer as before; nothing was paid: the earlier payment for request-id ${requestId} never went through
159228
- ` : paid ? `paid ${usdcOr(paid.amountAtomic)} from your private balance${route} (the chain does not show who paid); request-id ${requestId}${paid.replayed ? " (replayed: this request was paid before; nothing new was paid)" : ""}
159424
+ ` : paid ? `paid ${usdcOr(paid.amountAtomic)} from your private balance${route} (the chain does not show who paid); request-id ${requestId}${paid.replayed ? " (replayed: this request was paid before; nothing new was paid)" : ""}${paid.stallResent === true && !paid.replayed ? `
159425
+ ${stallResentLine()}` : ""}
159229
159426
  ` : `free (no 402): HTTP ${response.status}; nothing was paid
159230
159427
  `));
159231
159428
  if (values.has("--out")) {
@@ -159672,6 +159869,8 @@ function inferOutput(result, { values, io, model: model2, quiet, requestId, held
159672
159869
  `);
159673
159870
  if (plainPaid) {
159674
159871
  io.err(`${paidLine(BigInt(result.paidAtomic), { color: brandColor(process.stderr, process.env) })}${quiet ? "" : ` request-id ${result.requestId ?? requestId}`}${stopped}
159872
+ `);
159873
+ if (result.receipt?.stallResent === true) io.err(`${stallResentLine("the AI provider")}
159675
159874
  `);
159676
159875
  }
159677
159876
  }