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/src/cli.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { startDaemon } from "./start-daemon";
|
|
|
3
3
|
import {
|
|
4
4
|
handleDaemonCommand,
|
|
5
5
|
callDaemon,
|
|
6
|
+
callAuth,
|
|
6
7
|
ensureDaemonRunning,
|
|
7
8
|
isDaemonRunning,
|
|
8
9
|
loadConfig,
|
|
@@ -81,7 +82,7 @@ async function printLightningInvoice(invoice: string): Promise<void> {
|
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
async function installCocodOrExit(): Promise<void> {
|
|
84
|
-
|
|
85
|
+
console.log("cocod not found. Installing globally with bun...");
|
|
85
86
|
|
|
86
87
|
const installProc = Bun.spawn(
|
|
87
88
|
["bun", "install", "--global", "@routstr/cocod"],
|
|
@@ -93,13 +94,13 @@ async function installCocodOrExit(): Promise<void> {
|
|
|
93
94
|
|
|
94
95
|
const installCode = await installProc.exited;
|
|
95
96
|
if (installCode !== 0 || !(await isCocodInstalled())) {
|
|
96
|
-
|
|
97
|
+
console.error(
|
|
97
98
|
"Failed to install cocod. Please run 'bun install --global @routstr/cocod' manually.",
|
|
98
99
|
);
|
|
99
100
|
throw new Error("cocod installation failed");
|
|
100
101
|
}
|
|
101
102
|
|
|
102
|
-
|
|
103
|
+
console.log("cocod installed successfully.");
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
async function requireLocalDaemon(): Promise<void> {
|
|
@@ -113,12 +114,12 @@ async function requireLocalDaemon(): Promise<void> {
|
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
async function initDaemon(): Promise<void> {
|
|
116
|
-
|
|
117
|
+
console.log("Initializing routstrd...");
|
|
117
118
|
|
|
118
119
|
// Create config directory
|
|
119
120
|
if (!existsSync(CONFIG_DIR)) {
|
|
120
121
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
121
|
-
|
|
122
|
+
console.log(`Created config directory: ${CONFIG_DIR}`);
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
// Create initial config
|
|
@@ -128,7 +129,7 @@ async function initDaemon(): Promise<void> {
|
|
|
128
129
|
cocodPath: null,
|
|
129
130
|
};
|
|
130
131
|
await Bun.write(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
131
|
-
|
|
132
|
+
console.log(`Created config file: ${CONFIG_FILE}`);
|
|
132
133
|
}
|
|
133
134
|
|
|
134
135
|
const config = await loadConfig();
|
|
@@ -190,30 +191,30 @@ async function initDaemon(): Promise<void> {
|
|
|
190
191
|
const alreadyInitialized = combinedOutput.includes("already initialized");
|
|
191
192
|
|
|
192
193
|
if (initCode !== 0 && !alreadyInitialized) {
|
|
193
|
-
|
|
194
|
+
console.error(
|
|
194
195
|
"Failed to initialize cocod. Please run 'cocod init' manually.",
|
|
195
196
|
);
|
|
196
197
|
return;
|
|
197
198
|
}
|
|
198
199
|
|
|
199
200
|
if (alreadyInitialized) {
|
|
200
|
-
|
|
201
|
+
console.log("cocod is already initialized.");
|
|
201
202
|
} else {
|
|
202
|
-
|
|
203
|
+
console.log("cocod initialized successfully.");
|
|
203
204
|
}
|
|
204
205
|
|
|
205
206
|
await startDaemon({ port: String(config.port || 8008) });
|
|
206
207
|
|
|
207
208
|
await setupIntegration(config);
|
|
208
209
|
|
|
209
|
-
|
|
210
|
-
|
|
210
|
+
console.log("\nInitialization complete!");
|
|
211
|
+
console.log(
|
|
211
212
|
"\n use 'routstrd receive <cashu-token>' or 'routstrd receive 2100' to top up your local wallet using Lightning!",
|
|
212
213
|
);
|
|
213
|
-
|
|
214
|
+
console.log(
|
|
214
215
|
"\n full wallet commands still work too, e.g. 'routstrd wallet receive cashu <token>' and 'routstrd wallet receive bolt11 2100'.",
|
|
215
216
|
);
|
|
216
|
-
|
|
217
|
+
console.log(
|
|
217
218
|
"\nTo ensure routstrd persists across system restarts, run: 'routstrd service install'",
|
|
218
219
|
);
|
|
219
220
|
}
|
|
@@ -334,7 +335,8 @@ program
|
|
|
334
335
|
program
|
|
335
336
|
.command("remote <url>")
|
|
336
337
|
.description("Configure a remote daemon URL")
|
|
337
|
-
.
|
|
338
|
+
.option("--auth-url <authUrl>", "URL of the auth proxy for management commands (npubs, clients, usage)")
|
|
339
|
+
.action(async (url: string, options: { authUrl?: string }) => {
|
|
338
340
|
try {
|
|
339
341
|
new URL(url);
|
|
340
342
|
} catch {
|
|
@@ -342,12 +344,24 @@ program
|
|
|
342
344
|
process.exit(1);
|
|
343
345
|
}
|
|
344
346
|
|
|
347
|
+
if (options.authUrl) {
|
|
348
|
+
try {
|
|
349
|
+
new URL(options.authUrl);
|
|
350
|
+
} catch {
|
|
351
|
+
console.error(`Invalid auth URL: ${options.authUrl}`);
|
|
352
|
+
process.exit(1);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
345
356
|
if (!existsSync(CONFIG_DIR)) {
|
|
346
357
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
347
358
|
}
|
|
348
359
|
|
|
349
360
|
const config = await loadConfig();
|
|
350
361
|
const updates: Partial<RoutstrdConfig> = { daemonUrl: url };
|
|
362
|
+
if (options.authUrl) {
|
|
363
|
+
updates.authUrl = options.authUrl;
|
|
364
|
+
}
|
|
351
365
|
let generatedNpub: string | undefined;
|
|
352
366
|
|
|
353
367
|
if (!config.nsec) {
|
|
@@ -366,6 +380,9 @@ program
|
|
|
366
380
|
await Bun.write(CONFIG_FILE, JSON.stringify(updatedConfig, null, 2));
|
|
367
381
|
|
|
368
382
|
console.log(`Remote daemon URL set to: ${url}`);
|
|
383
|
+
if (options.authUrl) {
|
|
384
|
+
console.log(`Auth proxy URL set to: ${options.authUrl}`);
|
|
385
|
+
}
|
|
369
386
|
if (generatedNpub) {
|
|
370
387
|
console.log(
|
|
371
388
|
`\nA new Nostr identity has been generated for remote authentication.`,
|
|
@@ -666,7 +683,7 @@ program
|
|
|
666
683
|
? Math.min(requested, 1000)
|
|
667
684
|
: 10;
|
|
668
685
|
|
|
669
|
-
const result = await
|
|
686
|
+
const result = await callAuth(`/usage?limit=${limit}`);
|
|
670
687
|
if (result.error) {
|
|
671
688
|
console.log(result.error);
|
|
672
689
|
process.exit(1);
|
|
@@ -882,7 +899,7 @@ npubsCmd
|
|
|
882
899
|
await ensureDaemonRunning();
|
|
883
900
|
const config = await loadConfig();
|
|
884
901
|
const userNpub = getUserNpub(config);
|
|
885
|
-
const result = await
|
|
902
|
+
const result = await callAuth("/npubs");
|
|
886
903
|
if (result.error) {
|
|
887
904
|
console.log(result.error);
|
|
888
905
|
process.exit(1);
|
|
@@ -925,7 +942,7 @@ npubsCmd
|
|
|
925
942
|
);
|
|
926
943
|
process.exit(1);
|
|
927
944
|
}
|
|
928
|
-
const result = await
|
|
945
|
+
const result = await callAuth("/npubs");
|
|
929
946
|
if (result.error) {
|
|
930
947
|
console.log(result.error);
|
|
931
948
|
process.exit(1);
|
|
@@ -943,7 +960,7 @@ npubsCmd
|
|
|
943
960
|
console.error("Failed to normalize user npub.");
|
|
944
961
|
process.exit(1);
|
|
945
962
|
}
|
|
946
|
-
const addResult = await
|
|
963
|
+
const addResult = await callAuth("/npubs", {
|
|
947
964
|
method: "POST",
|
|
948
965
|
body: { npub: npubFromPubkey(normalized) },
|
|
949
966
|
});
|
|
@@ -977,7 +994,7 @@ npubsCmd
|
|
|
977
994
|
process.exit(1);
|
|
978
995
|
}
|
|
979
996
|
const body: Record<string, string> = { npub: npubFromPubkey(normalized), role: options.role };
|
|
980
|
-
const result = await
|
|
997
|
+
const result = await callAuth("/npubs", {
|
|
981
998
|
method: "POST",
|
|
982
999
|
body,
|
|
983
1000
|
});
|
|
@@ -1010,7 +1027,7 @@ npubsCmd
|
|
|
1010
1027
|
console.error("Invalid role. Expected 'admin' or 'user'.");
|
|
1011
1028
|
process.exit(1);
|
|
1012
1029
|
}
|
|
1013
|
-
const result = await
|
|
1030
|
+
const result = await callAuth("/npubs", {
|
|
1014
1031
|
method: "PATCH",
|
|
1015
1032
|
body: { npub: npubFromPubkey(normalized), role: options.role },
|
|
1016
1033
|
});
|
|
@@ -1039,7 +1056,7 @@ npubsCmd
|
|
|
1039
1056
|
console.error("Invalid npub value. Use npub1... or 64-char hex pubkey.");
|
|
1040
1057
|
process.exit(1);
|
|
1041
1058
|
}
|
|
1042
|
-
const result = await
|
|
1059
|
+
const result = await callAuth(
|
|
1043
1060
|
`/npubs/${encodeURIComponent(npubFromPubkey(normalized))}`,
|
|
1044
1061
|
{
|
|
1045
1062
|
method: "DELETE",
|
|
@@ -2,7 +2,6 @@ import { existsSync, mkdirSync } from "fs";
|
|
|
2
2
|
import { readFile, writeFile } from "fs/promises";
|
|
3
3
|
import { dirname } from "path";
|
|
4
4
|
import type { RoutstrdConfig } from "../utils/config";
|
|
5
|
-
import { logger } from "../utils/logger";
|
|
6
5
|
import type { IntegrationConfig, RoutstrModel } from "./registry";
|
|
7
6
|
import { callDaemon, getDaemonBaseUrl } from "../utils/daemon-client";
|
|
8
7
|
|
|
@@ -13,8 +12,8 @@ export async function installClaudeCodeIntegration(
|
|
|
13
12
|
): Promise<void> {
|
|
14
13
|
const { name, configPath } = integrationConfig;
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
console.log(`\nInstalling routstr configuration in ${configPath}...`);
|
|
16
|
+
console.log(`Using API key for ${name}`);
|
|
18
17
|
|
|
19
18
|
const baseUrl = getDaemonBaseUrl(config);
|
|
20
19
|
|
|
@@ -28,7 +27,7 @@ export async function installClaudeCodeIntegration(
|
|
|
28
27
|
settings = JSON.parse(content);
|
|
29
28
|
}
|
|
30
29
|
} catch (error) {
|
|
31
|
-
|
|
30
|
+
console.error(`Error reading ${configPath}, creating new one.`);
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
if (!settings.env) {
|
|
@@ -49,25 +48,25 @@ export async function installClaudeCodeIntegration(
|
|
|
49
48
|
settings.env["ANTHROPIC_DEFAULT_OPUS_MODEL"] = opus.id;
|
|
50
49
|
settings.env["ANTHROPIC_DEFAULT_SONNET_MODEL"] = sonnet.id;
|
|
51
50
|
settings.env["ANTHROPIC_DEFAULT_HAIKU_MODEL"] = haiku.id;
|
|
52
|
-
|
|
51
|
+
console.log(`Set Claude models: Opus=${opus.id}, Sonnet=${sonnet.id}, Haiku=${haiku.id}`);
|
|
53
52
|
} else if (models.length > 0) {
|
|
54
53
|
const model = models[0]!;
|
|
55
|
-
|
|
54
|
+
console.log(`Only ${models.length} models available, falling back to defaults.`);
|
|
56
55
|
settings.env["ANTHROPIC_DEFAULT_OPUS_MODEL"] = model.id;
|
|
57
56
|
settings.env["ANTHROPIC_DEFAULT_SONNET_MODEL"] = model.id;
|
|
58
57
|
settings.env["ANTHROPIC_DEFAULT_HAIKU_MODEL"] = model.id;
|
|
59
58
|
} else {
|
|
60
|
-
|
|
59
|
+
console.log("No models available from routstr daemon.");
|
|
61
60
|
}
|
|
62
61
|
} catch (error) {
|
|
63
|
-
|
|
62
|
+
console.error("Failed to fetch models for Claude Code integration:", error);
|
|
64
63
|
}
|
|
65
64
|
|
|
66
65
|
try {
|
|
67
66
|
mkdirSync(dirname(configPath), { recursive: true });
|
|
68
67
|
await writeFile(configPath, JSON.stringify(settings, null, 2));
|
|
69
|
-
|
|
68
|
+
console.log(`Successfully updated ${configPath} with routstr settings.`);
|
|
70
69
|
} catch (error) {
|
|
71
|
-
|
|
70
|
+
console.error(`Failed to write to ${configPath}:`, error);
|
|
72
71
|
}
|
|
73
72
|
}
|
|
@@ -2,7 +2,6 @@ import { existsSync, mkdirSync } from "fs";
|
|
|
2
2
|
import { readFile, writeFile } from "fs/promises";
|
|
3
3
|
import { dirname } from "path";
|
|
4
4
|
import type { RoutstrdConfig } from "../utils/config";
|
|
5
|
-
import { logger } from "../utils/logger";
|
|
6
5
|
import type { IntegrationConfig, RoutstrModel } from "./registry";
|
|
7
6
|
import { callDaemon, getDaemonBaseUrl } from "../utils/daemon-client";
|
|
8
7
|
|
|
@@ -13,8 +12,8 @@ export async function installHermesIntegration(
|
|
|
13
12
|
): Promise<void> {
|
|
14
13
|
const { name, configPath } = integrationConfig;
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
console.log(`\nInstalling routstr configuration in ${configPath}...`);
|
|
16
|
+
console.log(`Using API key for ${name}`);
|
|
18
17
|
|
|
19
18
|
const baseUrl = getDaemonBaseUrl(config);
|
|
20
19
|
const baseUrlV1 = `${baseUrl}/v1`;
|
|
@@ -27,16 +26,16 @@ export async function installHermesIntegration(
|
|
|
27
26
|
|
|
28
27
|
if (models.length >= 3) {
|
|
29
28
|
defaultModel = models[2]!.id;
|
|
30
|
-
|
|
29
|
+
console.log(`Set default model to 3rd available model: ${defaultModel}`);
|
|
31
30
|
} else if (models.length > 0) {
|
|
32
31
|
defaultModel = models[0]!.id;
|
|
33
|
-
|
|
32
|
+
console.log(`Only ${models.length} models available, using ${defaultModel} as default.`);
|
|
34
33
|
} else {
|
|
35
|
-
|
|
34
|
+
console.log("No models available from routstr daemon, using fallback default.");
|
|
36
35
|
}
|
|
37
36
|
} catch (error) {
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
console.error("Failed to fetch models for Hermes integration:", error);
|
|
38
|
+
console.log("Using fallback default model.");
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
let content = "";
|
|
@@ -45,7 +44,7 @@ export async function installHermesIntegration(
|
|
|
45
44
|
content = await readFile(configPath, "utf-8");
|
|
46
45
|
}
|
|
47
46
|
} catch (error) {
|
|
48
|
-
|
|
47
|
+
console.error(`Error reading ${configPath}, creating new one.`);
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
// Remove existing model block
|
|
@@ -80,8 +79,8 @@ export async function installHermesIntegration(
|
|
|
80
79
|
try {
|
|
81
80
|
mkdirSync(dirname(configPath), { recursive: true });
|
|
82
81
|
await writeFile(configPath, newContent);
|
|
83
|
-
|
|
82
|
+
console.log(`Successfully updated ${configPath} with routstr settings.`);
|
|
84
83
|
} catch (error) {
|
|
85
|
-
|
|
84
|
+
console.error(`Failed to write to ${configPath}:`, error);
|
|
86
85
|
}
|
|
87
86
|
}
|
|
@@ -2,7 +2,6 @@ import { existsSync, mkdirSync } from "fs";
|
|
|
2
2
|
import { readFile, writeFile } from "fs/promises";
|
|
3
3
|
import { dirname } from "path";
|
|
4
4
|
import type { RoutstrdConfig } from "../utils/config";
|
|
5
|
-
import { logger } from "../utils/logger";
|
|
6
5
|
import type { IntegrationConfig, RoutstrModel } from "./registry";
|
|
7
6
|
import { callDaemon, getDaemonBaseUrl } from "../utils/daemon-client";
|
|
8
7
|
|
|
@@ -56,8 +55,8 @@ export async function installOpenClawIntegration(
|
|
|
56
55
|
): Promise<void> {
|
|
57
56
|
const { name, configPath } = integrationConfig;
|
|
58
57
|
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
console.log("\nInstalling routstr models in openclaw.json...");
|
|
59
|
+
console.log(`Using API key for ${name}`);
|
|
61
60
|
|
|
62
61
|
const baseUrl = getDaemonBaseUrl(config);
|
|
63
62
|
|
|
@@ -92,7 +91,7 @@ export async function installOpenClawIntegration(
|
|
|
92
91
|
const models = (data.output as { models: RoutstrModel[] } | undefined)?.models || [];
|
|
93
92
|
|
|
94
93
|
if (models.length === 0) {
|
|
95
|
-
|
|
94
|
+
console.log("No models found from routstr daemon.");
|
|
96
95
|
return;
|
|
97
96
|
}
|
|
98
97
|
|
|
@@ -134,8 +133,8 @@ export async function installOpenClawIntegration(
|
|
|
134
133
|
// openclawConfig.agents.defaults.models = aliasMap;
|
|
135
134
|
|
|
136
135
|
await writeFile(configPath, JSON.stringify(openclawConfig, null, 2));
|
|
137
|
-
|
|
136
|
+
console.log(`Added "${OPENCLAW_PROVIDER_ID}" provider with ${models.length} models to openclaw.json`);
|
|
138
137
|
} catch (error) {
|
|
139
|
-
|
|
138
|
+
console.error("Failed to install models in openclaw.json:", error);
|
|
140
139
|
}
|
|
141
140
|
}
|
|
@@ -2,7 +2,6 @@ import { existsSync, mkdirSync } from "fs";
|
|
|
2
2
|
import { readFile, writeFile } from "fs/promises";
|
|
3
3
|
import { dirname } from "path";
|
|
4
4
|
import type { RoutstrdConfig } from "../utils/config";
|
|
5
|
-
import { logger } from "../utils/logger";
|
|
6
5
|
import type { IntegrationConfig, RoutstrModel } from "./registry";
|
|
7
6
|
import { callDaemon, getDaemonBaseUrl } from "../utils/daemon-client";
|
|
8
7
|
|
|
@@ -15,8 +14,8 @@ export async function installOpencodeIntegration(
|
|
|
15
14
|
): Promise<void> {
|
|
16
15
|
const { name, configPath } = integrationConfig;
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
console.log("\nInstalling routstr models in opencode.json...");
|
|
18
|
+
console.log(`Using API key for ${name}`);
|
|
20
19
|
|
|
21
20
|
const baseUrl = getDaemonBaseUrl(config);
|
|
22
21
|
|
|
@@ -56,7 +55,7 @@ export async function installOpencodeIntegration(
|
|
|
56
55
|
const models = (data.output as { models: RoutstrModel[] } | undefined)?.models || [];
|
|
57
56
|
|
|
58
57
|
if (models.length === 0) {
|
|
59
|
-
|
|
58
|
+
console.log("No models found from routstr daemon.");
|
|
60
59
|
return;
|
|
61
60
|
}
|
|
62
61
|
|
|
@@ -78,8 +77,8 @@ export async function installOpencodeIntegration(
|
|
|
78
77
|
opencodeConfig.small_model = OPENCODE_SMALL_MODEL;
|
|
79
78
|
|
|
80
79
|
await writeFile(configPath, JSON.stringify(opencodeConfig, null, 2));
|
|
81
|
-
|
|
80
|
+
console.log(`Added "routstr" provider with ${models.length} models to opencode.json`);
|
|
82
81
|
} catch (error) {
|
|
83
|
-
|
|
82
|
+
console.error("Failed to install models in opencode.json:", error);
|
|
84
83
|
}
|
|
85
84
|
}
|
package/src/integrations/pi.ts
CHANGED
|
@@ -2,12 +2,12 @@ import { existsSync, mkdirSync } from "fs";
|
|
|
2
2
|
import { readFile, writeFile } from "fs/promises";
|
|
3
3
|
import { dirname } from "path";
|
|
4
4
|
import type { RoutstrdConfig } from "../utils/config";
|
|
5
|
-
import { logger } from "../utils/logger";
|
|
6
5
|
import type { IntegrationConfig, RoutstrModel } from "./registry";
|
|
7
6
|
import { callDaemon, getDaemonBaseUrl } from "../utils/daemon-client";
|
|
8
7
|
|
|
9
8
|
type PiModelEntry = {
|
|
10
9
|
id: string;
|
|
10
|
+
contextWindow?: number;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
type PiProviderConfig = {
|
|
@@ -28,8 +28,8 @@ export async function installPiIntegration(
|
|
|
28
28
|
): Promise<void> {
|
|
29
29
|
const { name, configPath } = integrationConfig;
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
console.log("\nInstalling routstr models in pi models.json...");
|
|
32
|
+
console.log(`Using API key for ${name}`);
|
|
33
33
|
|
|
34
34
|
const baseUrl = `${getDaemonBaseUrl(config)}/v1`;
|
|
35
35
|
|
|
@@ -56,13 +56,17 @@ export async function installPiIntegration(
|
|
|
56
56
|
const models = (data.output as { models: RoutstrModel[] } | undefined)?.models || [];
|
|
57
57
|
|
|
58
58
|
if (models.length === 0) {
|
|
59
|
-
|
|
59
|
+
console.log("No models found from routstr daemon.");
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
const providerModels: PiModelEntry[] = models.map((model) =>
|
|
64
|
-
id: model.id
|
|
65
|
-
|
|
63
|
+
const providerModels: PiModelEntry[] = models.map((model) => {
|
|
64
|
+
const entry: PiModelEntry = { id: model.id };
|
|
65
|
+
if (model.context_length !== undefined && model.context_length > 0) {
|
|
66
|
+
entry.contextWindow = model.context_length;
|
|
67
|
+
}
|
|
68
|
+
return entry;
|
|
69
|
+
});
|
|
66
70
|
|
|
67
71
|
piConfig.providers["routstr"] = {
|
|
68
72
|
baseUrl,
|
|
@@ -72,8 +76,8 @@ export async function installPiIntegration(
|
|
|
72
76
|
};
|
|
73
77
|
|
|
74
78
|
await writeFile(configPath, JSON.stringify(piConfig, null, 2));
|
|
75
|
-
|
|
79
|
+
console.log(`Added "routstr" provider with ${models.length} models to pi models.json`);
|
|
76
80
|
} catch (error) {
|
|
77
|
-
|
|
81
|
+
console.error("Failed to install models in pi models.json:", error);
|
|
78
82
|
}
|
|
79
83
|
}
|
package/src/utils/clients.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
callAuth,
|
|
2
3
|
callDaemon,
|
|
3
4
|
loadConfig,
|
|
4
5
|
getDaemonBaseUrl,
|
|
@@ -56,7 +57,7 @@ export function getClientsFromStore(store: { getState(): any }): ClientEntry[] {
|
|
|
56
57
|
* Use this when running remotely (CLI in remote mode).
|
|
57
58
|
*/
|
|
58
59
|
export async function getClientsList(): Promise<ClientEntry[]> {
|
|
59
|
-
const result = await
|
|
60
|
+
const result = await callAuth("/clients");
|
|
60
61
|
const clients = (
|
|
61
62
|
result.output as
|
|
62
63
|
| {
|
|
@@ -107,7 +108,7 @@ export async function addDaemonClient(
|
|
|
107
108
|
return { client, created: false };
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
const result = await
|
|
111
|
+
const result = await callAuth("/clients/add", {
|
|
111
112
|
method: "POST",
|
|
112
113
|
body: { name, id: derivedId },
|
|
113
114
|
});
|
|
@@ -159,7 +160,7 @@ export async function listClientsAction(): Promise<void> {
|
|
|
159
160
|
export async function deleteClientAction(id: string): Promise<void> {
|
|
160
161
|
await ensureDaemonRunning();
|
|
161
162
|
|
|
162
|
-
const result = await
|
|
163
|
+
const result = await callAuth("/clients/delete", {
|
|
163
164
|
method: "POST",
|
|
164
165
|
body: { id },
|
|
165
166
|
});
|
package/src/utils/config.ts
CHANGED
|
@@ -35,6 +35,9 @@ export interface RoutstrdConfig {
|
|
|
35
35
|
cocodPath: string | null;
|
|
36
36
|
mode?: "xcashu" | "apikeys";
|
|
37
37
|
daemonUrl?: string;
|
|
38
|
+
/** URL of the auth proxy (routstrd-auth) for management endpoints (npubs, clients, usage).
|
|
39
|
+
* Defaults to daemonUrl or localhost:{port} if not set. */
|
|
40
|
+
authUrl?: string;
|
|
38
41
|
nsec?: string;
|
|
39
42
|
/** Nostr hex pubkey for routstr review/model events (kind 38425/38423). */
|
|
40
43
|
routstrPubkey?: string;
|
|
@@ -35,13 +35,20 @@ export function getDaemonBaseUrl(config: RoutstrdConfig): string {
|
|
|
35
35
|
);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export
|
|
38
|
+
export function getAuthBaseUrl(config: RoutstrdConfig): string {
|
|
39
|
+
if (config.authUrl) {
|
|
40
|
+
return config.authUrl.replace(/\/$/, "");
|
|
41
|
+
}
|
|
42
|
+
return getDaemonBaseUrl(config);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function _callUrl(
|
|
46
|
+
baseUrl: string,
|
|
39
47
|
path: string,
|
|
40
|
-
options: { method?: "GET" | "POST" | "PATCH" | "DELETE"; body?: object }
|
|
48
|
+
options: { method?: "GET" | "POST" | "PATCH" | "DELETE"; body?: object },
|
|
49
|
+
config: RoutstrdConfig,
|
|
41
50
|
): Promise<CommandResponse> {
|
|
42
51
|
const { method = "GET", body } = options;
|
|
43
|
-
const config = await loadConfig();
|
|
44
|
-
const baseUrl = getDaemonBaseUrl(config);
|
|
45
52
|
const url = `${baseUrl}${path}`;
|
|
46
53
|
|
|
47
54
|
const bodyString = body ? JSON.stringify(body) : undefined;
|
|
@@ -50,7 +57,7 @@ export async function callDaemon(
|
|
|
50
57
|
: undefined;
|
|
51
58
|
|
|
52
59
|
let authorization: string | undefined;
|
|
53
|
-
if (config.daemonUrl && config.nsec) {
|
|
60
|
+
if ((config.daemonUrl || config.authUrl) && config.nsec) {
|
|
54
61
|
const secretKey = parseSecretKey(config.nsec);
|
|
55
62
|
authorization = await createNIP98Authorization(
|
|
56
63
|
secretKey,
|
|
@@ -77,6 +84,26 @@ export async function callDaemon(
|
|
|
77
84
|
return response.json() as Promise<CommandResponse>;
|
|
78
85
|
}
|
|
79
86
|
|
|
87
|
+
export async function callDaemon(
|
|
88
|
+
path: string,
|
|
89
|
+
options: { method?: "GET" | "POST" | "PATCH" | "DELETE"; body?: object } = {},
|
|
90
|
+
): Promise<CommandResponse> {
|
|
91
|
+
const config = await loadConfig();
|
|
92
|
+
const baseUrl = getDaemonBaseUrl(config);
|
|
93
|
+
return _callUrl(baseUrl, path, options, config);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Like callDaemon but sends requests to the auth proxy URL instead.
|
|
97
|
+
* Falls back to the daemon URL if no authUrl is configured. */
|
|
98
|
+
export async function callAuth(
|
|
99
|
+
path: string,
|
|
100
|
+
options: { method?: "GET" | "POST" | "PATCH" | "DELETE"; body?: object } = {},
|
|
101
|
+
): Promise<CommandResponse> {
|
|
102
|
+
const config = await loadConfig();
|
|
103
|
+
const baseUrl = getAuthBaseUrl(config);
|
|
104
|
+
return _callUrl(baseUrl, path, options, config);
|
|
105
|
+
}
|
|
106
|
+
|
|
80
107
|
export async function isDaemonRunning(): Promise<boolean> {
|
|
81
108
|
try {
|
|
82
109
|
const config = await loadConfig();
|