routstrd 0.4.1 → 0.4.2

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/dist/index.js CHANGED
@@ -21234,7 +21234,10 @@ var init_constants = __esm(() => {
21234
21234
  // src/tui/usage/data.ts
21235
21235
  async function fetchStatus() {
21236
21236
  try {
21237
- const result = await callDaemon("/status");
21237
+ const [result, config] = await Promise.all([
21238
+ callDaemon("/status"),
21239
+ loadConfig()
21240
+ ]);
21238
21241
  if (result.error)
21239
21242
  return null;
21240
21243
  const output = result.output;
@@ -21242,6 +21245,7 @@ async function fetchStatus() {
21242
21245
  daemon: output?.daemon || "unknown",
21243
21246
  wallet: output?.wallet || "unknown",
21244
21247
  mode: output?.mode || "apikeys",
21248
+ url: getDaemonBaseUrl(config),
21245
21249
  error: output?.error
21246
21250
  };
21247
21251
  } catch {
@@ -21559,6 +21563,12 @@ function renderOverview(stats, balance, status, width) {
21559
21563
  const walletColor = status.wallet === "connected" ? COLORS.green : COLORS.red;
21560
21564
  const modeColor = COLORS.cyan;
21561
21565
  statusLines.push(`${COLORS.bold}Daemon:${COLORS.reset} ${daemonColor}${status.daemon}${COLORS.reset}`);
21566
+ if (status.url) {
21567
+ const label = "Running on: ";
21568
+ const maxUrlLen = Math.max(8, halfWidth2 - 4 - label.length);
21569
+ const url = status.url.length > maxUrlLen ? `${status.url.slice(0, Math.max(0, maxUrlLen - 1))}\u2026` : status.url;
21570
+ statusLines.push(`${COLORS.bold}${label}${COLORS.reset} ${COLORS.cyan}${url}${COLORS.reset}`);
21571
+ }
21562
21572
  statusLines.push(`${COLORS.bold}Wallet:${COLORS.reset} ${walletColor}${status.wallet}${COLORS.reset}`);
21563
21573
  statusLines.push(`${COLORS.bold}Mode:${COLORS.reset} ${modeColor}${status.mode}${COLORS.reset}`);
21564
21574
  if (status.error) {
@@ -22276,6 +22286,53 @@ var {
22276
22286
 
22277
22287
  // src/cli.ts
22278
22288
  init_start_daemon();
22289
+
22290
+ // src/daemon/config-store.ts
22291
+ init_config();
22292
+ init_logger();
22293
+ import {
22294
+ chmodSync,
22295
+ existsSync as existsSync4,
22296
+ mkdirSync as mkdirSync2,
22297
+ readFileSync,
22298
+ renameSync,
22299
+ unlinkSync,
22300
+ writeFileSync
22301
+ } from "fs";
22302
+ var REQUESTS_DIR = `${CONFIG_DIR}/requests`;
22303
+ function chmodIgnoreErrors(path, mode) {
22304
+ try {
22305
+ chmodSync(path, mode);
22306
+ } catch {}
22307
+ }
22308
+ function ensureDirsSync() {
22309
+ try {
22310
+ mkdirSync2(CONFIG_DIR, { recursive: true, mode: 448 });
22311
+ } catch {}
22312
+ chmodSync(CONFIG_DIR, 448);
22313
+ try {
22314
+ mkdirSync2(REQUESTS_DIR, { recursive: true, mode: 448 });
22315
+ } catch {}
22316
+ chmodSync(REQUESTS_DIR, 448);
22317
+ }
22318
+ function saveDaemonConfig(config) {
22319
+ ensureDirsSync();
22320
+ const temporaryFile = `${CONFIG_FILE}.${process.pid}.tmp`;
22321
+ try {
22322
+ writeFileSync(temporaryFile, JSON.stringify(config, null, 2), {
22323
+ mode: 384
22324
+ });
22325
+ renameSync(temporaryFile, CONFIG_FILE);
22326
+ } catch (error) {
22327
+ try {
22328
+ unlinkSync(temporaryFile);
22329
+ } catch {}
22330
+ throw error;
22331
+ }
22332
+ chmodIgnoreErrors(CONFIG_FILE, 384);
22333
+ }
22334
+
22335
+ // src/cli.ts
22279
22336
  init_daemon_client();
22280
22337
 
22281
22338
  // src/utils/clients.ts
@@ -22287,7 +22344,7 @@ import { join as join3 } from "path";
22287
22344
 
22288
22345
  // src/integrations/opencode.ts
22289
22346
  init_daemon_client();
22290
- import { existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
22347
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
22291
22348
  import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
22292
22349
  import { dirname as dirname2 } from "path";
22293
22350
  var OPENCODE_SMALL_MODEL = "routstr/minimax-m2.5";
@@ -22299,7 +22356,7 @@ Installing routstr models in opencode.json...`);
22299
22356
  const baseUrl = getDaemonBaseUrl(config);
22300
22357
  let opencodeConfig;
22301
22358
  try {
22302
- if (existsSync4(configPath)) {
22359
+ if (existsSync5(configPath)) {
22303
22360
  const content = await readFile2(configPath, "utf-8");
22304
22361
  opencodeConfig = JSON.parse(content);
22305
22362
  } else {
@@ -22313,7 +22370,7 @@ Installing routstr models in opencode.json...`);
22313
22370
  opencodeConfig.provider = {};
22314
22371
  }
22315
22372
  try {
22316
- mkdirSync2(dirname2(configPath), { recursive: true });
22373
+ mkdirSync3(dirname2(configPath), { recursive: true });
22317
22374
  const data = await callDaemon("/models");
22318
22375
  const models = data.output?.models || [];
22319
22376
  if (models.length === 0) {
@@ -22344,7 +22401,7 @@ Installing routstr models in opencode.json...`);
22344
22401
 
22345
22402
  // src/integrations/pi.ts
22346
22403
  init_daemon_client();
22347
- import { existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
22404
+ import { existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
22348
22405
  import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
22349
22406
  import { dirname as dirname3 } from "path";
22350
22407
  async function installPiIntegration(config, apiKey, integrationConfig) {
@@ -22355,7 +22412,7 @@ Installing routstr models in pi models.json...`);
22355
22412
  const baseUrl = `${getDaemonBaseUrl(config)}/v1`;
22356
22413
  let piConfig = {};
22357
22414
  try {
22358
- if (existsSync5(configPath)) {
22415
+ if (existsSync6(configPath)) {
22359
22416
  const content = await readFile3(configPath, "utf-8");
22360
22417
  piConfig = JSON.parse(content);
22361
22418
  }
@@ -22367,21 +22424,25 @@ Installing routstr models in pi models.json...`);
22367
22424
  piConfig.providers = {};
22368
22425
  }
22369
22426
  try {
22370
- mkdirSync3(dirname3(configPath), { recursive: true });
22427
+ mkdirSync4(dirname3(configPath), { recursive: true });
22371
22428
  const data = await callDaemon("/models");
22372
22429
  const models = data.output?.models || [];
22373
22430
  if (models.length === 0) {
22374
22431
  console.log("No models found from routstr daemon.");
22375
22432
  return;
22376
22433
  }
22434
+ const existingModels = new Map((piConfig.providers["routstr"]?.models ?? []).map((m) => [m.id, m]));
22377
22435
  const providerModels = models.map((model) => {
22378
- const entry = { id: model.id };
22436
+ const previous = existingModels.get(model.id);
22437
+ const entry = previous ? { ...previous } : { id: model.id };
22438
+ entry.id = model.id;
22379
22439
  if (model.context_length !== undefined && model.context_length > 0) {
22380
22440
  entry.contextWindow = model.context_length;
22381
22441
  }
22382
22442
  return entry;
22383
22443
  });
22384
22444
  piConfig.providers["routstr"] = {
22445
+ ...piConfig.providers["routstr"] ?? {},
22385
22446
  baseUrl,
22386
22447
  api: "openai-completions",
22387
22448
  apiKey,
@@ -22396,7 +22457,7 @@ Installing routstr models in pi models.json...`);
22396
22457
 
22397
22458
  // src/integrations/openclaw.ts
22398
22459
  init_daemon_client();
22399
- import { existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
22460
+ import { existsSync as existsSync7, mkdirSync as mkdirSync5 } from "fs";
22400
22461
  import { readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
22401
22462
  import { dirname as dirname4 } from "path";
22402
22463
  var OPENCLAW_PROVIDER_ID = "routstr";
@@ -22410,7 +22471,7 @@ Installing routstr models in openclaw.json...`);
22410
22471
  const baseUrl = getDaemonBaseUrl(config);
22411
22472
  let openclawConfig = {};
22412
22473
  try {
22413
- if (existsSync6(configPath)) {
22474
+ if (existsSync7(configPath)) {
22414
22475
  const content = await readFile4(configPath, "utf-8");
22415
22476
  openclawConfig = JSON.parse(content);
22416
22477
  }
@@ -22431,7 +22492,7 @@ Installing routstr models in openclaw.json...`);
22431
22492
  openclawConfig.agents.defaults = {};
22432
22493
  }
22433
22494
  try {
22434
- mkdirSync4(dirname4(configPath), { recursive: true });
22495
+ mkdirSync5(dirname4(configPath), { recursive: true });
22435
22496
  const data = await callDaemon("/models");
22436
22497
  const models = data.output?.models || [];
22437
22498
  if (models.length === 0) {
@@ -22472,7 +22533,7 @@ Installing routstr models in openclaw.json...`);
22472
22533
 
22473
22534
  // src/integrations/claudecode.ts
22474
22535
  init_daemon_client();
22475
- import { existsSync as existsSync7, mkdirSync as mkdirSync5 } from "fs";
22536
+ import { existsSync as existsSync8, mkdirSync as mkdirSync6 } from "fs";
22476
22537
  import { readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
22477
22538
  import { dirname as dirname5 } from "path";
22478
22539
  async function installClaudeCodeIntegration(config, apiKey, integrationConfig) {
@@ -22483,7 +22544,7 @@ Installing routstr configuration in ${configPath}...`);
22483
22544
  const baseUrl = getDaemonBaseUrl(config);
22484
22545
  let settings = {};
22485
22546
  try {
22486
- if (existsSync7(configPath)) {
22547
+ if (existsSync8(configPath)) {
22487
22548
  const content = await readFile5(configPath, "utf-8");
22488
22549
  settings = JSON.parse(content);
22489
22550
  }
@@ -22520,7 +22581,7 @@ Installing routstr configuration in ${configPath}...`);
22520
22581
  console.error("Failed to fetch models for Claude Code integration:", error);
22521
22582
  }
22522
22583
  try {
22523
- mkdirSync5(dirname5(configPath), { recursive: true });
22584
+ mkdirSync6(dirname5(configPath), { recursive: true });
22524
22585
  await writeFile5(configPath, JSON.stringify(settings, null, 2));
22525
22586
  console.log(`Successfully updated ${configPath} with routstr settings.`);
22526
22587
  } catch (error) {
@@ -22529,7 +22590,7 @@ Installing routstr configuration in ${configPath}...`);
22529
22590
  }
22530
22591
 
22531
22592
  // src/integrations/hermes.ts
22532
- import { existsSync as existsSync8, mkdirSync as mkdirSync6 } from "fs";
22593
+ import { existsSync as existsSync9, mkdirSync as mkdirSync7 } from "fs";
22533
22594
  import { readFile as readFile6, writeFile as writeFile6 } from "fs/promises";
22534
22595
  import { dirname as dirname6 } from "path";
22535
22596
 
@@ -22652,7 +22713,7 @@ Installing routstr configuration in ${configPath}...`);
22652
22713
  }
22653
22714
  let content = "";
22654
22715
  try {
22655
- if (existsSync8(configPath)) {
22716
+ if (existsSync9(configPath)) {
22656
22717
  content = await readFile6(configPath, "utf-8");
22657
22718
  }
22658
22719
  } catch (error) {
@@ -22675,7 +22736,7 @@ Installing routstr configuration in ${configPath}...`);
22675
22736
  console.log(`${configPath} already contains current routstr settings.`);
22676
22737
  return;
22677
22738
  }
22678
- mkdirSync6(dirname6(configPath), { recursive: true });
22739
+ mkdirSync7(dirname6(configPath), { recursive: true });
22679
22740
  await writeFile6(configPath, newContent);
22680
22741
  console.log(`Successfully updated ${configPath} with routstr settings.`);
22681
22742
  } catch (error) {
@@ -22912,7 +22973,7 @@ async function addClientAction(options) {
22912
22973
  // src/cli.ts
22913
22974
  init_config();
22914
22975
  init_logger();
22915
- import { chmodSync as chmodSync2, existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync4, statSync as statSync4, writeFileSync as writeFileSync2 } from "fs";
22976
+ import { chmodSync as chmodSync3, existsSync as existsSync14, mkdirSync as mkdirSync10, readFileSync as readFileSync5, statSync as statSync4, writeFileSync as writeFileSync3 } from "fs";
22916
22977
  import { execSync } from "child_process";
22917
22978
  import { dirname as dirname8, join as join9 } from "path";
22918
22979
 
@@ -24194,13 +24255,13 @@ k("Cashu_P2BK_v1");
24194
24255
  // src/daemon/wallet/coco-client.ts
24195
24256
  import {
24196
24257
  closeSync as closeSync2,
24197
- existsSync as existsSync9,
24198
- mkdirSync as mkdirSync7,
24258
+ existsSync as existsSync10,
24259
+ mkdirSync as mkdirSync8,
24199
24260
  openSync as openSync2,
24200
- readFileSync,
24201
- renameSync,
24202
- unlinkSync,
24203
- writeFileSync
24261
+ readFileSync as readFileSync2,
24262
+ renameSync as renameSync2,
24263
+ unlinkSync as unlinkSync2,
24264
+ writeFileSync as writeFileSync2
24204
24265
  } from "fs";
24205
24266
 
24206
24267
  // node_modules/@scure/bip39/index.js
@@ -24290,7 +24351,7 @@ var SAFE_COCO_LOG_FIELDS = new Set([
24290
24351
  "rollingBackOperations",
24291
24352
  "orphanedReservations"
24292
24353
  ]);
24293
- function isZombieProcess(pid, readFile7 = (path) => readFileSync(path, "utf-8")) {
24354
+ function isZombieProcess(pid, readFile7 = (path) => readFileSync2(path, "utf-8")) {
24294
24355
  try {
24295
24356
  const stat2 = readFile7(`/proc/${pid}/stat`);
24296
24357
  const commandEnd = stat2.lastIndexOf(")");
@@ -24322,7 +24383,7 @@ function hasErrorCode(error, codes) {
24322
24383
  }
24323
24384
  async function assertLegacyCocodNotRunning(options = {}) {
24324
24385
  const socketPath = options.socketPath || legacyCocodSocketPath();
24325
- const pathExists = options.pathExists || existsSync9;
24386
+ const pathExists = options.pathExists || existsSync10;
24326
24387
  if (!pathExists(socketPath))
24327
24388
  return;
24328
24389
  const fetchImpl = options.fetchImpl || fetch;
@@ -24345,8 +24406,8 @@ async function assertLegacyCocodNotRunning(options = {}) {
24345
24406
  async function stopLegacyCocod(options = {}) {
24346
24407
  const socketPath = options.socketPath || legacyCocodSocketPath();
24347
24408
  const pidFilePath = options.pidFilePath || legacyCocodPidPath();
24348
- const pathExists = options.pathExists || existsSync9;
24349
- const readFile7 = options.readFile || ((path) => readFileSync(path, "utf-8"));
24409
+ const pathExists = options.pathExists || existsSync10;
24410
+ const readFile7 = options.readFile || ((path) => readFileSync2(path, "utf-8"));
24350
24411
  const isProcessRunning2 = options.isProcessRunning || defaultIsProcessRunning;
24351
24412
  const fetchImpl = options.fetchImpl || fetch;
24352
24413
  const killProcess = options.killProcess || ((pid2, signal) => process.kill(pid2, signal));
@@ -24409,10 +24470,10 @@ function claimPidFile(options) {
24409
24470
  const pid = options.pid ?? process.pid;
24410
24471
  const label = options.label || "wallet process lock";
24411
24472
  const openExclusive = options.openExclusive || ((path) => openSync2(path, "wx", 384));
24412
- const writePid = options.writePid || ((fd2, ownerPid) => writeFileSync(fd2, String(ownerPid)));
24473
+ const writePid = options.writePid || ((fd2, ownerPid) => writeFileSync2(fd2, String(ownerPid)));
24413
24474
  const closeFile = options.closeFile || closeSync2;
24414
- const readFile7 = options.readFile || ((path) => readFileSync(path, "utf-8"));
24415
- const removeFile = options.removeFile || unlinkSync;
24475
+ const readFile7 = options.readFile || ((path) => readFileSync2(path, "utf-8"));
24476
+ const removeFile = options.removeFile || unlinkSync2;
24416
24477
  const isProcessRunning2 = options.isProcessRunning || defaultIsProcessRunning;
24417
24478
  let fd;
24418
24479
  try {
@@ -24469,11 +24530,11 @@ function claimPidFile(options) {
24469
24530
 
24470
24531
  // src/daemon/wallet/migration.ts
24471
24532
  import {
24472
- chmodSync,
24533
+ chmodSync as chmodSync2,
24473
24534
  copyFileSync,
24474
- existsSync as existsSync12,
24475
- mkdirSync as mkdirSync8,
24476
- renameSync as renameSync2,
24535
+ existsSync as existsSync13,
24536
+ mkdirSync as mkdirSync9,
24537
+ renameSync as renameSync3,
24477
24538
  rmSync,
24478
24539
  statSync as statSync3
24479
24540
  } from "fs";
@@ -24482,16 +24543,16 @@ import { basename, dirname as dirname7, join as join8 } from "path";
24482
24543
 
24483
24544
  // src/daemon/wallet/diagnostics.ts
24484
24545
  import { createHash } from "crypto";
24485
- import { existsSync as existsSync11, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
24546
+ import { existsSync as existsSync12, readFileSync as readFileSync4, statSync as statSync2 } from "fs";
24486
24547
  import { Database } from "bun:sqlite";
24487
24548
  import { join as join7 } from "path";
24488
24549
 
24489
24550
  // src/daemon/wallet/wallet-state.ts
24490
- import { existsSync as existsSync10, readFileSync as readFileSync2, statSync } from "fs";
24551
+ import { existsSync as existsSync11, readFileSync as readFileSync3, statSync } from "fs";
24491
24552
  import { join as join6 } from "path";
24492
24553
  function walletState(configPath, dbPath) {
24493
- const hasConfig = existsSync10(configPath);
24494
- const hasDb = existsSync10(dbPath);
24554
+ const hasConfig = existsSync11(configPath);
24555
+ const hasDb = existsSync11(dbPath);
24495
24556
  if (hasConfig)
24496
24557
  return "initialized";
24497
24558
  if (hasDb)
@@ -24499,11 +24560,11 @@ function walletState(configPath, dbPath) {
24499
24560
  return "absent";
24500
24561
  }
24501
24562
  function filesEqual(left, right) {
24502
- if (!existsSync10(left) || !existsSync10(right))
24563
+ if (!existsSync11(left) || !existsSync11(right))
24503
24564
  return false;
24504
24565
  if (statSync(left).size !== statSync(right).size)
24505
24566
  return false;
24506
- return readFileSync2(left).equals(readFileSync2(right));
24567
+ return readFileSync3(left).equals(readFileSync3(right));
24507
24568
  }
24508
24569
  function classifyWalletMigration(targetDir, sourceDir) {
24509
24570
  const targetConfig = join6(targetDir, "config.json");
@@ -24516,14 +24577,14 @@ function classifyWalletMigration(targetDir, sourceDir) {
24516
24577
  const sourceState = walletState(sourceConfig, sourceDb);
24517
24578
  if (targetState === "initialized" && sourceState === "initialized") {
24518
24579
  const configsMatch = filesEqual(targetConfig, sourceConfig);
24519
- const databasesMatch = !existsSync10(targetDb) && !existsSync10(sourceDb) ? true : filesEqual(targetDb, sourceDb);
24580
+ const databasesMatch = !existsSync11(targetDb) && !existsSync11(sourceDb) ? true : filesEqual(targetDb, sourceDb);
24520
24581
  if (configsMatch && databasesMatch)
24521
24582
  return { kind: "already-current" };
24522
24583
  return { kind: "conflict" };
24523
24584
  }
24524
24585
  if (targetState === "initialized")
24525
24586
  return { kind: "already-current" };
24526
- if (!existsSync10(sourceDb) && (existsSync10(sourceWal) || existsSync10(sourceShm))) {
24587
+ if (!existsSync11(sourceDb) && (existsSync11(sourceWal) || existsSync11(sourceShm))) {
24527
24588
  return { kind: "orphaned-sidecars" };
24528
24589
  }
24529
24590
  if (targetState === "database-only" || sourceState === "database-only") {
@@ -24598,11 +24659,11 @@ function summarizeDbReadonly(dbPath) {
24598
24659
  function summarizeConfig(configPath) {
24599
24660
  const result = { exists: false, path: configPath };
24600
24661
  try {
24601
- if (!existsSync11(configPath))
24662
+ if (!existsSync12(configPath))
24602
24663
  return result;
24603
24664
  result.exists = true;
24604
24665
  result.mtimeMs = statSync2(configPath).mtimeMs;
24605
- const parsed = JSON.parse(readFileSync3(configPath, "utf-8"));
24666
+ const parsed = JSON.parse(readFileSync4(configPath, "utf-8"));
24606
24667
  result.encrypted = parsed.encrypted === true;
24607
24668
  if (typeof parsed.createdAt === "string")
24608
24669
  result.createdAt = parsed.createdAt;
@@ -24624,7 +24685,7 @@ function summarizeConfig(configPath) {
24624
24685
  function summarizeDb(dbPath) {
24625
24686
  const result = { exists: false, path: dbPath };
24626
24687
  try {
24627
- if (!existsSync11(dbPath))
24688
+ if (!existsSync12(dbPath))
24628
24689
  return result;
24629
24690
  result.exists = true;
24630
24691
  const stats = statSync2(dbPath);
@@ -24933,21 +24994,21 @@ async function migrateLegacyWallet(options = {}) {
24933
24994
  const stagingDir = join8(dirname7(targetDir), `.${targetDir.split(/[\\/]/).at(-1) || "wallet"}.staging-${process.pid}-${Date.now()}`);
24934
24995
  try {
24935
24996
  await options.assertLegacyStopped?.();
24936
- mkdirSync8(dirname7(targetDir), { recursive: true, mode: 448 });
24937
- mkdirSync8(stagingDir, { mode: 448 });
24997
+ mkdirSync9(dirname7(targetDir), { recursive: true, mode: 448 });
24998
+ mkdirSync9(stagingDir, { mode: 448 });
24938
24999
  const stagedConfig = join8(stagingDir, "config.json");
24939
25000
  const stagedDb = join8(stagingDir, "coco.db");
24940
25001
  copyFileSync(sourceConfig, stagedConfig);
24941
- chmodSync(stagedConfig, 384);
24942
- const hasSourceDb = existsSync12(sourceDb);
25002
+ chmodSync2(stagedConfig, 384);
25003
+ const hasSourceDb = existsSync13(sourceDb);
24943
25004
  if (hasSourceDb) {
24944
25005
  snapshotDatabase(sourceDb, stagedDb);
24945
- chmodSync(stagedDb, 384);
25006
+ chmodSync2(stagedDb, 384);
24946
25007
  }
24947
25008
  if (statSync3(stagedConfig).size !== statSync3(sourceConfig).size) {
24948
25009
  throw new Error("Cannot migrate wallet: staged config failed size validation.");
24949
25010
  }
24950
- renameSync2(stagingDir, targetDir);
25011
+ renameSync3(stagingDir, targetDir);
24951
25012
  } catch (error) {
24952
25013
  rmSync(stagingDir, { recursive: true, force: true });
24953
25014
  throw error;
@@ -24955,13 +25016,13 @@ async function migrateLegacyWallet(options = {}) {
24955
25016
  releaseLegacyLock?.();
24956
25017
  }
24957
25018
  const cleanupWarnings = [];
24958
- const sourceFiles = [sourceConfig, sourceDb, sourceWal, sourceShm].filter(existsSync12);
25019
+ const sourceFiles = [sourceConfig, sourceDb, sourceWal, sourceShm].filter(existsSync13);
24959
25020
  if (sourceFiles.length > 0) {
24960
25021
  const archiveDir = join8(sourceDir, `wallet-migrated-${Date.now()}`);
24961
25022
  try {
24962
- mkdirSync8(archiveDir, { mode: 448 });
25023
+ mkdirSync9(archiveDir, { mode: 448 });
24963
25024
  for (const path of sourceFiles)
24964
- renameSync2(path, join8(archiveDir, basename(path)));
25025
+ renameSync3(path, join8(archiveDir, basename(path)));
24965
25026
  } catch (error) {
24966
25027
  const message = error instanceof Error ? error.message : String(error);
24967
25028
  cleanupWarnings.push(`Could not archive legacy wallet files: ${message}`);
@@ -27095,7 +27156,7 @@ zoo`.split(`
27095
27156
  // package.json
27096
27157
  var package_default = {
27097
27158
  name: "routstrd",
27098
- version: "0.4.1",
27159
+ version: "0.4.2",
27099
27160
  module: "src/index.ts",
27100
27161
  type: "module",
27101
27162
  private: false,
@@ -27121,7 +27182,7 @@ var package_default = {
27121
27182
  "@cashu/cashu-ts": "^4.3.0",
27122
27183
  "@cashu/coco-core": "^1.0.1",
27123
27184
  "@cashu/coco-sqlite-bun": "^1.0.1",
27124
- "@routstr/sdk": "^0.4.0",
27185
+ "@routstr/sdk": "^0.4.1",
27125
27186
  "@scure/bip39": "^2.2.0",
27126
27187
  "applesauce-core": "^5.1.0",
27127
27188
  "applesauce-relay": "^5.1.0",
@@ -27162,10 +27223,10 @@ ${invoice}`);
27162
27223
  }
27163
27224
  function initializeWallet(walletDir2 = walletDir()) {
27164
27225
  const walletConfig = join9(walletDir2, "config.json");
27165
- mkdirSync9(walletDir2, { recursive: true, mode: 448 });
27166
- chmodSync2(walletDir2, 448);
27167
- if (existsSync13(walletConfig)) {
27168
- chmodSync2(walletConfig, 384);
27226
+ mkdirSync10(walletDir2, { recursive: true, mode: 448 });
27227
+ chmodSync3(walletDir2, 448);
27228
+ if (existsSync14(walletConfig)) {
27229
+ chmodSync3(walletConfig, 384);
27169
27230
  console.log("Wallet already initialized.");
27170
27231
  return;
27171
27232
  }
@@ -27176,7 +27237,7 @@ function initializeWallet(walletDir2 = walletDir()) {
27176
27237
  encrypted: false,
27177
27238
  createdAt: new Date().toISOString()
27178
27239
  };
27179
- writeFileSync2(walletConfig, JSON.stringify(config, null, 2), {
27240
+ writeFileSync3(walletConfig, JSON.stringify(config, null, 2), {
27180
27241
  mode: 384,
27181
27242
  flag: "wx"
27182
27243
  });
@@ -27204,7 +27265,7 @@ Restarting routstrd daemon...`);
27204
27265
  for (let i2 = 0;i2 < 100; i2++) {
27205
27266
  await new Promise((resolve) => setTimeout(resolve, 100));
27206
27267
  const healthDown = !await isDaemonRunning();
27207
- const pidFileReleased = !existsSync13(pidFilePath);
27268
+ const pidFileReleased = !existsSync14(pidFilePath);
27208
27269
  if (healthDown && pidFileReleased)
27209
27270
  break;
27210
27271
  }
@@ -27247,16 +27308,16 @@ async function requireLocalDaemon() {
27247
27308
  }
27248
27309
  async function initDaemon() {
27249
27310
  console.log("Initializing routstrd...");
27250
- if (!existsSync13(CONFIG_DIR)) {
27251
- mkdirSync9(CONFIG_DIR, { recursive: true });
27311
+ if (!existsSync14(CONFIG_DIR)) {
27252
27312
  console.log(`Created config directory: ${CONFIG_DIR}`);
27253
27313
  }
27254
- if (!existsSync13(CONFIG_FILE)) {
27314
+ ensureDirsSync();
27315
+ if (!existsSync14(CONFIG_FILE)) {
27255
27316
  const config2 = {
27256
27317
  ...DEFAULT_CONFIG,
27257
27318
  cocodPath: null
27258
27319
  };
27259
- await Bun.write(CONFIG_FILE, JSON.stringify(config2, null, 2));
27320
+ saveDaemonConfig(config2);
27260
27321
  console.log(`Created config file: ${CONFIG_FILE}`);
27261
27322
  }
27262
27323
  const config = await loadConfig();
@@ -27265,7 +27326,7 @@ async function initDaemon() {
27265
27326
  const nsec = nip19_exports.nsecEncode(secretKey);
27266
27327
  const npub = npubFromSecretKey(secretKey);
27267
27328
  config.nsec = nsec;
27268
- await Bun.write(CONFIG_FILE, JSON.stringify(config, null, 2));
27329
+ saveDaemonConfig(config);
27269
27330
  console.log(`
27270
27331
  A new Nostr identity has been generated for authentication.`);
27271
27332
  console.log(`Your npub: ${npub}`);
@@ -27279,7 +27340,7 @@ A new Nostr identity has been generated for authentication.`);
27279
27340
  socketPath: legacyCocodSocketPath()
27280
27341
  }),
27281
27342
  acquireLegacyLock: () => {
27282
- mkdirSync9(dirname8(legacyCocodPidPath()), {
27343
+ mkdirSync10(dirname8(legacyCocodPidPath()), {
27283
27344
  recursive: true,
27284
27345
  mode: 448
27285
27346
  });
@@ -27307,10 +27368,7 @@ To ensure routstrd persists across system restarts, run: 'routstrd service insta
27307
27368
  }
27308
27369
  program.name("routstrd").description("Routstr daemon - Manage routstr processes").version(package_default.version, "--version", "output the version number");
27309
27370
  program.command("update").description("Update routstrd to the latest version").action(async () => {
27310
- const packages = [
27311
- { name: "routstrd", label: "routstrd" },
27312
- { name: "@routstr/cocod", label: "cocod" }
27313
- ];
27371
+ const packages = [{ name: "routstrd", label: "routstrd" }];
27314
27372
  let updatedAny = false;
27315
27373
  for (const { name, label } of packages) {
27316
27374
  const installed = await getGlobalPackageVersion(name);
@@ -27444,8 +27502,8 @@ program.command("remote [url]").description("Show the configured remote daemon,
27444
27502
  process.exit(1);
27445
27503
  }
27446
27504
  }
27447
- if (!existsSync13(CONFIG_DIR)) {
27448
- mkdirSync9(CONFIG_DIR, { recursive: true });
27505
+ if (!existsSync14(CONFIG_DIR)) {
27506
+ mkdirSync10(CONFIG_DIR, { recursive: true });
27449
27507
  }
27450
27508
  const updates = { daemonUrl: url };
27451
27509
  if (options.authUrl) {
@@ -27463,7 +27521,7 @@ program.command("remote [url]").description("Show the configured remote daemon,
27463
27521
  ...config,
27464
27522
  ...updates
27465
27523
  };
27466
- await Bun.write(CONFIG_FILE, JSON.stringify(updatedConfig, null, 2));
27524
+ saveDaemonConfig(updatedConfig);
27467
27525
  console.log(`Remote daemon URL set to: ${url}`);
27468
27526
  if (options.authUrl) {
27469
27527
  console.log(`Auth proxy URL set to: ${options.authUrl}`);
@@ -27485,7 +27543,7 @@ program.command("local").description("Switch back to local daemon mode (removes
27485
27543
  const previousAuthUrl = config.authUrl;
27486
27544
  const { daemonUrl: _daemonUrl, authUrl: _authUrl, ...rest } = config;
27487
27545
  const updatedConfig = rest;
27488
- await Bun.write(CONFIG_FILE, JSON.stringify(updatedConfig, null, 2));
27546
+ saveDaemonConfig(updatedConfig);
27489
27547
  console.log("Switched back to local daemon mode.");
27490
27548
  if (previousDaemonUrl) {
27491
27549
  console.log(` Removed remote daemon URL: ${previousDaemonUrl}`);
@@ -27816,6 +27874,46 @@ providersCmd.command("enable <indices...>").description("Enable providers by the
27816
27874
  }
27817
27875
  }
27818
27876
  });
27877
+ providersCmd.command("reviews").description("Show all known providers with their stored review events and event IDs").action(async () => {
27878
+ await ensureDaemonRunning();
27879
+ const result = await callDaemon("/providers/reviews");
27880
+ if (result.error) {
27881
+ console.log(result.error);
27882
+ process.exit(1);
27883
+ }
27884
+ const output = result.output;
27885
+ if (!output) {
27886
+ console.log("No provider review data available.");
27887
+ return;
27888
+ }
27889
+ console.log(`Providers (${output.totalCount} total, ${output.reviewEventCount} stored review events):
27890
+ `);
27891
+ for (const provider of output.providers) {
27892
+ const status = provider.disabled ? "DISABLED" : "enabled ";
27893
+ console.log(` [${provider.index}] ${status} ${provider.baseUrl} (${provider.reviewCount} review${provider.reviewCount === 1 ? "" : "s"})`);
27894
+ if (provider.nodePubkeys.length > 0) {
27895
+ console.log(` node pubkeys: ${provider.nodePubkeys.join(", ")}`);
27896
+ }
27897
+ for (const review of provider.reviews) {
27898
+ const label = review.label || "review";
27899
+ const created = new Date(review.createdAt * 1000).toISOString();
27900
+ console.log(` - ${label} eventId: ${review.eventId}`);
27901
+ console.log(` node: ${review.nodePubkey ?? "(none)"}`);
27902
+ console.log(` author: ${review.authorPubkey ?? "(none)"}`);
27903
+ console.log(` at: ${created}`);
27904
+ }
27905
+ }
27906
+ if (output.unmatchedReviews.length > 0) {
27907
+ console.log(`
27908
+ Unmatched review events (${output.unmatchedReviews.length} \u2014 node pubkey not in any known provider):`);
27909
+ for (const review of output.unmatchedReviews) {
27910
+ const created = new Date(review.createdAt * 1000).toISOString();
27911
+ console.log(` - eventId: ${review.eventId}`);
27912
+ console.log(` node: ${review.nodePubkey ?? "(none)"}`);
27913
+ console.log(` at: ${created}`);
27914
+ }
27915
+ }
27916
+ });
27819
27917
  var clientsCmd = program.command("clients").description("List and manage clients");
27820
27918
  clientsCmd.command("list").description("List all clients").action(async () => {
27821
27919
  await listClientsAction();
@@ -28338,7 +28436,7 @@ serviceCmd.command("install").description("Install and start routstrd using PM2
28338
28436
  const path = __require("path");
28339
28437
  daemonPath = path.join(path.dirname(import.meta.url).replace("file://", ""), "daemon", "index.js");
28340
28438
  }
28341
- if (!existsSync13(daemonPath)) {
28439
+ if (!existsSync14(daemonPath)) {
28342
28440
  console.error(`Could not find daemon at ${daemonPath}. Did you run 'bun run build'?`);
28343
28441
  process.exit(1);
28344
28442
  }
@@ -28386,7 +28484,7 @@ program.command("restart").description("Restart the background daemon").option("
28386
28484
  for (let i2 = 0;i2 < 100; i2++) {
28387
28485
  await new Promise((resolve) => setTimeout(resolve, 100));
28388
28486
  const healthDown = !await isDaemonRunning();
28389
- const pidFileReleased = !existsSync13(pidFilePath);
28487
+ const pidFileReleased = !existsSync14(pidFilePath);
28390
28488
  if (healthDown && pidFileReleased) {
28391
28489
  break;
28392
28490
  }
@@ -28444,7 +28542,7 @@ xcashu mode is coming soon! Only lazyrefund/apikeys is available at this time.`)
28444
28542
  ...config,
28445
28543
  mode: selectedMode
28446
28544
  };
28447
- await Bun.write(CONFIG_FILE, JSON.stringify(updatedConfig, null, 2));
28545
+ saveDaemonConfig(updatedConfig);
28448
28546
  console.log(`Mode set to '${selectedMode}'. Restarting daemon...`);
28449
28547
  const wasRunning = await isDaemonRunning();
28450
28548
  if (wasRunning) {
@@ -28477,7 +28575,7 @@ function getLogFileForDate2(logsDir, date = new Date) {
28477
28575
  return `${logsDir}/${year}-${month}-${day}.log`;
28478
28576
  }
28479
28577
  function readLastLines(file, lines) {
28480
- const content = readFileSync4(file, "utf8");
28578
+ const content = readFileSync5(file, "utf8");
28481
28579
  const allLines = content.replace(/\r\n/g, `
28482
28580
  `).split(`
28483
28581
  `);
@@ -28494,7 +28592,7 @@ async function followLogFile(file, lines) {
28494
28592
  let position = statSync4(file).size;
28495
28593
  while (true) {
28496
28594
  await new Promise((resolve) => setTimeout(resolve, 1000));
28497
- if (!existsSync13(file)) {
28595
+ if (!existsSync14(file)) {
28498
28596
  continue;
28499
28597
  }
28500
28598
  const size = statSync4(file).size;
@@ -28516,17 +28614,17 @@ program.command("logs").description("View daemon logs").option("-f, --follow", "
28516
28614
  const yesterday = new Date;
28517
28615
  yesterday.setDate(yesterday.getDate() - 1);
28518
28616
  const yesterdayFile = getLogFileForDate2(logsDir, yesterday);
28519
- if (!existsSync13(todayFile) && !existsSync13(yesterdayFile)) {
28617
+ if (!existsSync14(todayFile) && !existsSync14(yesterdayFile)) {
28520
28618
  console.log("No log files found. Daemon may not have started yet.");
28521
28619
  console.log(`Logs directory: ${logsDir}`);
28522
28620
  process.exit(1);
28523
28621
  }
28524
28622
  const lines = parseInt(options.lines, 10);
28525
28623
  const logFiles = [yesterdayFile, todayFile].filter((file, index, files) => {
28526
- return existsSync13(file) && files.indexOf(file) === index;
28624
+ return existsSync14(file) && files.indexOf(file) === index;
28527
28625
  });
28528
28626
  if (options.follow) {
28529
- if (existsSync13(todayFile)) {
28627
+ if (existsSync14(todayFile)) {
28530
28628
  await followLogFile(todayFile, lines);
28531
28629
  } else {
28532
28630
  console.log("No log file for today to follow.");