shinjuku-shield 0.3.95 → 0.3.96
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/manifest.json +4 -4
- package/package.json +3 -3
- package/shinjuku-wallet.mjs +44 -22
package/README.md
CHANGED
|
@@ -6,13 +6,13 @@ answers privately, in a terminal chat or for your agent app. Its `mcp`
|
|
|
6
6
|
command runs a local MCP server (stdio) for your agent. Your keys never
|
|
7
7
|
leave your machine.
|
|
8
8
|
|
|
9
|
-
This is version 0.3.
|
|
9
|
+
This is version 0.3.96. The npm packages `shinjuku-shield` and
|
|
10
10
|
`shinjuku-shielded` hold the same files; `shinjuku` is the short command.
|
|
11
11
|
|
|
12
12
|
## Set up
|
|
13
13
|
|
|
14
14
|
```sh
|
|
15
|
-
npx -y --no-audit --no-fund shinjuku-shield@0.3.
|
|
15
|
+
npx -y --no-audit --no-fund shinjuku-shield@0.3.96 setup
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
Setup makes the wallet on this machine, a private passphrase file, and the
|
|
@@ -24,7 +24,7 @@ server to that host's config.
|
|
|
24
24
|
## The `shinjuku` command
|
|
25
25
|
|
|
26
26
|
```sh
|
|
27
|
-
npm install -g shinjuku@0.3.
|
|
27
|
+
npm install -g shinjuku@0.3.96
|
|
28
28
|
shinjuku help
|
|
29
29
|
```
|
|
30
30
|
|
|
@@ -36,13 +36,13 @@ Every wallet command works after `shinjuku`, for example `shinjuku balance`,
|
|
|
36
36
|
Claude Code:
|
|
37
37
|
|
|
38
38
|
```sh
|
|
39
|
-
claude mcp add --scope user shinjuku-shielded -- npx -y --no-audit --no-fund shinjuku-shield@0.3.
|
|
39
|
+
claude mcp add --scope user shinjuku-shielded -- npx -y --no-audit --no-fund shinjuku-shield@0.3.96 mcp
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
Claude Desktop (`claude_desktop_config.json`) or Cursor (`~/.cursor/mcp.json`):
|
|
43
43
|
|
|
44
44
|
```json
|
|
45
|
-
{ "mcpServers": { "shinjuku-shielded": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.
|
|
45
|
+
{ "mcpServers": { "shinjuku-shielded": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.96", "mcp"] } } }
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
On native Windows, if the host cannot find `npx`, use `"command": "cmd"` and
|
package/manifest.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "carbon-shielded-wallet/bundle-manifest/v1",
|
|
3
3
|
"file": "shinjuku-wallet.mjs",
|
|
4
|
-
"sha256": "
|
|
5
|
-
"bytes":
|
|
6
|
-
"sourceCommit": "
|
|
4
|
+
"sha256": "4a3321b081e721e8815c614b5e68bb8bf31405cda64ff0b1b9f3b98e62958bab",
|
|
5
|
+
"bytes": 12723643,
|
|
6
|
+
"sourceCommit": "7a18460800537e3397d851bac7c0dc44b64333d8",
|
|
7
7
|
"sourceDirty": false,
|
|
8
8
|
"installRecordMatchesLockfile": true,
|
|
9
9
|
"releaseRule": "valid only when two fresh npm ci --ignore-scripts builds on different OSes give the same sha256; installRecordMatchesLockfile true means every entry npm installed equals its package-lock.json entry and every entry not marked optional, devOptional included, is installed: an optional entry (a package for another platform) may be absent",
|
|
@@ -1297,5 +1297,5 @@
|
|
|
1297
1297
|
"version": "1.8.0"
|
|
1298
1298
|
}
|
|
1299
1299
|
],
|
|
1300
|
-
"publishedAt": "2026-10-
|
|
1300
|
+
"publishedAt": "2026-10-24T06:44:24.102Z"
|
|
1301
1301
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shinjuku-shield",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.96",
|
|
4
4
|
"mcpName": "io.github.ShinjukuStaition/shinjuku-mcp",
|
|
5
5
|
"description": "Shinjuku Shielded, the private x402 facilitator on Solana: the self-custody wallet CLI and its MCP server. Shield, pay, and unshield USDC from any MCP agent, under caps you set.",
|
|
6
|
-
"shinjukuRelease": "
|
|
7
|
-
"shinjukuSha256": "
|
|
6
|
+
"shinjukuRelease": "4a3321b0",
|
|
7
|
+
"shinjukuSha256": "4a3321b081e721e8815c614b5e68bb8bf31405cda64ff0b1b9f3b98e62958bab",
|
|
8
8
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
9
9
|
"author": "Shinjuku Shielded",
|
|
10
10
|
"homepage": "https://github.com/ShinjukuStaition/shinjuku-mcp#readme",
|
package/shinjuku-wallet.mjs
CHANGED
|
@@ -104889,7 +104889,7 @@ function isOlderSetupEntry(existing, entry) {
|
|
|
104889
104889
|
if (!isPlainObject3(existing) || !Array.isArray(existing.args) || entry.command !== "npx" || !Array.isArray(entry.args)) return false;
|
|
104890
104890
|
const pinned = (args) => args.some((arg) => PINNED_PACKAGE.test(arg));
|
|
104891
104891
|
if (pinned(existing.args) && !pinned(entry.args)) return false;
|
|
104892
|
-
const plain = (args) => args.map((arg) => PINNED_PACKAGE.test(arg) || NPM_PACKAGE_NAMES.includes(arg) ? NPX_PACKAGE : arg);
|
|
104892
|
+
const plain = (args) => args.map((arg) => PINNED_PACKAGE.test(arg) || NPM_PACKAGE_NAMES.includes(arg) || arg === COMMAND_PACKAGE ? NPX_PACKAGE : arg);
|
|
104893
104893
|
const was = { ...existing, args: plain(existing.args) };
|
|
104894
104894
|
const now = { ...entry, args: plain(entry.args) };
|
|
104895
104895
|
return sameJson2(was, now) || sameJson2(was, { ...now, args: now.args.filter((arg) => !NPX_INSTALL_FLAGS.includes(arg)) });
|
|
@@ -104973,7 +104973,7 @@ function addToJsonHost(file, entry, { now = /* @__PURE__ */ new Date(), force =
|
|
|
104973
104973
|
}
|
|
104974
104974
|
return { file, changed: true, ...backup ? { backup } : {} };
|
|
104975
104975
|
}
|
|
104976
|
-
var import_web3118, CONFIG_SCHEMA, CONFIG_FILE, NPM_PACKAGE_NAMES,
|
|
104976
|
+
var import_web3118, CONFIG_SCHEMA, CONFIG_FILE, NPM_PACKAGE_NAMES, COMMAND_PACKAGE, NPX_PACKAGE, NPX_INSTALL_FLAGS, MCP_SERVER_NAME, P03_BINDING2, PRODUCTION, RETIRED_POOLS, NO_LIMIT_ATOMIC2, DEFAULT_CAPS, OLD_DEFAULT_SETUP_CAPS, OLD_DEFAULT_WALLET_BUDGETS, capText, POSITIVE_ATOMIC2, configPath, homeWalletPath, invalid3, isPubkey, MAX_OWN_ADDRESSES, isOwnAddressText, HOST_TARGETS, PINNED_PACKAGE, NPM_VERSION, knownNpmVersion, WINDOWS_SHELL_CODE, isPlainObject3, sameJson2;
|
|
104977
104977
|
var init_config2 = __esm({
|
|
104978
104978
|
"wallet/src/setup/config.mjs"() {
|
|
104979
104979
|
"use strict";
|
|
@@ -104983,8 +104983,8 @@ var init_config2 = __esm({
|
|
|
104983
104983
|
CONFIG_SCHEMA = "shinjuku-shielded/config/v1";
|
|
104984
104984
|
CONFIG_FILE = "config.json";
|
|
104985
104985
|
NPM_PACKAGE_NAMES = Object.freeze(["shinjuku-shield", "shinjuku-shielded"]);
|
|
104986
|
-
NPX_PACKAGE = NPM_PACKAGE_NAMES[0];
|
|
104987
104986
|
COMMAND_PACKAGE = "shinjuku";
|
|
104987
|
+
NPX_PACKAGE = COMMAND_PACKAGE;
|
|
104988
104988
|
NPX_INSTALL_FLAGS = Object.freeze(["--no-audit", "--no-fund"]);
|
|
104989
104989
|
MCP_SERVER_NAME = "shinjuku-shielded";
|
|
104990
104990
|
P03_BINDING2 = "carbon-shielded-exact/svm-v3";
|
|
@@ -105026,7 +105026,7 @@ var init_config2 = __esm({
|
|
|
105026
105026
|
MAX_OWN_ADDRESSES = 8;
|
|
105027
105027
|
isOwnAddressText = (value) => isPubkey(value);
|
|
105028
105028
|
HOST_TARGETS = Object.freeze(["claude-code", "claude-desktop", "cursor"]);
|
|
105029
|
-
PINNED_PACKAGE = /^shinjuku
|
|
105029
|
+
PINNED_PACKAGE = /^shinjuku(?:-shield(?:ed)?)?@(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/;
|
|
105030
105030
|
NPM_VERSION = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/;
|
|
105031
105031
|
knownNpmVersion = (npmVersion) => typeof npmVersion === "string" && npmVersion !== "0.0.0" && NPM_VERSION.test(npmVersion) ? npmVersion : void 0;
|
|
105032
105032
|
WINDOWS_SHELL_CODE = /[%$`"\r\n]/;
|
|
@@ -105344,7 +105344,7 @@ function computeBalance({ store, snapshotRead, source = "local", now = Date.now(
|
|
|
105344
105344
|
const awaiting = pendingDeposits.find((entry) => entry.state === "awaiting_funds");
|
|
105345
105345
|
if (records.every(planOnly)) {
|
|
105346
105346
|
Object.assign(detail, { unspentAtomic: "0", reservedAtomic: "0", balanceSource: "new_wallet_nothing_received" });
|
|
105347
|
-
return report("empty", 0n, "no deposit yet:
|
|
105347
|
+
return report("empty", 0n, "no deposit yet: run shinjuku add-funds --route exchange --amount 1 (change 1 to the USDC you want): it gives a one-time address and its QR code to send USDC to from any wallet or exchange (no SOL needed). If this wallet only holds restored keys or receives payments, run balance --refresh");
|
|
105348
105348
|
}
|
|
105349
105349
|
reasons.push("this wallet has a deposit, add-funds or payment record but no balance walk yet: its balance is not known until the first read");
|
|
105350
105350
|
return report("unknown", null, proved ? `deposit ${proved.depositId} is proved but not sent: back up (shinjuku help backup-export), then rerun the same deposit command with --submit --service <facilitator URL>` : awaiting ? `deposit ${awaiting.depositId} waits for USDC at its one-time address: fund it, then rerun the same deposit --relay command (it prints the address)` : refreshCommand(state));
|
|
@@ -110135,8 +110135,8 @@ function linkSay(a) {
|
|
|
110135
110135
|
const max = usdcText(a.roundMaxAtomic);
|
|
110136
110136
|
const what = hint ? `${hint} USDC` : max ? `up to ${max} USDC` : "USDC";
|
|
110137
110137
|
const send3 = `Send ${what} on Solana to ${address5}.`;
|
|
110138
|
-
const full = `${send3} After it arrives, ask for your balance once; it becomes private by itself a few minutes
|
|
110139
|
-
return words(full) <= SAY_MAX_WORDS ? full : `${send3} After it arrives, ask for your balance once; it becomes private a few minutes
|
|
110138
|
+
const full = `${send3} After it arrives, ask for your balance once; it becomes private by itself within a few minutes.`;
|
|
110139
|
+
return words(full) <= SAY_MAX_WORDS ? full : `${send3} After it arrives, ask for your balance once; it becomes private within a few minutes.`;
|
|
110140
110140
|
}
|
|
110141
110141
|
case "shielding":
|
|
110142
110142
|
case "partly_shielded": {
|
|
@@ -110342,6 +110342,8 @@ function balanceLine(a, room = SAY_MAX_WORDS) {
|
|
|
110342
110342
|
if (moving) return have(`. ${MOVE_LINE}`);
|
|
110343
110343
|
const held = heldByPaymentSay(a.detail);
|
|
110344
110344
|
if (balance === "0" && held) return held;
|
|
110345
|
+
const waitsAt = Array.isArray(a.addFunds) && a.addFunds.some((row) => row && row.state === "open" && row.landed !== true && (row.heldAtomic === null || row.heldAtomic === "0"));
|
|
110346
|
+
if (balance === "0" && !pubPart && waitsAt) return "Your private balance is 0. The wallet watches your add-funds address and shows the USDC here after it arrives.";
|
|
110345
110347
|
if (balance === "0" && !pubPart) return "Your private balance is empty. Use wallet_add_funds to get an address to send USDC to.";
|
|
110346
110348
|
const parts = Number.isSafeInteger(a.balanceParts) && a.balanceParts > 1 && !a.sendWaiting ? a.balanceParts : 0;
|
|
110347
110349
|
if (parts) {
|
|
@@ -119781,7 +119783,7 @@ function createAddFundsTool({
|
|
|
119781
119783
|
return {
|
|
119782
119784
|
name: "wallet_add_funds",
|
|
119783
119785
|
title: "Add money: a one-time address to send USDC to",
|
|
119784
|
-
description: 'Use this to add money to the wallet. Answers a NEW one-time Solana address of this wallet (with a solana: pay link and one line to paste). Send USDC to it from any wallet or exchange; after it arrives, ask for the balance once (wallet_balance): the wallet then sees the USDC and makes it private by itself after a random privacy wait of
|
|
119786
|
+
description: 'Use this to add money to the wallet. Answers a NEW one-time Solana address of this wallet (with a solana: pay link and one line to paste). Send USDC to it from any wallet or exchange; after it arrives, ask for the balance once (wallet_balance): the wallet then sees the USDC and makes it private by itself after a random privacy wait of up to 5 minutes (no other step). Up to 5 USDC (or the shield limit set at start) goes in at a time; more waits safely at the address and goes in a little at a time. amount (USDC text, like "0.37") is optional: a hint shown in the link. Without request_id each call gives a new address (at most 5 unused ones; then the newest unused one again). With a request_id: the first call makes its address, a later call answers that address and its state. Use each address for ONE payer: a second payer on the same address is linked to the first on chain. Moves no money by itself. Refusals: mcp_argument_invalid, payme_amount_invalid, payme_note_invalid, mcp_request_id_reused, mcp_request_id_reserved, payme_key_probe_exhausted, mcp_tool_disabled, wallet_locked, mcp_add_funds_failed.',
|
|
119785
119787
|
inputSchema: {
|
|
119786
119788
|
type: "object",
|
|
119787
119789
|
properties: {
|
|
@@ -127407,7 +127409,7 @@ ${canonical5}`;
|
|
|
127407
127409
|
return refuse12(
|
|
127408
127410
|
code2,
|
|
127409
127411
|
`the shielded balance is less than this payment needs (price + fee); nothing was paid.${facts}`,
|
|
127410
|
-
`Nothing was paid. Tell the user the balance is too low for this price: wallet_balance shows breakdown.shieldedAtomic (a refund still on its way shows as refundsInFlightAtomic and becomes spendable when it arrives). To pay, add USDC with wallet_add_funds (it gives an address; 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
|
|
127412
|
+
`Nothing was paid. Tell the user the balance is too low for this price: wallet_balance shows breakdown.shieldedAtomic (a refund still on its way shows as refundsInFlightAtomic and becomes spendable when it arrives). To pay, add USDC with wallet_add_funds (it gives an address; 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 up to 5 minutes), wait until wallet_balance counts it, then call ${tool} again with request_id "${requestId}" and ${same2} (it never pays twice)`,
|
|
127411
127413
|
{
|
|
127412
127414
|
requestId,
|
|
127413
127415
|
paid: false,
|
|
@@ -127469,7 +127471,7 @@ ${canonical5}`;
|
|
|
127469
127471
|
if (reads.size >= LINK_HELD_READS_MAX) break;
|
|
127470
127472
|
if (record.state !== "open" || typeof record.tokenAccount !== "string" || ATOMIC_TEXT.test(String(record.leftAtAddressAtomic ?? ""))) continue;
|
|
127471
127473
|
const seen = linkHeldSeen.get(record.id);
|
|
127472
|
-
if (seen && Date.now() - seen.atMs < LINK_HELD_FRESH_MS) {
|
|
127474
|
+
if (seen && seen.held !== "0" && Date.now() - seen.atMs < LINK_HELD_FRESH_MS) {
|
|
127473
127475
|
reads.set(record.id, Promise.resolve(seen.held));
|
|
127474
127476
|
continue;
|
|
127475
127477
|
}
|
|
@@ -127899,7 +127901,7 @@ ${canonical5}`;
|
|
|
127899
127901
|
else if (one.breakdown?.movingAtomic && one.breakdown.movingAtomic !== "0") next = "some of your balance moves to the facilitator's new pool now (movingAtomic): it counts in balanceAtomic and is spendable in a few minutes; the move field shows the move";
|
|
127900
127902
|
else if (unshielded.unshieldedAtomic && unshielded.unshieldedAtomic !== "0" && shieldEnabled) next = 'to make the public USDC private, call wallet_shield with amount (like "0.37")';
|
|
127901
127903
|
else if (one.balanceAtomic === "0" && shieldEnabled) {
|
|
127902
|
-
next = elsewhereEnabled ? `the shielded balance is 0, so x402_pay cannot pay yet. To add funds, call wallet_add_funds: it gives a one-time address; up to ${usdcText2(payMeRoundMax())} USDC sent there on Solana becomes private a few minutes after it arrives while this MCP server runs (or call wallet_add_funds with its request_id to finish it at once)` : `the shielded balance is 0, so x402_pay cannot pay yet. To add funds: send USDC on Solana to ownAddress
|
|
127904
|
+
next = elsewhereEnabled ? `the shielded balance is 0, so x402_pay cannot pay yet. To add funds, call wallet_add_funds: it gives a one-time address; up to ${usdcText2(payMeRoundMax())} USDC sent there on Solana becomes private within a few minutes after it arrives while this MCP server runs (or call wallet_add_funds with its request_id to finish it at once)` : `the shielded balance is 0, so x402_pay cannot pay yet. This server has no private deposit address, so the only way in is a deposit from this wallet's public address (ownAddress): the chain then shows that this wallet's public address added that amount; later payments stay private. Tell the user this BEFORE they send. To add funds that way: send USDC on Solana to ownAddress, then call wallet_shield with amount (any amount from ${usdcText2(10000n)} to ${usdcText2(MAX_SHIELDED_BALANCE_ATOMIC)} USDC)`;
|
|
127903
127905
|
} else next = "nothing to do; x402_pay pays from balanceAtomic, wallet_unshield sends from breakdown.shieldedAtomic";
|
|
127904
127906
|
const lastRead = one.balanceAtomic === null && refresh.refreshing === true && !firstRead && ATOMIC_TEXT.test(String(report.detail?.unspentAtomic ?? "")) && Number.isFinite(report.detail?.lastRefresh?.ageSeconds) ? { privateAtomic: String(report.detail.unspentAtomic), ageMinutes: Math.max(1, Math.round(report.detail.lastRefresh.ageSeconds / 60)) } : void 0;
|
|
127905
127907
|
if (lastRead) {
|
|
@@ -127988,6 +127990,7 @@ ${canonical5}`;
|
|
|
127988
127990
|
sendWaiting = void 0;
|
|
127989
127991
|
}
|
|
127990
127992
|
const arrivingAll = addFundsOpen.filter((link2) => link2.landed !== true && (link2.state === "shielding" || /^[1-9][0-9]*$/.test(String(link2.heldAtomic ?? ""))));
|
|
127993
|
+
const addFundsWaiting = addFundsOpen.filter((link2) => link2.state === "open" && link2.landed !== true && (link2.heldAtomic === null || link2.heldAtomic === "0"));
|
|
127991
127994
|
const arrivingLine = (arriving) => {
|
|
127992
127995
|
const amount = /^[1-9][0-9]*$/.test(String(arriving.shieldingAtomic ?? "")) ? `${usdcText2(arriving.shieldingAtomic)} USDC` : /^[1-9][0-9]*$/.test(String(arriving.heldAtomic ?? "")) ? `${usdcText2(arriving.heldAtomic)} USDC` : "USDC (an amount still being read)";
|
|
127993
127996
|
const when = arriving.state === "shielding" && !arriving.startsAtNextRequest ? "is becoming private now (its deposit transaction was sent; about 1 minute)" : arriving.startsInMinutes > 0 ? `waits about ${minutesText2(arriving.startsInMinutes)} (a random wait hides the link to the deposit), then becomes private by itself in about 1 minute more` : "becomes private by itself: its deposit starts now and takes about 1 minute";
|
|
@@ -127999,6 +128002,9 @@ ${canonical5}`;
|
|
|
127999
128002
|
next = `${landedNext ? `${landedNext}. ` : ""}${arrivingLine(arrivingAll[0])}. ${inWait(arrivingAll[0]) ? "Tell the user it becomes private by itself at that time; they can ask about the balance after that to see it" : "Tell the user it becomes private by itself in about 1 minute; they can ask about the balance after that to see it"}; do not hurry it.${runsOn} If balanceAtomic does not show it 10 minutes after that, call wallet_add_funds with request_id "${arrivingAll[0].requestId}": it finishes it now. Do not ask for a new address`;
|
|
128000
128003
|
} else if (arrivingAll.length > 1) {
|
|
128001
128004
|
next = `${landedNext ? `${landedNext}. ` : ""}${arrivingAll.map(arrivingLine).join("; ")}. ${arrivingAll.some(inWait) ? "Tell the user the total; each becomes private by itself at the time named, and they can ask about the balance after that to see it" : "Tell the user the total; it becomes private by itself in about 1 minute, and they can ask about the balance after that to see it"}; do not hurry it.${runsOn} If balanceAtomic does not show one 10 minutes after its time, call wallet_add_funds with its request_id: it finishes it now. Do not ask for a new address`;
|
|
128005
|
+
} else if (one.balanceAtomic === "0" && addFundsWaiting.length) {
|
|
128006
|
+
const ids = addFundsWaiting.map((link2) => `"${link2.requestId}"`).join(", ");
|
|
128007
|
+
next = `${landedNext ? `${landedNext}. ` : ""}the shielded balance is 0, and the wallet waits for USDC at the add-funds address${addFundsWaiting.length > 1 ? "es" : ""} it gave (request_id ${ids}); ${addFundsWaiting.some((link2) => link2.heldAtomic === null) ? "its chain read is not done yet" : "the chain shows no USDC there yet"}. Tell the user: after they send USDC there, the wallet sees it and makes it private by itself after a random privacy wait of up to 5 minutes; if they sent it already, it can take a minute to show: call wallet_balance again in a minute. Do not ask for a new address`;
|
|
128002
128008
|
}
|
|
128003
128009
|
const earlierDeposits = (ops.oneTimeAdopt === false ? [] : adopter.outcomes()).map((outcome) => ({
|
|
128004
128010
|
pool: outcome.pool,
|
|
@@ -131671,7 +131677,7 @@ ${canonical5}`;
|
|
|
131671
131677
|
}
|
|
131672
131678
|
}
|
|
131673
131679
|
};
|
|
131674
|
-
const RECEIVE_ONLY_NOTICE = "This wallet has nothing it can pay with yet (no shield in its saved balance or its local records). A payment to receiveShielded arrives in the shielded balance as a received payment. wallet_unshield sends a received payment out without a shield: one unshield sends one received payment, up to its amount. To pay with it (x402_pay), this wallet must first shield any amount once, or unshield some of a received payment once (the rest stays in the shielded balance and can pay then). To shield, use wallet_shield (even 0.01 USDC sent to ownAddress first; the facilitator pays its fee), before or after the payment arrives";
|
|
131680
|
+
const RECEIVE_ONLY_NOTICE = "This wallet has nothing it can pay with yet (no shield in its saved balance or its local records). A payment to receiveShielded arrives in the shielded balance as a received payment. wallet_unshield sends a received payment out without a shield: one unshield sends one received payment, up to its amount. To pay with it (x402_pay), this wallet must first shield any amount once, or unshield some of a received payment once (the rest stays in the shielded balance and can pay then). " + (elsewhereEnabled ? "To shield, use wallet_add_funds (even 0.01 USDC sent to its one-time address; the facilitator pays its fee), before or after the payment arrives" : "This server has no private deposit address: to shield, use wallet_shield (even 0.01 USDC sent to ownAddress first; the facilitator pays its fee), before or after the payment arrives. The chain then shows that this wallet's public address added that amount (later payments stay private): tell the user this before the deposit");
|
|
131675
131681
|
const RECEIVE_SHIELDED_NEXT = "Give receiveShielded to the payer: an OTC seller pastes it as receiveShielded, an OTC buyer as refundTo. Use a new one for each payment. A payment to it shows in wallet_balance after the wallet's next chain read: one runs when this server starts, after each payment, shield, or unshield of this wallet, and when wallet_balance is called more than a minute after the last read (that call answers refreshing: true; call wallet_balance again in about 30 s)";
|
|
131676
131682
|
const RECEIVE_SHIELDED_PRIVACY = "Only a Shinjuku Shield payer in the same pool can pay it, with a private pool payment. The chain shows no address of yours. Each call gives a new recipient: give each payer its own";
|
|
131677
131683
|
const receiveShielded = {
|
|
@@ -133603,7 +133609,9 @@ function createSetupTools({
|
|
|
133603
133609
|
pool: summary.pool,
|
|
133604
133610
|
caps: shownCaps({ maxPaymentAtomic: summary.caps.maxPayment, maxSessionAtomic: summary.caps.maxSession }),
|
|
133605
133611
|
wallet: summary.wallet.status,
|
|
133606
|
-
|
|
133612
|
+
// F2 (0.3.95 live run p95n, 06:19 UTC 2026-10-24): the agent offered the user "the public address above" (this field)
|
|
133613
|
+
// beside wallet_add_funds. The wallet's own address is not shown here; wallet_balance names it (ownAddress) for its public USDC.
|
|
133614
|
+
...summary.wallet.recoveryFile ? { recoveryFile: summary.wallet.recoveryFile } : {}
|
|
133607
133615
|
});
|
|
133608
133616
|
if (current.state === "restart") return restartAnswer(current);
|
|
133609
133617
|
if (current.state === "done") {
|
|
@@ -133620,7 +133628,7 @@ function createSetupTools({
|
|
|
133620
133628
|
...acceptedFacts(),
|
|
133621
133629
|
...summary.tor === true ? { tor: true } : {},
|
|
133622
133630
|
...privateInference ? { privateInference: true } : {},
|
|
133623
|
-
next: `${ACCEPTED_NEXT}The wallet tools are live in this server: the tool list changed (the setup tools are gone, wallet_status included; wallet_balance answers it). This is not a disconnect: do not tell the user to restart or reconnect. 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." : "") +
|
|
133631
|
+
next: `${ACCEPTED_NEXT}The wallet tools are live in this server: the tool list changed (the setup tools are gone, wallet_status included; wallet_balance answers it). This is not a disconnect: do not tell the user to restart or reconnect. 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." : "") + " 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 up to 5 minutes." + (privateInference ? " Private inference is on: after funding, call inference_chat (with no prompt it lists the models and prices); if this app's wallet entry turns Tor off, inference_chat refuses until the owner removes that setting there and reconnects the wallet, so it runs behind Tor." : "")
|
|
133624
133632
|
});
|
|
133625
133633
|
}
|
|
133626
133634
|
if (current.state === "confirming") return json3({ say: SETUP_CONFIRMING_SAY, ok: true, stage: "confirming", next: SETUP_CONFIRMING_NEXT });
|
|
@@ -133797,10 +133805,24 @@ function createSetupTools({
|
|
|
133797
133805
|
});
|
|
133798
133806
|
}
|
|
133799
133807
|
};
|
|
133808
|
+
const SETUP_MODE_PURPOSE = {
|
|
133809
|
+
wallet_balance: "Shows the private USDC balance and any USDC on its way in.",
|
|
133810
|
+
wallet_add_funds: "Gives a one-time address to add USDC to the private balance from any wallet or exchange.",
|
|
133811
|
+
x402_pay: "Pays an x402 URL (a paid web API or file) privately from the private balance and returns what it answers.",
|
|
133812
|
+
x402_preview: "Shows what an x402 URL costs before a payment; it pays nothing.",
|
|
133813
|
+
wallet_unshield: "Sends USDC from the private balance to a Solana address, privately.",
|
|
133814
|
+
wallet_cancel: "Stops an unfinished payment, send or add-funds request.",
|
|
133815
|
+
wallet_receipts: "Lists the recent payments and sends with their receipts.",
|
|
133816
|
+
wallet_shield: "Makes public USDC on this wallet's own address private.",
|
|
133817
|
+
wallet_transfer_token: "Sells a Solana token this wallet holds for USDC and sends that USDC privately to an address.",
|
|
133818
|
+
wallet_transfer_token_status: "Shows how a token sale and send goes, and can stop it.",
|
|
133819
|
+
inference_server: "Starts a private AI address on this computer for another AI app (an OpenAI-compatible base URL and key): each AI answer is paid privately from the private balance.",
|
|
133820
|
+
inference_chat: "Asks an AI model and pays for its answer privately from the private balance; with no prompt it lists the models and their prices."
|
|
133821
|
+
};
|
|
133800
133822
|
const notSetUp = (name) => ({
|
|
133801
133823
|
name,
|
|
133802
133824
|
title: `${name} (wallet not set up)`,
|
|
133803
|
-
description: `The wallet is not set up on this machine, so ${name} answers wallet_not_set_up and does nothing. Call shinjuku_setup first.`,
|
|
133825
|
+
description: `${SETUP_MODE_PURPOSE[name] ? `${SETUP_MODE_PURPOSE[name]} ` : ""}The wallet is not set up on this machine yet, so ${name} answers wallet_not_set_up and does nothing now. Call shinjuku_setup first.`,
|
|
133804
133826
|
inputSchema: { type: "object" },
|
|
133805
133827
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
133806
133828
|
// Hidden after setup are hidden here too (callable by name, not listed).
|
|
@@ -133941,7 +133963,7 @@ var init_tools = __esm({
|
|
|
133941
133963
|
TOKEN_UNIT_TOOLS = /* @__PURE__ */ new Set(["wallet_transfer_token", "wallet_transfer_token_status"]);
|
|
133942
133964
|
RESOURCE_PAYMENT_WAL_PREFIX2 = "resource-payment-";
|
|
133943
133965
|
POOL_LAYOUT_CODE = /pool_state_length_or_magic_invalid|pool_layout_table_invalid|pool_state_anchor_layout_invalid/;
|
|
133944
|
-
POOL_LAYOUT_UPDATE =
|
|
133966
|
+
POOL_LAYOUT_UPDATE = "This wallet release cannot read the pool's on-chain record: the pool program most likely changed its layout in an upgrade. A new wallet version is ready. If the app's MCP config names a fixed version (for example shinjuku-shield@0.3.86), change the version after the @ to latest (shinjuku-shield@latest), or to the newest version in the Releases table at https://github.com/ShinjukuStaition/shinjuku-shielded#releases. Then restart this MCP server in your app (or restart the app): a start with no fixed version, or with @latest, loads the latest version. Nothing was downloaded or changed yet";
|
|
133945
133967
|
USEPOD_VIA_INFERENCE_CHAT = "use inference_chat for AI answers: it sends the prompt only through Tor or the wallet's own proxy";
|
|
133946
133968
|
SEND_RUNS_ON = "The smaller payments go by themselves: when the agent host ends this MCP server, the wallet's send runner (a background wallet process) sends each one at its planned time and then ends. If the computer is off or asleep at the time of one, that payment waits a new random time after the next wallet start.";
|
|
133947
133969
|
DEPOSIT_RUNS_ON = "The deposit goes on by itself: when the agent host ends this MCP server, the wallet's send runner (a background wallet process) runs it at its time and then ends. If the computer is off or asleep then, or the background wallet process could not start, the next wallet process runs it.";
|
|
@@ -135520,7 +135542,7 @@ var init_stdioServer = __esm({
|
|
|
135520
135542
|
SUPPORTED_PROTOCOL_VERSIONS = Object.freeze(["2025-06-18", "2025-03-26", "2024-11-05"]);
|
|
135521
135543
|
MAX_LINE_BYTES = 4 * 1024 * 1024;
|
|
135522
135544
|
POSITIVE_ATOMIC7 = /^[1-9][0-9]{0,30}$/;
|
|
135523
|
-
INSTRUCTIONS = `A self-custody Shinjuku Shield wallet on this machine; the keys and the passphrase stay in this process and no tool takes or returns them. Every tool answer starts with say: one plain sentence to tell the user; the other fields hold the exact numbers. Map the user's plain request to one tool: "what is my balance" -> wallet_balance; "add money" / "deposit" / "fund the wallet" / "move USDC in from Phantom, an exchange, or another wallet" -> wallet_add_funds (it answers a one-time address; the money becomes private a few minutes after it arrives, at the next wallet call); "shield the USDC on this wallet's own address" -> wallet_shield (only public USDC already there); "stop" / "cancel" -> wallet_cancel with the request_id of what to stop; "pay this URL" -> x402_pay (call it directly, no preview is needed); "what does this URL cost" -> x402_preview (only when the user asks for the price); "find a paid API for X" -> x402_discover, then x402_pay on the url it found; "send 2 USDC to <address>" -> wallet_unshield. wallet_balance answers ONE balance (balanceAtomic), and x402_pay pays any x402 seller from it (through Shinjuku for a seller that cannot take a private payment: max_payment must cover the total amountAtomic, fee included; a refund comes back by itself within about 7 minutes). Fields ending in Atomic are atomic units (USDC: 1000000 = 1 USDC); tell the user amounts in USDC. The wallet does its upkeep by itself (chain reads, encrypted backups); the user never runs a CLI command for it. wallet_shield, wallet_add_funds, and wallet_unshield can run for minutes: call again with the SAME request_id as next says. Pass your own request_id to x402_pay: the same request_id never pays or moves money twice (on a code that ends in _retry_same_request, call again with it). wallet_unshield never sends to the wallet's own deposit address; a send to an address the owner did not approve ahead asks the user to confirm it in this client first. When the owner set limits, x402_pay never pays above them (one payment, and any 24 hours for this wallet across all MCP processes); with none, the balance is the only bound. Never claim a payment happened unless the answer has a transaction. Privacy: the chain does not show which wallet paid, but this MCP host and its model provider see every URL, body, price, and paid answer the agent handles. When an item of an answer's poolSwitch.items[] has tellUser true, tell the user its message once, in plain words; the wallet moves the balance by itself.`;
|
|
135545
|
+
INSTRUCTIONS = `A self-custody Shinjuku Shield wallet on this machine; the keys and the passphrase stay in this process and no tool takes or returns them. Every tool answer starts with say: one plain sentence to tell the user; the other fields hold the exact numbers. Map the user's plain request to one tool: "what is my balance" -> wallet_balance; "add money" / "deposit" / "fund the wallet" / "move USDC in from Phantom, an exchange, or another wallet" -> wallet_add_funds (it answers a one-time address; the money becomes private within a few minutes after it arrives, at the next wallet call); "shield the USDC on this wallet's own address" -> wallet_shield (only public USDC already there); "stop" / "cancel" -> wallet_cancel with the request_id of what to stop; "pay this URL" -> x402_pay (call it directly, no preview is needed); "what does this URL cost" -> x402_preview (only when the user asks for the price); "find a paid API for X" -> x402_discover, then x402_pay on the url it found; "send 2 USDC to <address>" -> wallet_unshield. wallet_balance answers ONE balance (balanceAtomic), and x402_pay pays any x402 seller from it (through Shinjuku for a seller that cannot take a private payment: max_payment must cover the total amountAtomic, fee included; a refund comes back by itself within about 7 minutes). Fields ending in Atomic are atomic units (USDC: 1000000 = 1 USDC); tell the user amounts in USDC. The wallet does its upkeep by itself (chain reads, encrypted backups); the user never runs a CLI command for it. wallet_shield, wallet_add_funds, and wallet_unshield can run for minutes: call again with the SAME request_id as next says. Pass your own request_id to x402_pay: the same request_id never pays or moves money twice (on a code that ends in _retry_same_request, call again with it). wallet_unshield never sends to the wallet's own deposit address; a send to an address the owner did not approve ahead asks the user to confirm it in this client first. When the owner set limits, x402_pay never pays above them (one payment, and any 24 hours for this wallet across all MCP processes); with none, the balance is the only bound. Never claim a payment happened unless the answer has a transaction. Privacy: the chain does not show which wallet paid, but this MCP host and its model provider see every URL, body, price, and paid answer the agent handles. When an item of an answer's poolSwitch.items[] has tellUser true, tell the user its message once, in plain words; the wallet moves the balance by itself.`;
|
|
135524
135546
|
MCP_LOG_LEVELS = Object.freeze(["debug", "info", "notice", "warning", "error", "critical", "alert", "emergency"]);
|
|
135525
135547
|
POOL_SWITCH_LOG_LEVEL = "info";
|
|
135526
135548
|
validId = (id) => id === null || typeof id === "string" || typeof id === "number" && Number.isFinite(id);
|
|
@@ -135531,7 +135553,7 @@ var init_stdioServer = __esm({
|
|
|
135531
135553
|
NPM_VERSION2 = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/;
|
|
135532
135554
|
GIT_COMMIT = /^[0-9a-f]{40}$/;
|
|
135533
135555
|
mcpServerVersion = (version3 = walletVersion()) => version3.npm ?? (version3.release ? `release-${version3.release}` : "source");
|
|
135534
|
-
UPDATE_NOTICE_TEXT =
|
|
135556
|
+
UPDATE_NOTICE_TEXT = "A new wallet version is ready. If your app's config names a fixed version (for example shinjuku-shield@0.3.86), change the version after the @ to latest (shinjuku-shield@latest), then restart this MCP server in your app (or restart the app). If the config names no version, just restart this MCP server in your app (or restart the app). Nothing was downloaded or changed yet, and this version keeps working until then.";
|
|
135535
135557
|
updateNoticeLine = (update3) => `Tell the user: ${UPDATE_NOTICE_TEXT} (release ${update3.current}; this wallet runs ${update3.running}.)`;
|
|
135536
135558
|
LAUNCH_NOTICE_TOOLS = Object.freeze(["wallet_balance", "wallet_status"]);
|
|
135537
135559
|
withLaunchLine = (instructions2, line) => !line ? instructions2 : () => `${typeof instructions2 === "function" ? instructions2() : instructions2} Tell the user: ${line}`;
|
|
@@ -162822,7 +162844,7 @@ function fundingStepText(tor) {
|
|
|
162822
162844
|
"Add money: the wallet starts empty. Two private ways, each for any amount from 0.01 USDC:",
|
|
162823
162845
|
` In this terminal: ${fundCommandText(tor)}`,
|
|
162824
162846
|
" It prints a one-time address and its QR code: send exactly that amount of USDC (Solana SPL) to it from an exchange or a phone wallet, and it makes the USDC private by itself (our relayer pays every fee). --amount is in USDC (2 = 2 USDC, 0.05 = 5 cents): change it to the amount you want.",
|
|
162825
|
-
' Or ask your agent: add the server to your agent host (above), then ask "Add 0.50 USDC to my private balance". It calls wallet_add_funds and gives a one-time address: send that USDC on Solana from any wallet or exchange, and it becomes private a few minutes after it arrives, at the next wallet call (no SOL needed; our relayer pays every fee).',
|
|
162847
|
+
' Or ask your agent: add the server to your agent host (above), then ask "Add 0.50 USDC to my private balance". It calls wallet_add_funds and gives a one-time address: send that USDC on Solana from any wallet or exchange, and it becomes private within a few minutes after it arrives, at the next wallet call (no SOL needed; our relayer pays every fee).',
|
|
162826
162848
|
""
|
|
162827
162849
|
].join("\n");
|
|
162828
162850
|
}
|
|
@@ -163211,7 +163233,7 @@ Copy it to two offline places now; it is the only way to restore this wallet.
|
|
|
163211
163233
|
];
|
|
163212
163234
|
if (summary.wallet.status === "created") {
|
|
163213
163235
|
lines.push(
|
|
163214
|
-
|
|
163236
|
+
" wallet created",
|
|
163215
163237
|
` recovery ${summary.wallet.recoveryFile}`,
|
|
163216
163238
|
"",
|
|
163217
163239
|
"BACK UP NOW: copy the recovery file to two offline places (it holds the seed and the key), then delete it from this machine.",
|
|
@@ -164092,7 +164114,7 @@ var COMMANDS = [
|
|
|
164092
164114
|
flag2("--own-address", "<address>", `optional, in your own terminal only (the same as the answer to setup's address question): your own wallet address (Phantom, Solflare, an exchange's deposit address), for sending money back to yourself: the MCP sends to it without asking each time (as mcp --unshield-to), also in an agent app that cannot show a question. Not this wallet's own address. Refused in a script, a pipe, or an agent's tool (no terminal), also with --yes: an agent must never approve an address. A rerun adds it to the ones config.json records (at most ${MAX_OWN_ADDRESSES})`),
|
|
164093
164115
|
flag2("--passphrase-file", "<file>", "your own passphrase file (8 or more characters); default: setup writes a new random passphrase to <home>/passphrase.txt, readable by you alone. Needed for a wallet that exists already"),
|
|
164094
164116
|
flag2("--facilitator", "<https origin>", `the facilitator whose release, pool, and proof tools setup uses; default ${GUIDE.facilitator}`, { check: "origin" }),
|
|
164095
|
-
flag2("--add-to", "<claude-code|claude-desktop|cursor>", `also add the server (npx -y --no-audit --no-fund ${NPX_AT_VERSION} mcp: the host starts this npm version; a wallet not installed from npm writes shinjuku
|
|
164117
|
+
flag2("--add-to", "<claude-code|claude-desktop|cursor>", `also add the server (npx -y --no-audit --no-fund ${NPX_AT_VERSION} mcp: the host starts this npm version; a wallet not installed from npm writes shinjuku without a version) to this agent host's config; repeat it for more. Without it, setup prints the configs`, { repeat: true }),
|
|
164096
164118
|
bool2("--force", "with --add-to: replace a different shinjuku-shielded entry already in a JSON host config (the old file is backed up first, mode 0600), or in Claude Code (claude mcp remove of that one server, then add)"),
|
|
164097
164119
|
flag2("--trust-proof-tools", "<sha256>", `ADVANCED: install the proof-tool set whose SHA256SUMS has this SHA-256 instead of the set this wallet build pins (needed for a facilitator the build does not pin). Check the set out of band first; the normal fix for a new set is npx -y --no-audit --no-fund ${NPX_PACKAGE}@latest setup`)
|
|
164098
164120
|
],
|
|
@@ -164109,7 +164131,7 @@ var COMMANDS = [
|
|
|
164109
164131
|
"The passphrase is never printed and no MCP tool takes or returns it. The recovery file holds the seed and the key: copy it to two offline places, then delete it from this machine.",
|
|
164110
164132
|
`The proof tools are the set this wallet build PINS (its SHA256SUMS hash is in the wallet; --trust-proof-tools replaces it). A facilitator whose /api/wallet/release names another set is refused (setup_proof_tools_pin_mismatch: update the wallet, npx -y --no-audit --no-fund ${NPX_PACKAGE}@latest setup). SHA256SUMS must have the pinned SHA-256, and every file must have the SHA-256 its line names, as /skill.md section 7b; bin/ and house/bin/ get the execute bit. A file that does not match is not kept. Each download has a hard size limit.`,
|
|
164111
164133
|
"Your own --passphrase-file must be private: on Linux and macOS setup refuses a file that group or other may read or write, or that another user owns (setup_passphrase_file_insecure: chmod 600 <file>). On Windows setup cannot read the access list; it accepts the file with a warning.",
|
|
164112
|
-
"--add-to for Claude Desktop or Cursor: a host config whose mcpServers is not a JSON object, or that has a different shinjuku-shielded entry (without --force), is left alone. Otherwise the old file is copied to <file>.bak-<time> (mode 0600 on Linux and macOS; on Windows the folder's access list) and the new file replaces it in one rename. An entry an older setup wrote (no version, another version, or
|
|
164134
|
+
"--add-to for Claude Desktop or Cursor: a host config whose mcpServers is not a JSON object, or that has a different shinjuku-shielded entry (without --force), is left alone. Otherwise the old file is copied to <file>.bak-<time> (mode 0600 on Linux and macOS; on Windows the folder's access list) and the new file replaces it in one rename. An entry an older setup wrote (no version, another version, or an old package name, shinjuku-shield or shinjuku-shielded; the same home) is replaced without --force. For Claude Code, a shinjuku-shielded server already there needs --force.",
|
|
164113
164135
|
"The provers are Linux programs. Linux: ready. Windows: the wallet runs them through WSL; setup checks that wsl.exe runs (wsl --install -d Ubuntu otherwise). macOS: not supported; setup says so and creates nothing.",
|
|
164114
164136
|
"Run it again at any time: it never changes an existing wallet, keeps the recorded caps unless you pass new ones, checks every proof-tool file again, downloads what is missing or newer, and rewrites config.json.",
|
|
164115
164137
|
`Then mcp needs no flags: npx -y --no-audit --no-fund ${NPX_AT_VERSION} mcp reads config.json (a flag on the command line still wins). Before setup, mcp in a terminal offers to run setup; started by an agent host, it serves shinjuku_setup, which runs this same setup after you confirm in the host.`,
|