shinjuku-shield 0.3.102 → 0.3.103
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 +92 -11
package/README.md
CHANGED
|
@@ -6,13 +6,13 @@ answers privately, in a terminal chat or for your agent app. Its `mcp`
|
|
|
6
6
|
command runs a local MCP server (stdio) for your agent. Your keys never
|
|
7
7
|
leave your machine.
|
|
8
8
|
|
|
9
|
-
This is version 0.3.
|
|
9
|
+
This is version 0.3.103. The npm packages `shinjuku-shield` and
|
|
10
10
|
`shinjuku-shielded` hold the same files. The command is `shinjuku`.
|
|
11
11
|
|
|
12
12
|
## Set up
|
|
13
13
|
|
|
14
14
|
```sh
|
|
15
|
-
npx -y --no-audit --no-fund shinjuku-shield@0.3.
|
|
15
|
+
npx -y --no-audit --no-fund shinjuku-shield@0.3.103 setup
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
Setup makes the wallet on this machine, a private passphrase file, and the
|
|
@@ -24,7 +24,7 @@ server to that host's config.
|
|
|
24
24
|
## The `shinjuku` command
|
|
25
25
|
|
|
26
26
|
```sh
|
|
27
|
-
npm install -g --no-audit --no-fund shinjuku@0.3.
|
|
27
|
+
npm install -g --no-audit --no-fund shinjuku@0.3.103
|
|
28
28
|
shinjuku help
|
|
29
29
|
```
|
|
30
30
|
|
|
@@ -36,13 +36,13 @@ Every wallet command works after `shinjuku`, for example `shinjuku balance`,
|
|
|
36
36
|
Claude Code:
|
|
37
37
|
|
|
38
38
|
```sh
|
|
39
|
-
claude mcp add --scope user shinjuku -- 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.103 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.103", "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": "b5da74cb566cf4df5a7381cbb3eb28797aff16377f170472b6fcefce230db2a2",
|
|
5
|
+
"bytes": 12800520,
|
|
6
|
+
"sourceCommit": "b5ed9d0ff1a26115297f6e4dc56473ca9b053446",
|
|
7
7
|
"sourceDirty": false,
|
|
8
8
|
"installRecordMatchesLockfile": true,
|
|
9
9
|
"releaseRule": "valid only when two fresh npm ci --ignore-scripts builds on different OSes give the same sha256; installRecordMatchesLockfile true means every entry npm installed equals its package-lock.json entry and every entry not marked optional, devOptional included, is installed: an optional entry (a package for another platform) may be absent",
|
|
@@ -1297,5 +1297,5 @@
|
|
|
1297
1297
|
"version": "1.8.0"
|
|
1298
1298
|
}
|
|
1299
1299
|
],
|
|
1300
|
-
"publishedAt": "2026-10-
|
|
1300
|
+
"publishedAt": "2026-10-24T16:04:06.349Z"
|
|
1301
1301
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shinjuku-shield",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.103",
|
|
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": "b5da74cb",
|
|
7
|
+
"shinjukuSha256": "b5da74cb566cf4df5a7381cbb3eb28797aff16377f170472b6fcefce230db2a2",
|
|
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
|
@@ -50123,6 +50123,7 @@ function whenRequestsSent(match, { count: count2 = 1, maxMs = 40, settled } = {}
|
|
|
50123
50123
|
}
|
|
50124
50124
|
}
|
|
50125
50125
|
timer = setTimeout(() => done(false), maxMs);
|
|
50126
|
+
timer.unref?.();
|
|
50126
50127
|
sent.subscribe(onSent);
|
|
50127
50128
|
failed.subscribe(onFailed);
|
|
50128
50129
|
settled?.then(() => done(false), () => done(false));
|
|
@@ -96324,8 +96325,12 @@ function returnArrivedFloatRefundBudgets(store, snapshot) {
|
|
|
96324
96325
|
for (const name of store.listWal()) {
|
|
96325
96326
|
if (!name.startsWith(FLOAT_PAYMENT_WAL_PREFIX)) continue;
|
|
96326
96327
|
const record = store.readWal(name);
|
|
96327
|
-
if (record?.schema !== FLOAT_PAYMENT_SCHEMA) continue;
|
|
96328
|
-
if (record.state
|
|
96328
|
+
if (record?.schema !== FLOAT_PAYMENT_SCHEMA || typeof record.innerRequestId !== "string") continue;
|
|
96329
|
+
if (record.state === "submitted") {
|
|
96330
|
+
if (refundArrived(snapshot, record.refundTo)) releaseRefundedReservation({ store, requestId: record.innerRequestId });
|
|
96331
|
+
continue;
|
|
96332
|
+
}
|
|
96333
|
+
if (record.state !== "refund_pending") continue;
|
|
96329
96334
|
const arrivedNow = refundArrived(snapshot, record.refundTo);
|
|
96330
96335
|
if (arrivedNow) releaseRefundedReservation({ store, requestId: record.innerRequestId });
|
|
96331
96336
|
const outcome = arrivedNow ? "refund_arrived" : record.refundOutcome === void 0 && refundCountStopped(record, refreshedAtMs, knowsRecipients) ? "refund_not_seen" : void 0;
|
|
@@ -105409,6 +105414,16 @@ function lazyProofEntry(store, name) {
|
|
|
105409
105414
|
return String(read()?.state);
|
|
105410
105415
|
} };
|
|
105411
105416
|
}
|
|
105417
|
+
function floatRefundNoteHeld(snapshot, refundTo) {
|
|
105418
|
+
const outputs = Array.isArray(snapshot?.outputs) ? snapshot.outputs : [];
|
|
105419
|
+
let address5;
|
|
105420
|
+
try {
|
|
105421
|
+
address5 = decodeShieldedSolanaP03Address(String(refundTo));
|
|
105422
|
+
} catch {
|
|
105423
|
+
return false;
|
|
105424
|
+
}
|
|
105425
|
+
return outputs.some((output2) => output2?.kind === "note" && output2.diversifier === address5.diversifier.toString() && output2.recipientX === address5.recipientX.toString());
|
|
105426
|
+
}
|
|
105412
105427
|
function classify(name, record) {
|
|
105413
105428
|
const state = String(record?.state);
|
|
105414
105429
|
if (name.startsWith("deposit-") && record?.schema === DEPOSIT_WAL_SCHEMA) {
|
|
@@ -105481,8 +105496,10 @@ function computeBalance({ store, snapshotRead, source = "local", now = Date.now(
|
|
|
105481
105496
|
...entry.record.relay?.approvedOnChain ? { approvalStanding: true } : {}
|
|
105482
105497
|
}));
|
|
105483
105498
|
const receipts = records.filter((entry) => entry.type === "payment" && entry.phase === "done");
|
|
105484
|
-
const refunded = new Set(records.filter((entry) => entry.type === "float-payment" && entry.state === "refund_pending").map((entry) => entry.record.innerRequestId).filter((id) => typeof id === "string"));
|
|
105485
|
-
const
|
|
105499
|
+
const refunded = new Set(records.filter((entry) => entry.type === "float-payment" && (entry.state === "refund_pending" || entry.state === "submitted" && floatRefundNoteHeld(snapshotRead?.snapshot, entry.record.refundTo))).map((entry) => entry.record.innerRequestId).filter((id) => typeof id === "string"));
|
|
105500
|
+
const sellerReceipts = receipts.filter((entry) => !String(entry.record.url ?? "").startsWith(SELF_PAY_ORIGIN2) && !String(entry.record.url ?? "").includes(POOL_MOVE_PATH2));
|
|
105501
|
+
const paid = sellerReceipts.filter((entry) => !refunded.has(entry.record.requestId));
|
|
105502
|
+
const refundedPaid = sellerReceipts.filter((entry) => refunded.has(entry.record.requestId));
|
|
105486
105503
|
const sum2 = (values) => values.reduce((total, value) => total + BigInt(value ?? "0"), 0n);
|
|
105487
105504
|
const config = state.config ?? {};
|
|
105488
105505
|
const capOrNone = (value) => String(value) === NO_LIMIT_ATOMIC2 ? "none" : value;
|
|
@@ -105506,6 +105523,8 @@ function computeBalance({ store, snapshotRead, source = "local", now = Date.now(
|
|
|
105506
105523
|
pendingDeposits,
|
|
105507
105524
|
paidAtomic: sum2(paid.map((entry) => paymentAmount(entry.record))).toString(),
|
|
105508
105525
|
paidReceipts: paid.length,
|
|
105526
|
+
refundedAtomic: sum2(refundedPaid.map((entry) => paymentAmount(entry.record))).toString(),
|
|
105527
|
+
refundedPayments: refundedPaid.length,
|
|
105509
105528
|
unshieldedAtomic: sum2(records.filter((entry) => entry.type === "unshield" && entry.phase === "done" && !entry.name.startsWith(POCKET_FILL_RECORD) && !entry.name.startsWith(MERGE_RECORD)).map((entry) => entry.record.amountAtomic)).toString(),
|
|
105510
105529
|
...budget ? { budget } : {},
|
|
105511
105530
|
lastRefresh: null
|
|
@@ -105833,6 +105852,7 @@ var init_balance = __esm({
|
|
|
105833
105852
|
init_config();
|
|
105834
105853
|
init_commandName();
|
|
105835
105854
|
init_requestId();
|
|
105855
|
+
init_ShieldedSolanaP03QuoteCrypto();
|
|
105836
105856
|
PAY_ME_WAL_SCHEMA = "carbon-shielded-wallet/pay-me/v1";
|
|
105837
105857
|
BALANCE_SNAPSHOT_SCHEMA = "carbon-shielded-wallet/balance-snapshot/v1";
|
|
105838
105858
|
BALANCE_SNAPSHOT_FILE = "balance-snapshot.json";
|
|
@@ -128665,7 +128685,9 @@ ${canonical5}`;
|
|
|
128665
128685
|
const sellerTransaction = view2.sellerTransaction ?? knownSellerTransfer(record) ?? (SIGNATURE_TEXT.test(String(read ?? "")) ? read : null);
|
|
128666
128686
|
row(name.slice(FLOAT_PAYMENT_WAL_PREFIX.length), record, { ...view2, sellerTransaction }, {
|
|
128667
128687
|
scheme: "exact",
|
|
128668
|
-
|
|
128688
|
+
// RC1 (mcp56 pass of 0.3.102, hypernatt): this said "a later wallet_receipts shows it", but Shinjuku drops a final
|
|
128689
|
+
// row's link fields, landedTransaction too (float.mjs retain, owner decision 4), about 1 s after the settle.
|
|
128690
|
+
...sellerTransaction === null ? { note: "the seller served this request, so it was paid and no refund comes; the seller sent no transfer signature, and Shinjuku keeps no link between this payment and its transfer once the payment is final, so this receipt has no seller transaction to show" } : {}
|
|
128669
128691
|
});
|
|
128670
128692
|
}
|
|
128671
128693
|
for (const name of names) {
|
|
@@ -134319,7 +134341,7 @@ var init_tools = __esm({
|
|
|
134319
134341
|
capRaiseText = (flag3) => {
|
|
134320
134342
|
if (capFlagFromLaunchLine(flag3)) {
|
|
134321
134343
|
const both = flag3 === "--max-payment" ? " (raise the 24-hour payment limit there too when it is below the new amount: the wallet does not start with it lower)" : "";
|
|
134322
|
-
return `The ${capName(flag3)} is set in this app's wallet entry; only the user (your owner) can change it there${both}, with amounts in USDC like 0.5, then reconnect the wallet (restart the agent host). Where the entry is: Claude Desktop: claude_desktop_config.json; Cursor: ~/.cursor/mcp.json; Claude Code: claude mcp get
|
|
134344
|
+
return `The ${capName(flag3)} is set in this app's wallet entry; only the user (your owner) can change it there${both}, with amounts in USDC like 0.5, then reconnect the wallet (restart the agent host). Where the entry is: Claude Desktop: claude_desktop_config.json; Cursor: ~/.cursor/mcp.json; Claude Code: claude mcp get ${MCP_SERVER_NAME} shows the entry (an entry added by hand can have another name: claude mcp list shows it), then claude mcp remove ${MCP_SERVER_NAME} and claude mcp add it again with the new value; Hermes: config.yaml. Running setup does not change this limit: the value in the entry wins over the limit setup records.`;
|
|
134323
134345
|
}
|
|
134324
134346
|
return `The ${capName(flag3)} comes from the wallet's settings. To change it, the user runs ${terminalCommand2("limits")} in a terminal: it asks each limit as a question (amounts in USDC like 0.5, or Enter for no limit). Then the user restarts the agent host.`;
|
|
134325
134347
|
};
|
|
@@ -136052,6 +136074,7 @@ __export(chat_exports, {
|
|
|
136052
136074
|
DEFAULT_MODEL: () => DEFAULT_MODEL2,
|
|
136053
136075
|
chatCaps: () => chatCaps,
|
|
136054
136076
|
hideProgressLines: () => hideProgressLines,
|
|
136077
|
+
holdProgressLines: () => holdProgressLines,
|
|
136055
136078
|
isProgressLine: () => isProgressLine,
|
|
136056
136079
|
knownPrivateBalance: () => knownPrivateBalance,
|
|
136057
136080
|
leastAnswerAtomic: () => leastAnswerAtomic,
|
|
@@ -136151,6 +136174,33 @@ function hideProgressLines(stream = process.stderr) {
|
|
|
136151
136174
|
stream.write = original;
|
|
136152
136175
|
};
|
|
136153
136176
|
}
|
|
136177
|
+
function holdProgressLines(stream = process.stderr) {
|
|
136178
|
+
const original = stream.write;
|
|
136179
|
+
const held = [];
|
|
136180
|
+
stream.write = function write(chunk, encoding, callback) {
|
|
136181
|
+
const text3 = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString(typeof encoding === "string" ? encoding : "utf8");
|
|
136182
|
+
let passed = "";
|
|
136183
|
+
let kept2 = 0;
|
|
136184
|
+
for (const line of text3.split(/(?<=\n)/)) {
|
|
136185
|
+
if (line.endsWith("\n") && PROGRESS_LINE.test(line)) {
|
|
136186
|
+
held.push(line);
|
|
136187
|
+
kept2 += 1;
|
|
136188
|
+
} else passed += line;
|
|
136189
|
+
}
|
|
136190
|
+
if (kept2 === 0) return original.call(stream, chunk, encoding, callback);
|
|
136191
|
+
const done = typeof encoding === "function" ? encoding : callback;
|
|
136192
|
+
if (passed) return original.call(stream, passed, done);
|
|
136193
|
+
if (typeof done === "function") done();
|
|
136194
|
+
return true;
|
|
136195
|
+
};
|
|
136196
|
+
let released = false;
|
|
136197
|
+
return () => {
|
|
136198
|
+
if (released) return;
|
|
136199
|
+
released = true;
|
|
136200
|
+
stream.write = original;
|
|
136201
|
+
if (held.length) original.call(stream, held.join(""));
|
|
136202
|
+
};
|
|
136203
|
+
}
|
|
136154
136204
|
function errorCodeOf(error) {
|
|
136155
136205
|
if (error?.name === "InferenceError" && typeof error.code === "string") return error.code;
|
|
136156
136206
|
if (error?.name === "SpendRefusalError" && typeof error.error === "string") return error.error;
|
|
@@ -162559,7 +162609,7 @@ async function runCurl(values, deps) {
|
|
|
162559
162609
|
${CURL_USEPOD_NEXT}`, { cause: error });
|
|
162560
162610
|
else throw curlFailure(error);
|
|
162561
162611
|
} finally {
|
|
162562
|
-
await session
|
|
162612
|
+
await closeTimed(session, "curl-price");
|
|
162563
162613
|
}
|
|
162564
162614
|
}
|
|
162565
162615
|
if (response) return curlOutput(response, values, deps, probeId);
|
|
@@ -162597,10 +162647,31 @@ ${CURL_USEPOD_NEXT}`, { cause: error });
|
|
|
162597
162647
|
}
|
|
162598
162648
|
throw curlFailure(error);
|
|
162599
162649
|
}
|
|
162650
|
+
sessionMark(session)("curl-paid-returned");
|
|
162651
|
+
return await curlOutput(response, values, deps, requestId);
|
|
162600
162652
|
} finally {
|
|
162601
|
-
await session
|
|
162653
|
+
await closeTimed(session, "curl");
|
|
162654
|
+
}
|
|
162655
|
+
}
|
|
162656
|
+
function sessionMark(session) {
|
|
162657
|
+
let mark = () => {
|
|
162658
|
+
};
|
|
162659
|
+
try {
|
|
162660
|
+
if (typeof session.timing === "function") mark = session.timing();
|
|
162661
|
+
} catch {
|
|
162602
162662
|
}
|
|
162603
|
-
return
|
|
162663
|
+
return (phase) => {
|
|
162664
|
+
try {
|
|
162665
|
+
mark(phase);
|
|
162666
|
+
} catch {
|
|
162667
|
+
}
|
|
162668
|
+
};
|
|
162669
|
+
}
|
|
162670
|
+
async function closeTimed(session, what) {
|
|
162671
|
+
const mark = sessionMark(session);
|
|
162672
|
+
mark(`${what}-close-start`);
|
|
162673
|
+
await session.close();
|
|
162674
|
+
mark(`${what}-closed`);
|
|
162604
162675
|
}
|
|
162605
162676
|
async function curlOutput(response, values, deps, requestId) {
|
|
162606
162677
|
const io = deps.io;
|
|
@@ -162823,11 +162894,19 @@ async function runInfer(values, deps) {
|
|
|
162823
162894
|
}
|
|
162824
162895
|
} catch (error) {
|
|
162825
162896
|
if (quiet && !given && !NOTHING_PAID_TEXT.test(String(error?.message ?? ""))) values.set(INFER_STOPPED_ID, requestId);
|
|
162897
|
+
stopWatch();
|
|
162898
|
+
await closeTimed(session, "infer");
|
|
162826
162899
|
throw error;
|
|
162900
|
+
}
|
|
162901
|
+
stopWatch();
|
|
162902
|
+
try {
|
|
162903
|
+
sessionMark(session)("infer-paid-returned");
|
|
162904
|
+
inferOutput(result, { values, io, model, quiet, requestId });
|
|
162827
162905
|
} finally {
|
|
162828
|
-
|
|
162829
|
-
await session.close();
|
|
162906
|
+
await closeTimed(session, "infer");
|
|
162830
162907
|
}
|
|
162908
|
+
}
|
|
162909
|
+
function inferOutput(result, { values, io, model, quiet, requestId }) {
|
|
162831
162910
|
const paid = String(result.paidAtomic ?? "?");
|
|
162832
162911
|
const paidText = usdcOr(result.paidAtomic);
|
|
162833
162912
|
const stopped = result.finishReason === "length" ? " (the answer stopped at --max-tokens)" : "";
|
|
@@ -167901,6 +167980,7 @@ function defaultDependencies() {
|
|
|
167901
167980
|
* what happened. Ctrl-C, or an input that ends, now stops the command with QuestionCancelled (one plain line).
|
|
167902
167981
|
*/
|
|
167903
167982
|
ask: (question) => new Promise((resolveAnswer, rejectAnswer) => {
|
|
167983
|
+
const releaseProgress = holdProgressLines(process.stderr);
|
|
167904
167984
|
const prompt = createInterface2({ input: process.stdin, output: process.stderr, terminal: true });
|
|
167905
167985
|
let answered2 = false;
|
|
167906
167986
|
let interrupted = false;
|
|
@@ -167910,6 +167990,7 @@ function defaultDependencies() {
|
|
|
167910
167990
|
prompt.close();
|
|
167911
167991
|
});
|
|
167912
167992
|
prompt.on("close", () => {
|
|
167993
|
+
releaseProgress();
|
|
167913
167994
|
if (!answered2) rejectAnswer(new QuestionCancelled(interrupted));
|
|
167914
167995
|
});
|
|
167915
167996
|
prompt.question(question, (answer) => {
|