shinjuku-shielded 0.3.27 → 0.3.28

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/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": "adb0f68b23e192445ecb391a89f3e05dba89f05d0177aacdb092fbea3539fa85",
5
- "bytes": 11154518,
6
- "sourceCommit": "e8d63cd7fd58f3f334eea244fa5dc0e7b1c5c6be",
4
+ "sha256": "dd6ce54a50e0e58be863f647620b767cb760d1278ee089b74c10c98068383047",
5
+ "bytes": 11159107,
6
+ "sourceCommit": "b5316573de1f09bb207ce09a78d5ec4d02fc8035",
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",
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "shinjuku-shielded",
3
- "version": "0.3.27",
3
+ "version": "0.3.28",
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": "adb0f68b",
7
- "shinjukuSha256": "adb0f68b23e192445ecb391a89f3e05dba89f05d0177aacdb092fbea3539fa85",
6
+ "shinjukuRelease": "dd6ce54a",
7
+ "shinjukuSha256": "dd6ce54a50e0e58be863f647620b767cb760d1278ee089b74c10c98068383047",
8
8
  "license": "SEE LICENSE IN LICENSE.txt",
9
9
  "author": "Shinjuku Shielded",
10
10
  "homepage": "https://github.com/ShinjukuStaition/shinjuku-mcp#readme",
@@ -121953,7 +121953,8 @@ var CHAIN_RECHECK_MS = 6 * 60 * 6e4;
121953
121953
  var MCP_POLL_LIMIT_MS = 3 * 6e4;
121954
121954
  var firstCode5 = (error) => String(error?.message ?? error ?? "").split(/[\s:;(]/, 1)[0];
121955
121955
  function createMoveScheduler({ session, underLease, log = () => {
121956
- }, env = process.env, deps = {} }) {
121956
+ }, env = process.env, onSettled = () => {
121957
+ }, deps = {} }) {
121957
121958
  const now = deps.now ?? Date.now;
121958
121959
  const home = deps.home ?? setupHome(env);
121959
121960
  const readConfig = deps.readConfig ?? (() => readSetupConfig(home));
@@ -121987,6 +121988,7 @@ function createMoveScheduler({ session, underLease, log = () => {
121987
121988
  let interval;
121988
121989
  let closed = false;
121989
121990
  const failedAt = /* @__PURE__ */ new Map();
121991
+ const lastCredit = /* @__PURE__ */ new Map();
121990
121992
  const leaseFor = (pool) => async (task) => {
121991
121993
  if (resolve21(homeWalletPath(home, pool)) === sessionPath) return underLease(() => task());
121992
121994
  let free;
@@ -122070,6 +122072,14 @@ function createMoveScheduler({ session, underLease, log = () => {
122070
122072
  withTargetLease: leaseFor(move.to.pool)
122071
122073
  });
122072
122074
  log(`MCP_MOVE ${move.from.pool.slice(0, 8)} ${result.state}${result.code ? ` ${result.code}` : ""}`);
122075
+ const credit = (result.legs ?? []).map((leg) => leg?.creditTransaction).filter((signature) => typeof signature === "string" && signature).at(-1);
122076
+ if (credit && credit !== lastCredit.get(move.from.pool)) {
122077
+ lastCredit.set(move.from.pool, credit);
122078
+ try {
122079
+ onSettled(credit);
122080
+ } catch {
122081
+ }
122082
+ }
122073
122083
  } catch (error) {
122074
122084
  const code = firstCode5(error) || "wallet_move_leg_failed";
122075
122085
  result = { state: code === "wallet_locked" ? "waiting" : "failed", code, fromPool: move.from.pool, toPool: move.to.pool };
@@ -122909,10 +122919,16 @@ var CARRY_WAIT_CODES = /* @__PURE__ */ new Set([
122909
122919
  "wallet_locked"
122910
122920
  ]);
122911
122921
  var carryRefusedForGood = (carry) => carry?.state === "refused" && !CARRY_WAIT_CODES.has(carry.code);
122912
- function pocketCarryText(carry) {
122913
- if (carry?.state !== "refused") return "";
122922
+ function pocketCarryReason(carry) {
122923
+ if (carry && CARRY_DONE.has(carry.state)) return { done: true, waits: false, code: null, reason: "" };
122924
+ if (carry?.state !== "refused") return { done: false, waits: true, code: null, reason: "the wallet has not finished its check of the pool switch" };
122914
122925
  const code = String(carry.code ?? "");
122915
122926
  const reason = code === "p03_pocket_carry_source_fill_pending" || code === "p03_pocket_carry_source_payment_pending" ? "a pocket top-up or a pocket payment is not final yet" : code === "wallet_locked" ? "another wallet command uses the old pool's wallet now" : CARRY_WAIT_CODES.has(code) ? "the wallet has not finished its check of the pool switch" : code === "p03_pocket_carry_target_not_empty" ? "the new pool's wallet already has pocket accounts of its own" : "the pocket records of the two wallets do not match";
122927
+ return { done: false, waits: CARRY_WAIT_CODES.has(code), code, reason };
122928
+ }
122929
+ function pocketCarryText(carry) {
122930
+ if (carry?.state !== "refused") return "";
122931
+ const { code, reason } = pocketCarryReason(carry);
122916
122932
  if (CARRY_WAIT_CODES.has(code)) {
122917
122933
  return ` Your pocket accounts stay in the old pool's records for now (${reason}). The money in them is safe. The wallet tries again by itself in a minute.`;
122918
122934
  }
@@ -123142,7 +123158,9 @@ function createSuccessionScheduler(options) {
123142
123158
  },
123143
123159
  log = () => {
123144
123160
  },
123145
- carry = carryPocketBook
123161
+ carry = carryPocketBook,
123162
+ onSettled = () => {
123163
+ }
123146
123164
  } = options;
123147
123165
  const now = options.now ?? Date.now;
123148
123166
  const randomInt9 = options.randomInt ?? cryptoRandomInt;
@@ -123337,6 +123355,12 @@ function createSuccessionScheduler(options) {
123337
123355
  } catch {
123338
123356
  }
123339
123357
  }
123358
+ if (counts.legsDone > (job.legsDone ?? 0) && counts.transactions.length) {
123359
+ try {
123360
+ onSettled(counts.transactions.at(-1));
123361
+ } catch {
123362
+ }
123363
+ }
123340
123364
  if (result.state === "moved") {
123341
123365
  if ((prepared.extraAccounts ?? 0) > 0) return save2(store, job, { ...counts, attempts: 0, lastCode: void 0, nextTryAtMs: now() });
123342
123366
  return save2(store, job, { ...counts, state: "moved", attempts: 0, lastCode: void 0, nextTryAtMs: void 0 });
@@ -123539,11 +123563,30 @@ function createSuccessionScheduler(options) {
123539
123563
  }
123540
123564
  return views;
123541
123565
  }
123566
+ function pocketCarries() {
123567
+ const carries = [];
123568
+ for (const entry of listEntries()) {
123569
+ let job;
123570
+ try {
123571
+ job = readSuccessionJob(storeOf(entry.from), entry.from);
123572
+ } catch {
123573
+ job = void 0;
123574
+ }
123575
+ if (typeof job?.to !== "string") continue;
123576
+ carries.push({
123577
+ from: job.from,
123578
+ to: job.to,
123579
+ pocketCarry: job.pocketCarry ? { state: job.pocketCarry.state, code: job.pocketCarry.code ?? null } : null
123580
+ });
123581
+ }
123582
+ return carries;
123583
+ }
123542
123584
  return Object.freeze({
123543
123585
  tick,
123544
123586
  beforePay,
123545
123587
  status,
123546
123588
  openJobs,
123589
+ pocketCarries,
123547
123590
  running: () => Boolean(active),
123548
123591
  acknowledge(from, state) {
123549
123592
  try {
@@ -123578,6 +123621,7 @@ function startSuccessionScheduler({ store, openStore, session, underLease, log =
123578
123621
  status: () => [],
123579
123622
  acknowledge: () => false,
123580
123623
  openJobs: () => [],
123624
+ pocketCarries: () => [],
123581
123625
  running: () => false
123582
123626
  });
123583
123627
  }
@@ -125356,7 +125400,7 @@ function createWalletTools({
125356
125400
  deps: ops.autoPockets ?? {}
125357
125401
  });
125358
125402
  if (money.autoPockets === true) autoPockets.start();
125359
- const mover = createMoveScheduler({ session, underLease, log, deps: ops.move && typeof ops.move === "object" ? ops.move : {} });
125403
+ const mover = createMoveScheduler({ session, underLease, log, onSettled: refreshAtFinality, deps: ops.move && typeof ops.move === "object" ? ops.move : {} });
125360
125404
  if (ops.move !== false) mover.start();
125361
125405
  const succession = ops.succession === false ? void 0 : {
125362
125406
  successionStatus,
@@ -125462,7 +125506,9 @@ function createWalletTools({
125462
125506
  ...eta === void 0 ? {} : { etaSeconds: eta },
125463
125507
  ...Number.isInteger(item.legsTotal) ? { legsDone: Number.isInteger(item.legsDone) ? item.legsDone : 0, legsTotal: item.legsTotal } : {},
125464
125508
  ...typeof item.lastCode === "string" && item.lastCode ? { code: item.lastCode } : {},
125465
- ...Number.isFinite(item.updatedAtMs) ? { updatedAt: new Date(item.updatedAtMs).toISOString() } : {}
125509
+ ...Number.isFinite(item.updatedAtMs) ? { updatedAt: new Date(item.updatedAtMs).toISOString() } : {},
125510
+ // The pocket book carry (scheduler.mjs carryPockets): a refused carry keeps the pockets in the old pool's records.
125511
+ ...item.pocketCarry && typeof item.pocketCarry.state === "string" ? { pocketCarry: { state: item.pocketCarry.state, code: typeof item.pocketCarry.code === "string" ? item.pocketCarry.code : null } } : {}
125466
125512
  };
125467
125513
  });
125468
125514
  };
@@ -126931,7 +126977,7 @@ function createWalletTools({
126931
126977
  const moveStatus = {
126932
126978
  name: "wallet_move_status",
126933
126979
  title: "Pool switch status",
126934
- description: "Use this when the user asks why their balance moved, whether the pool switch is done, or when an answer shows poolSwitch, or when wallet_balance shows movingAtomic or pools. When the facilitator switches to a new pool, this wallet moves the whole balance there by itself (no fee, no step by the user); poolSwitches lists each switch with its state (pending, scheduled, running, done, failed) and a plain message to tell the user. Also called wallet_pool_switch_status. When the facilitator retires a pool, this wallet moves its whole balance from the old pool to the new one by itself (no fee, no step by the user): each leg pays one account of the old pool to the facilitator, which credits the same amount to a one-time address of this wallet in the new pool. This tool reads the move's state and every leg (amountAtomic, state planned|paid|credited|done|failed, moveId); it pays nothing and signs nothing. state: none (no move announced), waiting or running (it continues by itself), done, failed (code, detail, and next say why and what to do).",
126980
+ description: "Use this when the user asks why their balance moved, whether the pool switch is done, or when an answer shows poolSwitch, or when wallet_balance shows movingAtomic or pools. When the facilitator switches to a new pool, this wallet moves the whole balance there by itself (no fee, no step by the user); poolSwitches lists each switch with its state (pending, scheduled, running, done, failed) and a plain message to tell the user, plus pocketCarry when the wallet tried to move the old pool's pocket records to the new pool (state carried, completed, already, none, or refused with a code; the message says what a refusal means). Also called wallet_pool_switch_status. When the facilitator retires a pool, this wallet moves its whole balance from the old pool to the new one by itself (no fee, no step by the user): each leg pays one account of the old pool to the facilitator, which credits the same amount to a one-time address of this wallet in the new pool. This tool reads the move's state and every leg (amountAtomic, state planned|paid|credited|done|failed, moveId); it pays nothing and signs nothing. state: none (no move announced), waiting or running (it continues by itself), done, failed (code, detail, and next say why and what to do).",
126935
126981
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
126936
126982
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
126937
126983
  async run() {
@@ -126970,7 +127016,14 @@ function createWalletTools({
126970
127016
  startSuccession: { value: () => {
126971
127017
  if (!succession || successionHandle) return;
126972
127018
  try {
126973
- successionHandle = succession.startSuccessionScheduler({ store: session.openStore(), openStore: () => session.openStore(), session, underLease, log });
127019
+ successionHandle = succession.startSuccessionScheduler({
127020
+ store: session.openStore(),
127021
+ openStore: () => session.openStore(),
127022
+ session,
127023
+ underLease,
127024
+ log,
127025
+ deps: { onSettled: refreshAtFinality }
127026
+ });
126974
127027
  } catch (error) {
126975
127028
  log(`MCP_POOL_SWITCH_SCHEDULER_NOT_STARTED: ${error?.name ?? "Error"}`);
126976
127029
  }
@@ -132595,6 +132648,55 @@ async function spendGate(args, values, deps, io, { amountAtomic, again }) {
132595
132648
  if (!followed || index < 0 || resolve37(followed) === walletFile) return args;
132596
132649
  return [...args.slice(0, index + 1), followed, ...args.slice(index + 2)];
132597
132650
  }
132651
+ async function pocketFillGate(args, values, deps, io) {
132652
+ if (!values.has("--wallet") || values.has("--dwell-check")) return args;
132653
+ const walletFile = resolve37(values.get("--wallet"));
132654
+ const session = lazySpendSession(walletFile, values, deps);
132655
+ let handle;
132656
+ try {
132657
+ handle = (deps.startSuccessionScheduler ?? startSuccessionScheduler)({
132658
+ session,
132659
+ openStore: () => session.openStore(),
132660
+ underLease: sessionLease(session),
132661
+ log: () => {
132662
+ },
132663
+ env: deps.env
132664
+ });
132665
+ } catch {
132666
+ return args;
132667
+ }
132668
+ let carries;
132669
+ try {
132670
+ await Promise.resolve(handle.tick?.()).catch(() => {
132671
+ });
132672
+ carries = handle.pocketCarries?.() ?? [];
132673
+ } catch {
132674
+ carries = [];
132675
+ } finally {
132676
+ handle.stop?.();
132677
+ }
132678
+ if (!carries.length) return args;
132679
+ const home = setupHome(deps.env);
132680
+ const pathOf = (pool) => resolve37(homeWalletPath(home, pool));
132681
+ let target = walletFile;
132682
+ for (let hop = 0; hop < carries.length; hop += 1) {
132683
+ const next = carries.find((item) => pathOf(item.from) === target && existsSync(pathOf(item.to)));
132684
+ if (!next) break;
132685
+ target = pathOf(next.to);
132686
+ }
132687
+ for (const item of carries.filter((entry) => pathOf(entry.to) === target)) {
132688
+ const carry = pocketCarryReason(item.pocketCarry);
132689
+ if (carry.done) continue;
132690
+ if (carry.waits) {
132691
+ throw new PublicFailure(`wallet_pool_switch_wait_retry_same_request: Your facilitator switched to a new pool, and your pocket records are not in the new pool's wallet yet (${carry.reason}). Your pockets and the money in them are safe; nothing was filled or signed. Run the same pocket fill command again in 60 s`);
132692
+ }
132693
+ throw new PublicFailure(`wallet_pool_switch_failed: Your facilitator switched to a new pool, and the wallet could not move your pocket records to the new pool's wallet (${carry.reason}). Your pockets and the money in them are safe; nothing was filled or signed. Tell the operator this code. lastCode: ${carry.code}`);
132694
+ }
132695
+ if (target === walletFile) return args;
132696
+ io.err("pool switch: pocket fill uses your wallet of the facilitator's new pool\n");
132697
+ const index = args.indexOf("--wallet");
132698
+ return index < 0 ? args : [...args.slice(0, index + 1), target, ...args.slice(index + 2)];
132699
+ }
132598
132700
  async function runCurl(values, deps) {
132599
132701
  const io = deps.io;
132600
132702
  const policy = createSpendPolicy({
@@ -133943,7 +134045,7 @@ var COMMANDS = [
133943
134045
  }
133944
134046
  }
133945
134047
  },
133946
- run: (args, values, deps) => deps.pocketMain(["fill", ...args])
134048
+ run: async (args, values, deps, io) => deps.pocketMain(["fill", ...await pocketFillGate(args, values, deps, io)])
133947
134049
  },
133948
134050
  {
133949
134051
  name: "pocket release",