routstrd 0.3.0 → 0.3.1
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/bun.lock +103 -17
- package/dist/daemon/index.js +17965 -6964
- package/dist/index.js +109 -82
- package/package.json +2 -2
- package/src/cli.ts +38 -21
- package/src/integrations/claudecode.ts +9 -10
- package/src/integrations/hermes.ts +10 -11
- package/src/integrations/openclaw.ts +5 -6
- package/src/integrations/opencode.ts +5 -6
- package/src/integrations/pi.ts +13 -9
- package/src/integrations/registry.ts +1 -0
- package/src/utils/clients.ts +4 -3
- package/src/utils/config.ts +3 -0
- package/src/utils/daemon-client.ts +32 -5
package/dist/index.js
CHANGED
|
@@ -9530,15 +9530,19 @@ async function loadConfig() {
|
|
|
9530
9530
|
function getDaemonBaseUrl(config) {
|
|
9531
9531
|
return config.daemonUrl?.replace(/\/$/, "") || `http://localhost:${config.port}`;
|
|
9532
9532
|
}
|
|
9533
|
-
|
|
9533
|
+
function getAuthBaseUrl(config) {
|
|
9534
|
+
if (config.authUrl) {
|
|
9535
|
+
return config.authUrl.replace(/\/$/, "");
|
|
9536
|
+
}
|
|
9537
|
+
return getDaemonBaseUrl(config);
|
|
9538
|
+
}
|
|
9539
|
+
async function _callUrl(baseUrl, path, options, config) {
|
|
9534
9540
|
const { method = "GET", body } = options;
|
|
9535
|
-
const config = await loadConfig();
|
|
9536
|
-
const baseUrl = getDaemonBaseUrl(config);
|
|
9537
9541
|
const url = `${baseUrl}${path}`;
|
|
9538
9542
|
const bodyString = body ? JSON.stringify(body) : undefined;
|
|
9539
9543
|
const bodyBytes = bodyString ? new TextEncoder().encode(bodyString) : undefined;
|
|
9540
9544
|
let authorization;
|
|
9541
|
-
if (config.daemonUrl && config.nsec) {
|
|
9545
|
+
if ((config.daemonUrl || config.authUrl) && config.nsec) {
|
|
9542
9546
|
const secretKey = parseSecretKey(config.nsec);
|
|
9543
9547
|
authorization = await createNIP98Authorization(secretKey, url, method, bodyBytes);
|
|
9544
9548
|
}
|
|
@@ -9556,6 +9560,16 @@ async function callDaemon(path, options = {}) {
|
|
|
9556
9560
|
}
|
|
9557
9561
|
return response.json();
|
|
9558
9562
|
}
|
|
9563
|
+
async function callDaemon(path, options = {}) {
|
|
9564
|
+
const config = await loadConfig();
|
|
9565
|
+
const baseUrl = getDaemonBaseUrl(config);
|
|
9566
|
+
return _callUrl(baseUrl, path, options, config);
|
|
9567
|
+
}
|
|
9568
|
+
async function callAuth(path, options = {}) {
|
|
9569
|
+
const config = await loadConfig();
|
|
9570
|
+
const baseUrl = getAuthBaseUrl(config);
|
|
9571
|
+
return _callUrl(baseUrl, path, options, config);
|
|
9572
|
+
}
|
|
9559
9573
|
async function isDaemonRunning() {
|
|
9560
9574
|
try {
|
|
9561
9575
|
const config = await loadConfig();
|
|
@@ -15066,7 +15080,6 @@ init_logger();
|
|
|
15066
15080
|
import { join as join3 } from "path";
|
|
15067
15081
|
|
|
15068
15082
|
// src/integrations/opencode.ts
|
|
15069
|
-
init_logger();
|
|
15070
15083
|
init_daemon_client();
|
|
15071
15084
|
import { existsSync as existsSync3, mkdirSync } from "fs";
|
|
15072
15085
|
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
@@ -15074,9 +15087,9 @@ import { dirname as dirname2 } from "path";
|
|
|
15074
15087
|
var OPENCODE_SMALL_MODEL = "routstr/minimax-m2.5";
|
|
15075
15088
|
async function installOpencodeIntegration(config, apiKey, integrationConfig) {
|
|
15076
15089
|
const { name, configPath } = integrationConfig;
|
|
15077
|
-
|
|
15090
|
+
console.log(`
|
|
15078
15091
|
Installing routstr models in opencode.json...`);
|
|
15079
|
-
|
|
15092
|
+
console.log(`Using API key for ${name}`);
|
|
15080
15093
|
const baseUrl = getDaemonBaseUrl(config);
|
|
15081
15094
|
let opencodeConfig;
|
|
15082
15095
|
try {
|
|
@@ -15097,7 +15110,7 @@ Installing routstr models in opencode.json...`);
|
|
|
15097
15110
|
const data = await callDaemon("/models");
|
|
15098
15111
|
const models = data.output?.models || [];
|
|
15099
15112
|
if (models.length === 0) {
|
|
15100
|
-
|
|
15113
|
+
console.log("No models found from routstr daemon.");
|
|
15101
15114
|
return;
|
|
15102
15115
|
}
|
|
15103
15116
|
const modelsObj = {};
|
|
@@ -15116,23 +15129,22 @@ Installing routstr models in opencode.json...`);
|
|
|
15116
15129
|
};
|
|
15117
15130
|
opencodeConfig.small_model = OPENCODE_SMALL_MODEL;
|
|
15118
15131
|
await writeFile2(configPath, JSON.stringify(opencodeConfig, null, 2));
|
|
15119
|
-
|
|
15132
|
+
console.log(`Added "routstr" provider with ${models.length} models to opencode.json`);
|
|
15120
15133
|
} catch (error) {
|
|
15121
|
-
|
|
15134
|
+
console.error("Failed to install models in opencode.json:", error);
|
|
15122
15135
|
}
|
|
15123
15136
|
}
|
|
15124
15137
|
|
|
15125
15138
|
// src/integrations/pi.ts
|
|
15126
|
-
init_logger();
|
|
15127
15139
|
init_daemon_client();
|
|
15128
15140
|
import { existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
|
|
15129
15141
|
import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
15130
15142
|
import { dirname as dirname3 } from "path";
|
|
15131
15143
|
async function installPiIntegration(config, apiKey, integrationConfig) {
|
|
15132
15144
|
const { name, configPath } = integrationConfig;
|
|
15133
|
-
|
|
15145
|
+
console.log(`
|
|
15134
15146
|
Installing routstr models in pi models.json...`);
|
|
15135
|
-
|
|
15147
|
+
console.log(`Using API key for ${name}`);
|
|
15136
15148
|
const baseUrl = `${getDaemonBaseUrl(config)}/v1`;
|
|
15137
15149
|
let piConfig = {};
|
|
15138
15150
|
try {
|
|
@@ -15151,12 +15163,16 @@ Installing routstr models in pi models.json...`);
|
|
|
15151
15163
|
const data = await callDaemon("/models");
|
|
15152
15164
|
const models = data.output?.models || [];
|
|
15153
15165
|
if (models.length === 0) {
|
|
15154
|
-
|
|
15166
|
+
console.log("No models found from routstr daemon.");
|
|
15155
15167
|
return;
|
|
15156
15168
|
}
|
|
15157
|
-
const providerModels = models.map((model) =>
|
|
15158
|
-
id: model.id
|
|
15159
|
-
|
|
15169
|
+
const providerModels = models.map((model) => {
|
|
15170
|
+
const entry = { id: model.id };
|
|
15171
|
+
if (model.context_length !== undefined && model.context_length > 0) {
|
|
15172
|
+
entry.contextWindow = model.context_length;
|
|
15173
|
+
}
|
|
15174
|
+
return entry;
|
|
15175
|
+
});
|
|
15160
15176
|
piConfig.providers["routstr"] = {
|
|
15161
15177
|
baseUrl,
|
|
15162
15178
|
api: "openai-completions",
|
|
@@ -15164,14 +15180,13 @@ Installing routstr models in pi models.json...`);
|
|
|
15164
15180
|
models: providerModels
|
|
15165
15181
|
};
|
|
15166
15182
|
await writeFile3(configPath, JSON.stringify(piConfig, null, 2));
|
|
15167
|
-
|
|
15183
|
+
console.log(`Added "routstr" provider with ${models.length} models to pi models.json`);
|
|
15168
15184
|
} catch (error) {
|
|
15169
|
-
|
|
15185
|
+
console.error("Failed to install models in pi models.json:", error);
|
|
15170
15186
|
}
|
|
15171
15187
|
}
|
|
15172
15188
|
|
|
15173
15189
|
// src/integrations/openclaw.ts
|
|
15174
|
-
init_logger();
|
|
15175
15190
|
init_daemon_client();
|
|
15176
15191
|
import { existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
15177
15192
|
import { readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
@@ -15181,9 +15196,9 @@ var OPENCLAW_DEFAULT_PRIMARY_MODEL = "routstr/minimax-m2.5";
|
|
|
15181
15196
|
var OPENCLAW_DEFAULT_FALLBACK_MODEL = "routstr/kimi-k2.5";
|
|
15182
15197
|
async function installOpenClawIntegration(config, apiKey, integrationConfig) {
|
|
15183
15198
|
const { name, configPath } = integrationConfig;
|
|
15184
|
-
|
|
15199
|
+
console.log(`
|
|
15185
15200
|
Installing routstr models in openclaw.json...`);
|
|
15186
|
-
|
|
15201
|
+
console.log(`Using API key for ${name}`);
|
|
15187
15202
|
const baseUrl = getDaemonBaseUrl(config);
|
|
15188
15203
|
let openclawConfig = {};
|
|
15189
15204
|
try {
|
|
@@ -15211,7 +15226,7 @@ Installing routstr models in openclaw.json...`);
|
|
|
15211
15226
|
const data = await callDaemon("/models");
|
|
15212
15227
|
const models = data.output?.models || [];
|
|
15213
15228
|
if (models.length === 0) {
|
|
15214
|
-
|
|
15229
|
+
console.log("No models found from routstr daemon.");
|
|
15215
15230
|
return;
|
|
15216
15231
|
}
|
|
15217
15232
|
const providerModels = models.map((model) => ({
|
|
@@ -15240,23 +15255,22 @@ Installing routstr models in openclaw.json...`);
|
|
|
15240
15255
|
};
|
|
15241
15256
|
}
|
|
15242
15257
|
await writeFile4(configPath, JSON.stringify(openclawConfig, null, 2));
|
|
15243
|
-
|
|
15258
|
+
console.log(`Added "${OPENCLAW_PROVIDER_ID}" provider with ${models.length} models to openclaw.json`);
|
|
15244
15259
|
} catch (error) {
|
|
15245
|
-
|
|
15260
|
+
console.error("Failed to install models in openclaw.json:", error);
|
|
15246
15261
|
}
|
|
15247
15262
|
}
|
|
15248
15263
|
|
|
15249
15264
|
// src/integrations/claudecode.ts
|
|
15250
|
-
init_logger();
|
|
15251
15265
|
init_daemon_client();
|
|
15252
15266
|
import { existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
|
|
15253
15267
|
import { readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
|
|
15254
15268
|
import { dirname as dirname5 } from "path";
|
|
15255
15269
|
async function installClaudeCodeIntegration(config, apiKey, integrationConfig) {
|
|
15256
15270
|
const { name, configPath } = integrationConfig;
|
|
15257
|
-
|
|
15271
|
+
console.log(`
|
|
15258
15272
|
Installing routstr configuration in ${configPath}...`);
|
|
15259
|
-
|
|
15273
|
+
console.log(`Using API key for ${name}`);
|
|
15260
15274
|
const baseUrl = getDaemonBaseUrl(config);
|
|
15261
15275
|
let settings = {};
|
|
15262
15276
|
try {
|
|
@@ -15265,7 +15279,7 @@ Installing routstr configuration in ${configPath}...`);
|
|
|
15265
15279
|
settings = JSON.parse(content);
|
|
15266
15280
|
}
|
|
15267
15281
|
} catch (error) {
|
|
15268
|
-
|
|
15282
|
+
console.error(`Error reading ${configPath}, creating new one.`);
|
|
15269
15283
|
}
|
|
15270
15284
|
if (!settings.env) {
|
|
15271
15285
|
settings.env = {};
|
|
@@ -15282,39 +15296,38 @@ Installing routstr configuration in ${configPath}...`);
|
|
|
15282
15296
|
settings.env["ANTHROPIC_DEFAULT_OPUS_MODEL"] = opus.id;
|
|
15283
15297
|
settings.env["ANTHROPIC_DEFAULT_SONNET_MODEL"] = sonnet.id;
|
|
15284
15298
|
settings.env["ANTHROPIC_DEFAULT_HAIKU_MODEL"] = haiku.id;
|
|
15285
|
-
|
|
15299
|
+
console.log(`Set Claude models: Opus=${opus.id}, Sonnet=${sonnet.id}, Haiku=${haiku.id}`);
|
|
15286
15300
|
} else if (models.length > 0) {
|
|
15287
15301
|
const model = models[0];
|
|
15288
|
-
|
|
15302
|
+
console.log(`Only ${models.length} models available, falling back to defaults.`);
|
|
15289
15303
|
settings.env["ANTHROPIC_DEFAULT_OPUS_MODEL"] = model.id;
|
|
15290
15304
|
settings.env["ANTHROPIC_DEFAULT_SONNET_MODEL"] = model.id;
|
|
15291
15305
|
settings.env["ANTHROPIC_DEFAULT_HAIKU_MODEL"] = model.id;
|
|
15292
15306
|
} else {
|
|
15293
|
-
|
|
15307
|
+
console.log("No models available from routstr daemon.");
|
|
15294
15308
|
}
|
|
15295
15309
|
} catch (error) {
|
|
15296
|
-
|
|
15310
|
+
console.error("Failed to fetch models for Claude Code integration:", error);
|
|
15297
15311
|
}
|
|
15298
15312
|
try {
|
|
15299
15313
|
mkdirSync4(dirname5(configPath), { recursive: true });
|
|
15300
15314
|
await writeFile5(configPath, JSON.stringify(settings, null, 2));
|
|
15301
|
-
|
|
15315
|
+
console.log(`Successfully updated ${configPath} with routstr settings.`);
|
|
15302
15316
|
} catch (error) {
|
|
15303
|
-
|
|
15317
|
+
console.error(`Failed to write to ${configPath}:`, error);
|
|
15304
15318
|
}
|
|
15305
15319
|
}
|
|
15306
15320
|
|
|
15307
15321
|
// src/integrations/hermes.ts
|
|
15308
|
-
init_logger();
|
|
15309
15322
|
init_daemon_client();
|
|
15310
15323
|
import { existsSync as existsSync7, mkdirSync as mkdirSync5 } from "fs";
|
|
15311
15324
|
import { readFile as readFile6, writeFile as writeFile6 } from "fs/promises";
|
|
15312
15325
|
import { dirname as dirname6 } from "path";
|
|
15313
15326
|
async function installHermesIntegration(config, apiKey, integrationConfig) {
|
|
15314
15327
|
const { name, configPath } = integrationConfig;
|
|
15315
|
-
|
|
15328
|
+
console.log(`
|
|
15316
15329
|
Installing routstr configuration in ${configPath}...`);
|
|
15317
|
-
|
|
15330
|
+
console.log(`Using API key for ${name}`);
|
|
15318
15331
|
const baseUrl = getDaemonBaseUrl(config);
|
|
15319
15332
|
const baseUrlV1 = `${baseUrl}/v1`;
|
|
15320
15333
|
let defaultModel = "minimax-m2.7";
|
|
@@ -15323,16 +15336,16 @@ Installing routstr configuration in ${configPath}...`);
|
|
|
15323
15336
|
const models = data.output?.models || [];
|
|
15324
15337
|
if (models.length >= 3) {
|
|
15325
15338
|
defaultModel = models[2].id;
|
|
15326
|
-
|
|
15339
|
+
console.log(`Set default model to 3rd available model: ${defaultModel}`);
|
|
15327
15340
|
} else if (models.length > 0) {
|
|
15328
15341
|
defaultModel = models[0].id;
|
|
15329
|
-
|
|
15342
|
+
console.log(`Only ${models.length} models available, using ${defaultModel} as default.`);
|
|
15330
15343
|
} else {
|
|
15331
|
-
|
|
15344
|
+
console.log("No models available from routstr daemon, using fallback default.");
|
|
15332
15345
|
}
|
|
15333
15346
|
} catch (error) {
|
|
15334
|
-
|
|
15335
|
-
|
|
15347
|
+
console.error("Failed to fetch models for Hermes integration:", error);
|
|
15348
|
+
console.log("Using fallback default model.");
|
|
15336
15349
|
}
|
|
15337
15350
|
let content = "";
|
|
15338
15351
|
try {
|
|
@@ -15340,7 +15353,7 @@ Installing routstr configuration in ${configPath}...`);
|
|
|
15340
15353
|
content = await readFile6(configPath, "utf-8");
|
|
15341
15354
|
}
|
|
15342
15355
|
} catch (error) {
|
|
15343
|
-
|
|
15356
|
+
console.error(`Error reading ${configPath}, creating new one.`);
|
|
15344
15357
|
}
|
|
15345
15358
|
content = content.replace(/^model:\n(?: .*\n)*/gm, "");
|
|
15346
15359
|
content = content.replace(/^custom_providers:\n(?:- .*\n(?: .*\n)*)*/gm, "");
|
|
@@ -15370,9 +15383,9 @@ Installing routstr configuration in ${configPath}...`);
|
|
|
15370
15383
|
try {
|
|
15371
15384
|
mkdirSync5(dirname6(configPath), { recursive: true });
|
|
15372
15385
|
await writeFile6(configPath, newContent);
|
|
15373
|
-
|
|
15386
|
+
console.log(`Successfully updated ${configPath} with routstr settings.`);
|
|
15374
15387
|
} catch (error) {
|
|
15375
|
-
|
|
15388
|
+
console.error(`Failed to write to ${configPath}:`, error);
|
|
15376
15389
|
}
|
|
15377
15390
|
}
|
|
15378
15391
|
|
|
@@ -15427,7 +15440,7 @@ async function runIntegrationsForClients(clientIds, config) {
|
|
|
15427
15440
|
|
|
15428
15441
|
// src/utils/clients.ts
|
|
15429
15442
|
async function getClientsList() {
|
|
15430
|
-
const result = await
|
|
15443
|
+
const result = await callAuth("/clients");
|
|
15431
15444
|
const clients = result.output?.clients;
|
|
15432
15445
|
if (!clients) {
|
|
15433
15446
|
return [];
|
|
@@ -15456,7 +15469,7 @@ async function addDaemonClient(name) {
|
|
|
15456
15469
|
};
|
|
15457
15470
|
return { client, created: false };
|
|
15458
15471
|
}
|
|
15459
|
-
const result = await
|
|
15472
|
+
const result = await callAuth("/clients/add", {
|
|
15460
15473
|
method: "POST",
|
|
15461
15474
|
body: { name, id: derivedId }
|
|
15462
15475
|
});
|
|
@@ -15494,7 +15507,7 @@ async function listClientsAction() {
|
|
|
15494
15507
|
}
|
|
15495
15508
|
async function deleteClientAction(id) {
|
|
15496
15509
|
await ensureDaemonRunning();
|
|
15497
|
-
const result = await
|
|
15510
|
+
const result = await callAuth("/clients/delete", {
|
|
15498
15511
|
method: "POST",
|
|
15499
15512
|
body: { id }
|
|
15500
15513
|
});
|
|
@@ -15618,14 +15631,14 @@ function parseChoice(input) {
|
|
|
15618
15631
|
return 1;
|
|
15619
15632
|
}
|
|
15620
15633
|
async function setupIntegration(config) {
|
|
15621
|
-
|
|
15634
|
+
console.log(`
|
|
15622
15635
|
Choose an integration to set up:`);
|
|
15623
|
-
|
|
15624
|
-
|
|
15625
|
-
|
|
15626
|
-
|
|
15627
|
-
|
|
15628
|
-
|
|
15636
|
+
console.log("1. OpenCode (default)");
|
|
15637
|
+
console.log("2. OpenClaw");
|
|
15638
|
+
console.log("3. Pi");
|
|
15639
|
+
console.log("4. Claude Code");
|
|
15640
|
+
console.log("5. Hermes");
|
|
15641
|
+
console.log("6. Skip for now");
|
|
15629
15642
|
const answer = await ask("Select integration [1]: ");
|
|
15630
15643
|
const choice = parseChoice(answer);
|
|
15631
15644
|
const integrationByChoice = {
|
|
@@ -15637,15 +15650,15 @@ Choose an integration to set up:`);
|
|
|
15637
15650
|
};
|
|
15638
15651
|
const key = integrationByChoice[choice];
|
|
15639
15652
|
if (!key) {
|
|
15640
|
-
|
|
15653
|
+
console.log("Skipping integration setup.");
|
|
15641
15654
|
return;
|
|
15642
15655
|
}
|
|
15643
15656
|
const integrationConfig = CLIENT_CONFIGS[key];
|
|
15644
15657
|
const { client, created } = await addDaemonClient(integrationConfig.name);
|
|
15645
15658
|
if (created) {
|
|
15646
|
-
|
|
15659
|
+
console.log(`Created new API key for ${integrationConfig.name}`);
|
|
15647
15660
|
} else {
|
|
15648
|
-
|
|
15661
|
+
console.log(`Using existing API key for ${integrationConfig.name}`);
|
|
15649
15662
|
}
|
|
15650
15663
|
if (key === "opencode") {
|
|
15651
15664
|
await installOpencodeIntegration(config, client.apiKey, integrationConfig);
|
|
@@ -15770,7 +15783,7 @@ async function isCocodInstalled(cocodPath) {
|
|
|
15770
15783
|
// package.json
|
|
15771
15784
|
var package_default = {
|
|
15772
15785
|
name: "routstrd",
|
|
15773
|
-
version: "0.3.
|
|
15786
|
+
version: "0.3.1",
|
|
15774
15787
|
module: "src/index.ts",
|
|
15775
15788
|
type: "module",
|
|
15776
15789
|
private: false,
|
|
@@ -15794,7 +15807,7 @@ var package_default = {
|
|
|
15794
15807
|
},
|
|
15795
15808
|
dependencies: {
|
|
15796
15809
|
"@cashu/cashu-ts": "^4.3.0",
|
|
15797
|
-
"@routstr/sdk": "^0.3.
|
|
15810
|
+
"@routstr/sdk": "^0.3.9",
|
|
15798
15811
|
"applesauce-core": "^5.1.0",
|
|
15799
15812
|
"applesauce-relay": "^5.1.0",
|
|
15800
15813
|
"applesauce-wallet-connect": "^6.0.0",
|
|
@@ -15829,17 +15842,17 @@ Invoice:
|
|
|
15829
15842
|
${invoice}`);
|
|
15830
15843
|
}
|
|
15831
15844
|
async function installCocodOrExit() {
|
|
15832
|
-
|
|
15845
|
+
console.log("cocod not found. Installing globally with bun...");
|
|
15833
15846
|
const installProc = Bun.spawn(["bun", "install", "--global", "@routstr/cocod"], {
|
|
15834
15847
|
stdout: "inherit",
|
|
15835
15848
|
stderr: "inherit"
|
|
15836
15849
|
});
|
|
15837
15850
|
const installCode = await installProc.exited;
|
|
15838
15851
|
if (installCode !== 0 || !await isCocodInstalled()) {
|
|
15839
|
-
|
|
15852
|
+
console.error("Failed to install cocod. Please run 'bun install --global @routstr/cocod' manually.");
|
|
15840
15853
|
throw new Error("cocod installation failed");
|
|
15841
15854
|
}
|
|
15842
|
-
|
|
15855
|
+
console.log("cocod installed successfully.");
|
|
15843
15856
|
}
|
|
15844
15857
|
async function requireLocalDaemon() {
|
|
15845
15858
|
const config = await loadConfig();
|
|
@@ -15849,10 +15862,10 @@ async function requireLocalDaemon() {
|
|
|
15849
15862
|
}
|
|
15850
15863
|
}
|
|
15851
15864
|
async function initDaemon() {
|
|
15852
|
-
|
|
15865
|
+
console.log("Initializing routstrd...");
|
|
15853
15866
|
if (!existsSync9(CONFIG_DIR)) {
|
|
15854
15867
|
mkdirSync6(CONFIG_DIR, { recursive: true });
|
|
15855
|
-
|
|
15868
|
+
console.log(`Created config directory: ${CONFIG_DIR}`);
|
|
15856
15869
|
}
|
|
15857
15870
|
if (!existsSync9(CONFIG_FILE)) {
|
|
15858
15871
|
const config2 = {
|
|
@@ -15860,7 +15873,7 @@ async function initDaemon() {
|
|
|
15860
15873
|
cocodPath: null
|
|
15861
15874
|
};
|
|
15862
15875
|
await Bun.write(CONFIG_FILE, JSON.stringify(config2, null, 2));
|
|
15863
|
-
|
|
15876
|
+
console.log(`Created config file: ${CONFIG_FILE}`);
|
|
15864
15877
|
}
|
|
15865
15878
|
const config = await loadConfig();
|
|
15866
15879
|
if (!await isCocodInstalled(config.cocodPath)) {
|
|
@@ -15903,23 +15916,23 @@ Initializing cocod...`);
|
|
|
15903
15916
|
${initStderr}`.toLowerCase();
|
|
15904
15917
|
const alreadyInitialized = combinedOutput.includes("already initialized");
|
|
15905
15918
|
if (initCode !== 0 && !alreadyInitialized) {
|
|
15906
|
-
|
|
15919
|
+
console.error("Failed to initialize cocod. Please run 'cocod init' manually.");
|
|
15907
15920
|
return;
|
|
15908
15921
|
}
|
|
15909
15922
|
if (alreadyInitialized) {
|
|
15910
|
-
|
|
15923
|
+
console.log("cocod is already initialized.");
|
|
15911
15924
|
} else {
|
|
15912
|
-
|
|
15925
|
+
console.log("cocod initialized successfully.");
|
|
15913
15926
|
}
|
|
15914
15927
|
await startDaemon({ port: String(config.port || 8008) });
|
|
15915
15928
|
await setupIntegration(config);
|
|
15916
|
-
|
|
15929
|
+
console.log(`
|
|
15917
15930
|
Initialization complete!`);
|
|
15918
|
-
|
|
15931
|
+
console.log(`
|
|
15919
15932
|
use 'routstrd receive <cashu-token>' or 'routstrd receive 2100' to top up your local wallet using Lightning!`);
|
|
15920
|
-
|
|
15933
|
+
console.log(`
|
|
15921
15934
|
full wallet commands still work too, e.g. 'routstrd wallet receive cashu <token>' and 'routstrd wallet receive bolt11 2100'.`);
|
|
15922
|
-
|
|
15935
|
+
console.log(`
|
|
15923
15936
|
To ensure routstrd persists across system restarts, run: 'routstrd service install'`);
|
|
15924
15937
|
}
|
|
15925
15938
|
program.name("routstrd").description("Routstr daemon - Manage routstr processes").version(package_default.version, "--version", "output the version number");
|
|
@@ -15992,18 +16005,29 @@ Results:`);
|
|
|
15992
16005
|
process.exit(1);
|
|
15993
16006
|
}
|
|
15994
16007
|
});
|
|
15995
|
-
program.command("remote <url>").description("Configure a remote daemon URL").action(async (url) => {
|
|
16008
|
+
program.command("remote <url>").description("Configure a remote daemon URL").option("--auth-url <authUrl>", "URL of the auth proxy for management commands (npubs, clients, usage)").action(async (url, options) => {
|
|
15996
16009
|
try {
|
|
15997
16010
|
new URL(url);
|
|
15998
16011
|
} catch {
|
|
15999
16012
|
console.error(`Invalid URL: ${url}`);
|
|
16000
16013
|
process.exit(1);
|
|
16001
16014
|
}
|
|
16015
|
+
if (options.authUrl) {
|
|
16016
|
+
try {
|
|
16017
|
+
new URL(options.authUrl);
|
|
16018
|
+
} catch {
|
|
16019
|
+
console.error(`Invalid auth URL: ${options.authUrl}`);
|
|
16020
|
+
process.exit(1);
|
|
16021
|
+
}
|
|
16022
|
+
}
|
|
16002
16023
|
if (!existsSync9(CONFIG_DIR)) {
|
|
16003
16024
|
mkdirSync6(CONFIG_DIR, { recursive: true });
|
|
16004
16025
|
}
|
|
16005
16026
|
const config = await loadConfig();
|
|
16006
16027
|
const updates = { daemonUrl: url };
|
|
16028
|
+
if (options.authUrl) {
|
|
16029
|
+
updates.authUrl = options.authUrl;
|
|
16030
|
+
}
|
|
16007
16031
|
let generatedNpub;
|
|
16008
16032
|
if (!config.nsec) {
|
|
16009
16033
|
const secretKey = generateSecretKey();
|
|
@@ -16018,6 +16042,9 @@ program.command("remote <url>").description("Configure a remote daemon URL").act
|
|
|
16018
16042
|
};
|
|
16019
16043
|
await Bun.write(CONFIG_FILE, JSON.stringify(updatedConfig, null, 2));
|
|
16020
16044
|
console.log(`Remote daemon URL set to: ${url}`);
|
|
16045
|
+
if (options.authUrl) {
|
|
16046
|
+
console.log(`Auth proxy URL set to: ${options.authUrl}`);
|
|
16047
|
+
}
|
|
16021
16048
|
if (generatedNpub) {
|
|
16022
16049
|
console.log(`
|
|
16023
16050
|
A new Nostr identity has been generated for remote authentication.`);
|
|
@@ -16195,7 +16222,7 @@ program.command("usage").description("Show recent usage logs and total sats cost
|
|
|
16195
16222
|
await ensureDaemonRunning();
|
|
16196
16223
|
const requested = Number.parseInt(options.limit, 10);
|
|
16197
16224
|
const limit = Number.isFinite(requested) && requested > 0 ? Math.min(requested, 1000) : 10;
|
|
16198
|
-
const result = await
|
|
16225
|
+
const result = await callAuth(`/usage?limit=${limit}`);
|
|
16199
16226
|
if (result.error) {
|
|
16200
16227
|
console.log(result.error);
|
|
16201
16228
|
process.exit(1);
|
|
@@ -16302,7 +16329,7 @@ npubsCmd.command("list").description("List configured npubs with their roles").a
|
|
|
16302
16329
|
await ensureDaemonRunning();
|
|
16303
16330
|
const config = await loadConfig();
|
|
16304
16331
|
const userNpub = getUserNpub(config);
|
|
16305
|
-
const result = await
|
|
16332
|
+
const result = await callAuth("/npubs");
|
|
16306
16333
|
if (result.error) {
|
|
16307
16334
|
console.log(result.error);
|
|
16308
16335
|
process.exit(1);
|
|
@@ -16335,7 +16362,7 @@ npubsCmd.command("register").description("Register yourself as the first admin (
|
|
|
16335
16362
|
console.error("No Nostr identity configured. Run 'routstrd remote <url>' to set one up.");
|
|
16336
16363
|
process.exit(1);
|
|
16337
16364
|
}
|
|
16338
|
-
const result = await
|
|
16365
|
+
const result = await callAuth("/npubs");
|
|
16339
16366
|
if (result.error) {
|
|
16340
16367
|
console.log(result.error);
|
|
16341
16368
|
process.exit(1);
|
|
@@ -16352,7 +16379,7 @@ npubsCmd.command("register").description("Register yourself as the first admin (
|
|
|
16352
16379
|
console.error("Failed to normalize user npub.");
|
|
16353
16380
|
process.exit(1);
|
|
16354
16381
|
}
|
|
16355
|
-
const addResult = await
|
|
16382
|
+
const addResult = await callAuth("/npubs", {
|
|
16356
16383
|
method: "POST",
|
|
16357
16384
|
body: { npub: npubFromPubkey(normalized) }
|
|
16358
16385
|
});
|
|
@@ -16379,7 +16406,7 @@ npubsCmd.command("add <npub>").description("Add a npub (hex pubkey or npub1...).
|
|
|
16379
16406
|
process.exit(1);
|
|
16380
16407
|
}
|
|
16381
16408
|
const body = { npub: npubFromPubkey(normalized), role: options.role };
|
|
16382
|
-
const result = await
|
|
16409
|
+
const result = await callAuth("/npubs", {
|
|
16383
16410
|
method: "POST",
|
|
16384
16411
|
body
|
|
16385
16412
|
});
|
|
@@ -16403,7 +16430,7 @@ npubsCmd.command("update <npub>").description("Update the role of an existing np
|
|
|
16403
16430
|
console.error("Invalid role. Expected 'admin' or 'user'.");
|
|
16404
16431
|
process.exit(1);
|
|
16405
16432
|
}
|
|
16406
|
-
const result = await
|
|
16433
|
+
const result = await callAuth("/npubs", {
|
|
16407
16434
|
method: "PATCH",
|
|
16408
16435
|
body: { npub: npubFromPubkey(normalized), role: options.role }
|
|
16409
16436
|
});
|
|
@@ -16425,7 +16452,7 @@ npubsCmd.command("delete <npub>").description("Delete an npub (hex pubkey or npu
|
|
|
16425
16452
|
console.error("Invalid npub value. Use npub1... or 64-char hex pubkey.");
|
|
16426
16453
|
process.exit(1);
|
|
16427
16454
|
}
|
|
16428
|
-
const result = await
|
|
16455
|
+
const result = await callAuth(`/npubs/${encodeURIComponent(npubFromPubkey(normalized))}`, {
|
|
16429
16456
|
method: "DELETE"
|
|
16430
16457
|
});
|
|
16431
16458
|
if (result.error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "routstrd",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"module": "src/index.ts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@cashu/cashu-ts": "^4.3.0",
|
|
27
|
-
"@routstr/sdk": "^0.3.
|
|
27
|
+
"@routstr/sdk": "^0.3.9",
|
|
28
28
|
"applesauce-core": "^5.1.0",
|
|
29
29
|
"applesauce-relay": "^5.1.0",
|
|
30
30
|
"applesauce-wallet-connect": "^6.0.0",
|