routstrd 0.2.8 → 0.2.10

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
@@ -2122,6 +2122,71 @@ var require_commander = __commonJS((exports) => {
2122
2122
  exports.InvalidOptionArgumentError = InvalidArgumentError;
2123
2123
  });
2124
2124
 
2125
+ // src/utils/logger.ts
2126
+ import { appendFile, mkdir } from "fs/promises";
2127
+ import { existsSync } from "fs";
2128
+ import { join } from "path";
2129
+ function getLogFileForDate(date = new Date) {
2130
+ const year = date.getFullYear();
2131
+ const month = String(date.getMonth() + 1).padStart(2, "0");
2132
+ const day = String(date.getDate()).padStart(2, "0");
2133
+ return join(LOGS_DIR, `${year}-${month}-${day}.log`);
2134
+ }
2135
+ async function ensureLogDir() {
2136
+ if (!existsSync(LOGS_DIR)) {
2137
+ await mkdir(LOGS_DIR, { recursive: true });
2138
+ }
2139
+ }
2140
+ async function writeLog(level, ...args) {
2141
+ await ensureLogDir();
2142
+ const timestamp = new Date().toISOString();
2143
+ const message = args.map((a) => {
2144
+ if (a instanceof Error) {
2145
+ return `${a.message}${a.stack ? `
2146
+ ${a.stack}` : ""}`;
2147
+ }
2148
+ if (typeof a === "object") {
2149
+ try {
2150
+ return JSON.stringify(a);
2151
+ } catch {
2152
+ return String(a);
2153
+ }
2154
+ }
2155
+ return String(a);
2156
+ }).join(" ");
2157
+ const line = `[${timestamp}] [${level}] ${message}
2158
+ `;
2159
+ const logFile = getLogFileForDate(new Date(timestamp));
2160
+ try {
2161
+ await appendFile(logFile, line);
2162
+ } catch (error) {
2163
+ console.error("Failed to write log:", error);
2164
+ }
2165
+ }
2166
+ var HOME, LOG_DIR, LOGS_DIR, logger;
2167
+ var init_logger = __esm(() => {
2168
+ HOME = process.env.HOME || process.env.USERPROFILE || "";
2169
+ LOG_DIR = process.env.ROUTSTRD_DIR || `${HOME}/.routstrd`;
2170
+ LOGS_DIR = join(LOG_DIR, "logs");
2171
+ logger = {
2172
+ log: (...args) => {
2173
+ console.log(...args);
2174
+ writeLog("INFO", ...args);
2175
+ },
2176
+ debug: (...args) => {
2177
+ writeLog("DEBUG", ...args);
2178
+ },
2179
+ error: (...args) => {
2180
+ console.error(...args);
2181
+ writeLog("ERROR", ...args);
2182
+ },
2183
+ info: (...args) => {
2184
+ console.log(...args);
2185
+ writeLog("INFO", ...args);
2186
+ }
2187
+ };
2188
+ });
2189
+
2125
2190
  // src/utils/config.ts
2126
2191
  var HOME2, CONFIG_DIR, SOCKET_PATH, PID_FILE, DB_PATH, CONFIG_FILE, LOGS_DIR2, DEFAULT_CONFIG;
2127
2192
  var init_config = __esm(() => {
@@ -2140,6 +2205,193 @@ var init_config = __esm(() => {
2140
2205
  };
2141
2206
  });
2142
2207
 
2208
+ // src/utils/process-lock.ts
2209
+ import { randomUUID } from "crypto";
2210
+ import { mkdir as mkdir2, readFile, rm, stat, writeFile } from "fs/promises";
2211
+ import { dirname } from "path";
2212
+ function delay(ms) {
2213
+ return new Promise((resolve) => setTimeout(resolve, ms));
2214
+ }
2215
+ function isProcessRunning(pid) {
2216
+ if (!Number.isFinite(pid) || pid <= 0) {
2217
+ return false;
2218
+ }
2219
+ try {
2220
+ process.kill(pid, 0);
2221
+ return true;
2222
+ } catch (error) {
2223
+ const code = error.code;
2224
+ return code === "EPERM";
2225
+ }
2226
+ }
2227
+ async function readLockOwner(lockDir) {
2228
+ try {
2229
+ const raw = await readFile(`${lockDir}/owner.json`, "utf8");
2230
+ const parsed = JSON.parse(raw);
2231
+ if (typeof parsed.pid === "number" && typeof parsed.createdAt === "number") {
2232
+ return {
2233
+ pid: parsed.pid,
2234
+ createdAt: parsed.createdAt,
2235
+ token: typeof parsed.token === "string" ? parsed.token : undefined
2236
+ };
2237
+ }
2238
+ } catch {
2239
+ }
2240
+ return null;
2241
+ }
2242
+ async function isLockStale(lockDir, staleAfterMs) {
2243
+ const owner = await readLockOwner(lockDir);
2244
+ if (owner) {
2245
+ return !isProcessRunning(owner.pid) || Date.now() - owner.createdAt > staleAfterMs;
2246
+ }
2247
+ try {
2248
+ const info = await stat(lockDir);
2249
+ return Date.now() - info.mtimeMs > staleAfterMs;
2250
+ } catch {
2251
+ return false;
2252
+ }
2253
+ }
2254
+ async function acquireCrossProcessLock(lockDir, options = {}) {
2255
+ const acquireTimeoutMs = options.acquireTimeoutMs ?? 120000;
2256
+ const retryIntervalMs = options.retryIntervalMs ?? 100;
2257
+ const staleAfterMs = options.staleAfterMs ?? 120000;
2258
+ const deadline = Date.now() + acquireTimeoutMs;
2259
+ await mkdir2(dirname(lockDir), { recursive: true });
2260
+ while (true) {
2261
+ try {
2262
+ await mkdir2(lockDir);
2263
+ const token = randomUUID();
2264
+ const owner = { pid: process.pid, createdAt: Date.now(), token };
2265
+ await writeFile(`${lockDir}/owner.json`, JSON.stringify(owner), "utf8");
2266
+ let released = false;
2267
+ return async () => {
2268
+ if (released)
2269
+ return;
2270
+ released = true;
2271
+ const currentOwner = await readLockOwner(lockDir);
2272
+ if (currentOwner?.token === token) {
2273
+ await rm(lockDir, { recursive: true, force: true });
2274
+ }
2275
+ };
2276
+ } catch (error) {
2277
+ const code = error.code;
2278
+ if (code !== "EEXIST") {
2279
+ throw error;
2280
+ }
2281
+ if (await isLockStale(lockDir, staleAfterMs)) {
2282
+ options.log?.(`Removing stale lock at ${lockDir}`);
2283
+ await rm(lockDir, { recursive: true, force: true });
2284
+ continue;
2285
+ }
2286
+ if (Date.now() >= deadline) {
2287
+ throw new Error(`Timed out waiting to acquire lock ${lockDir}`);
2288
+ }
2289
+ await delay(retryIntervalMs);
2290
+ }
2291
+ }
2292
+ }
2293
+ async function withCrossProcessLock(lockDir, fn, options = {}) {
2294
+ const release = await acquireCrossProcessLock(lockDir, options);
2295
+ try {
2296
+ return await fn();
2297
+ } finally {
2298
+ await release();
2299
+ }
2300
+ }
2301
+ var init_process_lock = () => {
2302
+ };
2303
+
2304
+ // src/start-daemon.ts
2305
+ import { existsSync as existsSync2 } from "fs";
2306
+ function getTodayLogFile() {
2307
+ const now = new Date;
2308
+ const year = now.getFullYear();
2309
+ const month = String(now.getMonth() + 1).padStart(2, "0");
2310
+ const day = String(now.getDate()).padStart(2, "0");
2311
+ return `${LOGS_DIR2}/${year}-${month}-${day}.log`;
2312
+ }
2313
+ async function isDaemonHealthy(port) {
2314
+ const controller = new AbortController;
2315
+ const timeoutId = setTimeout(() => controller.abort(), 2000);
2316
+ try {
2317
+ const existing = await fetch(`http://localhost:${port}/health`, {
2318
+ signal: controller.signal
2319
+ });
2320
+ return existing.ok;
2321
+ } catch {
2322
+ return false;
2323
+ } finally {
2324
+ clearTimeout(timeoutId);
2325
+ }
2326
+ }
2327
+ async function startDaemonUnlocked(options) {
2328
+ const args = [];
2329
+ const port = options.port || "8008";
2330
+ const pollIntervalMs = 250;
2331
+ const startupTimeoutMs = 10 * 60 * 1000;
2332
+ if (await isDaemonHealthy(port)) {
2333
+ logger.log(`Routstr daemon already running on http://localhost:${port}/v1`);
2334
+ return;
2335
+ }
2336
+ if (options.port) {
2337
+ args.push("--port", options.port);
2338
+ }
2339
+ if (options.provider) {
2340
+ args.push("--provider", options.provider);
2341
+ }
2342
+ if (!existsSync2(LOGS_DIR2)) {
2343
+ await Bun.$`mkdir -p ${LOGS_DIR2}`;
2344
+ }
2345
+ const daemonScript = new URL("./daemon/index.js", import.meta.url).pathname;
2346
+ const todayLogFile = getTodayLogFile();
2347
+ const shellCmd = `bun run "${daemonScript}" ${args.map((a) => `'${a}'`).join(" ")} >> "${todayLogFile}" 2>&1`;
2348
+ const proc = Bun.spawn(["sh", "-c", shellCmd], {
2349
+ stdout: "inherit",
2350
+ stderr: "inherit",
2351
+ stdin: "ignore",
2352
+ detached: true
2353
+ });
2354
+ proc.unref();
2355
+ let exitCode = null;
2356
+ proc.exited.then((code) => {
2357
+ exitCode = code;
2358
+ });
2359
+ const maxPolls = Math.ceil(startupTimeoutMs / pollIntervalMs);
2360
+ for (let i = 0;i < maxPolls; i++) {
2361
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
2362
+ if (exitCode !== null) {
2363
+ throw new Error(`Daemon process exited early with code ${exitCode}. Check logs in ${LOGS_DIR2}`);
2364
+ }
2365
+ if (await isDaemonHealthy(port)) {
2366
+ logger.log(`Routstr daemon started (PID: ${proc.pid}).`);
2367
+ return;
2368
+ }
2369
+ }
2370
+ throw new Error(`Daemon failed to start within ${Math.round(startupTimeoutMs / 1000)} seconds. Check logs in ${LOGS_DIR2}`);
2371
+ }
2372
+ async function startDaemon(options = {}) {
2373
+ const port = options.port || "8008";
2374
+ const startupTimeoutMs = 10 * 60 * 1000;
2375
+ if (await isDaemonHealthy(port)) {
2376
+ logger.log(`Routstr daemon already running on http://localhost:${port}/v1`);
2377
+ return;
2378
+ }
2379
+ await withCrossProcessLock(DAEMON_STARTUP_LOCK_PATH, async () => {
2380
+ await startDaemonUnlocked(options);
2381
+ }, {
2382
+ acquireTimeoutMs: startupTimeoutMs + 30000,
2383
+ staleAfterMs: startupTimeoutMs + 30000,
2384
+ log: (message) => logger.debug(message)
2385
+ });
2386
+ }
2387
+ var DAEMON_STARTUP_LOCK_PATH;
2388
+ var init_start_daemon = __esm(() => {
2389
+ init_logger();
2390
+ init_config();
2391
+ init_process_lock();
2392
+ DAEMON_STARTUP_LOCK_PATH = `${CONFIG_DIR}/routstrd-startup.lock`;
2393
+ });
2394
+
2143
2395
  // node_modules/nostr-tools/node_modules/@noble/curves/node_modules/@noble/hashes/esm/_assert.js
2144
2396
  function number(n) {
2145
2397
  if (!Number.isSafeInteger(n) || n < 0)
@@ -9325,23 +9577,11 @@ function getNpubSuffix(config) {
9325
9577
  return npub.slice(-7);
9326
9578
  }
9327
9579
  async function startDaemonProcess() {
9328
- if (!existsSync3(LOGS_DIR2)) {
9329
- await Bun.$`mkdir -p ${LOGS_DIR2}`;
9330
- }
9331
- const proc = Bun.spawn(["bun", "run", `${import.meta.dir}/../daemon/index.ts`], {
9332
- stdout: "inherit",
9333
- stderr: "inherit",
9334
- stdin: "ignore",
9335
- detached: true
9580
+ const config = await loadConfig();
9581
+ await startDaemon({
9582
+ port: String(config.port || 8008),
9583
+ provider: config.provider || undefined
9336
9584
  });
9337
- proc.unref();
9338
- for (let i2 = 0;i2 < 50; i2++) {
9339
- await new Promise((resolve) => setTimeout(resolve, 100));
9340
- if (await isDaemonRunning()) {
9341
- return;
9342
- }
9343
- }
9344
- throw new Error("Daemon failed to start within 5 seconds");
9345
9585
  }
9346
9586
  async function ensureDaemonRunning() {
9347
9587
  if (await isDaemonRunning()) {
@@ -9386,6 +9626,7 @@ async function handleDaemonCommand(path, options = {}) {
9386
9626
  }
9387
9627
  }
9388
9628
  var init_daemon_client = __esm(() => {
9629
+ init_start_daemon();
9389
9630
  init_config();
9390
9631
  init_nip98();
9391
9632
  });
@@ -14667,157 +14908,24 @@ var {
14667
14908
  Help
14668
14909
  } = import__.default;
14669
14910
 
14670
- // src/utils/logger.ts
14671
- import { appendFile, mkdir } from "fs/promises";
14672
- import { existsSync } from "fs";
14673
- import { join } from "path";
14674
- var HOME = process.env.HOME || process.env.USERPROFILE || "";
14675
- var LOG_DIR = process.env.ROUTSTRD_DIR || `${HOME}/.routstrd`;
14676
- var LOGS_DIR = join(LOG_DIR, "logs");
14677
- function getLogFileForDate(date = new Date) {
14678
- const year = date.getFullYear();
14679
- const month = String(date.getMonth() + 1).padStart(2, "0");
14680
- const day = String(date.getDate()).padStart(2, "0");
14681
- return join(LOGS_DIR, `${year}-${month}-${day}.log`);
14682
- }
14683
- async function ensureLogDir() {
14684
- if (!existsSync(LOGS_DIR)) {
14685
- await mkdir(LOGS_DIR, { recursive: true });
14686
- }
14687
- }
14688
- async function writeLog(level, ...args) {
14689
- await ensureLogDir();
14690
- const timestamp = new Date().toISOString();
14691
- const message = args.map((a) => {
14692
- if (a instanceof Error) {
14693
- return `${a.message}${a.stack ? `
14694
- ${a.stack}` : ""}`;
14695
- }
14696
- if (typeof a === "object") {
14697
- try {
14698
- return JSON.stringify(a);
14699
- } catch {
14700
- return String(a);
14701
- }
14702
- }
14703
- return String(a);
14704
- }).join(" ");
14705
- const line = `[${timestamp}] [${level}] ${message}
14706
- `;
14707
- const logFile = getLogFileForDate(new Date(timestamp));
14708
- try {
14709
- await appendFile(logFile, line);
14710
- } catch (error) {
14711
- console.error("Failed to write log:", error);
14712
- }
14713
- }
14714
- var logger = {
14715
- log: (...args) => {
14716
- console.log(...args);
14717
- writeLog("INFO", ...args);
14718
- },
14719
- debug: (...args) => {
14720
- writeLog("DEBUG", ...args);
14721
- },
14722
- error: (...args) => {
14723
- console.error(...args);
14724
- writeLog("ERROR", ...args);
14725
- },
14726
- info: (...args) => {
14727
- console.log(...args);
14728
- writeLog("INFO", ...args);
14729
- }
14730
- };
14731
-
14732
- // src/start-daemon.ts
14733
- init_config();
14734
- import { existsSync as existsSync2 } from "fs";
14735
- function getTodayLogFile() {
14736
- const now = new Date;
14737
- const year = now.getFullYear();
14738
- const month = String(now.getMonth() + 1).padStart(2, "0");
14739
- const day = String(now.getDate()).padStart(2, "0");
14740
- return `${LOGS_DIR2}/${year}-${month}-${day}.log`;
14741
- }
14742
- async function startDaemon(options = {}) {
14743
- const args = [];
14744
- const port = options.port || "8008";
14745
- const pollIntervalMs = 250;
14746
- const startupTimeoutMs = 10 * 60 * 1000;
14747
- try {
14748
- const controller = new AbortController;
14749
- const timeoutId = setTimeout(() => controller.abort(), 2000);
14750
- const existing = await fetch(`http://localhost:${port}/health`, {
14751
- signal: controller.signal
14752
- });
14753
- clearTimeout(timeoutId);
14754
- if (existing.ok) {
14755
- logger.log(`Routstr daemon already running on http://localhost:${port}/v1`);
14756
- return;
14757
- }
14758
- } catch {
14759
- }
14760
- if (options.port) {
14761
- args.push("--port", options.port);
14762
- }
14763
- if (options.provider) {
14764
- args.push("--provider", options.provider);
14765
- }
14766
- if (!existsSync2(LOGS_DIR2)) {
14767
- await Bun.$`mkdir -p ${LOGS_DIR2}`;
14768
- }
14769
- const daemonScript = new URL("./daemon/index.js", import.meta.url).pathname;
14770
- const todayLogFile = getTodayLogFile();
14771
- const shellCmd = `bun run "${daemonScript}" ${args.map((a) => `'${a}'`).join(" ")} >> "${todayLogFile}" 2>&1`;
14772
- const proc = Bun.spawn(["sh", "-c", shellCmd], {
14773
- stdout: "inherit",
14774
- stderr: "inherit",
14775
- stdin: "ignore",
14776
- detached: true
14777
- });
14778
- proc.unref();
14779
- let exitCode = null;
14780
- proc.exited.then((code) => {
14781
- exitCode = code;
14782
- });
14783
- const maxPolls = Math.ceil(startupTimeoutMs / pollIntervalMs);
14784
- for (let i = 0;i < maxPolls; i++) {
14785
- await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
14786
- if (exitCode !== null) {
14787
- throw new Error(`Daemon process exited early with code ${exitCode}. Check logs in ${LOGS_DIR2}`);
14788
- }
14789
- try {
14790
- const controller = new AbortController;
14791
- const timeoutId = setTimeout(() => controller.abort(), 2000);
14792
- const res = await fetch(`http://localhost:${port}/health`, {
14793
- signal: controller.signal
14794
- });
14795
- clearTimeout(timeoutId);
14796
- if (res.ok) {
14797
- logger.log(`Routstr daemon started (PID: ${proc.pid}).`);
14798
- return;
14799
- }
14800
- } catch {
14801
- }
14802
- }
14803
- throw new Error(`Daemon failed to start within ${Math.round(startupTimeoutMs / 1000)} seconds. Check logs in ${LOGS_DIR2}`);
14804
- }
14805
-
14806
14911
  // src/cli.ts
14912
+ init_start_daemon();
14807
14913
  init_daemon_client();
14808
14914
 
14809
14915
  // src/utils/clients.ts
14810
14916
  init_daemon_client();
14811
14917
  init_nip98();
14918
+ init_logger();
14812
14919
 
14813
14920
  // src/integrations/registry.ts
14814
14921
  import { join as join3 } from "path";
14815
14922
 
14816
14923
  // src/integrations/opencode.ts
14817
- import { existsSync as existsSync4, mkdirSync } from "fs";
14818
- import { readFile, writeFile } from "fs/promises";
14819
- import { dirname } from "path";
14924
+ init_logger();
14820
14925
  init_daemon_client();
14926
+ import { existsSync as existsSync4, mkdirSync } from "fs";
14927
+ import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
14928
+ import { dirname as dirname2 } from "path";
14821
14929
  var OPENCODE_SMALL_MODEL = "routstr/minimax-m2.5";
14822
14930
  async function installOpencodeIntegration(config, apiKey, integrationConfig) {
14823
14931
  const { name, configPath } = integrationConfig;
@@ -14828,7 +14936,7 @@ Installing routstr models in opencode.json...`);
14828
14936
  let opencodeConfig;
14829
14937
  try {
14830
14938
  if (existsSync4(configPath)) {
14831
- const content = await readFile(configPath, "utf-8");
14939
+ const content = await readFile2(configPath, "utf-8");
14832
14940
  opencodeConfig = JSON.parse(content);
14833
14941
  } else {
14834
14942
  opencodeConfig = { provider: {} };
@@ -14840,7 +14948,7 @@ Installing routstr models in opencode.json...`);
14840
14948
  opencodeConfig.provider = {};
14841
14949
  }
14842
14950
  try {
14843
- mkdirSync(dirname(configPath), { recursive: true });
14951
+ mkdirSync(dirname2(configPath), { recursive: true });
14844
14952
  const data = await callDaemon("/models");
14845
14953
  const models = data.output?.models || [];
14846
14954
  if (models.length === 0) {
@@ -14862,7 +14970,7 @@ Installing routstr models in opencode.json...`);
14862
14970
  models: modelsObj
14863
14971
  };
14864
14972
  opencodeConfig.small_model = OPENCODE_SMALL_MODEL;
14865
- await writeFile(configPath, JSON.stringify(opencodeConfig, null, 2));
14973
+ await writeFile2(configPath, JSON.stringify(opencodeConfig, null, 2));
14866
14974
  logger.log(`Added "routstr" provider with ${models.length} models to opencode.json`);
14867
14975
  } catch (error) {
14868
14976
  logger.error("Failed to install models in opencode.json:", error);
@@ -14870,10 +14978,11 @@ Installing routstr models in opencode.json...`);
14870
14978
  }
14871
14979
 
14872
14980
  // src/integrations/pi.ts
14873
- import { existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
14874
- import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
14875
- import { dirname as dirname2 } from "path";
14981
+ init_logger();
14876
14982
  init_daemon_client();
14983
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
14984
+ import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
14985
+ import { dirname as dirname3 } from "path";
14877
14986
  async function installPiIntegration(config, apiKey, integrationConfig) {
14878
14987
  const { name, configPath } = integrationConfig;
14879
14988
  logger.log(`
@@ -14883,7 +14992,7 @@ Installing routstr models in pi models.json...`);
14883
14992
  let piConfig = {};
14884
14993
  try {
14885
14994
  if (existsSync5(configPath)) {
14886
- const content = await readFile2(configPath, "utf-8");
14995
+ const content = await readFile3(configPath, "utf-8");
14887
14996
  piConfig = JSON.parse(content);
14888
14997
  }
14889
14998
  } catch {
@@ -14893,7 +15002,7 @@ Installing routstr models in pi models.json...`);
14893
15002
  piConfig.providers = {};
14894
15003
  }
14895
15004
  try {
14896
- mkdirSync2(dirname2(configPath), { recursive: true });
15005
+ mkdirSync2(dirname3(configPath), { recursive: true });
14897
15006
  const data = await callDaemon("/models");
14898
15007
  const models = data.output?.models || [];
14899
15008
  if (models.length === 0) {
@@ -14909,7 +15018,7 @@ Installing routstr models in pi models.json...`);
14909
15018
  apiKey,
14910
15019
  models: providerModels
14911
15020
  };
14912
- await writeFile2(configPath, JSON.stringify(piConfig, null, 2));
15021
+ await writeFile3(configPath, JSON.stringify(piConfig, null, 2));
14913
15022
  logger.log(`Added "routstr" provider with ${models.length} models to pi models.json`);
14914
15023
  } catch (error) {
14915
15024
  logger.error("Failed to install models in pi models.json:", error);
@@ -14917,10 +15026,11 @@ Installing routstr models in pi models.json...`);
14917
15026
  }
14918
15027
 
14919
15028
  // src/integrations/openclaw.ts
14920
- import { existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
14921
- import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
14922
- import { dirname as dirname3 } from "path";
15029
+ init_logger();
14923
15030
  init_daemon_client();
15031
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
15032
+ import { readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
15033
+ import { dirname as dirname4 } from "path";
14924
15034
  var OPENCLAW_PROVIDER_ID = "routstr";
14925
15035
  var OPENCLAW_DEFAULT_PRIMARY_MODEL = "routstr/minimax-m2.5";
14926
15036
  var OPENCLAW_DEFAULT_FALLBACK_MODEL = "routstr/kimi-k2.5";
@@ -14933,7 +15043,7 @@ Installing routstr models in openclaw.json...`);
14933
15043
  let openclawConfig = {};
14934
15044
  try {
14935
15045
  if (existsSync6(configPath)) {
14936
- const content = await readFile3(configPath, "utf-8");
15046
+ const content = await readFile4(configPath, "utf-8");
14937
15047
  openclawConfig = JSON.parse(content);
14938
15048
  }
14939
15049
  } catch {
@@ -14952,7 +15062,7 @@ Installing routstr models in openclaw.json...`);
14952
15062
  openclawConfig.agents.defaults = {};
14953
15063
  }
14954
15064
  try {
14955
- mkdirSync3(dirname3(configPath), { recursive: true });
15065
+ mkdirSync3(dirname4(configPath), { recursive: true });
14956
15066
  const data = await callDaemon("/models");
14957
15067
  const models = data.output?.models || [];
14958
15068
  if (models.length === 0) {
@@ -14984,7 +15094,7 @@ Installing routstr models in openclaw.json...`);
14984
15094
  fallbacks: [OPENCLAW_DEFAULT_FALLBACK_MODEL]
14985
15095
  };
14986
15096
  }
14987
- await writeFile3(configPath, JSON.stringify(openclawConfig, null, 2));
15097
+ await writeFile4(configPath, JSON.stringify(openclawConfig, null, 2));
14988
15098
  logger.log(`Added "${OPENCLAW_PROVIDER_ID}" provider with ${models.length} models to openclaw.json`);
14989
15099
  } catch (error) {
14990
15100
  logger.error("Failed to install models in openclaw.json:", error);
@@ -14992,10 +15102,11 @@ Installing routstr models in openclaw.json...`);
14992
15102
  }
14993
15103
 
14994
15104
  // src/integrations/claudecode.ts
14995
- import { existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
14996
- import { readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
14997
- import { dirname as dirname4 } from "path";
15105
+ init_logger();
14998
15106
  init_daemon_client();
15107
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
15108
+ import { readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
15109
+ import { dirname as dirname5 } from "path";
14999
15110
  async function installClaudeCodeIntegration(config, apiKey, integrationConfig) {
15000
15111
  const { name, configPath } = integrationConfig;
15001
15112
  logger.log(`
@@ -15005,7 +15116,7 @@ Installing routstr configuration in ${configPath}...`);
15005
15116
  let settings = {};
15006
15117
  try {
15007
15118
  if (existsSync7(configPath)) {
15008
- const content = await readFile4(configPath, "utf-8");
15119
+ const content = await readFile5(configPath, "utf-8");
15009
15120
  settings = JSON.parse(content);
15010
15121
  }
15011
15122
  } catch (error) {
@@ -15040,8 +15151,8 @@ Installing routstr configuration in ${configPath}...`);
15040
15151
  logger.error("Failed to fetch models for Claude Code integration:", error);
15041
15152
  }
15042
15153
  try {
15043
- mkdirSync4(dirname4(configPath), { recursive: true });
15044
- await writeFile4(configPath, JSON.stringify(settings, null, 2));
15154
+ mkdirSync4(dirname5(configPath), { recursive: true });
15155
+ await writeFile5(configPath, JSON.stringify(settings, null, 2));
15045
15156
  logger.log(`Successfully updated ${configPath} with routstr settings.`);
15046
15157
  } catch (error) {
15047
15158
  logger.error(`Failed to write to ${configPath}:`, error);
@@ -15129,9 +15240,13 @@ async function getClientsList() {
15129
15240
  lastUsed: c.lastUsed
15130
15241
  }));
15131
15242
  }
15132
- async function addDaemonClient(name, clientId) {
15243
+ async function addDaemonClient(name) {
15133
15244
  const existingClients = await getClientsList();
15134
- const existing = clientId ? existingClients.find((c) => c.clientId === clientId) : existingClients.find((c) => c.name === name);
15245
+ const derivedId = name.replace(/\s+/g, "-").toLowerCase();
15246
+ const config = await loadConfig();
15247
+ const suffix = getNpubSuffix2(config);
15248
+ const clientId = suffix ? addSuffixToId(derivedId, suffix) : derivedId;
15249
+ const existing = existingClients.find((c) => c.clientId === clientId);
15135
15250
  if (existing) {
15136
15251
  const client = {
15137
15252
  id: existing.clientId,
@@ -15142,7 +15257,6 @@ async function addDaemonClient(name, clientId) {
15142
15257
  };
15143
15258
  return { client, created: false };
15144
15259
  }
15145
- const derivedId = name.replace(/\s+/g, "-").toLowerCase();
15146
15260
  const result = await callDaemon("/clients/add", {
15147
15261
  method: "POST",
15148
15262
  body: { name, id: derivedId }
@@ -15216,7 +15330,7 @@ async function addClientAction(options) {
15216
15330
  if (!integrationFn || !integrationConfig)
15217
15331
  continue;
15218
15332
  try {
15219
- const { client, created } = await addDaemonClient(integrationConfig.name, integrationConfig.clientId);
15333
+ const { client, created } = await addDaemonClient(integrationConfig.name);
15220
15334
  if (created) {
15221
15335
  logger.log(`Created new API key for ${integrationConfig.name}`);
15222
15336
  } else {
@@ -15267,9 +15381,12 @@ async function addClientAction(options) {
15267
15381
 
15268
15382
  // src/cli.ts
15269
15383
  init_config();
15384
+ init_logger();
15270
15385
  import { existsSync as existsSync9, mkdirSync as mkdirSync5 } from "fs";
15271
15386
  import { execSync } from "child_process";
15387
+
15272
15388
  // src/integrations/index.ts
15389
+ init_logger();
15273
15390
  function ask(question) {
15274
15391
  process.stdout.write(question);
15275
15392
  if (!process.stdin.isTTY) {
@@ -15413,6 +15530,8 @@ init_esm2();
15413
15530
 
15414
15531
  // src/daemon/wallet/cocod-client.ts
15415
15532
  import { existsSync as existsSync8 } from "fs";
15533
+ init_logger();
15534
+ init_process_lock();
15416
15535
  var DEFAULT_CONFIG_DIR = process.env.COCOD_DIR || `${process.env.HOME || process.env.USERPROFILE || ""}/.cocod`;
15417
15536
  var DEFAULT_SOCKET_PATH = process.env.COCOD_SOCKET || `${DEFAULT_CONFIG_DIR}/cocod.sock`;
15418
15537
  function resolveCocodExecutable(cocodPath) {
@@ -15438,7 +15557,7 @@ async function isCocodInstalled(cocodPath) {
15438
15557
  // package.json
15439
15558
  var package_default = {
15440
15559
  name: "routstrd",
15441
- version: "0.2.8",
15560
+ version: "0.2.10",
15442
15561
  module: "src/index.ts",
15443
15562
  type: "module",
15444
15563
  private: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "routstrd",
3
- "version": "0.2.8",
3
+ "version": "0.2.10",
4
4
  "module": "src/index.ts",
5
5
  "type": "module",
6
6
  "private": false,