shinjuku-shielded 0.3.154 → 0.3.156

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,19 +6,19 @@ 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.154. The npm packages `shinjuku-shield` and
9
+ This is version 0.3.156. 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
- npm install -g shinjuku@0.3.154
15
+ npm install -g shinjuku@0.3.156
16
16
  shinjuku setup
17
17
  ```
18
18
 
19
19
  Type the two lines as they are. `npx install shinjuku` does not work: npx
20
20
  reads `install` as the name of another npm package. To set up without
21
- installing, type `npx shinjuku@0.3.154 setup`.
21
+ installing, type `npx shinjuku@0.3.156 setup`.
22
22
 
23
23
  Setup makes the wallet on this machine, a private passphrase file, and the
24
24
  checked proof tools (about 191 MB), and writes `config.json`. It also writes
@@ -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 -- npx -y --no-audit --no-fund shinjuku-shield@0.3.154 mcp
39
+ claude mcp add --scope user shinjuku -- npx -y --no-audit --no-fund shinjuku-shield@0.3.156 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": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.154", "mcp"] } } }
45
+ { "mcpServers": { "shinjuku": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.156", "mcp"] } } }
46
46
  ```
47
47
 
48
48
  On native Windows, if the host cannot find `npx`, use `"command": "cmd"` and
@@ -55,7 +55,7 @@ Codex (the Codex app and Codex CLI read the same file, `~/.codex/config.toml`):
55
55
  ```toml
56
56
  [mcp_servers.shinjuku]
57
57
  command = "npx"
58
- args = ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.154", "mcp"]
58
+ args = ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.156", "mcp"]
59
59
  startup_timeout_sec = 120
60
60
  tool_timeout_sec = 300
61
61
  ```
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": "706b774ac8ab6d671a81f7aa269e2a1d1e222d60f545ddde48945fbfdc8b0bcd",
5
- "bytes": 9052676,
6
- "sourceCommit": "7b23397db24686bbab6bd45734cb9560c914981a",
4
+ "sha256": "003fb669ed2395e72fbedad6336c943c92c940fba878d03c4fa03245e2b5ae78",
5
+ "bytes": 9056153,
6
+ "sourceCommit": "41849a3c692d96c166971d1dd5e13ca84cbceb12",
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-03T05:31:30.536Z"
1041
+ "publishedAt": "2026-11-03T06:19:18.430Z"
1042
1042
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "shinjuku-shielded",
3
- "version": "0.3.154",
3
+ "version": "0.3.156",
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": "706b774a",
7
- "shinjukuSha256": "706b774ac8ab6d671a81f7aa269e2a1d1e222d60f545ddde48945fbfdc8b0bcd",
6
+ "shinjukuRelease": "003fb669",
7
+ "shinjukuSha256": "003fb669ed2395e72fbedad6336c943c92c940fba878d03c4fa03245e2b5ae78",
8
8
  "license": "SEE LICENSE IN LICENSE.txt",
9
9
  "author": "Shinjuku Shielded",
10
10
  "homepage": "https://github.com/ShinjukuStaition/shinjuku-shield#readme",
@@ -42618,6 +42618,15 @@ function markPhase(phase, outcome) {
42618
42618
  } catch {
42619
42619
  }
42620
42620
  }
42621
+ function boundMarkPhase() {
42622
+ const write = scope.getStore();
42623
+ return (phase, outcome) => {
42624
+ try {
42625
+ write?.(phase, outcome);
42626
+ } catch {
42627
+ }
42628
+ };
42629
+ }
42621
42630
  function poolReadOutcome(slot3, moved) {
42622
42631
  let text3;
42623
42632
  try {
@@ -42917,6 +42926,9 @@ function tunnelRefused(statusCode) {
42917
42926
  }
42918
42927
  function optimisticConnect(params, { proxyHost, proxyPort, closedInRow }) {
42919
42928
  const target = String(params.path);
42929
+ const mark = boundMarkPhase();
42930
+ const startedAt = Date.now();
42931
+ let dials = 0;
42920
42932
  const head = `CONNECT ${target} HTTP/1.1\r
42921
42933
  ${Object.entries(params.headers ?? {}).filter(([name, value2]) => value2 !== void 0 && !/[\r\n]/.test(`${name}${value2}`)).map(([name, value2]) => `${name}: ${value2}\r
42922
42934
  `).join("")}\r
@@ -42969,6 +42981,7 @@ ${Object.entries(params.headers ?? {}).filter(([name, value2]) => value2 !== voi
42969
42981
  if (first) pendingReject = reject;
42970
42982
  reply = Buffer.alloc(0);
42971
42983
  ready = false;
42984
+ dials += 1;
42972
42985
  socket = net.connect(proxyPort, proxyHost);
42973
42986
  socket.setNoDelay(true);
42974
42987
  let connected = false;
@@ -42977,6 +42990,7 @@ ${Object.entries(params.headers ?? {}).filter(([name, value2]) => value2 !== voi
42977
42990
  socket.write(head);
42978
42991
  for (const chunk of sent) socket.write(chunk);
42979
42992
  ready = true;
42993
+ mark("tunnel-sent", `dial${dials}`);
42980
42994
  if (first) pendingReject = void 0;
42981
42995
  resolve39();
42982
42996
  });
@@ -42990,9 +43004,11 @@ ${Object.entries(params.headers ?? {}).filter(([name, value2]) => value2 !== voi
42990
43004
  if (end < 0) return;
42991
43005
  const status = Number(/^HTTP\/1\.[01] (\d{3})/.exec(reply.subarray(0, reply.indexOf("\r\n")).toString("latin1"))?.[1] ?? 0);
42992
43006
  if (status !== 200) {
43007
+ mark("tunnel-refused", `http${status}`);
42993
43008
  stream.destroy(tunnelRefused(status));
42994
43009
  return;
42995
43010
  }
43011
+ mark("tunnel-200", `ms${Date.now() - startedAt}_dial${dials}`);
42996
43012
  open4 = true;
42997
43013
  sent.length = 0;
42998
43014
  closedInRow.delete(target);
@@ -43019,6 +43035,7 @@ ${Object.entries(params.headers ?? {}).filter(([name, value2]) => value2 !== voi
43019
43035
  return;
43020
43036
  }
43021
43037
  const closed = (closedInRow.get(target) ?? 0) + 1;
43038
+ mark("tunnel-closed", `n${closed}`);
43022
43039
  if (closed < TUNNEL_CLOSED_TRIES) {
43023
43040
  closedInRow.set(target, closed);
43024
43041
  dial(false).catch((error) => stream.destroy(error));
@@ -43042,6 +43059,7 @@ var init_tunnelGuard = __esm({
43042
43059
  "wallet/src/net/tunnelGuard.mjs"() {
43043
43060
  "use strict";
43044
43061
  init_keepAlive();
43062
+ init_phaseTiming();
43045
43063
  RUN_MARK = "SHINJUKU_WALLET_PROXIED";
43046
43064
  TUNNEL_CLOSED_TRIES = 3;
43047
43065
  }
@@ -59679,7 +59697,7 @@ async function readCompactP03HistoryNow({
59679
59697
  poolPreRead,
59680
59698
  // walletHistory.mjs, with poolPreRead: page 0 asked beside the same refresh (requestCompactFirstPage).
59681
59699
  // Used as this read's page 0 when this read asks page 0 at all; readPages checks it as any page.
59682
- // Ignored with knownSnapshot.
59700
+ // Ignored with knownSnapshot, except in the read again after a refused tail hit (`tail` false).
59683
59701
  firstPreRead,
59684
59702
  // compactP03HistoryReport: run beside the spot checks once the initialization is verified
59685
59703
  // ({ snapshot, initialization, contexts }); its result comes back as `alongside`.
@@ -59693,7 +59711,7 @@ async function readCompactP03HistoryNow({
59693
59711
  // result and any throw are ignored.
59694
59712
  onList,
59695
59713
  // compactP03HistoryReport: the records of a compact cache that is not warm (cached.served). When the
59696
- // list is read (no knownSnapshot), these records (or `served`'s, when the pool outgrew them) that pass
59714
+ // list is read (no page 0 handed over by a behind wait), these records (or `served`'s, when the pool outgrew them) that pass
59697
59715
  // the start of the pool's last grid page take that page instead of every page (3b, combineCompactTail);
59698
59716
  // page 0 still goes out and is read to its end.
59699
59717
  prefix,
@@ -59702,8 +59720,8 @@ async function readCompactP03HistoryNow({
59702
59720
  // false: no tail path (compactP03HistoryReport's read again after a refused tail hit; it sent its set already).
59703
59721
  tail = true,
59704
59722
  // compactP03HistoryReport's read again (with tail false): the set the refused tail hit sent at this same count
59705
- // (sendRestOfSet's { pages, tail }), so the read again takes its pages instead of asking them a second time.
59706
- // Ignored with knownSnapshot.
59723
+ // (sendRestOfSet's { pages, tail }), so the read again takes its pages instead of asking them a second time,
59724
+ // with knownSnapshot too.
59707
59725
  restPreRead,
59708
59726
  // compactP03HistoryReport: called on a tail hit with { first (page 0's answer promise), snapshot (the pool
59709
59727
  // account read), check, rest (the set sent at the count) }, so a refused list can be read again from that same
@@ -59728,7 +59746,7 @@ async function readCompactP03HistoryNow({
59728
59746
  const hintIndex = knownSnapshot?.currentIndex ?? knownIndex;
59729
59747
  const cachedReachesKnown = hintIndex !== void 0 && served !== void 0 && Array.isArray(served.records) && Boolean(served.initialization) && BigInt(served.records.length) * SUBTREE_LEAVES3 >= hintIndex;
59730
59748
  const reusedFirst = knownSnapshot !== void 0 && knownFirst !== void 0 ? knownFirst : void 0;
59731
- const preFirst = knownSnapshot === void 0 ? firstPreRead : void 0;
59749
+ const preFirst = knownSnapshot === void 0 || !tail ? firstPreRead : void 0;
59732
59750
  const first = reusedFirst ?? (served === void 0 || hintIndex !== void 0 && !cachedReachesKnown ? preFirst ?? requestPage(source, poolString, 0, signal) : void 0);
59733
59751
  if (first !== void 0 && reusedFirst === void 0) markPhase(preFirst !== void 0 ? "compact-page0-handed-over" : "compact-page0-sent");
59734
59752
  let early = heldPicks.early;
@@ -59792,7 +59810,7 @@ async function readCompactP03HistoryNow({
59792
59810
  const count2 = Number(snapshot.currentIndex / SUBTREE_LEAVES3);
59793
59811
  if (!Number.isSafeInteger(count2)) throw refuse3("p03_compact_history_snapshot_invalid");
59794
59812
  const anchors = freezeFinalizedAnchors(snapshot);
59795
- const preRest = knownSnapshot === void 0 ? restPreRead : void 0;
59813
+ const preRest = knownSnapshot === void 0 || !tail ? restPreRead : void 0;
59796
59814
  let rest;
59797
59815
  const restOfSet = () => rest ??= preRest ?? sendRestOfSet(source, poolString, count2, tailGrid, signal);
59798
59816
  let aheadHere;
@@ -59837,7 +59855,7 @@ async function readCompactP03HistoryNow({
59837
59855
  };
59838
59856
  let prefixCheck;
59839
59857
  const readTailOrPages = async () => {
59840
- if (knownSnapshot !== void 0 || !tail) return readServedPages();
59858
+ if (reusedFirst !== void 0 || !tail) return readServedPages();
59841
59859
  const zero = first ?? preFirst ?? requestPage(source, poolString, 0, signal);
59842
59860
  if (first === void 0 && preFirst === void 0) markPhase("compact-page0-sent");
59843
59861
  const from = tailFrom(count2, tailGrid);
@@ -111049,9 +111067,9 @@ async function payTurn({ session, target, method, headers, body, maxPrice, polic
111049
111067
  if (session.closed) fail26("fetch_session_closed", "this payer session is closed; open a new one");
111050
111068
  const paymentStartedAt = Date.now();
111051
111069
  const timing = typeof opts?.timing === "function" ? opts.timing : session.timing();
111052
- const mark = (phase) => {
111070
+ const mark = (phase, outcome) => {
111053
111071
  try {
111054
- timing?.(phase);
111072
+ timing?.(phase, outcome);
111055
111073
  } catch {
111056
111074
  }
111057
111075
  };
@@ -111069,12 +111087,12 @@ async function payTurn({ session, target, method, headers, body, maxPrice, polic
111069
111087
  warmFloatConfig({ origin: new URL(session.memoServiceUrl).origin, timing: mark });
111070
111088
  startRecoveredPaymentTools(lazyProofTools(session));
111071
111089
  }
111072
- const response = await unpaidRequest(target, () => keepAliveInit({
111090
+ const response = await withPhaseScope(mark, "fetch", () => unpaidRequest(target, () => keepAliveInit({
111073
111091
  method,
111074
111092
  headers,
111075
111093
  ...body ? { body } : {},
111076
111094
  redirect: "manual"
111077
- }), { timeoutMs: Number.isSafeInteger(opts?.unpaidTimeoutMs) && opts.unpaidTimeoutMs > 0 ? opts.unpaidTimeoutMs : void 0, onCut: opts?.onUnpaidCut });
111095
+ }), { timeoutMs: Number.isSafeInteger(opts?.unpaidTimeoutMs) && opts.unpaidTimeoutMs > 0 ? opts.unpaidTimeoutMs : void 0, onCut: opts?.onUnpaidCut }));
111078
111096
  if (response.status !== 402) return response;
111079
111097
  const encoded = response.headers.get("PAYMENT-REQUIRED");
111080
111098
  void drainBody(response);
@@ -144691,13 +144709,30 @@ var init_homeScreen = __esm({
144691
144709
 
144692
144710
  // wallet/src/inference/brand.mjs
144693
144711
  function columnsOf(text3) {
144712
+ const parts = GRAPHEMES ? Array.from(GRAPHEMES.segment(text3), (part) => part.segment) : Array.from(text3);
144694
144713
  let count2 = 0;
144695
- for (const ch of text3) {
144696
- const code2 = ch.codePointAt(0);
144697
- count2 += code2 >= 11904 && code2 <= 42191 || code2 >= 65280 && code2 <= 65376 ? 2 : 1;
144714
+ for (const part of parts) {
144715
+ if (/^[\p{M}\p{Cf}]+$/u.test(part)) continue;
144716
+ count2 += new RegExp("\\p{Extended_Pictographic}|[\\u{1F1E6}-\\u{1F1FF}]|\u20E3", "u").test(part) || wideCode(part.codePointAt(0)) ? 2 : 1;
144698
144717
  }
144699
144718
  return count2;
144700
144719
  }
144720
+ function expandTabs(line, start = 0) {
144721
+ if (!line.includes(" ")) return line;
144722
+ let out = "";
144723
+ let column = start;
144724
+ for (const piece of line.match(/\x1b\[[0-9;]*m|\t|[^\t\x1b]+|\x1b/g) ?? []) {
144725
+ if (piece === " ") {
144726
+ const spaces = 8 - column % 8;
144727
+ out += " ".repeat(spaces);
144728
+ column += spaces;
144729
+ } else {
144730
+ out += piece;
144731
+ if (!piece.startsWith("\x1B[")) column += columnsOf(piece);
144732
+ }
144733
+ }
144734
+ return out;
144735
+ }
144701
144736
  function brandColor(stream = process.stderr, env = process.env) {
144702
144737
  if (!stream?.isTTY || (env.CI ?? "") !== "" || env.TERM === "dumb") return 0;
144703
144738
  return screenColor(stream, env);
@@ -144772,10 +144807,57 @@ function brandLine({ model: model2, tor = true, color = 0 }) {
144772
144807
  ...tor ? [[" \xB7 ", "ash"], ["Tor on", "brass"]] : []
144773
144808
  ], color);
144774
144809
  }
144810
+ function fitColumns(text3, columns, { prefix = "" } = {}) {
144811
+ const width = Math.floor(Number(columns));
144812
+ if (!(width >= 1)) return `${prefix}${text3}`;
144813
+ const visible = (part) => part.replace(/\x1b\[[0-9;]*m/g, "");
144814
+ return String(text3).split("\n").map((raw, index) => {
144815
+ const head = index === 0 ? prefix : "";
144816
+ const headColumns = columnsOf(visible(head));
144817
+ const line = expandTabs(raw, headColumns);
144818
+ if (headColumns + columnsOf(visible(line)) <= width) return `${head}${raw}`;
144819
+ const pad = " ".repeat(Math.min(visible(line).match(/^ */)[0].length, Math.max(0, width - 1)));
144820
+ const out = [];
144821
+ let current = head;
144822
+ let used = headColumns;
144823
+ let hasWord = false;
144824
+ let spaces = "";
144825
+ for (const piece of line.match(/ +|(?:\x1b\[[0-9;]*m|\x1b|[^ \x1b])+/g) ?? []) {
144826
+ if (piece[0] === " ") {
144827
+ if (hasWord) spaces += piece;
144828
+ else {
144829
+ const kept3 = Math.max(0, Math.min(piece.length, width - 1 - used));
144830
+ current += " ".repeat(kept3);
144831
+ used += kept3;
144832
+ }
144833
+ continue;
144834
+ }
144835
+ const seen = columnsOf(visible(piece));
144836
+ if (seen === 0) {
144837
+ current += piece;
144838
+ continue;
144839
+ }
144840
+ if (hasWord && used + spaces.length + seen > width) {
144841
+ out.push(current);
144842
+ current = pad;
144843
+ used = pad.length;
144844
+ } else {
144845
+ current += spaces;
144846
+ used += spaces.length;
144847
+ }
144848
+ spaces = "";
144849
+ current += piece;
144850
+ used += seen;
144851
+ hasWord = true;
144852
+ }
144853
+ out.push(current);
144854
+ return out.join("\n");
144855
+ }).join("\n");
144856
+ }
144775
144857
  function paidLine(atomic4, { color = 0, tail = "" } = {}) {
144776
144858
  return paint([["\u2713 ", "brass"], ["paid privately ", "dim"], [usdcWords(atomic4), "verm"], ...tail ? [[tail, "mute"]] : []], color);
144777
144859
  }
144778
- var HEADER_COLUMNS, STATEMENTS, KATAKANA2, PRIVATE_AI, TONES, joinParts2;
144860
+ var HEADER_COLUMNS, STATEMENTS, KATAKANA2, GRAPHEMES, wideCode, PRIVATE_AI, TONES, joinParts2;
144779
144861
  var init_brand = __esm({
144780
144862
  "wallet/src/inference/brand.mjs"() {
144781
144863
  "use strict";
@@ -144785,6 +144867,8 @@ var init_brand = __esm({
144785
144867
  HEADER_COLUMNS = 80;
144786
144868
  STATEMENTS = "Shield once. Take it everywhere. Pay unseen.";
144787
144869
  KATAKANA2 = Array.from({ length: 65438 - 65382 }, (_, index) => String.fromCharCode(65382 + index));
144870
+ GRAPHEMES = typeof Intl.Segmenter === "function" ? new Intl.Segmenter("en", { granularity: "grapheme" }) : void 0;
144871
+ wideCode = (code2) => code2 >= 4352 && code2 <= 4447 || code2 >= 11904 && code2 <= 42191 || code2 >= 44032 && code2 <= 55203 || code2 >= 63744 && code2 <= 64255 || code2 >= 65072 && code2 <= 65103 || code2 >= 65280 && code2 <= 65376 || code2 >= 65504 && code2 <= 65510 || code2 >= 131072 && code2 <= 262141;
144788
144872
  PRIVATE_AI = [["Private ", "bone"], ["AI", "crim"]];
144789
144873
  TONES = { b: "brass", c: "crim", o: "crimdim" };
144790
144874
  joinParts2 = (cells) => cells.reduce((parts, [ch, cls]) => {
@@ -145079,7 +145163,8 @@ async function runChat({ io, values, deps = {} }) {
145079
145163
  servedNow();
145080
145164
  const color = brandColor(process.stderr, env);
145081
145165
  const answerColor = brandColor(process.stdout, env);
145082
- const say3 = (line) => io.err(`${line}
145166
+ const fitErr = (text3) => fitColumns(text3, process.stderr.isTTY ? process.stderr.columns : 0);
145167
+ const say3 = (line) => io.err(`${fitErr(line)}
145083
145168
  `);
145084
145169
  const modeName = () => state.mode === "each" ? "one question at a time" : "a conversation";
145085
145170
  const youPrompt = () => paint([
@@ -145614,7 +145699,7 @@ When it says ready, type your message here.`);
145614
145699
  lineAbove = (text3) => {
145615
145700
  lastLineAt = Date.now();
145616
145701
  clearStatus();
145617
- io.err(String(text3).endsWith("\n") ? String(text3) : `${text3}
145702
+ io.err(`${fitErr(String(text3).replace(/\n$/, ""))}
145618
145703
  `);
145619
145704
  if (inPlace) status();
145620
145705
  };
@@ -145683,7 +145768,11 @@ When it says ready, type your message here.`);
145683
145768
  }
145684
145769
  state.answers += 1;
145685
145770
  if (state.mode === "talk") state.history = [...turn.messages, { role: "assistant", content }];
145686
- io.out(`${answerColor ? paint([["AI ", "crim"], ["\u203A ", "ash"]], answerColor) : ""}${content}
145771
+ io.out(`${fitColumns(
145772
+ content,
145773
+ process.stdout.isTTY ? process.stdout.columns : 0,
145774
+ { prefix: answerColor ? paint([["AI ", "crim"], ["\u203A ", "ash"]], answerColor) : "" }
145775
+ )}
145687
145776
  `);
145688
145777
  const cut2 = result.finishReason === "length" ? `(the answer stopped at its ${turn.maxTokens}-token limit) ` : "";
145689
145778
  const plainPaid = paid !== void 0 && !replayed && !unpaid;