shinjuku-shielded 0.3.128 → 0.3.129
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 +275 -71
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.129. 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.129
|
|
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.129 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.129 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.129", "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": "1de148b9fd19cd1bac5b690267cb77c227a3e74300873fa9eda02085833ccb2f",
|
|
5
|
+
"bytes": 8826955,
|
|
6
|
+
"sourceCommit": "2c963caa0410c71651cd64a18c704efa8b0ce95c",
|
|
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-30T06:56:34.660Z"
|
|
1041
1041
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shinjuku-shielded",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.129",
|
|
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": "1de148b9",
|
|
7
|
+
"shinjukuSha256": "1de148b9fd19cd1bac5b690267cb77c227a3e74300873fa9eda02085833ccb2f",
|
|
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
|
@@ -47684,7 +47684,7 @@ function proxiedChild(args, mode, plainProxy, stdio) {
|
|
|
47684
47684
|
delete env[QUIET_RUN_MARK];
|
|
47685
47685
|
const quiet = quietRun(args);
|
|
47686
47686
|
if (quiet) env[QUIET_RUN_MARK] = quiet;
|
|
47687
|
-
return spawn(process.execPath, [...proxiedExecArgv(process.execArgv), process.argv[1], ...args], { env, stdio });
|
|
47687
|
+
return spawn(process.execPath, [...proxiedExecArgv(process.execArgv), process.argv[1], ...args], { env, stdio, windowsHide: true });
|
|
47688
47688
|
}
|
|
47689
47689
|
function reexec(args, mode, plainProxy) {
|
|
47690
47690
|
return new Promise((resolvePromise) => {
|
|
@@ -47721,7 +47721,8 @@ async function proxyEntry(argv2, run4, { err = (text3) => process.stderr.write(t
|
|
|
47721
47721
|
try {
|
|
47722
47722
|
torVersion = await proveProxy(mode, proxy);
|
|
47723
47723
|
} catch (error) {
|
|
47724
|
-
|
|
47724
|
+
const refusal3 = `${error.message}${mode === "tor" && process.env[TOR_FROM_CONFIG_ENV] === "1" && !error.torHintInside ? TOR_FROM_CONFIG_HINT : ""}`;
|
|
47725
|
+
err(`shinjuku: ${process.stderr.isTTY ? refusal3.replace(/^[a-z][a-z0-9_]*: /, "") : refusal3}
|
|
47725
47726
|
`);
|
|
47726
47727
|
if (mcpRefused2 && argv2[0] === "mcp" && !process.stdin.isTTY && !process.env[TOR_RUN_STARTED_ENV]) {
|
|
47727
47728
|
return mcpRefused2({
|
|
@@ -47776,7 +47777,7 @@ function torChild(argv2, stdio) {
|
|
|
47776
47777
|
if (!options.mode) throw new ProxyUsageError("torChild needs --tor or --proxy");
|
|
47777
47778
|
return proxiedChild(options.args, options.mode, options.proxy, stdio);
|
|
47778
47779
|
}
|
|
47779
|
-
var TOR_HTTP_TUNNEL, TOR_CHECK, PROOF_TIMEOUT_MS, LOCAL_PROOF_TIMEOUT_MS, LOCAL_PROOF_MAX_BYTES, torProvenAt, proxyProvenAt, MARK, TOR_RUN_STARTED_ENV, ownProxyRefused, ONION_V3, RETRY_AFTER_CAP_MS, RETRY_AFTER_FLOOR_MS, RETRY_AFTER_DEFAULT_MS, RPC_NO_ANSWER_LIMIT_MS, RPC_PACING_CAP_MS, PACING_NOTICE_EVERY_MS, PACING_RATE_WINDOW_MS, TOR_MAX_ROTATIONS, runStartedAt, rpcNotBefore, pacingWaiters, pacingSince, pacedMs, rpcAnswered, lastAnswerAt, readSteps, pacingNoticeAt, pacingSamples, torMoves, torCircuitId, torMovesRefused, pendingMove, inTorRun, runNetworkMode, isOnionOrigin, ProxyUsageError, isOnionHost, TOR_MIN_VERSION, localTorProof, TOR_EXPERT_BUNDLE, TOR_EXPERT_BUNDLE_SHA256, TUNNEL_LINE, TOR_DEB_KEY, TOR_DEB_KEYRING, TOR_INSTALL, torStart, LOCAL_TUNNEL, torStartText, TOR_WINDOW, torNotRunningMessage, torUpdateHow, torTooOldWhy, torTooOldMessage, NOTICE, TOR_NOTICE_LINE, ONION_DETAIL_LINE, withoutOnionDetail, QUIET_RUN_MARK, QUIET_NOTICE, QUIET_TERMINAL_COMMANDS, INFER_SUBCOMMANDS, quietRun, TOR_TROUBLE_LINE, TOR_WAIT_PLAIN, TOR_TROUBLE_PLAIN, TOR_TROUBLE_SAID, quietTorErr, withRunTag, proxyEnv, pacedSoFar, RESENDABLE_METHOD, torCircuit, GLOBAL_DISPATCHER3, laneDispatchers, laneOfDispatcher, PROXY_WARNING_FLAG, proxiedExecArgv, proxiedNodeOptions, TOR_FROM_CONFIG_ENV, TOR_FROM_CONFIG_HINT, TOR_FROM_CONFIG_SENTENCE;
|
|
47780
|
+
var TOR_HTTP_TUNNEL, TOR_CHECK, PROOF_TIMEOUT_MS, LOCAL_PROOF_TIMEOUT_MS, LOCAL_PROOF_MAX_BYTES, torProvenAt, proxyProvenAt, MARK, TOR_RUN_STARTED_ENV, ownProxyRefused, ONION_V3, RETRY_AFTER_CAP_MS, RETRY_AFTER_FLOOR_MS, RETRY_AFTER_DEFAULT_MS, RPC_NO_ANSWER_LIMIT_MS, RPC_PACING_CAP_MS, PACING_NOTICE_EVERY_MS, PACING_RATE_WINDOW_MS, TOR_MAX_ROTATIONS, runStartedAt, rpcNotBefore, pacingWaiters, pacingSince, pacedMs, rpcAnswered, lastAnswerAt, readSteps, pacingNoticeAt, pacingSamples, torMoves, torCircuitId, torMovesRefused, pendingMove, inTorRun, runNetworkMode, isOnionOrigin, ProxyUsageError, isOnionHost, TOR_MIN_VERSION, localTorProof, TOR_EXPERT_BUNDLE, TOR_EXPERT_BUNDLE_SHA256, TUNNEL_LINE, TOR_DEB_KEY, TOR_DEB_KEYRING, TOR_INSTALL, torStart, LOCAL_TUNNEL, torStartText, TOR_WINDOW, torNotRunningMessage, torUpdateHow, TOR_STOP_OLD_WINDOWS, torTooOldWhy, torTooOldMessage, NOTICE, TOR_NOTICE_LINE, ONION_DETAIL_LINE, withoutOnionDetail, QUIET_RUN_MARK, QUIET_NOTICE, QUIET_TERMINAL_COMMANDS, INFER_SUBCOMMANDS, quietRun, TOR_TROUBLE_LINE, TOR_WAIT_PLAIN, TOR_TROUBLE_PLAIN, TOR_TROUBLE_SAID, quietTorErr, withRunTag, proxyEnv, pacedSoFar, RESENDABLE_METHOD, torCircuit, GLOBAL_DISPATCHER3, laneDispatchers, laneOfDispatcher, PROXY_WARNING_FLAG, proxiedExecArgv, proxiedNodeOptions, TOR_FROM_CONFIG_ENV, TOR_FROM_CONFIG_HINT, TOR_FROM_CONFIG_SENTENCE;
|
|
47780
47781
|
var init_proxy = __esm({
|
|
47781
47782
|
"wallet/src/net/proxy.mjs"() {
|
|
47782
47783
|
"use strict";
|
|
@@ -47833,7 +47834,7 @@ var init_proxy = __esm({
|
|
|
47833
47834
|
TOR_INSTALL = Object.freeze({
|
|
47834
47835
|
windows: `iwr https://archive.torproject.org/tor-package-archive/torbrowser/${TOR_EXPERT_BUNDLE}/tor-expert-bundle-windows-x86_64-${TOR_EXPERT_BUNDLE}.tar.gz -OutFile $env:TEMP\\tor.tar.gz; if ((Get-FileHash $env:TEMP\\tor.tar.gz -Algorithm SHA256).Hash -ne '${TOR_EXPERT_BUNDLE_SHA256}') { Remove-Item $env:TEMP\\tor.tar.gz; throw 'The Tor download does not match its pinned sha256, so it was deleted and not run' }; mkdir -Force $env:LOCALAPPDATA\\tor | Out-Null; & $env:SystemRoot\\System32\\tar.exe -xzf $env:TEMP\\tor.tar.gz -C $env:LOCALAPPDATA\\tor; & $env:LOCALAPPDATA\\tor\\tor\\tor.exe --HTTPTunnelPort '127.0.0.1:9080 IsolateDestAddr' --SocksPort 0`,
|
|
47835
47836
|
macos: `brew install tor && (grep -qxF '${TUNNEL_LINE}' "$(brew --prefix)/etc/tor/torrc" || echo '${TUNNEL_LINE}' >> "$(brew --prefix)/etc/tor/torrc") && brew services restart tor`,
|
|
47836
|
-
linux: `sudo apt install -y apt-transport-https gnupg wget && wget -qO- ${TOR_DEB_KEY} | gpg --dearmor | sudo tee ${TOR_DEB_KEYRING} >/dev/null && printf 'Types: deb\\nURIs: https://deb.torproject.org/torproject.org/\\nSuites: %s\\nComponents: main\\nSigned-By: ${TOR_DEB_KEYRING}\\n' "$(. /etc/os-release && echo "$VERSION_CODENAME")" | sudo tee /etc/apt/sources.list.d/tor.sources >/dev/null && sudo apt update && sudo apt install -y tor deb.torproject.org-keyring && (grep -qxF '${TUNNEL_LINE}' /etc/tor/torrc || echo '${TUNNEL_LINE}' | sudo tee -a /etc/tor/torrc) && sudo
|
|
47837
|
+
linux: `sudo apt install -y apt-transport-https gnupg wget && wget -qO- ${TOR_DEB_KEY} | gpg --dearmor | sudo tee ${TOR_DEB_KEYRING} >/dev/null && printf 'Types: deb\\nURIs: https://deb.torproject.org/torproject.org/\\nSuites: %s\\nComponents: main\\nSigned-By: ${TOR_DEB_KEYRING}\\n' "$(. /etc/os-release && echo "$VERSION_CODENAME")" | sudo tee /etc/apt/sources.list.d/tor.sources >/dev/null && sudo apt update && sudo apt install -y tor deb.torproject.org-keyring && (grep -qxF '${TUNNEL_LINE}' /etc/tor/torrc || echo '${TUNNEL_LINE}' | sudo tee -a /etc/tor/torrc) && sudo service tor restart`
|
|
47837
47838
|
});
|
|
47838
47839
|
torStart = (platform = process.platform, tunnelHost) => {
|
|
47839
47840
|
const base = platform === "win32" ? { where: "PowerShell (keep its window open while the wallet runs)", command: TOR_INSTALL.windows } : platform === "darwin" ? { where: "Terminal", command: TOR_INSTALL.macos } : { where: "a terminal", command: TOR_INSTALL.linux };
|
|
@@ -47860,7 +47861,8 @@ ${command}`;
|
|
|
47860
47861
|
return `tor_not_running: Tor is not running on this machine, so nothing was sent.${fromConfig ? TOR_FROM_CONFIG_SENTENCE : ""} Tor hides your IP address. Start it with the command below in ${TOR_WINDOW[platform] ?? "a terminal"}${keep}:
|
|
47861
47862
|
${command}`;
|
|
47862
47863
|
};
|
|
47863
|
-
torUpdateHow = (platform = process.platform) => platform === "win32" ?
|
|
47864
|
+
torUpdateHow = (platform = process.platform) => platform === "win32" ? `${TOR_STOP_OLD_WINDOWS} Then start a newer Tor with the command below in PowerShell and keep that window open` : `Install a newer Tor with the command below in ${TOR_WINDOW[platform] ?? "a terminal"}`;
|
|
47865
|
+
TOR_STOP_OLD_WINDOWS = "Stop your old Tor first: close the window it runs in, or for a Tor in WSL run wsl -u root service tor stop .";
|
|
47864
47866
|
torTooOldWhy = (version3) => `Your Tor program is too old (${version3}). It has a known fault that can link two of your payments, so the wallet sent nothing.`;
|
|
47865
47867
|
torTooOldMessage = (version3, platform = process.platform, { fromConfig = false, tunnelHost } = {}) => {
|
|
47866
47868
|
const { command } = torStart(platform, tunnelHost);
|
|
@@ -51152,7 +51154,7 @@ var init_anchorClock = __esm({
|
|
|
51152
51154
|
init_phaseTiming();
|
|
51153
51155
|
EPOCH_MS = 3e5;
|
|
51154
51156
|
SUB_ANCHOR_MS = 3e4;
|
|
51155
|
-
SUB_ANCHOR_FINALITY_MS =
|
|
51157
|
+
SUB_ANCHOR_FINALITY_MS = 6e3;
|
|
51156
51158
|
OBSERVATION_MAX_AGE_MS = 6e5;
|
|
51157
51159
|
ANCHOR_REQUEST_TIMEOUT_MS = 9e4;
|
|
51158
51160
|
MAX_FOLLOW_UPS = 3;
|
|
@@ -60661,6 +60663,16 @@ function spendHeads(spendableAtomic, largestAtomic, change = {}, options = {}) {
|
|
|
60661
60663
|
if (change?.changeSettling === true) {
|
|
60662
60664
|
const seconds2 = change.changeReadyInSeconds;
|
|
60663
60665
|
const upTo = String(change.changeUpToAtomic ?? "");
|
|
60666
|
+
if (Number.isSafeInteger(change.changeCount) && change.changeCount >= 2 && ATOMIC.test(upTo) && BigInt(upTo) > 0n && BigInt(upTo) < BigInt(spendable)) {
|
|
60667
|
+
const part = usdcWords(upTo);
|
|
60668
|
+
return Number.isSafeInteger(seconds2) && seconds2 > 0 ? [
|
|
60669
|
+
`You have ${total}; after your recent payments settle (about ${seconds2} s), one payment can use up to ${part} and later payments the rest`,
|
|
60670
|
+
`You have ${total}; one payment can use ${part} in about ${seconds2} s`
|
|
60671
|
+
] : [
|
|
60672
|
+
`You have ${total}; after your recent payments settle, one payment can use up to ${part} and later payments the rest`,
|
|
60673
|
+
`You have ${total}, ${part} for one payment after your recent ones settle`
|
|
60674
|
+
];
|
|
60675
|
+
}
|
|
60664
60676
|
if (ATOMIC.test(upTo) && BigInt(upTo) > 0n && BigInt(upTo) < BigInt(spendable)) {
|
|
60665
60677
|
const part = usdcWords(upTo);
|
|
60666
60678
|
return Number.isSafeInteger(seconds2) && seconds2 > 0 ? [
|
|
@@ -67229,6 +67241,9 @@ var init_errorCodes = __esm({
|
|
|
67229
67241
|
"fetch_gate_stopped",
|
|
67230
67242
|
"mcp_cap_required",
|
|
67231
67243
|
"mcp_cap_invalid",
|
|
67244
|
+
// mcp/tools.mjs maxPaymentNotUsdc: max_payment written in atomic units (a whole number of 1000 or more, above the whole
|
|
67245
|
+
// balance); nothing was requested or paid (UX129-12, 2026-10-30).
|
|
67246
|
+
"mcp_max_payment_not_usdc",
|
|
67232
67247
|
"fetch_proof_tools_unavailable",
|
|
67233
67248
|
"fetch_offer_confidential",
|
|
67234
67249
|
"wallet_spend_refused_per_payment_cap_exceeded",
|
|
@@ -101461,7 +101476,7 @@ function computeBalance({ store, snapshotRead, source = "local", now = Date.now(
|
|
|
101461
101476
|
let heldAtomic;
|
|
101462
101477
|
let heldWholeAtomic;
|
|
101463
101478
|
let spareMost = 0n;
|
|
101464
|
-
const report = (status, gross, next2, cause, largest2, change) => {
|
|
101479
|
+
const report = (status, gross, next2, cause, largest2, change, changes) => {
|
|
101465
101480
|
const atomic4 = gross === null || privateSendPending === null ? null : gross > privateSendPending ? gross - privateSendPending : 0n;
|
|
101466
101481
|
const built = {
|
|
101467
101482
|
// The one number: shielded + pockets. Null when either part is unknown.
|
|
@@ -101500,7 +101515,10 @@ function computeBalance({ store, snapshotRead, source = "local", now = Date.now(
|
|
|
101500
101515
|
const cap = atomic4 - BigInt(detail.successionMovableAtomic ?? "0");
|
|
101501
101516
|
const one = cap <= 0n ? 0n : largest2 < cap ? largest2 : cap;
|
|
101502
101517
|
LARGEST_PAYMENTS.set(built, one.toString());
|
|
101503
|
-
if (change !== void 0 && one === 0n && atomic4 > 0n)
|
|
101518
|
+
if (change !== void 0 && one === 0n && atomic4 > 0n) {
|
|
101519
|
+
CHANGE_SETTLING.set(built, (change < atomic4 ? change : atomic4).toString());
|
|
101520
|
+
if (Number.isSafeInteger(changes) && changes >= 2) CHANGE_COUNT.set(built, changes);
|
|
101521
|
+
}
|
|
101504
101522
|
}
|
|
101505
101523
|
return built;
|
|
101506
101524
|
};
|
|
@@ -101789,12 +101807,16 @@ If a payment to this wallet settled, read the chain again with:
|
|
|
101789
101807
|
}
|
|
101790
101808
|
if (settling.length || movedInAtomic > 0n) {
|
|
101791
101809
|
reasons.push(...settlingReasons);
|
|
101792
|
-
const [only] = settling;
|
|
101793
101810
|
const sendHeldAtomic = sendHold === null || sendHold.notes.size > 0 ? null : sum2(free.filter(isHeld).map((output2) => output2.valueAtomic));
|
|
101794
|
-
const
|
|
101795
|
-
const
|
|
101811
|
+
const inputsOf = (payment) => sum2(payment.inputs.map((commitment) => unspent.get(commitment).valueAtomic));
|
|
101812
|
+
const distinctInputs = new Set(settling.flatMap((payment) => payment.inputs)).size === settling.reduce((count2, payment) => count2 + payment.inputs.length, 0);
|
|
101813
|
+
const inputsAtomic = settling.length > 0 && distinctInputs ? sum2(settling.map(inputsOf)) : 0n;
|
|
101814
|
+
const changeAtomic = settling.reduce((most, payment) => {
|
|
101815
|
+
const change = inputsOf(payment) - payment.amountAtomic;
|
|
101816
|
+
return change > most ? change : most;
|
|
101817
|
+
}, 0n);
|
|
101796
101818
|
const changeFreeAtomic = sendHold === null || sendHold.unpacked.length === 0 ? changeAtomic : changeAtomic > privateSendPending ? changeAtomic - privateSendPending : 0n;
|
|
101797
|
-
const changeOnly = settling.length === 1 &&
|
|
101819
|
+
const changeOnly = settling.length > 0 && distinctInputs && (settling.length === 1 || sendHeldAtomic === 0n && privateSendPending === 0n) && settling.every((payment) => payment.join !== true && payment.exit !== true && inputsOf(payment) > payment.amountAtomic) && reservedAtomic === 0n && detail.joiningAtomic === "0" && successionMovableAtomic === 0n && sendHeldAtomic !== null && unspentAtomic - sendHeldAtomic === inputsAtomic && changeFreeAtomic > 0n;
|
|
101798
101820
|
return report(
|
|
101799
101821
|
"stale",
|
|
101800
101822
|
spendable + successionMovableAtomic,
|
|
@@ -101803,7 +101825,8 @@ If a payment to this wallet settled, read the chain again with:
|
|
|
101803
101825
|
// still settling" while the only answered item was a join).
|
|
101804
101826
|
settlingRecent ? movedInAtomic === 0n && settling.length > 0 && settling.every((payment) => payment.join) ? "account_join" : "payment_settling" : movedInAtomic > 0n ? "pool_move" : void 0,
|
|
101805
101827
|
largest,
|
|
101806
|
-
changeOnly ? changeFreeAtomic : void 0
|
|
101828
|
+
changeOnly ? changeFreeAtomic : void 0,
|
|
101829
|
+
settling.length
|
|
101807
101830
|
);
|
|
101808
101831
|
}
|
|
101809
101832
|
return report("current", spendable + successionMovableAtomic, next, void 0, largest);
|
|
@@ -101822,7 +101845,7 @@ function combinePoolBalances(partsAtomic, movingAtomic = "0") {
|
|
|
101822
101845
|
if (!canonicalAtomic(String(movingAtomic))) return null;
|
|
101823
101846
|
return (partsAtomic.reduce((total, part) => total + BigInt(part), 0n) + BigInt(movingAtomic)).toString();
|
|
101824
101847
|
}
|
|
101825
|
-
var PAY_ME_WAL_SCHEMA, BALANCE_SNAPSHOT_SCHEMA, BALANCE_SNAPSHOT_FILE, STALE_CAUSES, staleCauseOf, LARGEST_PAYMENTS, largestPaymentOf, CHANGE_SETTLING, changeSettlingOf, changeUpToOf, SPEND_INPUTS, SEND_HOLDS, sendHoldOf, PAYMENT_SETTLING_MS, NO_VALUE_TYPES, PLAN_ONLY_TYPES, UNSENT_SELF_PAY_FIELDS, isUnsentSelfPay, planOnly, SNAPSHOT_KEY_LABEL, SPEND_STATUSES, MAINNET_USDC, SELF_PAY_ORIGIN, POCKET_FILL_RECORD, MERGE_RECORD2, POOL_MOVE_SCHEMA, FLOAT_PAYMENT_SCHEMA, POOL_MOVE_PATH, POOL_SUCCESSION_SCHEMAS, digestKey, canonicalAtomic, SUCCESSION_JOB_SCHEMA, MERGE_PAYMENT_PATH, spendEntry, PROOF_RECORD;
|
|
101848
|
+
var PAY_ME_WAL_SCHEMA, BALANCE_SNAPSHOT_SCHEMA, BALANCE_SNAPSHOT_FILE, STALE_CAUSES, staleCauseOf, LARGEST_PAYMENTS, largestPaymentOf, CHANGE_SETTLING, changeSettlingOf, changeUpToOf, CHANGE_COUNT, changeCountOf, SPEND_INPUTS, SEND_HOLDS, sendHoldOf, PAYMENT_SETTLING_MS, NO_VALUE_TYPES, PLAN_ONLY_TYPES, UNSENT_SELF_PAY_FIELDS, isUnsentSelfPay, planOnly, SNAPSHOT_KEY_LABEL, SPEND_STATUSES, MAINNET_USDC, SELF_PAY_ORIGIN, POCKET_FILL_RECORD, MERGE_RECORD2, POOL_MOVE_SCHEMA, FLOAT_PAYMENT_SCHEMA, POOL_MOVE_PATH, POOL_SUCCESSION_SCHEMAS, digestKey, canonicalAtomic, SUCCESSION_JOB_SCHEMA, MERGE_PAYMENT_PATH, spendEntry, PROOF_RECORD;
|
|
101826
101849
|
var init_balance = __esm({
|
|
101827
101850
|
"wallet/src/balance/balance.mjs"() {
|
|
101828
101851
|
"use strict";
|
|
@@ -101847,6 +101870,8 @@ var init_balance = __esm({
|
|
|
101847
101870
|
CHANGE_SETTLING = /* @__PURE__ */ new WeakMap();
|
|
101848
101871
|
changeSettlingOf = (report) => report !== null && typeof report === "object" && CHANGE_SETTLING.has(report);
|
|
101849
101872
|
changeUpToOf = (report) => report !== null && typeof report === "object" ? CHANGE_SETTLING.get(report) : void 0;
|
|
101873
|
+
CHANGE_COUNT = /* @__PURE__ */ new WeakMap();
|
|
101874
|
+
changeCountOf = (report) => report !== null && typeof report === "object" ? CHANGE_COUNT.get(report) : void 0;
|
|
101850
101875
|
SPEND_INPUTS = /* @__PURE__ */ new WeakMap();
|
|
101851
101876
|
SEND_HOLDS = /* @__PURE__ */ new WeakMap();
|
|
101852
101877
|
sendHoldOf = (report) => report !== null && typeof report === "object" ? SEND_HOLDS.get(report) : void 0;
|
|
@@ -105596,15 +105621,7 @@ async function waitForNextAnchor(requirement, state, deps, ring) {
|
|
|
105596
105621
|
const start = now();
|
|
105597
105622
|
state.deadline ??= start + ANCHOR_WAIT_CAP_MS;
|
|
105598
105623
|
const subAnchors = subAnchorPool(start) !== void 0;
|
|
105599
|
-
|
|
105600
|
-
let waitMs;
|
|
105601
|
-
if (subAnchors) {
|
|
105602
|
-
waitMs = nextAnchorWaitMs(start, ANCHOR_MARGIN_MS);
|
|
105603
|
-
anchorAt = start + waitMs - SUB_ANCHOR_FINALITY_MS;
|
|
105604
|
-
} else {
|
|
105605
|
-
anchorAt = (epoch + 1) * ANCHOR_EPOCH_MS;
|
|
105606
|
-
waitMs = Math.max(anchorAt - start, 0) + ANCHOR_MARGIN_MS;
|
|
105607
|
-
}
|
|
105624
|
+
const waitMs = subAnchors ? nextAnchorWaitMs(start, ANCHOR_MARGIN_MS) : Math.max((epoch + 1) * ANCHOR_EPOCH_MS - start, 0) + ANCHOR_MARGIN_MS;
|
|
105608
105625
|
if (start + waitMs > state.deadline) return false;
|
|
105609
105626
|
const before = subAnchors ? await readRingBefore(ring, start) : void 0;
|
|
105610
105627
|
if (ringCoversTree(before) && !state.coveredSkip) {
|
|
@@ -105613,7 +105630,7 @@ async function waitForNextAnchor(requirement, state, deps, ring) {
|
|
|
105613
105630
|
return true;
|
|
105614
105631
|
}
|
|
105615
105632
|
try {
|
|
105616
|
-
process.stderr.write(`
|
|
105633
|
+
process.stderr.write(`Waiting ${before ? "up to " : "about "}${Math.ceil(waitMs / 1e3)} s for your last payment or deposit to be ready to spend (nothing was signed yet); then it goes on by itself.
|
|
105617
105634
|
`);
|
|
105618
105635
|
} catch {
|
|
105619
105636
|
}
|
|
@@ -106928,7 +106945,6 @@ var init_payResource = __esm({
|
|
|
106928
106945
|
init_anchorClock();
|
|
106929
106946
|
init_requestId();
|
|
106930
106947
|
init_keepAlive();
|
|
106931
|
-
init_commandName();
|
|
106932
106948
|
fail24 = (reason) => {
|
|
106933
106949
|
throw new Error(`p03_resource_payment_${reason}`);
|
|
106934
106950
|
};
|
|
@@ -107545,6 +107561,10 @@ function refusalSay(a, tool, again, npmVersion) {
|
|
|
107545
107561
|
const seller = tool === "inference_chat" ? "the AI provider" : "the seller";
|
|
107546
107562
|
const Seller = `${seller[0].toUpperCase()}${seller.slice(1)}`;
|
|
107547
107563
|
const data = tool === "inference_chat" ? "answer" : "data";
|
|
107564
|
+
if (code2 === "mcp_max_payment_not_usdc") {
|
|
107565
|
+
const cap = usdcText2(a.capAtomic);
|
|
107566
|
+
return `Nothing was paid: ${cap ? `a cap of ${cap} USDC` : "the cap"} is more than your balance. A cap is in USDC, like 0.01 for one cent. Ask again.`;
|
|
107567
|
+
}
|
|
107548
107568
|
if (a.walletUpdateNeeded === true) {
|
|
107549
107569
|
const cannot = "this wallet version cannot read the private balance record";
|
|
107550
107570
|
const update3 = "Restart the wallet on the latest version, then ask again";
|
|
@@ -107624,7 +107644,10 @@ function refusalSay(a, tool, again, npmVersion) {
|
|
|
107624
107644
|
const more = Number.isSafeInteger(a.retryMaxTokens) ? ` Ask again with a length limit of ${a.retryMaxTokens} tokens.` : " Ask again with a longer length limit.";
|
|
107625
107645
|
if (a.replayed === true && a.paid === false) return `Nothing was paid, and the stored answer is empty.${more}`;
|
|
107626
107646
|
if (a.replayed === true) return `Already paid; the stored answer is empty and nothing new was paid.${more}`;
|
|
107627
|
-
|
|
107647
|
+
const price = usdcText2(a.priceAtomic);
|
|
107648
|
+
const fee = usdcText2(a.feeAtomic);
|
|
107649
|
+
const head = `${paid ? `Paid ${paid} USDC${price && positive(fee) ? ` (${price} price + ${fee} Shinjuku fee)` : ""}` : "Paid"}, but`;
|
|
107650
|
+
return firstFit(`${head} the model reached the answer's length limit before it answered.${more}`, `${head} the answer hit its length limit.${more}`);
|
|
107628
107651
|
}
|
|
107629
107652
|
if (code2 === "inference_no_provider") {
|
|
107630
107653
|
return "Nothing was paid: no AI provider can take this wallet's payment for this model right now. Ask for another model, or ask again later.";
|
|
@@ -108582,16 +108605,20 @@ function build(a, tool, npmVersion) {
|
|
|
108582
108605
|
if (a.replayed === true) return "This request was already paid. Here is the same answer; nothing new was paid.";
|
|
108583
108606
|
if (tool === "inference_chat" || typeof a.model === "string" && Object.hasOwn(a, "content")) {
|
|
108584
108607
|
const paid = usdcText2(a.paidAtomic);
|
|
108585
|
-
|
|
108608
|
+
const price2 = usdcText2(a.priceAtomic);
|
|
108609
|
+
const fee2 = usdcText2(a.feeAtomic);
|
|
108610
|
+
const split4 = paid && price2 && positive(fee2) ? ` (${price2} price + ${fee2} Shinjuku fee)` : "";
|
|
108611
|
+
return `Answered by ${str(a.model).trim() || "the model"}.${paid ? ` Paid ${paid} USDC${split4}.` : ""}`;
|
|
108586
108612
|
}
|
|
108587
108613
|
const total = usdcText2(a.amountAtomic);
|
|
108588
108614
|
const price = usdcText2(a.priceAtomic);
|
|
108589
108615
|
const fee = usdcText2(a.feeAtomic);
|
|
108590
108616
|
if (!total) return withBalance("Paid. Here is the answer.", a);
|
|
108591
|
-
|
|
108592
|
-
|
|
108593
|
-
|
|
108594
|
-
|
|
108617
|
+
if (price && positive(fee)) {
|
|
108618
|
+
const paid = `Paid ${total} USDC (${price} price + ${fee} Shinjuku fee).`;
|
|
108619
|
+
return withBalance([`${paid} Here is the answer.`, paid], a);
|
|
108620
|
+
}
|
|
108621
|
+
return withBalance(`Paid ${total} USDC. Here is the answer.`, a);
|
|
108595
108622
|
}
|
|
108596
108623
|
if (a.paid === false && !Object.hasOwn(a, "stage") && (tool === void 0 || tool === "x402_pay")) {
|
|
108597
108624
|
const status = Number(a.status);
|
|
@@ -111304,6 +111331,7 @@ function partsOf(report, store, snapshot) {
|
|
|
111304
111331
|
changeSettling,
|
|
111305
111332
|
changeReadyInSeconds: changeSettling ? changeReadyInSeconds() : null,
|
|
111306
111333
|
changeUpToAtomic: changeSettling ? changeUpToOf(report) ?? null : null,
|
|
111334
|
+
...changeSettling && Number.isSafeInteger(changeCountOf(report)) ? { changeCount: changeCountOf(report) } : {},
|
|
111307
111335
|
refundsInFlightAtomic: refunds.proven.toString(),
|
|
111308
111336
|
refundsNotCertainAtomic: refunds.notCertain.toString(),
|
|
111309
111337
|
refundsInFlight: refunds.provenFor,
|
|
@@ -111558,10 +111586,9 @@ async function exitWhenAnchored(run4, { now = Date.now, sleep: sleep4 = (ms) =>
|
|
|
111558
111586
|
const start = now();
|
|
111559
111587
|
const subAnchors = subAnchorPool(start) !== void 0;
|
|
111560
111588
|
const waitMs = nextAnchorWaitMs(start, EPOCH_MARGIN_MS);
|
|
111561
|
-
const anchorAt = subAnchors ? start + waitMs - SUB_ANCHOR_FINALITY_MS : start - start % EPOCH_MS2 + EPOCH_MS2;
|
|
111562
111589
|
if (start + waitMs > deadline) throw error;
|
|
111563
111590
|
const before = subAnchors ? await readRingBefore(ring, start) : void 0;
|
|
111564
|
-
progress(`
|
|
111591
|
+
progress(`Waiting about ${Math.ceil(waitMs / 1e3)} s for your balance to be ready to send (nothing was signed yet); then the send goes on by itself`);
|
|
111565
111592
|
markPhase("anchor-wait-start");
|
|
111566
111593
|
await sleepForAnchor(waitMs, { ring, before, now, sleep: sleep4 });
|
|
111567
111594
|
markPhase("anchor-wait-done");
|
|
@@ -124349,6 +124376,7 @@ async function tidyMove({ plan, steps, now }) {
|
|
|
124349
124376
|
state: "signed",
|
|
124350
124377
|
account: account.address,
|
|
124351
124378
|
signature: built.signature,
|
|
124379
|
+
...typeof account.lamports === "bigint" ? { rentLamports: account.lamports.toString() } : {},
|
|
124352
124380
|
txBase64: Buffer.from(built.raw).toString("base64"),
|
|
124353
124381
|
lastValidBlockHeight: Number.isSafeInteger(built.lastValidBlockHeight) ? built.lastValidBlockHeight : null,
|
|
124354
124382
|
signedAt: at()
|
|
@@ -124577,9 +124605,10 @@ function transferLeftoverView(plan) {
|
|
|
124577
124605
|
const tidy = !plan.tidy || plan.tidy.state === "pending" ? { ...plan.tidy ?? {}, state: "kept", reason: TIDY_LATE_REASON } : plan.tidy;
|
|
124578
124606
|
const state = tidy.state === "signed" ? "closing" : tidy.state;
|
|
124579
124607
|
const lamports = /^\d+$/.test(String(tidy.solLamports ?? "")) ? BigInt(tidy.solLamports) : null;
|
|
124608
|
+
const rent = /^\d+$/.test(String(tidy.rentLamports ?? "")) ? ` (${solText(BigInt(tidy.rentLamports))} SOL)` : "";
|
|
124580
124609
|
const tokenAccount2 = {
|
|
124581
|
-
closing:
|
|
124582
|
-
closed:
|
|
124610
|
+
closing: `the close of the sold token's empty holder on the own key, sent before the send started, is not final yet; its rent${rent} comes back to the key when it lands`,
|
|
124611
|
+
closed: `the wallet closed the sold token's empty holder on its own key, so its rent${rent} came back to the key`,
|
|
124583
124612
|
gone: "the own key holds none of the sold token and has no holder for it left",
|
|
124584
124613
|
kept: `the sold token's holder on the own key stays open: ${tidy.reason ?? "it was not empty"}`,
|
|
124585
124614
|
failed: `the sold token's empty holder on the own key stays open: ${tidy.reason ?? "its close did not land"}`
|
|
@@ -124866,7 +124895,7 @@ async function readSoldAccount({ connection, owner, mint, commitment = "finalize
|
|
|
124866
124895
|
const { programId, address: address4 } = candidates[index];
|
|
124867
124896
|
if (!info.owner.equals(programId)) continue;
|
|
124868
124897
|
const account = unpackAccount(address4, info, programId);
|
|
124869
|
-
const view2 = { address: address4.toBase58(), programId: programId.toBase58(), amountAtomic: account.amount };
|
|
124898
|
+
const view2 = { address: address4.toBase58(), programId: programId.toBase58(), amountAtomic: account.amount, lamports: BigInt(info.lamports) };
|
|
124870
124899
|
if (!account.mint.equals(mintKey) || !account.owner.equals(ownerKey)) return { ...view2, closeable: false, why: "the account is not the own key's account of this token" };
|
|
124871
124900
|
if (account.isNative) return { ...view2, closeable: false, why: "the account is a wrapped SOL account" };
|
|
124872
124901
|
if (account.closeAuthority && !account.closeAuthority.equals(ownerKey)) return { ...view2, closeable: false, why: "another key may close this account, not the own key" };
|
|
@@ -128333,6 +128362,29 @@ function createWalletTools({
|
|
|
128333
128362
|
return null;
|
|
128334
128363
|
}
|
|
128335
128364
|
};
|
|
128365
|
+
const maxPaymentNotUsdc = (args, atomic4, tool) => {
|
|
128366
|
+
const raw = args?.max_payment;
|
|
128367
|
+
const text3 = typeof raw === "number" && Number.isSafeInteger(raw) ? String(raw) : typeof raw === "string" ? raw.trim() : "";
|
|
128368
|
+
if (atomic4 === void 0 || !/^[0-9]{1,31}$/.test(text3) || BigInt(text3) < MAX_PAYMENT_ATOMIC_LEAST) return void 0;
|
|
128369
|
+
let whole;
|
|
128370
|
+
try {
|
|
128371
|
+
const parts = balanceNow(session.openStore(), { programId: session.programId });
|
|
128372
|
+
if (!ATOMIC_TEXT.test(String(parts?.totalAtomic ?? ""))) return void 0;
|
|
128373
|
+
const atomicOf = (value2) => ATOMIC_TEXT.test(String(value2 ?? "")) ? BigInt(value2) : 0n;
|
|
128374
|
+
whole = BigInt(parts.totalAtomic) + atomicOf(parts.refundsNotCertainAtomic) + (parts.report?.detail?.pendingDeposits ?? []).reduce((sum2, deposit) => sum2 + atomicOf(deposit?.amountAtomic), 0n);
|
|
128375
|
+
} catch {
|
|
128376
|
+
return void 0;
|
|
128377
|
+
}
|
|
128378
|
+
if (BigInt(atomic4) <= whole) return void 0;
|
|
128379
|
+
const cap = usdcText3(atomic4);
|
|
128380
|
+
const meant = usdcText3(BigInt(text3));
|
|
128381
|
+
return [
|
|
128382
|
+
"mcp_max_payment_not_usdc",
|
|
128383
|
+
`max_payment "${text3}" is ${cap} USDC (max_payment is in USDC, not atomic units), more than the wallet's whole balance of ${usdcText3(whole)} USDC; nothing was requested or paid`,
|
|
128384
|
+
`max_payment is in USDC, like "0.01" for one cent; "${text3}" in atomic units is max_payment "${meant}". Call ${tool} again now with max_payment in USDC (the amount the user named), or leave max_payment out`,
|
|
128385
|
+
{ paid: false, capAtomic: String(atomic4), wholeBalanceAtomic: whole.toString() }
|
|
128386
|
+
];
|
|
128387
|
+
};
|
|
128336
128388
|
const savedBalanceShort = (store, neededAtomic) => {
|
|
128337
128389
|
if (!store) return void 0;
|
|
128338
128390
|
try {
|
|
@@ -128470,9 +128522,9 @@ function createWalletTools({
|
|
|
128470
128522
|
const doneInMinutesFields = (joins, startAtMs) => {
|
|
128471
128523
|
if (!Number.isSafeInteger(joins) || joins < 1) return {};
|
|
128472
128524
|
const left = Number.isSafeInteger(startAtMs) ? Math.max(0, startAtMs - Date.now()) : void 0;
|
|
128473
|
-
const
|
|
128525
|
+
const least = (left ?? 0) + joins * JOIN_TIME_MS.joinLikely + JOIN_TIME_MS.sendLikely;
|
|
128474
128526
|
const most = (left ?? joinSoonMaxMs) + joins * JOIN_TIME_MS.joinMost + JOIN_TIME_MS.sendMost;
|
|
128475
|
-
const low = Math.max(1, Math.
|
|
128527
|
+
const low = Math.max(1, Math.floor(least / 6e4));
|
|
128476
128528
|
return { doneInMinutesLow: low, doneInMinutesHigh: Math.max(low + 1, Math.ceil(most / 6e4)) };
|
|
128477
128529
|
};
|
|
128478
128530
|
const doneInWords = ({ doneInMinutesLow: low, doneInMinutesHigh: high } = {}) => Number.isSafeInteger(low) && Number.isSafeInteger(high) ? `about ${low} to ${high} minutes` : "";
|
|
@@ -129074,7 +129126,7 @@ function createWalletTools({
|
|
|
129074
129126
|
method: { type: "string", enum: ["GET", "POST"], description: "HTTP method; default GET." },
|
|
129075
129127
|
headers: { type: "object", additionalProperties: { type: "string" }, description: "Extra request headers (never payment or transport headers)." },
|
|
129076
129128
|
body: { type: "string", description: "Request body text (POST only)." },
|
|
129077
|
-
max_payment: { type: "string", description: 'Optional: the most this call may pay, in USDC, like "0.
|
|
129129
|
+
max_payment: { type: "string", description: 'Optional: the most this call may pay, in USDC, like "0.01" (not atomic units); at most the spending limit.' },
|
|
129078
129130
|
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." },
|
|
129079
129131
|
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." }
|
|
129080
129132
|
},
|
|
@@ -129091,6 +129143,8 @@ function createWalletTools({
|
|
|
129091
129143
|
if (request.refusal) return refuse12(...request.refusal);
|
|
129092
129144
|
const capArg = payCapArgument(args);
|
|
129093
129145
|
if (capArg.refusal) return refuse12(...capArg.refusal);
|
|
129146
|
+
const notUsdc = maxPaymentNotUsdc(args, capArg.atomic, "x402_pay");
|
|
129147
|
+
if (notUsdc) return refuse12(...notUsdc);
|
|
129094
129148
|
const argument2 = capArg.atomic;
|
|
129095
129149
|
const given = args.request_id !== void 0 && args.request_id !== null && args._autoRequestId !== true;
|
|
129096
129150
|
const requestId = args.request_id !== void 0 && args.request_id !== null ? args.request_id : `mcp-${randomBytes23(8).toString("hex")}`;
|
|
@@ -129638,7 +129692,7 @@ ${canonical5}`;
|
|
|
129638
129692
|
...floatPaid ? { via: "shinjuku", shinjukuTransaction } : {},
|
|
129639
129693
|
...balanceAnswer(one),
|
|
129640
129694
|
...notices,
|
|
129641
|
-
next: (unpaid ? "nothing was paid: this request id's payment never landed (the pool's public history proves it), and the answer it got came back again; nothing new was paid. Tell the user nothing was paid for it" : receipt.replayed === true ? "this request id was already paid: the stored receipt came back and nothing new was paid" : floatPaid ? "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") + (notices.refundNotices ? ". Tell the user each refundNotices line" : "")
|
|
129695
|
+
next: (unpaid ? "nothing was paid: this request id's payment never landed (the pool's public history proves it), and the answer it got came back again; nothing new was paid. Tell the user nothing was paid for it" : receipt.replayed === true ? "this request id was already paid: the stored receipt came back and nothing new was paid" : floatPaid ? "paid through Shinjuku (privately: the chain shows Shinjuku paying the seller, not this wallet); tell the user the price (priceAtomic), the Shinjuku fee (feeAtomic; never a network fee), 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") + (notices.refundNotices ? ". Tell the user each refundNotices line" : "")
|
|
129642
129696
|
}, "x402_pay")
|
|
129643
129697
|
}));
|
|
129644
129698
|
}
|
|
@@ -131755,7 +131809,7 @@ ${canonical5}`;
|
|
|
131755
131809
|
}
|
|
131756
131810
|
}
|
|
131757
131811
|
let payments = kind === "moves" ? [] : paymentRows(store, names, refunds.states);
|
|
131758
|
-
const missing = (row) => row.state
|
|
131812
|
+
const missing = (row) => row.state !== "never_landed" && row.state !== "cancelled" && row.privateTransaction === null && (row.scheme === "shielded-exact" || Boolean(row.facilitator));
|
|
131759
131813
|
if (payments.some(missing) && [...payments].sort((left, right) => right.at - left.at).slice(0, limit).some(missing)) {
|
|
131760
131814
|
try {
|
|
131761
131815
|
if (latestPrewarmedWalletHistory() === void 0 && paysInFlight === 0 && !historyPrewarmRunning()) warmPaymentHistory(session);
|
|
@@ -134679,7 +134733,7 @@ ${canonical5}`;
|
|
|
134679
134733
|
const unshield = {
|
|
134680
134734
|
name: "wallet_unshield",
|
|
134681
134735
|
title: "Send USDC privately",
|
|
134682
|
-
description: `Use this when the user says "send 2 USDC to <address>" or "withdraw to my wallet" (leave \`to\` out
|
|
134736
|
+
description: `Use this when the user says "send 2 USDC to <address>" or "withdraw to my wallet" (for "my wallet" leave \`to\` out: it uses the address saved at setup, or says how to set one; never ask the user first): it sends amount (USDC, like "2"; or amount_atomic) from the PRIVATE balance as plain USDC to \`to\`, a public Solana address (it receives the USDC at that address). BEFORE you call it to send all of the balance when wallet_balance showed balanceParts above 1, write to the user that the wallet first gets the balance ready to send (do not tell the user how the wallet stores the balance; some apps show nothing until this call ends). Privately: the chain shows the pool paying the address, not which wallet paid. The wallet's own key (ownAddress in wallet_balance) is this wallet's public address: it holds the public USDC, wallet_shield deposits from it, and wallet_transfer_token sells from it. So it is refused as \`to\`: an exit there would show on chain that the private balance belongs to this wallet. This holds whether or not that key ever deposited: wallet_add_funds deposits come from one-time addresses, not from this key, so never tell the user the deposits came from it. Shinjuku pays every network fee; no SOL is needed. The user's saved own addresses (setup or this app's wallet entry) send at once. Any other address is sent only after the user confirms it in this app (a confirmation dialog); a client that cannot ask is refused (mcp_unshield_to_not_allowed) and a decline sends nothing (mcp_unshield_declined). \`to\` must already be able to receive USDC: an address that cannot is refused before any dialog (mcp_unshield_to_invalid). It runs in steps and may wait for the pool's next anchor: the call answers within about 20 s with stage (confirming, queued, refreshing, self-pay = preparing, exit = sending, done; joining = the wallet first gets the balance ready to send, then sends; each call goes on with it (joinSteps: its steps, one after another; doneInMinutesLow to doneInMinutesHigh: the time to say), ok: true); call wallet_unshield again with the SAME request_id, amount, and to for the status (each call answers within about 20 s, at once when the send ends; a confirmation dialog the user answers may take longer). When the wallet must first get the balance ready to send, the FIRST call answers at once with stage joining and joinTellFirst: true; write its say to the user, then call again with the same request_id at once. One exception: for a send whose balance must first be made ready, when this app sends a progress token with the call, that next call gets the balance ready and then sends, with a progress line every ${JOIN_STEP_MS / 1e3} s ("getting your balance ready to send"; some apps show none of them, so the line is said before the call, as above). It answers when the send is done, or after about ${joinAnswerSeconds(JOIN_CALL_MAX_MS)} s with how far it got (joinsDone; sendState sending: the USDC is leaving, never say nothing moved); then call again with the same request_id. Without a progress token it answers within about 20 s with stage joining: call again until it sends. The same request_id never sends twice, also after a restart. request_id is optional: without it the answer names the id it made, and the same call again within 10 minutes after it ends reads that same send. When it lands, the wallet writes an encrypted backup (backupPath). x402_pay calls wait while it runs. An optional limit the user sets (the unshield limit) may bound each call and what this wallet sends in any 24 hours, from every app that runs it (mcp_unshield_cap_exceeded: tell the user). Other refusals: mcp_argument_invalid, mcp_request_id_reused, mcp_unshield_to_invalid, wallet_locked, mcp_tool_disabled, mcp_unshield_failed, and the unshield's own p03_* codes. A send is one payment to \`to\`. ${HOST_BLOCKED_LINE}`,
|
|
134683
134737
|
inputSchema: {
|
|
134684
134738
|
type: "object",
|
|
134685
134739
|
properties: {
|
|
@@ -136389,7 +136443,7 @@ ${canonical5}`;
|
|
|
136389
136443
|
prompt: { type: "string", description: "One user message (instead of messages)." },
|
|
136390
136444
|
max_tokens: { type: "integer", minimum: 1, description: `Optional, default 4096 (512 for claude-opus-5), at least ${INFERENCE_MIN_MAX_TOKENS}. The answer's length limit, in tokens; the call pays for all of them up front. A reasoning model spends its first tokens thinking, so fewer can end with no answer.` },
|
|
136391
136445
|
temperature: { type: "number", minimum: 0, maximum: 2, description: "Sampling temperature; leave it out for the model's default." },
|
|
136392
|
-
max_payment: { type: "string", description: 'Optional: the most this call may pay, in USDC, like "0.
|
|
136446
|
+
max_payment: { type: "string", description: 'Optional: the most this call may pay, in USDC, like "0.01" (not atomic units); at most the spending limit.' },
|
|
136393
136447
|
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." },
|
|
136394
136448
|
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." }
|
|
136395
136449
|
},
|
|
@@ -136433,6 +136487,8 @@ ${canonical5}`;
|
|
|
136433
136487
|
}
|
|
136434
136488
|
const maxPayment = usdcAmountArg(args, { usdc: "max_payment", atomic: "max_payment_atomic", required: false });
|
|
136435
136489
|
if (!maxPayment.ok) return refuse12("inference_max_payment_invalid", maxPayment.detail.replace(/nothing was moved/, "nothing was paid"), maxPayment.next);
|
|
136490
|
+
const notUsdc = maxPaymentNotUsdc(args, maxPayment.atomic, "inference_chat");
|
|
136491
|
+
if (notUsdc) return refuse12(...notUsdc);
|
|
136436
136492
|
const messages = typeof args.prompt === "string" ? [{ role: "user", content: args.prompt }] : args.messages;
|
|
136437
136493
|
const asked = { model: args.model, messages, maxTokens: args.max_tokens };
|
|
136438
136494
|
let ceiling;
|
|
@@ -137633,7 +137689,7 @@ function createSetupTools({
|
|
|
137633
137689
|
doneTool: sayOnRefusal(doneTool)
|
|
137634
137690
|
};
|
|
137635
137691
|
}
|
|
137636
|
-
var import_web3133, shownCaps, RELEASE_RETRY_MS, STAGE_WORDS, stageWords, INTERNAL_BALANCE_DETAIL, shownBreakdown, sessionLeftShown, TOKEN_UNIT_TOOLS, RESOURCE_PAYMENT_WAL_PREFIX2, POOL_LAYOUT_CODE, POOL_LAYOUT_UPDATE, USEPOD_VIA_INFERENCE_CHAT, SEND_RUNS_ON, DEPOSIT_RUNS_ON, CLI_FUNDS_PLAN_PREFIX, CLI_FUNDS_SCHEMA, SELF_PAY_ORIGIN3, REQUEST_ID4, POSITIVE_ATOMIC6, PRIVATE_HOST3, FORBIDDEN_HEADERS3, MAX_BODY_BYTES2, PREVIEW_TIMEOUT_MS, PREVIEW_SELLER_READ_MS, CALL_BUDGET_MS, budgetLeft, PAY_ANSWER_MARGIN_MS, MONEY_FIRST_ANSWER_MS, BALANCE_AFTER_LANDING_MS, JOIN_CALL_MAX_MS, JOIN_CALL_ANSWER_MARGIN_S, PAY_AFTER_JOIN_MS, joinAnswerSeconds, JOIN_TIME_MS, JOIN_NUDGE_QUIET_MS, JOIN_STEP_MS, sleep2, PROGRESS_EVERY_MS2, READ_BUDGET_MS, UNPAID_TOR_TRY_MS, UNPAID_CLEAR_MS, READ_BUDGET_TOOLS, FLOAT_BUSY_CODES, RETRY_MARGIN_MS, ASK_PAY_CODES, runningNpmVersion, terminalCommand2, capPlaceWords, noLimitSetLine, CAP_NAMES, capName, entryPlaces, capRaiseText, runningLimits, payCapFlag, noPriceFits, cheaperText, limitNext, overLimitStep, SAFE_TEXT, causesLog, MCP_TOOL_ALIASES, POOL_SWITCH_WHY, POOL_SWITCH_NEXT, SWITCH_STATES, quietSwitch, switchKey, ATOMIC_TEXT, movedTo, FLOAT_ID, ANSWERED_EXIT_RETRY_MS, ANSWERED_EXIT_UNCONFIRMED_MS, ANSWERED_EXIT_RETRY_WINDOW_MS, ANSWERED_EXIT_CLOSED, switchAmount, switchEta, switchRows, OWNER_CAP_CODES, JOIN_END_MCP, JOIN_END_TERMINAL_LIBRARY, JOIN_RETRY_BACKOFF_MS, WALLET_CAP_FIX, ENTRY_CAP_CODES, MCP_CAP_FIX, capFix, ownerOnlyNext, mcpNext, CONFIDENTIAL_RETIRED, json3, answerResult, discoverTool, LAUNCH_CAP_CODES, dayCapKind, refuse12, newRequestIdFor, payCapName, publicOffer, FLOAT_PAID_CODES, FLOAT_NOT_CERTAIN_CODES, FLOAT_PRIVATE_LEG, SELLER_ONLY_HERE, outsideWalletRule, proxyStartStep, MONEY_ID2, toRecordId, linkKindOf, moneyId, REFUSED_CODES, refusedCodeOf, PLAIN_REASONS, insufficientCause, INSUFFICIENT_REASONS, reasonOf, plainReason, KEPT_SEND_TRIES, shownId, isSplitSend, PROMISED_NEXT, partFailReason, sendAnswerOf, PUBLIC_READ_TIMEOUT_MS, RECIPIENT_CHECK_TIMEOUT_MS, withTimeout, ownKey, readFailure, OWN_KEY_TOKENS_MAX, tokenAmountText, elsewhereId, AGENT_ID_SCHEMA, agentIdName, minutesText2, ageWords2, DEPOSIT_SENT_STATES, depositLanded, usdcText3, walkWalletHistory, REFRESH_LEASE_WALK_MS, HOME_MARKS_SETTLED_MS2, AUTO_BACKUPS_KEPT, AUTO_BACKUP_NAME, AUTO_BACKUP_VERIFIED, FRONTED_SETTLE_MARGIN_SLOTS, UNSHIELD_WINDOW_YIELD_MS, NOT_FINAL_YET, FINISH_FINALITY_WAIT_MS, FINISH_FINALITY_WAITS, FINISH_FINALITY_RECENT_MS, walkStillCurrent, DIRECT_EXIT_GONE, BALANCE_REFRESH_WAIT_MS, BALANCE_REFRESH_GRACE_MS, BALANCE_REFRESH_LONG_MS, INBOUND_REFRESH_AGE_MS, changeFields, balanceAnswer, CAP_BALANCE_WAIT_MS, CAP_BALANCE_RETRY_MS, REFRESH_RETRY_MS, FINALITY_POLL_MS, FINALITY_WAIT_MS, FINALITY_REFRESH_LIMIT_MS, POOL_WATCH_MS, POOL_WATCH_POLL_MS, EARLY_BALANCE_DELAY_MS, FINALITY_SETTLE_WINDOW_SLOTS, PUBLIC_READ_ANSWER_MS, LINK_READ_ANSWER_MS, OWN_READS_AHEAD_MS, OWN_PUBLIC_KNOWN_MS, FLOAT_CORRECT_WAIT_MS, SWITCH_WAIT_MS, UNSHIELD_TO_NO_USDC_DETAIL, UNSHIELD_TO_INVALID_NEXT, INFERENCE_MIN_MAX_TOKENS, ELICIT_TIMEOUT_MS, ELICIT_UNSHOWN_MS, elicitUnshown, POLL_SECONDS2, TRANSFER_CHANGE_READ_MS, TEMP_CLEAN_DELAY_MS, KEPT_ON_DISK, MAX_SHIELDED_BALANCE_ATOMIC, receiveGenerator, MCP_TOOL_NAMES, MCP_HIDDEN_TOOL_NAMES, setupTerminalNext, SETUP_RUNNING_SAY, ACCEPTED_NEXT, SETUP_RUNNING_NEXT, SETUP_ANSWER_WAIT_MS, SETUP_CONFIRMING_SAY, SETUP_CONFIRMING_NEXT, OWN_ADDRESS_QUESTION, OWN_ADDRESS_WHERE, OWN_ADDRESS_INVALID, PRIVATE_INFERENCE_WHY, RESTART_STEPS, TOR_BROWSER_PORT, SETUP_TOR_TITLE, SETUP_TOR_WHY;
|
|
137692
|
+
var import_web3133, shownCaps, RELEASE_RETRY_MS, STAGE_WORDS, stageWords, INTERNAL_BALANCE_DETAIL, shownBreakdown, sessionLeftShown, TOKEN_UNIT_TOOLS, RESOURCE_PAYMENT_WAL_PREFIX2, POOL_LAYOUT_CODE, POOL_LAYOUT_UPDATE, USEPOD_VIA_INFERENCE_CHAT, SEND_RUNS_ON, DEPOSIT_RUNS_ON, CLI_FUNDS_PLAN_PREFIX, CLI_FUNDS_SCHEMA, SELF_PAY_ORIGIN3, REQUEST_ID4, POSITIVE_ATOMIC6, PRIVATE_HOST3, FORBIDDEN_HEADERS3, MAX_BODY_BYTES2, PREVIEW_TIMEOUT_MS, PREVIEW_SELLER_READ_MS, CALL_BUDGET_MS, budgetLeft, PAY_ANSWER_MARGIN_MS, MONEY_FIRST_ANSWER_MS, BALANCE_AFTER_LANDING_MS, JOIN_CALL_MAX_MS, JOIN_CALL_ANSWER_MARGIN_S, PAY_AFTER_JOIN_MS, joinAnswerSeconds, JOIN_TIME_MS, JOIN_NUDGE_QUIET_MS, JOIN_STEP_MS, sleep2, PROGRESS_EVERY_MS2, READ_BUDGET_MS, UNPAID_TOR_TRY_MS, UNPAID_CLEAR_MS, READ_BUDGET_TOOLS, FLOAT_BUSY_CODES, RETRY_MARGIN_MS, ASK_PAY_CODES, runningNpmVersion, terminalCommand2, capPlaceWords, noLimitSetLine, CAP_NAMES, capName, entryPlaces, capRaiseText, runningLimits, payCapFlag, noPriceFits, cheaperText, limitNext, overLimitStep, SAFE_TEXT, causesLog, MCP_TOOL_ALIASES, POOL_SWITCH_WHY, POOL_SWITCH_NEXT, SWITCH_STATES, quietSwitch, switchKey, ATOMIC_TEXT, MAX_PAYMENT_ATOMIC_LEAST, movedTo, FLOAT_ID, ANSWERED_EXIT_RETRY_MS, ANSWERED_EXIT_UNCONFIRMED_MS, ANSWERED_EXIT_RETRY_WINDOW_MS, ANSWERED_EXIT_CLOSED, switchAmount, switchEta, switchRows, OWNER_CAP_CODES, JOIN_END_MCP, JOIN_END_TERMINAL_LIBRARY, JOIN_RETRY_BACKOFF_MS, WALLET_CAP_FIX, ENTRY_CAP_CODES, MCP_CAP_FIX, capFix, ownerOnlyNext, mcpNext, CONFIDENTIAL_RETIRED, json3, answerResult, discoverTool, LAUNCH_CAP_CODES, dayCapKind, refuse12, newRequestIdFor, payCapName, publicOffer, FLOAT_PAID_CODES, FLOAT_NOT_CERTAIN_CODES, FLOAT_PRIVATE_LEG, SELLER_ONLY_HERE, outsideWalletRule, proxyStartStep, MONEY_ID2, toRecordId, linkKindOf, moneyId, REFUSED_CODES, refusedCodeOf, PLAIN_REASONS, insufficientCause, INSUFFICIENT_REASONS, reasonOf, plainReason, KEPT_SEND_TRIES, shownId, isSplitSend, PROMISED_NEXT, partFailReason, sendAnswerOf, PUBLIC_READ_TIMEOUT_MS, RECIPIENT_CHECK_TIMEOUT_MS, withTimeout, ownKey, readFailure, OWN_KEY_TOKENS_MAX, tokenAmountText, elsewhereId, AGENT_ID_SCHEMA, agentIdName, minutesText2, ageWords2, DEPOSIT_SENT_STATES, depositLanded, usdcText3, walkWalletHistory, REFRESH_LEASE_WALK_MS, HOME_MARKS_SETTLED_MS2, AUTO_BACKUPS_KEPT, AUTO_BACKUP_NAME, AUTO_BACKUP_VERIFIED, FRONTED_SETTLE_MARGIN_SLOTS, UNSHIELD_WINDOW_YIELD_MS, NOT_FINAL_YET, FINISH_FINALITY_WAIT_MS, FINISH_FINALITY_WAITS, FINISH_FINALITY_RECENT_MS, walkStillCurrent, DIRECT_EXIT_GONE, BALANCE_REFRESH_WAIT_MS, BALANCE_REFRESH_GRACE_MS, BALANCE_REFRESH_LONG_MS, INBOUND_REFRESH_AGE_MS, changeFields, balanceAnswer, CAP_BALANCE_WAIT_MS, CAP_BALANCE_RETRY_MS, REFRESH_RETRY_MS, FINALITY_POLL_MS, FINALITY_WAIT_MS, FINALITY_REFRESH_LIMIT_MS, POOL_WATCH_MS, POOL_WATCH_POLL_MS, EARLY_BALANCE_DELAY_MS, FINALITY_SETTLE_WINDOW_SLOTS, PUBLIC_READ_ANSWER_MS, LINK_READ_ANSWER_MS, OWN_READS_AHEAD_MS, OWN_PUBLIC_KNOWN_MS, FLOAT_CORRECT_WAIT_MS, SWITCH_WAIT_MS, UNSHIELD_TO_NO_USDC_DETAIL, UNSHIELD_TO_INVALID_NEXT, INFERENCE_MIN_MAX_TOKENS, ELICIT_TIMEOUT_MS, ELICIT_UNSHOWN_MS, elicitUnshown, POLL_SECONDS2, TRANSFER_CHANGE_READ_MS, TEMP_CLEAN_DELAY_MS, KEPT_ON_DISK, MAX_SHIELDED_BALANCE_ATOMIC, receiveGenerator, MCP_TOOL_NAMES, MCP_HIDDEN_TOOL_NAMES, setupTerminalNext, SETUP_RUNNING_SAY, ACCEPTED_NEXT, SETUP_RUNNING_NEXT, SETUP_ANSWER_WAIT_MS, SETUP_CONFIRMING_SAY, SETUP_CONFIRMING_NEXT, OWN_ADDRESS_QUESTION, OWN_ADDRESS_WHERE, OWN_ADDRESS_INVALID, PRIVATE_INFERENCE_WHY, RESTART_STEPS, HOST_BLOCKED_LINE, TOR_BROWSER_PORT, SETUP_TOR_TITLE, SETUP_TOR_WHY;
|
|
137637
137693
|
var init_tools = __esm({
|
|
137638
137694
|
"wallet/src/mcp/tools.mjs"() {
|
|
137639
137695
|
"use strict";
|
|
@@ -137826,6 +137882,7 @@ var init_tools = __esm({
|
|
|
137826
137882
|
quietSwitch = (item) => item.state === "done" && item.tellUser !== true;
|
|
137827
137883
|
switchKey = (item) => `${item.from}:${item.state}`;
|
|
137828
137884
|
ATOMIC_TEXT = /^[0-9]{1,31}$/;
|
|
137885
|
+
MAX_PAYMENT_ATOMIC_LEAST = 1000n;
|
|
137829
137886
|
movedTo = (response, requested) => {
|
|
137830
137887
|
if (![301, 302, 303, 307, 308].includes(response.status)) return void 0;
|
|
137831
137888
|
const location = response.headers.get("location");
|
|
@@ -138112,7 +138169,9 @@ var init_tools = __esm({
|
|
|
138112
138169
|
return {
|
|
138113
138170
|
changeSettling: true,
|
|
138114
138171
|
...Number.isSafeInteger(one.changeReadyInSeconds) ? { changeReadyInSeconds: one.changeReadyInSeconds } : {},
|
|
138115
|
-
...ATOMIC_TEXT.test(shown) && ATOMIC_TEXT.test(upTo) && BigInt(upTo) < BigInt(shown) ? { changeUpToAtomic: upTo } : {}
|
|
138172
|
+
...ATOMIC_TEXT.test(shown) && ATOMIC_TEXT.test(upTo) && BigInt(upTo) < BigInt(shown) ? { changeUpToAtomic: upTo } : {},
|
|
138173
|
+
// UX129-9: the value is the changes of this many recent payments (2 or more); changeUpToAtomic is then the largest.
|
|
138174
|
+
...Number.isSafeInteger(one.changeCount) && one.changeCount >= 2 ? { changeCount: one.changeCount } : {}
|
|
138116
138175
|
};
|
|
138117
138176
|
};
|
|
138118
138177
|
balanceAnswer = (one, { shown = true } = {}) => one ? {
|
|
@@ -138193,6 +138252,7 @@ var init_tools = __esm({
|
|
|
138193
138252
|
OWN_ADDRESS_INVALID = "That is not a Solana address (32 to 44 letters and digits, as your wallet app shows it)";
|
|
138194
138253
|
PRIVATE_INFERENCE_WHY = "Your agent then buys AI answers from an AI provider, paid from your private balance over Tor; the AI provider and the company that runs the model see the prompt, not who paid.";
|
|
138195
138254
|
RESTART_STEPS = `In Claude Code: type /mcp, pick ${MCP_SERVER_NAME}, and choose Reconnect. In Claude Desktop: quit it and open it again. In another app: restart it`;
|
|
138255
|
+
HOST_BLOCKED_LINE = "If this app blocks a wallet tool (Claude Code's auto mode can), say nothing moved; in Claude Code, shift+tab turns auto mode off, then ask again. Never suggest a rule that lets a payment or send run with no question, or another way around the block.";
|
|
138196
138256
|
TOR_BROWSER_PORT = "http://127.0.0.1:9150";
|
|
138197
138257
|
SETUP_TOR_TITLE = "Use Tor?";
|
|
138198
138258
|
SETUP_TOR_WHY = "It hides your IP address from the payment service and sellers.";
|
|
@@ -139592,7 +139652,7 @@ async function runSetupModeServer({
|
|
|
139592
139652
|
}
|
|
139593
139653
|
return { closed: ended };
|
|
139594
139654
|
}
|
|
139595
|
-
var import_web3134, SUPPORTED_PROTOCOL_VERSIONS, MAX_LINE_BYTES, POSITIVE_ATOMIC7, INSTRUCTIONS, MCP_LOG_LEVELS, POOL_SWITCH_LOG_LEVEL, validId, PRODUCT_NAME, listedTitle, BUNDLED_SOURCE_DIR, SHA256_HEX, UPDATE_NOTICE_TOOLS, UPDATE_NOTICE_MAX_TEXT, NPM_VERSION2, GIT_COMMIT, ownWalletVersion, mcpServerVersion, UPDATE_NOTICE_TEXT, updateNoticeLine, commandUpdateField, LAUNCH_NOTICE_TOOLS, withLaunchLine, capRequired, setupInvalid, TOOL_ROOTS_WAIT_MS, ROOTS_FREE_TOOLS, MCP_CLOSE_BOUND_MS, MCP_CLOSE_HISTORY_BOUND_MS, MCP_CLOSE_UNREADABLE_BOUND_MS, MCP_CLOSE_POLL_MS, closeHistoryBusy, SETUP_INSTRUCTIONS, TOR_RELAY_READY_MS, RELAY_INIT_ID, runMcp;
|
|
139655
|
+
var import_web3134, SUPPORTED_PROTOCOL_VERSIONS, MAX_LINE_BYTES, POSITIVE_ATOMIC7, INSTRUCTIONS_BASE, INSTRUCTIONS, MCP_LOG_LEVELS, POOL_SWITCH_LOG_LEVEL, validId, PRODUCT_NAME, listedTitle, BUNDLED_SOURCE_DIR, SHA256_HEX, UPDATE_NOTICE_TOOLS, UPDATE_NOTICE_MAX_TEXT, NPM_VERSION2, GIT_COMMIT, ownWalletVersion, mcpServerVersion, UPDATE_NOTICE_TEXT, updateNoticeLine, commandUpdateField, LAUNCH_NOTICE_TOOLS, withLaunchLine, capRequired, setupInvalid, TOOL_ROOTS_WAIT_MS, ROOTS_FREE_TOOLS, MCP_CLOSE_BOUND_MS, MCP_CLOSE_HISTORY_BOUND_MS, MCP_CLOSE_UNREADABLE_BOUND_MS, MCP_CLOSE_POLL_MS, closeHistoryBusy, SETUP_INSTRUCTIONS, TOR_RELAY_READY_MS, RELAY_INIT_ID, runMcp;
|
|
139596
139656
|
var init_stdioServer = __esm({
|
|
139597
139657
|
"wallet/src/mcp/stdioServer.mjs"() {
|
|
139598
139658
|
"use strict";
|
|
@@ -139625,7 +139685,8 @@ var init_stdioServer = __esm({
|
|
|
139625
139685
|
SUPPORTED_PROTOCOL_VERSIONS = Object.freeze(["2025-06-18", "2025-03-26", "2024-11-05"]);
|
|
139626
139686
|
MAX_LINE_BYTES = 4 * 1024 * 1024;
|
|
139627
139687
|
POSITIVE_ATOMIC7 = /^[1-9][0-9]{0,30}$/;
|
|
139628
|
-
|
|
139688
|
+
INSTRUCTIONS_BASE = `A self-custody Shinjuku Shield wallet on this machine; no tool takes or returns its keys or passphrase. Each answer's say is one plain sentence for the user; other fields hold the numbers. Never tell the user a tool, field, code or protocol name (x402, MCP) unless told to. Map the user's plain request to one tool: "what is my balance" -> wallet_balance (safe at any time); "add money" / "deposit" / "move USDC in from Phantom or an exchange" -> wallet_add_funds (a one-time address; the next wallet_balance after the USDC arrives makes it private, up to 5 USDC private); "shield the USDC on this wallet's own address" -> wallet_shield; "stop" / "cancel" -> wallet_cancel with the request_id of what to stop; "pay this URL" -> x402_pay (no preview needed); "what does this URL cost" -> x402_preview (only when asked); "find a paid API for X" -> x402_discover, then x402_pay on the url it found; "send 2 USDC to <address>" -> wallet_unshield; "show my payments" -> wallet_receipts; "send another token" -> wallet_transfer_token; "ask an AI model" / "which AI models" -> inference_chat (with no prompt it lists the models and prices); "give my other AI app a private AI" -> inference_server (a local OpenAI-compatible URL and key for that app). wallet_balance answers ONE balance (balanceAtomic), and x402_pay pays any paid URL from it (a seller that cannot take a private payment is paid through Shinjuku: max_payment covers amountAtomic, fee included). Fields ending in Atomic are atomic units (1000000 = 1 USDC); tell the user USDC. The wallet does its own upkeep (no user command). A shield, add-funds or unshield call 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 (a code ending in _retry_same_request: call again with it). A wallet_unshield send to an address not approved ahead asks the user to confirm first. x402_pay never pays above the user's spending limits (one payment; any 24 hours); 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 app and its model provider see every URL, body, price and paid answer you handle; reach a seller or its domain only through these tools, never yourself (no curl, browser or DNS lookup, DNS-over-HTTPS too), also when the user asks for no Tor: it shows the user's IP address to the site or a DNS company. 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.`;
|
|
139689
|
+
INSTRUCTIONS = `${INSTRUCTIONS_BASE} ${HOST_BLOCKED_LINE}`;
|
|
139629
139690
|
MCP_LOG_LEVELS = Object.freeze(["debug", "info", "notice", "warning", "error", "critical", "alert", "emergency"]);
|
|
139630
139691
|
POOL_SWITCH_LOG_LEVEL = "info";
|
|
139631
139692
|
validId = (id) => id === null || typeof id === "string" || typeof id === "number" && Number.isFinite(id);
|
|
@@ -139663,7 +139724,7 @@ var init_stdioServer = __esm({
|
|
|
139663
139724
|
MCP_CLOSE_UNREADABLE_BOUND_MS = 6e4;
|
|
139664
139725
|
MCP_CLOSE_POLL_MS = 500;
|
|
139665
139726
|
closeHistoryBusy = (server) => () => compactHistoryReadsRunning() > 0 || memoReadsAheadRunning() > 0 || server.refreshOpen?.() === true;
|
|
139666
|
-
SETUP_INSTRUCTIONS = `This Shinjuku Shield wallet is NOT SET UP yet: every money tool answers wallet_not_set_up. When the user wants to pay, check a balance, or add money, call shinjuku_setup: it asks the user to confirm, creates the wallet and downloads the setup files (minutes: call again as next says). At stage done the wallet tools work. After setup: ${
|
|
139727
|
+
SETUP_INSTRUCTIONS = `This Shinjuku Shield wallet is NOT SET UP yet: every money tool answers wallet_not_set_up. When the user wants to pay, check a balance, or add money, call shinjuku_setup: it asks the user to confirm, creates the wallet and downloads the setup files (minutes: call again as next says). At stage done the wallet tools work. After setup: ${INSTRUCTIONS_BASE}`;
|
|
139667
139728
|
TOR_RELAY_READY_MS = 18e4;
|
|
139668
139729
|
RELAY_INIT_ID = "shinjuku-wallet-relay-initialize";
|
|
139669
139730
|
runMcp = runMcpServer;
|
|
@@ -142007,7 +142068,7 @@ function torTooOldAnswer(version3, { tunnelHost, platform = process.platform } =
|
|
|
142007
142068
|
ok: false,
|
|
142008
142069
|
error: "tor_too_old",
|
|
142009
142070
|
detail: `${torTooOldWhy(version3)} Tor 0.4.9.13 and newer fix that fault. Nothing was paid.`,
|
|
142010
|
-
next: `Tell the user why: their Tor program is too old and has a known fault that can link two of their payments, and the wallet never falls back to a direct connection. Show torUpdateCommand in one code block, to copy into ${where}: it installs a newer Tor and starts it for the wallet.${platform === "win32" ?
|
|
142071
|
+
next: `Tell the user why: their Tor program is too old and has a known fault that can link two of their payments, and the wallet never falls back to a direct connection. Show torUpdateCommand in one code block, to copy into ${where}: it installs a newer Tor and starts it for the wallet.${platform === "win32" ? ` Before it, the user stops the old Tor: ${TOR_STOP_OLD_WINDOWS.replace(/^Stop your old Tor first: /, "")}` : ""} If you can run commands here, offer to run it for the user. When the newer Tor runs: ${RESTART}.`,
|
|
142011
142072
|
torUpdateCommand: command
|
|
142012
142073
|
};
|
|
142013
142074
|
}
|
|
@@ -142056,7 +142117,7 @@ async function serveTorMissingMcp({ message, recheck = async () => ({ answer: fa
|
|
|
142056
142117
|
const dispatch = createMcpDispatcher({
|
|
142057
142118
|
tools,
|
|
142058
142119
|
aliases: MCP_TOOL_ALIASES,
|
|
142059
|
-
instructions: tooOldAtStart ? `The Shinjuku Shield wallet is set to run behind Tor, and the Tor program on this machine is too old (it has a known fault that can link two payments). Call
|
|
142120
|
+
instructions: tooOldAtStart ? `The Shinjuku Shield wallet is set to run behind Tor, and the Tor program on this machine is too old (it has a known fault that can link two payments). Call any wallet tool you may use (x402_pay too): its answer has the command that installs a newer Tor, and it moves no money. ${RESTART} after the newer Tor starts.` : `The Shinjuku Shield wallet is set to run behind Tor, and Tor is not running on this machine. Call any wallet tool you may use (x402_pay too): its answer has the install command for the user's OS, and it moves no money. ${RESTART} after Tor starts.`
|
|
142060
142121
|
});
|
|
142061
142122
|
await serveStdio({ input, output: output2, dispatch, log });
|
|
142062
142123
|
return 1;
|
|
@@ -147802,12 +147863,22 @@ function noticeLines(notice, width, compact = false) {
|
|
|
147802
147863
|
}
|
|
147803
147864
|
return lines;
|
|
147804
147865
|
}
|
|
147866
|
+
function balanceShown(data) {
|
|
147867
|
+
const balance = clean4(data.balance);
|
|
147868
|
+
if (balance) return { bar: balance, row: balance, cls: "verm", step: null };
|
|
147869
|
+
const command = `${clean4(data.command) || "shinjuku"} balance`;
|
|
147870
|
+
if (data.balanceRead === "reading") return { bar: "reading your balance\u2026", row: "reading\u2026", cls: "mute", step: null };
|
|
147871
|
+
if (data.balanceRead === "slow") return { bar: "balance not known yet", row: "not known yet: the read is slow", cls: "mute", step: "it goes on, and shows here when it ends." };
|
|
147872
|
+
if (data.balanceRead === "failed") return { bar: "balance not known yet", row: "not known yet: the read failed", cls: "mute", step: `run ${command} to see why.` };
|
|
147873
|
+
if (data.balanceRead === "done") return { bar: "balance not known yet", row: "not known yet", cls: "mute", step: `run ${command} to read it again.` };
|
|
147874
|
+
return { bar: "balance not known yet", row: "not known yet", cls: "mute", step: null };
|
|
147875
|
+
}
|
|
147805
147876
|
function homeStatus(data, wide, width) {
|
|
147806
147877
|
const notices = walletNotices(data);
|
|
147807
147878
|
const [notice] = notices;
|
|
147808
147879
|
const head = notice ? [[" \u25CB ", "mute"], [notice.state, "bone"]] : [[" \u25CF ", "brass"], ["ready", "bone"]];
|
|
147809
|
-
const
|
|
147810
|
-
const middle = [[
|
|
147880
|
+
const shown = balanceShown(data);
|
|
147881
|
+
const middle = [[shown.bar, shown.cls]];
|
|
147811
147882
|
if (data.tor === true || data.tor === false) middle.push([data.tor ? "tor on" : "tor off", "bone"]);
|
|
147812
147883
|
const bar = (items) => [...head, ...items.flatMap((item) => [[" \u2502 ", "ash"], item])];
|
|
147813
147884
|
const command = notices.find((item) => item.command)?.command;
|
|
@@ -147928,12 +147999,13 @@ function publicRows(data, w) {
|
|
|
147928
147999
|
return { row: ["public", value2, "verm"], step: Object.hasOwn(PUBLIC_STEP, pub.step) ? [PUBLIC_STEP[pub.step]] : [] };
|
|
147929
148000
|
}
|
|
147930
148001
|
function walletBlock(data, wide, w, compact = false) {
|
|
147931
|
-
const
|
|
148002
|
+
const shown = balanceShown(data);
|
|
147932
148003
|
const notices = walletNotices(data);
|
|
147933
148004
|
const state = notices.length ? `\u25CB ${notices[0].state}` : "\u25CF ready";
|
|
147934
148005
|
const extra = notices.flatMap((notice) => noticeLines(notice, w - 4, compact));
|
|
147935
148006
|
if (compact) return rowsBlock(PANELS.wallet, state, "mute", [], extra, "dim");
|
|
147936
|
-
const rows2 = [["balance",
|
|
148007
|
+
const rows2 = [["balance", shown.row, shown.cls]];
|
|
148008
|
+
if (shown.step) extra.unshift(...wrap(shown.step, w - 4));
|
|
147937
148009
|
const adding = clean4(data.addingFunds);
|
|
147938
148010
|
const moving = clean4(data.movingOut);
|
|
147939
148011
|
const live = (value2) => value2 === "none" ? "bone" : "verm";
|
|
@@ -148165,7 +148237,7 @@ async function stopReading(stdin) {
|
|
|
148165
148237
|
handle.readStop();
|
|
148166
148238
|
}
|
|
148167
148239
|
}
|
|
148168
|
-
async function openHomeScreen({ stdout = process.stdout, stdin = process.stdin, env = process.env, platform = process.platform, data } = {}) {
|
|
148240
|
+
async function openHomeScreen({ stdout = process.stdout, stdin = process.stdin, env = process.env, platform = process.platform, data, watch } = {}) {
|
|
148169
148241
|
if (!homeScreenAllowed(stdout, env) || !stdin?.isTTY || typeof stdin.setRawMode !== "function") return { outcome: "off" };
|
|
148170
148242
|
if (!compose(data, stdout.columns - 1, stdout.rows)) return { outcome: "off" };
|
|
148171
148243
|
const codes = paletteFor(screenColor(stdout, env));
|
|
@@ -148228,6 +148300,7 @@ async function openHomeScreen({ stdout = process.stdout, stdin = process.stdin,
|
|
|
148228
148300
|
const rawBefore = Boolean(stdin.isRaw);
|
|
148229
148301
|
let reading = false;
|
|
148230
148302
|
let timer;
|
|
148303
|
+
let stopWatch;
|
|
148231
148304
|
process.once("exit", restoreScreen);
|
|
148232
148305
|
for (const signal of signals) process.on(signal, onSignal);
|
|
148233
148306
|
stdout.on?.("resize", onResize);
|
|
@@ -148240,11 +148313,21 @@ async function openHomeScreen({ stdout = process.stdout, stdin = process.stdin,
|
|
|
148240
148313
|
write("\x1B[?1049h\x1B[?25l");
|
|
148241
148314
|
draw();
|
|
148242
148315
|
timer = setInterval(spin, BAND_MS2);
|
|
148316
|
+
stopWatch = watch?.((next) => {
|
|
148317
|
+
if (result === void 0 && next) {
|
|
148318
|
+
data = next;
|
|
148319
|
+
draw();
|
|
148320
|
+
}
|
|
148321
|
+
});
|
|
148243
148322
|
await settled;
|
|
148244
148323
|
} catch {
|
|
148245
148324
|
finish({ outcome: "off" });
|
|
148246
148325
|
} finally {
|
|
148247
148326
|
clearInterval(timer);
|
|
148327
|
+
try {
|
|
148328
|
+
stopWatch?.();
|
|
148329
|
+
} catch {
|
|
148330
|
+
}
|
|
148248
148331
|
stdout.removeListener?.("resize", onResize);
|
|
148249
148332
|
for (const signal of signals) process.removeListener(signal, onSignal);
|
|
148250
148333
|
process.removeListener("exit", restoreScreen);
|
|
@@ -148357,12 +148440,16 @@ function sellerWords(seller) {
|
|
|
148357
148440
|
return text3.length > SELLER_CHARS ? `${text3.slice(0, SELLER_CHARS - 3)}...` : text3;
|
|
148358
148441
|
}
|
|
148359
148442
|
var REFUND_WORDS = Object.freeze({ refunded: "refunded", refund_sent: "coming back", refund_pending: "coming back", refund_not_seen: "refund not seen" });
|
|
148443
|
+
function aiPaymentWords(item) {
|
|
148444
|
+
const parts = /^private AI: (.+) \(([^()]+)\)$/.exec(item);
|
|
148445
|
+
return parts ? `private AI, ${parts[2]}: ${parts[1]}` : item;
|
|
148446
|
+
}
|
|
148360
148447
|
function paymentRow(name, record, store, walk) {
|
|
148361
148448
|
let ok;
|
|
148362
148449
|
let at;
|
|
148363
148450
|
let words2;
|
|
148364
148451
|
const view2 = receiptView(record);
|
|
148365
|
-
const seller = view2.kind === "inference" && typeof view2.item === "string" ? view2.item : sellerWords(view2.seller);
|
|
148452
|
+
const seller = view2.kind === "inference" && typeof view2.item === "string" ? aiPaymentWords(view2.item) : sellerWords(view2.seller);
|
|
148366
148453
|
if (name.startsWith(FLOAT_PAYMENT_WAL_PREFIX2)) {
|
|
148367
148454
|
if (record?.schema !== FLOAT_PAYMENT_SCHEMA2) return void 0;
|
|
148368
148455
|
const state = floatRecordState(record);
|
|
@@ -150894,16 +150981,26 @@ function allowWalletChecks(deps) {
|
|
|
150894
150981
|
const file = claudeCodeSettingsFile({ env: deps.env, home: deps.homedir() });
|
|
150895
150982
|
try {
|
|
150896
150983
|
const { changed, backup } = allowInClaudeCode(file);
|
|
150897
|
-
return { same: !changed, say: `Claude Code runs the wallet's checks that move no money (balance, receipts) without a question${backup ? ` (its old settings file was copied to ${backup}, readable by you alone)` : ""}.
|
|
150984
|
+
return { same: !changed, say: `Claude Code runs the wallet's checks that move no money (balance, receipts) without a question${backup ? ` (its old settings file was copied to ${backup}, readable by you alone)` : ""}. In Claude Code's default mode, payments and sends still ask first; its auto mode may pay with no question or block a send (press shift+tab until auto mode is off). To undo the wallet's rules, remove the shinjuku rules in Claude Code's /permissions.` };
|
|
150898
150985
|
} catch (error) {
|
|
150899
150986
|
const unreadable = String(error.message).startsWith("setup_host_config_unreadable:");
|
|
150900
150987
|
return { same: false, say: `Claude Code still asks before each wallet check: ${unreadable ? `the wallet cannot read the settings in ${file}, so it did not change that file` : `the wallet could not write ${file}`}.` };
|
|
150901
150988
|
}
|
|
150902
150989
|
}
|
|
150903
|
-
function
|
|
150990
|
+
function otherHomeOfClaudeCodeEntry(existing, options) {
|
|
150991
|
+
const named = existing?.env?.SHIELDED_WALLET_HOME;
|
|
150992
|
+
const env = { ...options.env };
|
|
150993
|
+
delete env.SHIELDED_WALLET_HOME;
|
|
150994
|
+
if (typeof named === "string" && named) env.SHIELDED_WALLET_HOME = named;
|
|
150995
|
+
const home = setupHome(env);
|
|
150996
|
+
if (!isOlderClaudeCodeEntry(existing, { ...options, env, home })) return void 0;
|
|
150997
|
+
return resolve33(home) === resolve33(options.home) ? void 0 : home;
|
|
150998
|
+
}
|
|
150999
|
+
async function addToHosts(targets, home, deps, { force = false, npmVersion, ask } = {}) {
|
|
150904
151000
|
const io = deps.io;
|
|
150905
151001
|
const options = { home, env: deps.env, platform: deps.platform ?? process.platform, npmVersion };
|
|
150906
151002
|
const done = /* @__PURE__ */ new Set();
|
|
151003
|
+
const kept2 = /* @__PURE__ */ new Set();
|
|
150907
151004
|
for (const target of targets) {
|
|
150908
151005
|
if (target === "claude-code") {
|
|
150909
151006
|
const why = claudeCodeShellWhy(options);
|
|
@@ -150926,11 +151023,21 @@ function addToHosts(targets, home, deps, { force = false, npmVersion } = {}) {
|
|
|
150926
151023
|
continue;
|
|
150927
151024
|
}
|
|
150928
151025
|
const olderOwn = !force && existing !== void 0 && isOlderClaudeCodeEntry(existing, options) && quiet(["mcp", "remove", "--scope", "user", MCP_SERVER_NAME]) === 0;
|
|
151026
|
+
const otherHome = !force && !olderOwn && existing !== void 0 ? otherHomeOfClaudeCodeEntry(existing, options) : void 0;
|
|
151027
|
+
const replace = otherHome !== void 0 && ask !== void 0 ? yes(await ask(`Claude Code already has a Shinjuku Shield entry for another wallet home (${otherHome}). Replace it with this one? [y/N] `)) : void 0;
|
|
151028
|
+
if (replace === false) {
|
|
151029
|
+
kept2.add(target);
|
|
151030
|
+
io.out(`Claude Code keeps the wallet in ${otherHome}; nothing was changed. To use this wallet there instead, do this step again and answer y.
|
|
151031
|
+
`);
|
|
151032
|
+
continue;
|
|
151033
|
+
}
|
|
151034
|
+
const replacedOther = replace === true && quiet(["mcp", "remove", "--scope", "user", MCP_SERVER_NAME]) === 0;
|
|
150929
151035
|
let status = deps.runClaudeCli(claudeCodeArgs(options));
|
|
150930
|
-
const removed = olderOwn || status !== 0 && force && quiet(["mcp", "remove", "--scope", "user", MCP_SERVER_NAME]) === 0;
|
|
151036
|
+
const removed = olderOwn || replacedOther || status !== 0 && force && quiet(["mcp", "remove", "--scope", "user", MCP_SERVER_NAME]) === 0;
|
|
150931
151037
|
if (removed && status !== 0) status = deps.runClaudeCli(claudeCodeArgs(options));
|
|
150932
151038
|
if (status === 0) done.add(target);
|
|
150933
|
-
|
|
151039
|
+
const homeNow = replacedOther ? ` Claude Code now uses the wallet in ${home}; the wallet in ${otherHome} is unchanged.` : "";
|
|
151040
|
+
io.out(status === 0 ? `${removed ? "Replaced the wallet in" : "Added the wallet to"} Claude Code, for all your folders.${homeNow} ${allowWalletChecks(deps).say} ${RESTART_APP("Claude Code")}
|
|
150934
151041
|
` : `Claude Code did not take the server; its message is above. Run this yourself:
|
|
150935
151042
|
${claudeCodeCommand(options)}
|
|
150936
151043
|
` + (removed ? `Setup removed the old ${MCP_SERVER_NAME} entry first, so Claude Code has none until that line runs.
|
|
@@ -150956,7 +151063,7 @@ function addToHosts(targets, home, deps, { force = false, npmVersion } = {}) {
|
|
|
150956
151063
|
`);
|
|
150957
151064
|
}
|
|
150958
151065
|
}
|
|
150959
|
-
return done;
|
|
151066
|
+
return { added: done, kept: kept2 };
|
|
150960
151067
|
}
|
|
150961
151068
|
function setupArgvOf(values) {
|
|
150962
151069
|
const usdcNames = new Set(COMMAND_BY_NAME.get("setup").flags.filter((spec) => spec.usdc).map((spec) => spec.name));
|
|
@@ -151278,7 +151385,13 @@ Copy it to two offline places now; it is the only way to restore this wallet.
|
|
|
151278
151385
|
`);
|
|
151279
151386
|
const rerun = values.get(SETUP_RERUN) === "settings";
|
|
151280
151387
|
const targets = values.get("--add-to") ?? [];
|
|
151281
|
-
const
|
|
151388
|
+
const hosts = targets.length ? await addToHosts(
|
|
151389
|
+
targets,
|
|
151390
|
+
home,
|
|
151391
|
+
deps,
|
|
151392
|
+
{ force: values.has("--force"), npmVersion, ask: interactive && deps.stdinIsTTY() ? deps.ask : void 0 }
|
|
151393
|
+
) : void 0;
|
|
151394
|
+
const added = /* @__PURE__ */ new Set([...hosts?.added ?? [], ...hosts?.kept ?? []]);
|
|
151282
151395
|
const config = setupConfigOf(home);
|
|
151283
151396
|
if (readsBack) {
|
|
151284
151397
|
await readBackHere(config, deps, values.get(RESTORED) ?? `Run setup again when the connection works; it continues there:
|
|
@@ -154449,7 +154562,7 @@ async function runBalance(args, values, deps, io) {
|
|
|
154449
154562
|
await refreshed.prune();
|
|
154450
154563
|
publicSince = Date.now();
|
|
154451
154564
|
store = refreshed.store;
|
|
154452
|
-
earlierDeposits = await (deps.adoptOneTime ?? adoptOneTimeForBalance)({ store, values, deps, io });
|
|
154565
|
+
if (deps.env[HOME_READ_ENV] !== "1") earlierDeposits = await (deps.adoptOneTime ?? adoptOneTimeForBalance)({ store, values, deps, io });
|
|
154453
154566
|
} else {
|
|
154454
154567
|
store = openPoolWallet(values, deps);
|
|
154455
154568
|
}
|
|
@@ -154992,7 +155105,7 @@ function failureHint(command, reason, deps, values, floatError) {
|
|
|
154992
155105
|
return "this payment settled, but in another transaction than the seller's receipt names; the wallet counts the settled one. Do not pay this request again";
|
|
154993
155106
|
}
|
|
154994
155107
|
if (/p03_quote_anchor_older_than_note_wait_next_epoch/.test(reason)) {
|
|
154995
|
-
return
|
|
155108
|
+
return "your last payment or deposit is not ready to spend yet, and the wallet's wait for it ran out. Nothing was signed or paid. Run the same command again in a minute";
|
|
154996
155109
|
}
|
|
154997
155110
|
if (/p03_merchant_respend_(insufficient_recovered_value|accounts_split_merge_first)/.test(reason)) {
|
|
154998
155111
|
const parts = runBalanceParts(values, deps);
|
|
@@ -155426,21 +155539,104 @@ Every command: ${cli2()} help
|
|
|
155426
155539
|
`;
|
|
155427
155540
|
}
|
|
155428
155541
|
var bareAnimationPlayed = false;
|
|
155542
|
+
var HOME_READ_CAP_MS = 6e4;
|
|
155543
|
+
var HOME_READ_ENV = "SHINJUKU_WALLET_HOME_READ";
|
|
155544
|
+
function homeBalanceReadRun(argv2, env) {
|
|
155545
|
+
const words2 = ["balance", "--refresh", "--fresh"];
|
|
155546
|
+
if (runNetworkMode() !== null) {
|
|
155547
|
+
const proxy = childRunProxy(env);
|
|
155548
|
+
return { args: [...words2, ...proxy.args], env: { ...proxy.env, [HOME_READ_ENV]: "1" } };
|
|
155549
|
+
}
|
|
155550
|
+
const own = { ...env, [HOME_READ_ENV]: "1" };
|
|
155551
|
+
return { args: torArgv([...words2, ...argv2], own), env: own };
|
|
155552
|
+
}
|
|
155553
|
+
function startHomeBalanceRead(argv2, env) {
|
|
155554
|
+
if (cliEntry2 === void 0) return void 0;
|
|
155555
|
+
const run4 = homeBalanceReadRun(argv2, env);
|
|
155556
|
+
let child;
|
|
155557
|
+
try {
|
|
155558
|
+
child = spawn9(process.execPath, [...process.execArgv, cliEntry2, ...run4.args], { env: run4.env, stdio: "ignore", detached: true, windowsHide: true });
|
|
155559
|
+
} catch {
|
|
155560
|
+
return void 0;
|
|
155561
|
+
}
|
|
155562
|
+
child.unref();
|
|
155563
|
+
return new Promise((done) => {
|
|
155564
|
+
child.once("error", () => done(1));
|
|
155565
|
+
child.once("exit", (code2) => done(code2 ?? 1));
|
|
155566
|
+
});
|
|
155567
|
+
}
|
|
155568
|
+
function homeBalanceRead(data, argv2, deps, readData) {
|
|
155569
|
+
if (data?.setUp !== true || data.balance !== null || data.walletIssue || data.restoreUnread || data.setupFilesMissing) return void 0;
|
|
155570
|
+
const ended = deps.homeBalanceRead(argv2, deps.env);
|
|
155571
|
+
if (!ended) return void 0;
|
|
155572
|
+
const startedAt = deps.now();
|
|
155573
|
+
let current = { ...data, balanceRead: "reading" };
|
|
155574
|
+
let endCode;
|
|
155575
|
+
const watchers = /* @__PURE__ */ new Set();
|
|
155576
|
+
const show = (next) => {
|
|
155577
|
+
current = next;
|
|
155578
|
+
for (const watcher of watchers) watcher(next);
|
|
155579
|
+
};
|
|
155580
|
+
const reread = () => {
|
|
155581
|
+
let next;
|
|
155582
|
+
try {
|
|
155583
|
+
next = readData();
|
|
155584
|
+
} catch {
|
|
155585
|
+
next = { ...current, balance: null };
|
|
155586
|
+
}
|
|
155587
|
+
show(next?.balance !== null && next?.balance !== void 0 ? next : { ...next ?? current, balanceRead: endCode === 0 ? "done" : "failed" });
|
|
155588
|
+
};
|
|
155589
|
+
const cap = setTimeout(() => {
|
|
155590
|
+
if (endCode === void 0) show({ ...current, balanceRead: "slow" });
|
|
155591
|
+
}, HOME_READ_CAP_MS);
|
|
155592
|
+
cap.unref?.();
|
|
155593
|
+
const settled = ended.then((code2) => {
|
|
155594
|
+
endCode = code2;
|
|
155595
|
+
clearTimeout(cap);
|
|
155596
|
+
if (watchers.size) reread();
|
|
155597
|
+
});
|
|
155598
|
+
return {
|
|
155599
|
+
data: () => current,
|
|
155600
|
+
watch(watcher) {
|
|
155601
|
+
watchers.add(watcher);
|
|
155602
|
+
if (endCode !== void 0 && current.balanceRead === "reading") reread();
|
|
155603
|
+
return () => {
|
|
155604
|
+
watchers.delete(watcher);
|
|
155605
|
+
};
|
|
155606
|
+
},
|
|
155607
|
+
async finish(io) {
|
|
155608
|
+
const left = HOME_READ_CAP_MS - (deps.now() - startedAt);
|
|
155609
|
+
if (endCode !== void 0 || left <= 0) return;
|
|
155610
|
+
io.err(`Finishing the balance read first (at most ${Math.ceil(left / 1e3)} s)\u2026
|
|
155611
|
+
`);
|
|
155612
|
+
let timer;
|
|
155613
|
+
await Promise.race([settled, new Promise((done) => {
|
|
155614
|
+
timer = setTimeout(done, left);
|
|
155615
|
+
})]);
|
|
155616
|
+
clearTimeout(timer);
|
|
155617
|
+
}
|
|
155618
|
+
};
|
|
155619
|
+
}
|
|
155429
155620
|
function defaultDependencies() {
|
|
155430
155621
|
return {
|
|
155431
155622
|
env: process.env,
|
|
155432
155623
|
now: () => Date.now(),
|
|
155433
155624
|
io: { out: (text3) => process.stdout.write(text3), err: (text3) => process.stderr.write(text3) },
|
|
155434
155625
|
openAnimation: () => playOpenAnimation(),
|
|
155435
|
-
/**
|
|
155626
|
+
/**
|
|
155627
|
+
* The facts of the bare command's home screen (cli/homeData.mjs), from local files only. The screen's one network
|
|
155628
|
+
* read is homeBalanceRead, a balance child run behind the run's Tor, only when these facts give no balance.
|
|
155629
|
+
*/
|
|
155436
155630
|
homeData: (options) => readHomeData(options),
|
|
155631
|
+
/** The home screen's balance read (startHomeBalanceRead): a promise of its exit code, or undefined when none starts. */
|
|
155632
|
+
homeBalanceRead: (argv2, env) => startHomeBalanceRead(argv2, env),
|
|
155437
155633
|
/**
|
|
155438
155634
|
* True when the bare command's home screen can draw: stdout and stdin a terminal, CI unset, TERM not dumb, a window it
|
|
155439
155635
|
* fits. Only then are its facts read, so a pipe never opens the wallet.
|
|
155440
155636
|
*/
|
|
155441
155637
|
homeScreenOn: (env) => homeScreenAllowed(process.stdout, env) && Boolean(process.stdin.isTTY),
|
|
155442
|
-
/** The bare command's home screen (cli/homeScreen.mjs) for `data` (homeData): { outcome, key }. */
|
|
155443
|
-
homeScreen: (data, env) => openHomeScreen({ env, data }),
|
|
155638
|
+
/** The bare command's home screen (cli/homeScreen.mjs) for `data` (homeData), redrawn on each `watch` change: { outcome, key }. */
|
|
155639
|
+
homeScreen: (data, env, watch) => openHomeScreen({ env, data, watch }),
|
|
155444
155640
|
/**
|
|
155445
155641
|
* The one job a home screen key runs, as the bin runs that typed command (bin/shinjuku-wallet.mjs): help text in this
|
|
155446
155642
|
* process; any other command through torArgv and proxyEntry, so a home whose setup recorded Tor runs it behind Tor
|
|
@@ -155661,11 +155857,14 @@ async function runShinjukuWallet(argv2, overrides = {}) {
|
|
|
155661
155857
|
if (name === void 0 || name === "help" || name === "--help" || name === "-h") {
|
|
155662
155858
|
if (name === void 0) {
|
|
155663
155859
|
const screenOn = deps.homeScreenOn(deps.env);
|
|
155664
|
-
const
|
|
155860
|
+
const torRun = homeJobTor(argv2, deps.env);
|
|
155861
|
+
const readData = () => deps.homeData({ env: deps.env, walletVersion: deps.walletVersion, torRun });
|
|
155862
|
+
const data = screenOn ? readData() : void 0;
|
|
155863
|
+
const balanceRead = screenOn ? homeBalanceRead(data, argv2, deps, readData) : void 0;
|
|
155665
155864
|
const played = await deps.openAnimation();
|
|
155666
155865
|
bareAnimationPlayed = true;
|
|
155667
155866
|
if (played === "interrupted") return 130;
|
|
155668
|
-
const screen = screenOn ? await deps.homeScreen(data, deps.env) : { outcome: "off" };
|
|
155867
|
+
const screen = screenOn ? await deps.homeScreen(balanceRead ? balanceRead.data() : data, deps.env, balanceRead?.watch) : { outcome: "off" };
|
|
155669
155868
|
if (screen.outcome === "interrupted") return 130;
|
|
155670
155869
|
if (screen.outcome === "quit") return 0;
|
|
155671
155870
|
if (screen.outcome !== "key") {
|
|
@@ -155676,7 +155875,10 @@ async function runShinjukuWallet(argv2, overrides = {}) {
|
|
|
155676
155875
|
io.out(overviewText());
|
|
155677
155876
|
return 0;
|
|
155678
155877
|
}
|
|
155679
|
-
const job = (words3) =>
|
|
155878
|
+
const job = async (words3) => {
|
|
155879
|
+
await balanceRead?.finish(io);
|
|
155880
|
+
return deps.runHomeJob([...words3, ...argv2], overrides);
|
|
155881
|
+
};
|
|
155680
155882
|
if (screen.key === "s") return job(["setup"]);
|
|
155681
155883
|
if (screen.key === "a") return job(["add-funds"]);
|
|
155682
155884
|
if (screen.key === "u") return job(["unshield"]);
|
|
@@ -155711,7 +155913,9 @@ ${HOST_TARGETS.map((host, index) => ` ${index + 1} ${hostNames[host] ?? host}`
|
|
|
155711
155913
|
}
|
|
155712
155914
|
const home = setupHome(deps.env);
|
|
155713
155915
|
const npmVersion = deps.walletVersion().npm;
|
|
155714
|
-
|
|
155916
|
+
const hosts = await addToHosts([host], home, deps, { npmVersion, ask: deps.stdinIsTTY() ? deps.ask : void 0 });
|
|
155917
|
+
if (hosts.kept.has(host)) return 0;
|
|
155918
|
+
if (hosts.added.has(host)) {
|
|
155715
155919
|
io.out(`Next: ask ${hostNames[host]} "what is my balance".
|
|
155716
155920
|
`);
|
|
155717
155921
|
return 0;
|