shinjuku-shield 0.3.110 → 0.3.112
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 +55 -53
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.
|
|
9
|
+
This is version 0.3.112. 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.
|
|
15
|
+
npm install -g shinjuku@0.3.112
|
|
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.
|
|
21
|
+
installing, type `npx shinjuku@0.3.112 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.
|
|
39
|
+
claude mcp add --scope user shinjuku -- npx -y --no-audit --no-fund shinjuku-shield@0.3.112 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.
|
|
45
|
+
{ "mcpServers": { "shinjuku": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.112", "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": "1406c0d44399772d43e33dc6b4cfb7428f9f24215e13389ac46f5dd6dc28d224",
|
|
5
|
+
"bytes": 8331849,
|
|
6
|
+
"sourceCommit": "c46e085c7ef73488d9a62c58b19f13891a4724b5",
|
|
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",
|
|
@@ -1037,5 +1037,5 @@
|
|
|
1037
1037
|
"version": "1.8.0"
|
|
1038
1038
|
}
|
|
1039
1039
|
],
|
|
1040
|
-
"publishedAt": "2026-10-
|
|
1040
|
+
"publishedAt": "2026-10-27T15:32:15.515Z"
|
|
1041
1041
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shinjuku-shield",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.112",
|
|
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": "1406c0d4",
|
|
7
|
+
"shinjukuSha256": "1406c0d44399772d43e33dc6b4cfb7428f9f24215e13389ac46f5dd6dc28d224",
|
|
8
8
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
9
9
|
"author": "Shinjuku Shielded",
|
|
10
10
|
"homepage": "https://github.com/ShinjukuStaition/shinjuku-shield#readme",
|
package/shinjuku-wallet.mjs
CHANGED
|
@@ -119435,16 +119435,15 @@ function plainSentence(next, room) {
|
|
|
119435
119435
|
}
|
|
119436
119436
|
return "";
|
|
119437
119437
|
}
|
|
119438
|
-
function heldBySendSay(
|
|
119439
|
-
|
|
119440
|
-
return send3 ? `Nothing was ${verb}. Your private send ${send3.requestId} set this money aside for its next payment; stop that send to pay now, or add money.` : `Nothing was ${verb}. A private send in progress set this money aside. Stop that send to pay now, or add money.`;
|
|
119438
|
+
function heldBySendSay(verb) {
|
|
119439
|
+
return `Nothing was ${verb}. A private send in progress set this money aside. Stop that send to pay now, or add money.`;
|
|
119441
119440
|
}
|
|
119442
119441
|
function refusalSay(a, tool, again, npmVersion) {
|
|
119443
119442
|
const code2 = str(a.error);
|
|
119444
119443
|
const detail = str(a.detail);
|
|
119445
119444
|
const next = str(a.next);
|
|
119446
119445
|
const moneyVerb = MOVE_CAP_CODES.has(code2) || tool === "wallet_shield" || tool === "wallet_unshield" ? "moved" : "paid";
|
|
119447
|
-
const ask =
|
|
119446
|
+
const ask = "Ask again";
|
|
119448
119447
|
if (/_refund_pending$/.test(code2)) {
|
|
119449
119448
|
const total2 = usdcText2(a.refundAtomic ?? a.paidAtomic);
|
|
119450
119449
|
const when = Number.isSafeInteger(a.refundEtaSeconds) && a.refundEtaSeconds > 0 ? ` within about ${minutesText(Math.ceil(a.refundEtaSeconds / 60))}` : "";
|
|
@@ -119461,13 +119460,13 @@ function refusalSay(a, tool, again, npmVersion) {
|
|
|
119461
119460
|
if (a.refundArrived === true) return `The seller did not take it. ${yours} is back in your private balance. ${other}`;
|
|
119462
119461
|
return `The seller did not take it; ${total2 ? `${total2} USDC` : "your money"} comes back by itself${when}. ${other}`;
|
|
119463
119462
|
}
|
|
119463
|
+
const askAgain = "Asking again pays again.";
|
|
119464
119464
|
if (code2 === "p03_float_receipt_pruned" && a.conversationNotKept === true) {
|
|
119465
|
-
return
|
|
119465
|
+
return `Paid once, not again: the wallet keeps no copy of a private conversation. ${askAgain}`;
|
|
119466
119466
|
}
|
|
119467
|
-
if (code2 === "p03_float_receipt_pruned") return
|
|
119467
|
+
if (code2 === "p03_float_receipt_pruned") return `This request was paid more than 10 minutes ago. ${askAgain}`;
|
|
119468
119468
|
if (/^p03_(float|resource_payment)_request_(id_conflict|data_mismatch)$/.test(code2)) {
|
|
119469
|
-
|
|
119470
|
-
return `Nothing was paid: this request_id belongs to an earlier payment. For this request, ask again with ${fresh}.`;
|
|
119469
|
+
return "Nothing was paid: this request matched an earlier payment with other details. Ask again to pay for this one.";
|
|
119471
119470
|
}
|
|
119472
119471
|
if (code2 === "p03_resource_payment_memory_only_needs_float") {
|
|
119473
119472
|
return "Nothing was paid: this seller now asks a payment whose record would keep your words, and a private call never pays that way. Ask again.";
|
|
@@ -119567,7 +119566,7 @@ function refusalSay(a, tool, again, npmVersion) {
|
|
|
119567
119566
|
if (code2 === "mcp_setup_restart_needed") return "The wallet is set up, but it must reconnect once. Follow the steps below, then try again. Nothing was paid.";
|
|
119568
119567
|
if (code2 === "mcp_restart_needed") return "Nothing was paid. Restart this app, then try again.";
|
|
119569
119568
|
if (code2 === "p03_merchant_respend_value_held_by_private_send") {
|
|
119570
|
-
return heldBySendSay(
|
|
119569
|
+
return heldBySendSay(tool === "wallet_unshield" || tool === "wallet_transfer_token" || tool === "wallet_transfer_token_status" ? "sent" : "paid");
|
|
119571
119570
|
}
|
|
119572
119571
|
if (/accounts_split/.test(code2) || /accounts_split/.test(detail) || typeof a.joining === "boolean") {
|
|
119573
119572
|
const verb = tool === "wallet_unshield" ? "sent" : "paid";
|
|
@@ -119836,8 +119835,7 @@ function heldByPaymentSay(detail) {
|
|
|
119836
119835
|
if (!items.length) return "";
|
|
119837
119836
|
const held = usdcText2(detail.unspentAtomic);
|
|
119838
119837
|
const what = positive(held) ? `${held} USDC is` : "Your USDC is";
|
|
119839
|
-
|
|
119840
|
-
return id ? `${what} held by an unfinished payment (request_id ${id}). Ask me to finish it, or to close it with wallet_cancel.` : `${what} held by an unfinished payment. Ask me to finish it, or to close it with wallet_cancel.`;
|
|
119838
|
+
return `${what} held by an unfinished payment. Ask me to finish it, or to close it with wallet_cancel.`;
|
|
119841
119839
|
}
|
|
119842
119840
|
function ownWorkWords(lockedBy) {
|
|
119843
119841
|
return typeof lockedBy === "string" && Object.hasOwn(OWN_WORK_WORDS, lockedBy) ? OWN_WORK_WORDS[lockedBy] : void 0;
|
|
@@ -119913,25 +119911,29 @@ function balanceLine(a, room = SAY_MAX_WORDS) {
|
|
|
119913
119911
|
const going = sends.find((send3) => Number.isSafeInteger(send3.failedTries) && send3.failedTries > 0) ?? sends[0];
|
|
119914
119912
|
if (going && !moving) {
|
|
119915
119913
|
const left = usdcText2(going.leftAtomic) ?? "";
|
|
119914
|
+
const total = usdcText2(going.amountAtomic);
|
|
119915
|
+
const to = typeof going.to === "string" && going.to.length > 10 ? ` to ${going.to.slice(0, 4)}...${going.to.slice(-4)}` : "";
|
|
119916
|
+
const named = `your private send${total ? ` of ${total} USDC` : ""}${to}`;
|
|
119917
|
+
const short = `your private send${to}`;
|
|
119916
119918
|
if (Number.isSafeInteger(going.failedTries) && going.failedTries > 0) {
|
|
119917
119919
|
const tries = `${going.failedTries} ${going.failedTries === 1 ? "try" : "tries"}`;
|
|
119918
119920
|
return have(
|
|
119919
|
-
`;
|
|
119920
|
-
`;
|
|
119921
|
+
`; ${named} has ${left} USDC not sent: its next payment did not go through (${tries}).`,
|
|
119922
|
+
`; ${short}: next payment did not go through (${tries}).`,
|
|
119921
119923
|
"; a private send's next payment did not go through yet."
|
|
119922
119924
|
);
|
|
119923
119925
|
}
|
|
119924
119926
|
if (!(Number.isSafeInteger(going.nextPaymentInMinutes) && going.nextPaymentInMinutes > 0)) {
|
|
119925
119927
|
return have(
|
|
119926
|
-
`;
|
|
119927
|
-
`;
|
|
119928
|
+
`; ${named} has ${left} USDC not sent yet, and the wallet tries its next payment again by itself.`,
|
|
119929
|
+
`; ${short}: ${left} USDC not sent yet.`,
|
|
119928
119930
|
"; a private send is not all sent yet."
|
|
119929
119931
|
);
|
|
119930
119932
|
}
|
|
119931
119933
|
const when = `in about ${minutesText(going.nextPaymentInMinutes)}`;
|
|
119932
119934
|
return have(
|
|
119933
|
-
`;
|
|
119934
|
-
`;
|
|
119935
|
+
`; ${named} has ${left} USDC left to go, and its next payment goes ${when}.`,
|
|
119936
|
+
`; ${short}: next payment ${when}.`,
|
|
119935
119937
|
`; a private send's next payment goes ${when}.`
|
|
119936
119938
|
);
|
|
119937
119939
|
}
|
|
@@ -120032,6 +120034,9 @@ function transferSay(a) {
|
|
|
120032
120034
|
const sent = usdcText2(a.send?.amountAtomic);
|
|
120033
120035
|
const kept2 = a.send?.keptPrivateAtomic && a.send.keptPrivateAtomic !== "0" ? usdcText2(a.send.keptPrivateAtomic) : null;
|
|
120034
120036
|
const later = "If this chat ends first, it continues at your next request.";
|
|
120037
|
+
if (a.replayed === true) {
|
|
120038
|
+
return `This request matched an earlier transfer to ${to}; this call moved nothing. Ask again to transfer again.`;
|
|
120039
|
+
}
|
|
120035
120040
|
switch (a.stage) {
|
|
120036
120041
|
case "selling":
|
|
120037
120042
|
return `Selling the token for ${usdc6}; then it goes privately to ${to}. ${later}`;
|
|
@@ -120041,7 +120046,7 @@ function transferSay(a) {
|
|
|
120041
120046
|
// At most 24 words with the kept part (SAY_MAX_WORDS 25). A send step that stopped (tools.mjs transferAnswer sendStop,
|
|
120042
120047
|
// 0.3.109 fault 5) says why first: money another send set aside, or money the wallet gets ready by itself.
|
|
120043
120048
|
case "sending":
|
|
120044
|
-
if (Array.isArray(a.privateSends)) return heldBySendSay(
|
|
120049
|
+
if (Array.isArray(a.privateSends)) return heldBySendSay("sent");
|
|
120045
120050
|
if (a.joining === true) return "Not sent yet: the wallet gets the money ready by itself. Ask again in a few minutes; do not cancel.";
|
|
120046
120051
|
return sent ? `Sending ${sent} USDC (not the token) privately to ${to}${kept2 ? `; ${kept2} USDC stays private` : ""}. ${later}` : `Sending ${usdc6} privately to ${to}. It gets USDC, not the token. ${later}`;
|
|
120047
120052
|
case "sold_waiting_room":
|
|
@@ -120084,8 +120089,7 @@ function stoppedSay(a) {
|
|
|
120084
120089
|
}
|
|
120085
120090
|
function build(a, tool, npmVersion) {
|
|
120086
120091
|
if (!a || typeof a !== "object" || Array.isArray(a)) return void 0;
|
|
120087
|
-
const
|
|
120088
|
-
const again = id ? `Ask again with request_id ${id}; it never pays twice.` : "Ask again with the same request_id; it never pays twice.";
|
|
120092
|
+
const again = "Ask again; it never pays twice.";
|
|
120089
120093
|
if (a.ok === false) return refusalSay(a, tool, again, npmVersion);
|
|
120090
120094
|
if (TRANSFER_TOOLS.has(tool) || tool === void 0 && a.delivers === "USDC" && (a.token || Array.isArray(a.transfers))) return transferSay(a);
|
|
120091
120095
|
if (tool === "wallet_receive_shielded" || tool === void 0 && typeof a.receiveShielded === "string") {
|
|
@@ -120128,7 +120132,7 @@ function build(a, tool, npmVersion) {
|
|
|
120128
120132
|
return `${what} The wallet first gets your whole balance ready to send${steps}, then sends it.`;
|
|
120129
120133
|
}
|
|
120130
120134
|
const head = `Not sent yet: the wallet is getting your balance ready to send${steps}.`;
|
|
120131
|
-
const ask =
|
|
120135
|
+
const ask = "Ask again until it sends";
|
|
120132
120136
|
return [`${head} ${ask}; it never sends twice.`, `${head} ${ask}.`].find((line) => words(line) <= SAY_MAX_WORDS) ?? head;
|
|
120133
120137
|
}
|
|
120134
120138
|
if (typeof a.to === "string" && a.to && Object.hasOwn(a, "stage")) {
|
|
@@ -120163,15 +120167,14 @@ function build(a, tool, npmVersion) {
|
|
|
120163
120167
|
if (typeof a.address === "string" && a.address && typeof a.stage === "string") return linkSay(a);
|
|
120164
120168
|
if (a.stage === "waiting_for_funds" && typeof a.depositAddress === "string") {
|
|
120165
120169
|
const send3 = usdcText2(a.sendAtomic ?? a.amountAtomic);
|
|
120166
|
-
return `Send exactly ${send3 ? `${send3} USDC` : "the amount"} on Solana to ${a.depositAddress} in one transfer. Then ask again
|
|
120170
|
+
return `Send exactly ${send3 ? `${send3} USDC` : "the amount"} on Solana to ${a.depositAddress} in one transfer. Then ask again.`;
|
|
120167
120171
|
}
|
|
120168
120172
|
const shieldJob = SHIELD_TOOLS.has(tool) || tool === void 0 && Object.hasOwn(a, "amountAtomic") && Object.hasOwn(a, "stage") && !Object.hasOwn(a, "paid");
|
|
120169
120173
|
if (shieldJob && typeof a.stage === "string") {
|
|
120170
120174
|
const amount = usdcText2(a.amountAtomic);
|
|
120171
120175
|
const what = amount ? `${amount} USDC` : "The USDC";
|
|
120172
120176
|
if (a.done === true && a.replayed === true) {
|
|
120173
|
-
|
|
120174
|
-
return `This request_id finished earlier (${what} made private then); this call moved nothing. To shield more, ask again with ${fresh}.`;
|
|
120177
|
+
return `This request finished earlier (${what} made private then); this call moved nothing. Ask again to shield more.`;
|
|
120175
120178
|
}
|
|
120176
120179
|
if (a.done === true) return withBalance(`${what} is now private.`, a);
|
|
120177
120180
|
if (a.stage === "waiting" && a.code === "mcp_balance_unknown") {
|
|
@@ -120184,14 +120187,14 @@ function build(a, tool, npmVersion) {
|
|
|
120184
120187
|
}
|
|
120185
120188
|
if (tool === "wallet_receipts" && Number.isSafeInteger(a.count)) {
|
|
120186
120189
|
const arrived = Array.isArray(a.receipts) ? a.receipts.find((row) => row?.kind === "add-funds" && /^[1-9][0-9]*$/.test(String(row.heldAtomic ?? ""))) : void 0;
|
|
120187
|
-
if (arrived) return `${a.count} ${a.count === 1 ? "entry" : "entries"}. ${usdcText2(arrived.heldAtomic)} USDC reached add-funds address
|
|
120190
|
+
if (arrived) return `${a.count} ${a.count === 1 ? "entry" : "entries"}. ${usdcText2(arrived.heldAtomic)} USDC reached an add-funds address and becomes private by itself.`;
|
|
120188
120191
|
return a.count === 0 ? "No receipts or wallet moves yet." : `${a.count} ${a.count === 1 ? "entry" : "entries, newest first"}. Each payment names its seller; pay.shinjukustaition.com is Shinjuku, the private payment service.`;
|
|
120189
120192
|
}
|
|
120190
120193
|
if (Array.isArray(a.models) && a.models.length > 0 && a.paid === void 0) {
|
|
120191
120194
|
const count2 = `${a.models.length} AI ${a.models.length === 1 ? "model is" : "models are"}`;
|
|
120192
120195
|
return a.ready === false ? `Nothing was asked or paid. ${count2} listed, but asking one needs Tor on; the next step says how to turn it on.` : `Nothing was asked or paid. ${count2} ready: ask a question, and each answer is paid privately from your balance.`;
|
|
120193
120196
|
}
|
|
120194
|
-
if (a.done === false) return
|
|
120197
|
+
if (a.done === false) return "Still running. Ask again in about 30 seconds; it never moves money twice.";
|
|
120195
120198
|
return "Done.";
|
|
120196
120199
|
}
|
|
120197
120200
|
function sayFor(answer, { tool, npmVersion } = {}) {
|
|
@@ -127078,7 +127081,7 @@ function createWalletTools({
|
|
|
127078
127081
|
body: { type: "string", description: "Request body text (POST only)." },
|
|
127079
127082
|
max_payment: { type: "string", description: 'Optional: the most this call may pay, in USDC, like "0.05"; at most the spending limit.' },
|
|
127080
127083
|
max_payment_atomic: { type: "string", pattern: "^[1-9][0-9]*$", description: "The same in atomic units (1000000 = 1 USDC). Give max_payment or max_payment_atomic, not both with different values." },
|
|
127081
|
-
request_id: { type: "string", pattern: "^[A-Za-z0-9._:-]{1,128}$", description: "
|
|
127084
|
+
request_id: { type: "string", pattern: "^[A-Za-z0-9._:-]{1,128}$", description: "Optional. Leave it out for a new payment (the answer names the id it made). Pass the request_id of an earlier answer only to resume that payment; it never pays twice." }
|
|
127082
127085
|
},
|
|
127083
127086
|
required: ["url"],
|
|
127084
127087
|
additionalProperties: false
|
|
@@ -127107,7 +127110,7 @@ ${canonical5}`;
|
|
|
127107
127110
|
log("MCP_PAY_JOINED");
|
|
127108
127111
|
return running;
|
|
127109
127112
|
}
|
|
127110
|
-
const task = payCall({ target, request, argument: argument2, requestId, given, calledAt, progress: progress3, canProgress, signal })
|
|
127113
|
+
const task = payCall({ target, request, argument: argument2, requestId, given, calledAt, progress: progress3, canProgress, signal });
|
|
127111
127114
|
if (joinKey !== void 0) {
|
|
127112
127115
|
paysRunning.set(joinKey, task);
|
|
127113
127116
|
task.then(() => paysRunning.delete(joinKey), () => paysRunning.delete(joinKey));
|
|
@@ -127331,7 +127334,6 @@ ${canonical5}`;
|
|
|
127331
127334
|
}
|
|
127332
127335
|
const { bytes: bytes2, truncated } = await readBody(response);
|
|
127333
127336
|
const payment = response.headers.get(PAYMENT_HEADER);
|
|
127334
|
-
const autoId = given ? void 0 : requestId;
|
|
127335
127337
|
if (!payment) {
|
|
127336
127338
|
const moved2 = movedTo(response, target.url);
|
|
127337
127339
|
return answerResult(paidAnswerContent({
|
|
@@ -127351,8 +127353,7 @@ ${canonical5}`;
|
|
|
127351
127353
|
detail: `the URL answered HTTP ${response.status} without asking for payment; nothing was paid`,
|
|
127352
127354
|
...moved2 ? { movedTo: moved2, next: `nothing was paid: this URL answered HTTP ${response.status}, which says it moved to ${moved2}, and gave no data. Tell the user it moved. If the user wants it, call x402_pay again with url "${moved2}", the same method, headers and body, and a NEW request_id` } : response.status >= 200 && response.status < 300 ? {} : { next: `nothing was paid: this URL answered HTTP ${response.status} and did not ask for payment, so it gave no data; check the URL, or pay another seller` }
|
|
127353
127355
|
},
|
|
127354
|
-
"x402_pay"
|
|
127355
|
-
autoId
|
|
127356
|
+
"x402_pay"
|
|
127356
127357
|
)
|
|
127357
127358
|
}));
|
|
127358
127359
|
}
|
|
@@ -127425,13 +127426,9 @@ ${canonical5}`;
|
|
|
127425
127426
|
...balanceAnswer(one),
|
|
127426
127427
|
...takeRefundNotices(),
|
|
127427
127428
|
next: receipt.replayed === true ? "this request id was already paid: the stored receipt came back and nothing new was paid" : floatPaid ? "paid through Shinjuku (privately: the chain shows Shinjuku paying the seller, not this wallet); tell the user the price (priceAtomic), the fee (feeAtomic), the total (amountAtomic), and the transaction (the seller's settle transaction; null when the seller returned none)" + (shinjukuTransaction ? ". shinjukuTransaction is this wallet's private payment to Shinjuku" : ". shinjukuTransaction (this wallet's private payment to Shinjuku) is not recorded yet; wallet_receipts shows it once it settles") + ". wallet_balance shows the new balance" : "paid; tell the user what was paid (amountAtomic, transaction). wallet_receipts lists this payment, wallet_balance shows the new balance"
|
|
127428
|
-
}, "x402_pay"
|
|
127429
|
+
}, "x402_pay")
|
|
127429
127430
|
}));
|
|
127430
127431
|
}
|
|
127431
|
-
const withIdSentence = (say3, id) => {
|
|
127432
|
-
const line = `${say3} Its request_id is ${id}.`;
|
|
127433
|
-
return line.trim().split(/\s+/).length <= SAY_MAX_WORDS ? line : say3;
|
|
127434
|
-
};
|
|
127435
127432
|
function networkFields() {
|
|
127436
127433
|
const mode = runNetworkMode();
|
|
127437
127434
|
let onion = false;
|
|
@@ -127442,9 +127439,8 @@ ${canonical5}`;
|
|
|
127442
127439
|
}
|
|
127443
127440
|
return { network: mode === "tor" ? { mode: "tor", detail: `every request of this wallet goes through Tor (checked at start)${onion ? "; the facilitator is reached over its onion service, so no Tor exit sees those requests" : ""}` } : mode === "proxy" ? { mode: "proxy", detail: "every request of this wallet goes through the proxy this wallet was started with; it is not checked as Tor" } : { mode: "direct", detail: `no Tor: the facilitator, the RPC provider and each seller see this computer's IP address. To hide it, the user runs ${terminalCommand2("setup --yes --prefer-tor")} once in a terminal (it records Tor and checks the wallet's files again; nothing else changes; if Tor is not running, it says how to start it), then closes this app and opens it again` } };
|
|
127444
127441
|
}
|
|
127445
|
-
function sayFirst(fields, tool
|
|
127446
|
-
|
|
127447
|
-
if (autoId) say3 = withIdSentence(say3, autoId);
|
|
127442
|
+
function sayFirst(fields, tool) {
|
|
127443
|
+
const say3 = sayFor(fields, { tool, npmVersion });
|
|
127448
127444
|
const usdc6 = usdcFields(fields);
|
|
127449
127445
|
let news = [];
|
|
127450
127446
|
try {
|
|
@@ -127454,21 +127450,19 @@ ${canonical5}`;
|
|
|
127454
127450
|
}
|
|
127455
127451
|
return { say: say3, ...fields, ...Object.keys(usdc6).length ? { usdc: usdc6 } : {}, ...Array.isArray(news) && news.length ? { news } : {} };
|
|
127456
127452
|
}
|
|
127457
|
-
function withAutoId(output2, tool,
|
|
127453
|
+
function withAutoId(output2, tool, nextNote) {
|
|
127458
127454
|
const said = addSay(output2, tool, { news: watcher, npmVersion });
|
|
127459
127455
|
const blocks = Array.isArray(said?.content) && said.content.length ? said.content : void 0;
|
|
127460
127456
|
const text3 = blocks ? blocks[0]?.type === "text" ? blocks[0].text : void 0 : said?.text;
|
|
127461
127457
|
if (typeof text3 !== "string" || text3.length > 262144 || !/^\s*\{\s*"say"\s*:/.test(text3.slice(0, 64))) return said;
|
|
127462
|
-
const named = text3.slice(0, 600).includes(`Its request_id is ${requestId}.`);
|
|
127463
|
-
if (named && !nextNote) return said;
|
|
127464
127458
|
let parsed2;
|
|
127465
127459
|
try {
|
|
127466
127460
|
parsed2 = JSON.parse(text3);
|
|
127467
127461
|
} catch {
|
|
127468
127462
|
return said;
|
|
127469
127463
|
}
|
|
127470
|
-
if (
|
|
127471
|
-
|
|
127464
|
+
if (typeof parsed2.next !== "string") return said;
|
|
127465
|
+
parsed2.next = `${parsed2.next.replace(/[.\s]+$/, "")}. ${nextNote}`;
|
|
127472
127466
|
const out = JSON.stringify(parsed2, null, /^\s*\{\s*\n/.test(text3) ? 2 : void 0);
|
|
127473
127467
|
return { ...said, text: out, ...blocks ? { content: [{ ...blocks[0], text: out }, ...blocks.slice(1)] } : {} };
|
|
127474
127468
|
}
|
|
@@ -127543,7 +127537,9 @@ ${canonical5}`;
|
|
|
127543
127537
|
const float = floatRefusal(error);
|
|
127544
127538
|
if (float && float[0] === code2) {
|
|
127545
127539
|
const [, detail, sharedNext] = float;
|
|
127546
|
-
const
|
|
127540
|
+
const prunedId = code2 === "p03_float_receipt_pruned" ? newRequestIdFor(requestId) : void 0;
|
|
127541
|
+
const sharedFloatNext = inference ? sharedNext.replace(/\bx402_pay\b/g, tool) : sharedNext;
|
|
127542
|
+
const floatNext = prunedId ? `${sharedFloatNext}: use the new request_id "${prunedId}"` : sharedFloatNext;
|
|
127547
127543
|
let one;
|
|
127548
127544
|
try {
|
|
127549
127545
|
one = readBalance(paidStore ?? session.openStore());
|
|
@@ -127578,6 +127574,7 @@ ${canonical5}`;
|
|
|
127578
127574
|
...typeof error?.feeAtomic === "string" ? { feeAtomic: error.feeAtomic } : {},
|
|
127579
127575
|
// conversationNotKept (floatPay.mjs finishedPruned): a private conversation, whose answer the wallet never kept.
|
|
127580
127576
|
...error?.conversationNotKept === true ? { conversationNotKept: true } : {},
|
|
127577
|
+
...prunedId ? { newRequestId: prunedId } : {},
|
|
127581
127578
|
// floatId: Shinjuku's id of this payment, which wallet_receipts shows with the refund's state and transaction (realSpeed3
|
|
127582
127579
|
// force-live 5r, 2026-10-22: the answer gave no id, so nobody could look the refund up).
|
|
127583
127580
|
// refundAtomic and refundEtaSeconds (Shinjuku's time) for a proven refund; an unproven send carries ambiguous: true.
|
|
@@ -128356,6 +128353,7 @@ ${canonical5}`;
|
|
|
128356
128353
|
privateSends.push({
|
|
128357
128354
|
requestId: transfer ? plan.transferTokenId : shownId(plan.mcpRequestId, recordId2),
|
|
128358
128355
|
...transfer ? { tool: "wallet_transfer_token" } : {},
|
|
128356
|
+
to: plan.mcpTo,
|
|
128359
128357
|
amountAtomic: plan.amountAtomic,
|
|
128360
128358
|
sentAtomic: send3.sentAtomic,
|
|
128361
128359
|
leftAtomic: send3.remainingAtomic,
|
|
@@ -130403,7 +130401,6 @@ ${canonical5}`;
|
|
|
130403
130401
|
return withAutoId(
|
|
130404
130402
|
answer,
|
|
130405
130403
|
spec.tool,
|
|
130406
|
-
claimed.requestId,
|
|
130407
130404
|
"The same call without request_id within 10 minutes after it ends reads this same request; to do it again later, ask after 10 minutes or give a new request_id."
|
|
130408
130405
|
);
|
|
130409
130406
|
}
|
|
@@ -131714,7 +131711,7 @@ ${canonical5}`;
|
|
|
131714
131711
|
properties: {
|
|
131715
131712
|
amount: { type: "string", description: 'USDC to shield, like "0.37" (up to 6 decimals). Pass this or amount_atomic.' },
|
|
131716
131713
|
amount_atomic: { type: "string", pattern: "^[1-9][0-9]*$", description: "USDC to shield, in atomic units (1000000 = 1 USDC, 370000 = 0.37 USDC): any amount from 10000 (0.01 USDC) while the balance stays at most 5 USDC." },
|
|
131717
|
-
request_id: { type: "string", pattern: "^[A-Za-z0-9._:-]{1,128}$", description: "Optional.
|
|
131714
|
+
request_id: { type: "string", pattern: "^[A-Za-z0-9._:-]{1,128}$", description: "Optional. Leave it out for a new deposit (the answer names the id it made). Pass the request_id of an earlier answer only to read or continue that deposit." }
|
|
131718
131715
|
},
|
|
131719
131716
|
required: [],
|
|
131720
131717
|
additionalProperties: false
|
|
@@ -131732,7 +131729,7 @@ ${canonical5}`;
|
|
|
131732
131729
|
amount: { type: "string", description: 'USDC to send, like "2" or "0.37" (up to 6 decimals). Pass this or amount_atomic.' },
|
|
131733
131730
|
amount_atomic: { type: "string", pattern: "^[1-9][0-9]*$", description: "USDC to send, in atomic units (1000000 = 1 USDC)." },
|
|
131734
131731
|
to: { type: "string", description: "The receiving Solana address (base58), exactly as the user gave it. Leave it out to send to the owner's own wallet when the owner set exactly one (wallet_balance session.unshield.to); with none or several set, pass it." },
|
|
131735
|
-
request_id: { type: "string", pattern: "^[A-Za-z0-9._:-]{1,128}$", description: "Optional.
|
|
131732
|
+
request_id: { type: "string", pattern: "^[A-Za-z0-9._:-]{1,128}$", description: "Optional. Leave it out for a new send (the answer names the id it made). Pass the request_id of an earlier answer only to read or continue that send." },
|
|
131736
131733
|
parts: { type: "integer", minimum: 1, maximum: 8, description: "Optional, default 1: send the amount as this many smaller payments (a private send), of random sizes in whole 0.01 USDC: the sizes differ only when the amount allows it (0.02 USDC in 2 goes as 0.01 + 0.01; privateSend lists each amount). Each one carries at least 10000 atomic (0.01 USDC). Above 1 it needs max_delay_minutes 1-60 (smaller payments with no wait are refused: they would leave together). Each one is sent after a random wait of up to max_delay_minutes (the first one too), so the chain shows no single exit of this amount at this time; max_delay_minutes alone delays one exit. " + SEND_RUNS_ON + ` Late ones never go together. While some are unsent, x402_pay may spend only the rest of the balance. The plan is saved in the wallet before the first one, so the same request_id (with the same \`parts\` and max_delay_minutes) continues after a restart and never sends one twice; the answer's privateSend lists each one (state, amount, when it may go, transactions), sentAtomic, and remainingAtomic. The user confirms the whole send once. Each one is a full unshield, so it takes as long as one, and the facilitator pays the network fee of each. Privacy limit (tell the user): every payment goes to the SAME \`to\`, so anyone who adds up that address's incoming transfers sees the total; the smaller payments hide the time and the single amount of the exit, not the sum the address received. wallet_cancel with the same request_id stops the ones not sent yet (their value stays in the private balance); while one is being sent, that call waits for it to finish, up to about ${CALL_BUDGET_MS / 1e3} s.` },
|
|
131737
131734
|
max_delay_minutes: { type: "integer", minimum: 0, maximum: 60, description: "Optional, default 0: each smaller payment, the first included, is sent after a random wait of up to this many minutes (a private send)." }
|
|
131738
131735
|
},
|
|
@@ -131773,7 +131770,7 @@ ${canonical5}`;
|
|
|
131773
131770
|
properties: {
|
|
131774
131771
|
amount: { type: "string", description: 'USDC to shield, like "0.37" (up to 6 decimals). Pass this or amount_atomic, unless action is cancel.' },
|
|
131775
131772
|
amount_atomic: { type: "string", pattern: "^[1-9][0-9]*$", description: "USDC to shield, in atomic units (1000000 = 1 USDC, 370000 = 0.37 USDC): any amount from 10000 (0.01 USDC) while the balance stays at most 5 USDC. Required unless action is cancel." },
|
|
131776
|
-
request_id: { type: "string", pattern: "^[A-Za-z0-9._:-]{1,128}$", description: "Optional for a deposit, needed for cancel.
|
|
131773
|
+
request_id: { type: "string", pattern: "^[A-Za-z0-9._:-]{1,128}$", description: "Optional for a deposit, needed for cancel. Leave it out for a new deposit (the answer names the id it made). Pass the request_id of an earlier answer (with the same amount) only to read, continue, or cancel that deposit." },
|
|
131777
131774
|
action: { type: "string", enum: ["deposit", "cancel"], description: "deposit (the default): start or read this deposit. cancel: close this request's one-time address while nothing at all reached it (no amount needed)." }
|
|
131778
131775
|
},
|
|
131779
131776
|
required: [],
|
|
@@ -132674,7 +132671,10 @@ ${canonical5}`;
|
|
|
132674
132671
|
} else if (sendStop === "split") {
|
|
132675
132672
|
next = `${sentSome ? "Nothing more was sent" : "Nothing was sent yet"}: the private balance holds the next payment of this send, but the wallet must first get that money ready to send. It does that by itself, at each wallet request. Do not cancel the send: tell the user it is not stuck. In a few minutes, ${poll} again: it continues the send where it stopped (it never sends a payment twice)`;
|
|
132676
132673
|
}
|
|
132677
|
-
|
|
132674
|
+
if (extra.replayed === true) {
|
|
132675
|
+
next = `This request_id belongs to an earlier transfer; this call moved nothing new. About that transfer: ${next.replace(/\.$/, "")}. To transfer again, call wallet_transfer_token with the new request_id "${extra.newRequestId}"`;
|
|
132676
|
+
}
|
|
132677
|
+
const inBox = plan.approval?.by === "elicitation" && extra.replayed !== true;
|
|
132678
132678
|
return json3({
|
|
132679
132679
|
ok: true,
|
|
132680
132680
|
...view2,
|
|
@@ -132796,7 +132796,9 @@ ${canonical5}`;
|
|
|
132796
132796
|
const existing = readTransferToken(store, id);
|
|
132797
132797
|
if (existing) {
|
|
132798
132798
|
if (!sameTransfer(existing, request)) return transferReused(id);
|
|
132799
|
-
|
|
132799
|
+
if (TRANSFER_RUNNING_STATES.has(existing.state) && existing.state !== "sold_waiting_room" || tidyOpen(existing)) return await answerSoon(id, { reused: true }, call);
|
|
132800
|
+
const ended = ["done", "cancelled"].includes(existing.state) ? { replayed: true, newRequestId: `${id.slice(0, 31)}-${Date.now().toString(36)}` } : {};
|
|
132801
|
+
return transferAnswer(existing, { reused: true, ...ended });
|
|
132800
132802
|
}
|
|
132801
132803
|
} catch (error) {
|
|
132802
132804
|
return transferRefusal(error, "transfer_plan_unreadable", "tell your owner");
|
|
@@ -133042,7 +133044,7 @@ ${canonical5}`;
|
|
|
133042
133044
|
token_mint: { type: "string", description: "The base58 mint address of the token to sell, like DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263 (BONK). Never a symbol." },
|
|
133043
133045
|
amount_atomic: { type: "string", pattern: "^[1-9][0-9]*$", description: 'How much of the token to sell, in its own base units: "1250000" = 1.25 of a 6-decimal token.' },
|
|
133044
133046
|
to: { type: "string", description: "The receiving Solana address (base58), exactly as the user gave it. It receives USDC and must already be able to receive USDC." },
|
|
133045
|
-
request_id: { type: "string", pattern: "^[A-Za-z0-9_-]{1,40}$", description: "
|
|
133047
|
+
request_id: { type: "string", pattern: "^[A-Za-z0-9_-]{1,40}$", description: "A new name for each new transfer, like move-bonk-k7q2 (an id an earlier transfer used only reads that transfer and moves nothing); wallet_transfer_token_status takes it." },
|
|
133046
133048
|
parts: { type: "integer", minimum: 2, maximum: 8, description: "Optional, default 2: the USDC leaves as this many payments of random sizes in whole 0.01 USDC (each at least 0.01 USDC; the sizes differ only when the amount allows it: 0.02 USDC in 2 goes as 0.01 + 0.01)." },
|
|
133047
133049
|
max_delay_minutes: { type: "integer", minimum: 1, maximum: 60, description: "Optional, default 30: each payment waits a random time up to this many minutes before it leaves." },
|
|
133048
133050
|
max_slippage_bps: { type: "integer", minimum: 1, maximum: 300, description: "Optional, default 50 (0.5 %): the sell fails rather than give less than the quote minus this." },
|
|
@@ -133258,7 +133260,7 @@ ${canonical5}`;
|
|
|
133258
133260
|
temperature: { type: "number", minimum: 0, maximum: 2, description: "Sampling temperature; leave it out for the model's default." },
|
|
133259
133261
|
max_payment: { type: "string", description: 'Optional: the most this call may pay, in USDC, like "0.05"; at most the spending limit.' },
|
|
133260
133262
|
max_payment_atomic: { type: "string", pattern: "^[1-9][0-9]*$", description: "The most this call may pay, in atomic units; at most the spending limit." },
|
|
133261
|
-
request_id: { type: "string", pattern: "^[A-Za-z0-9._:-]{1,128}$", description: "
|
|
133263
|
+
request_id: { type: "string", pattern: "^[A-Za-z0-9._:-]{1,128}$", description: "Optional. Leave it out for a new question (the answer names the id it made). Pass the request_id of an earlier answer only to resume that call; it never pays twice." }
|
|
133262
133264
|
},
|
|
133263
133265
|
additionalProperties: false
|
|
133264
133266
|
},
|