routstrd 0.2.0 → 0.2.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/SKILL.md +0 -4
- package/bun.lock +198 -2
- package/dist/daemon/index.js +380 -234
- package/dist/index.js +92 -43
- package/package.json +2 -3
- package/src/cli.ts +99 -48
- package/src/daemon/http/index.ts +55 -3
- package/src/integrations/claudecode.ts +23 -6
package/dist/index.js
CHANGED
|
@@ -29002,9 +29002,26 @@ Installing routstr configuration in ${configPath}...`);
|
|
|
29002
29002
|
}
|
|
29003
29003
|
settings.env["ANTHROPIC_AUTH_TOKEN"] = apiKey;
|
|
29004
29004
|
settings.env["ANTHROPIC_BASE_URL"] = `http://localhost:${port}`;
|
|
29005
|
-
|
|
29006
|
-
|
|
29007
|
-
|
|
29005
|
+
try {
|
|
29006
|
+
const response = await fetch(`http://localhost:${port}/models`);
|
|
29007
|
+
const data = await response.json();
|
|
29008
|
+
const models = data.output?.models || [];
|
|
29009
|
+
if (models.length >= 3) {
|
|
29010
|
+
settings.env["ANTHROPIC_DEFAULT_OPUS_MODEL"] = models[0].id;
|
|
29011
|
+
settings.env["ANTHROPIC_DEFAULT_SONNET_MODEL"] = models[1].id;
|
|
29012
|
+
settings.env["ANTHROPIC_DEFAULT_HAIKU_MODEL"] = models[2].id;
|
|
29013
|
+
logger.log(`Set Claude models: Opus=${models[0].id}, Sonnet=${models[1].id}, Haiku=${models[2].id}`);
|
|
29014
|
+
} else if (models.length > 0) {
|
|
29015
|
+
logger.log(`Only ${models.length} models available, falling back to defaults.`);
|
|
29016
|
+
settings.env["ANTHROPIC_DEFAULT_OPUS_MODEL"] = models[0].id;
|
|
29017
|
+
settings.env["ANTHROPIC_DEFAULT_SONNET_MODEL"] = models[0].id;
|
|
29018
|
+
settings.env["ANTHROPIC_DEFAULT_HAIKU_MODEL"] = models[0].id;
|
|
29019
|
+
} else {
|
|
29020
|
+
logger.log("No models available from routstr daemon.");
|
|
29021
|
+
}
|
|
29022
|
+
} catch (error) {
|
|
29023
|
+
logger.error("Failed to fetch models for Claude Code integration:", error);
|
|
29024
|
+
}
|
|
29008
29025
|
try {
|
|
29009
29026
|
mkdirSync3(dirname3(configPath), { recursive: true });
|
|
29010
29027
|
await writeFile3(configPath, JSON.stringify(settings, null, 2));
|
|
@@ -36370,8 +36387,8 @@ var AuditLogger = class _AuditLogger {
|
|
|
36370
36387
|
if (typeof window === "undefined") {
|
|
36371
36388
|
try {
|
|
36372
36389
|
const fs2 = await import("fs");
|
|
36373
|
-
const
|
|
36374
|
-
const logPath =
|
|
36390
|
+
const path = await import("path");
|
|
36391
|
+
const logPath = path.join(process.cwd(), "audit.log");
|
|
36375
36392
|
fs2.appendFileSync(logPath, logLine);
|
|
36376
36393
|
} catch (error) {
|
|
36377
36394
|
console.error("[AuditLogger] Failed to write to file:", error);
|
|
@@ -36914,6 +36931,9 @@ function parsePositiveIntOrExit(value, fieldName) {
|
|
|
36914
36931
|
}
|
|
36915
36932
|
return parsed;
|
|
36916
36933
|
}
|
|
36934
|
+
function isPositiveIntegerString(value) {
|
|
36935
|
+
return /^[1-9]\d*$/.test(value.trim());
|
|
36936
|
+
}
|
|
36917
36937
|
async function printLightningInvoice(invoice) {
|
|
36918
36938
|
const paymentUri = `lightning:${invoice}`;
|
|
36919
36939
|
const qr = await $toString(paymentUri, {
|
|
@@ -36924,21 +36944,21 @@ async function printLightningInvoice(invoice) {
|
|
|
36924
36944
|
Invoice:
|
|
36925
36945
|
${invoice}`);
|
|
36926
36946
|
}
|
|
36947
|
+
async function installCocodOrExit() {
|
|
36948
|
+
logger.log("cocod not found. Installing globally with bun...");
|
|
36949
|
+
const installProc = Bun.spawn(["bun", "install", "--global", "@routstr/cocod"], {
|
|
36950
|
+
stdout: "inherit",
|
|
36951
|
+
stderr: "inherit"
|
|
36952
|
+
});
|
|
36953
|
+
const installCode = await installProc.exited;
|
|
36954
|
+
if (installCode !== 0 || !await isCocodInstalled()) {
|
|
36955
|
+
logger.error("Failed to install cocod. Please run 'bun install --global @routstr/cocod' manually.");
|
|
36956
|
+
throw new Error("cocod installation failed");
|
|
36957
|
+
}
|
|
36958
|
+
logger.log("cocod installed successfully.");
|
|
36959
|
+
}
|
|
36927
36960
|
async function initDaemon() {
|
|
36928
36961
|
logger.log("Initializing routstrd...");
|
|
36929
|
-
if (!await checkCocodInstalled()) {
|
|
36930
|
-
logger.log("cocod not found. Installing globally with bun...");
|
|
36931
|
-
const installProc = Bun.spawn(["bun", "install", "--global", "cocod"], {
|
|
36932
|
-
stdout: "inherit",
|
|
36933
|
-
stderr: "inherit"
|
|
36934
|
-
});
|
|
36935
|
-
const installCode = await installProc.exited;
|
|
36936
|
-
if (installCode !== 0 || !await checkCocodInstalled()) {
|
|
36937
|
-
logger.error("Failed to install cocod. Please run 'bun install --global cocod' manually.");
|
|
36938
|
-
return;
|
|
36939
|
-
}
|
|
36940
|
-
logger.log("cocod installed successfully.");
|
|
36941
|
-
}
|
|
36942
36962
|
if (!existsSync9(CONFIG_DIR)) {
|
|
36943
36963
|
mkdirSync5(CONFIG_DIR, { recursive: true });
|
|
36944
36964
|
logger.log(`Created config directory: ${CONFIG_DIR}`);
|
|
@@ -36952,24 +36972,14 @@ async function initDaemon() {
|
|
|
36952
36972
|
logger.log(`Created config file: ${CONFIG_FILE}`);
|
|
36953
36973
|
}
|
|
36954
36974
|
const config = await loadConfig();
|
|
36955
|
-
const cocodExecutable = resolveCocodExecutable(config.cocodPath);
|
|
36956
36975
|
if (!await isCocodInstalled(config.cocodPath)) {
|
|
36957
36976
|
if (config.cocodPath) {
|
|
36958
36977
|
logger.error(`Configured cocod executable was not found: ${config.cocodPath}`);
|
|
36959
36978
|
return;
|
|
36960
36979
|
}
|
|
36961
|
-
|
|
36962
|
-
const installProc = Bun.spawn(["bun", "install", "--global", "cocod"], {
|
|
36963
|
-
stdout: "inherit",
|
|
36964
|
-
stderr: "inherit"
|
|
36965
|
-
});
|
|
36966
|
-
const installCode = await installProc.exited;
|
|
36967
|
-
if (installCode !== 0 || !await isCocodInstalled(config.cocodPath)) {
|
|
36968
|
-
logger.error("Failed to install cocod. Please run 'bun install --global cocod' manually.");
|
|
36969
|
-
return;
|
|
36970
|
-
}
|
|
36971
|
-
logger.log("cocod installed successfully.");
|
|
36980
|
+
await installCocodOrExit();
|
|
36972
36981
|
}
|
|
36982
|
+
const cocodExecutable = resolveCocodExecutable(config.cocodPath);
|
|
36973
36983
|
console.log(`Database will be stored at: ${DB_PATH}`);
|
|
36974
36984
|
console.log(`
|
|
36975
36985
|
Initializing cocod...`);
|
|
@@ -37017,22 +37027,12 @@ ${initStderr}`.toLowerCase();
|
|
|
37017
37027
|
logger.log(`
|
|
37018
37028
|
Initialization complete!`);
|
|
37019
37029
|
logger.log(`
|
|
37020
|
-
use 'routstrd
|
|
37030
|
+
use 'routstrd receive <cashu-token>' or 'routstrd receive 2100' to top up your local wallet using Lightning!`);
|
|
37031
|
+
logger.log(`
|
|
37032
|
+
full wallet commands still work too, e.g. 'routstrd wallet receive cashu <token>' and 'routstrd wallet receive bolt11 2100'.`);
|
|
37021
37033
|
logger.log(`
|
|
37022
37034
|
To ensure routstrd persists across system restarts, run: 'routstrd service install'`);
|
|
37023
37035
|
}
|
|
37024
|
-
async function checkCocodInstalled() {
|
|
37025
|
-
try {
|
|
37026
|
-
const proc = Bun.spawn({
|
|
37027
|
-
cmd: ["which", "cocod"],
|
|
37028
|
-
stdout: "pipe"
|
|
37029
|
-
});
|
|
37030
|
-
const code = await proc.exited;
|
|
37031
|
-
return code === 0;
|
|
37032
|
-
} catch {
|
|
37033
|
-
return false;
|
|
37034
|
-
}
|
|
37035
|
-
}
|
|
37036
37036
|
program.name("routstrd").description("Routstr daemon - Manage routstr processes").version(cliVersion, "--version", "output the version number");
|
|
37037
37037
|
program.command("onboard").description("Initialize routstrd (creates config directory and initializes cocod)").action(async () => {
|
|
37038
37038
|
await initDaemon();
|
|
@@ -37330,6 +37330,55 @@ program.command("top").description("Open interactive TUI for usage monitoring (a
|
|
|
37330
37330
|
const { runUsageTui: runUsageTui2 } = await Promise.resolve().then(() => (init_usage(), exports_usage));
|
|
37331
37331
|
await runUsageTui2();
|
|
37332
37332
|
});
|
|
37333
|
+
program.command("send <target>").description("Shortcut: numbers send Cashu, non-numbers pay a Lightning invoice").option("--mint-url <url>", "Mint URL to use").action(async (target, options) => {
|
|
37334
|
+
if (isPositiveIntegerString(target)) {
|
|
37335
|
+
await handleDaemonCommand("/wallet/send/cashu", {
|
|
37336
|
+
method: "POST",
|
|
37337
|
+
body: {
|
|
37338
|
+
amount: parsePositiveIntOrExit(target, "amount"),
|
|
37339
|
+
mintUrl: options.mintUrl
|
|
37340
|
+
}
|
|
37341
|
+
});
|
|
37342
|
+
return;
|
|
37343
|
+
}
|
|
37344
|
+
await handleDaemonCommand("/wallet/send/bolt11", {
|
|
37345
|
+
method: "POST",
|
|
37346
|
+
body: {
|
|
37347
|
+
invoice: target,
|
|
37348
|
+
mintUrl: options.mintUrl
|
|
37349
|
+
}
|
|
37350
|
+
});
|
|
37351
|
+
});
|
|
37352
|
+
program.command("receive <value>").description("Shortcut: numbers create a Lightning invoice, non-numbers receive a Cashu token").option("--mint-url <url>", "Mint URL to use for bolt11 receive").action(async (value, options) => {
|
|
37353
|
+
if (isPositiveIntegerString(value)) {
|
|
37354
|
+
try {
|
|
37355
|
+
await ensureDaemonRunning();
|
|
37356
|
+
const result = await callDaemon("/wallet/receive/bolt11", {
|
|
37357
|
+
method: "POST",
|
|
37358
|
+
body: {
|
|
37359
|
+
amount: parsePositiveIntOrExit(value, "amount"),
|
|
37360
|
+
mintUrl: options.mintUrl
|
|
37361
|
+
}
|
|
37362
|
+
});
|
|
37363
|
+
const output4 = result.output;
|
|
37364
|
+
if (typeof output4?.invoice === "string" && output4.invoice) {
|
|
37365
|
+
await printLightningInvoice(output4.invoice);
|
|
37366
|
+
return;
|
|
37367
|
+
}
|
|
37368
|
+
if (result.output !== undefined) {
|
|
37369
|
+
console.log(JSON.stringify(result.output, null, 2));
|
|
37370
|
+
}
|
|
37371
|
+
} catch (error) {
|
|
37372
|
+
console.error(error.message);
|
|
37373
|
+
process.exit(1);
|
|
37374
|
+
}
|
|
37375
|
+
return;
|
|
37376
|
+
}
|
|
37377
|
+
await handleDaemonCommand("/wallet/receive/cashu", {
|
|
37378
|
+
method: "POST",
|
|
37379
|
+
body: { token: value }
|
|
37380
|
+
});
|
|
37381
|
+
});
|
|
37333
37382
|
var walletCmd = program.command("wallet").description("Wallet operations");
|
|
37334
37383
|
walletCmd.command("status").description("Check wallet status").action(async () => {
|
|
37335
37384
|
await handleDaemonCommand("/wallet/status");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "routstrd",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"module": "src/index.ts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
"lint": "tsc --noEmit",
|
|
14
14
|
"test": "bun test",
|
|
15
15
|
"build": "mkdir -p dist/daemon && bun build src/index.ts --target=bun --outfile=dist/index.js && bun build src/daemon/index.ts --target=bun --outfile=dist/daemon/index.js",
|
|
16
|
-
"build:dev": "sed -i '' 's/\"@routstr\\/sdk\": \"\\^0.2.11\"/\"@routstr\\/sdk\": \"file:..\\/routstr-chat\\/sdk\"/' package.json && bun install && bun run build && sed -i '' 's/\"@routstr\\/sdk\": \"file:..\\/routstr-chat\\/sdk\"/\"@routstr\\/sdk\": \"^0.2.11\"/' package.json && bun install",
|
|
17
16
|
"prepublishOnly": "bun run build"
|
|
18
17
|
},
|
|
19
18
|
"devDependencies": {
|
|
@@ -25,7 +24,7 @@
|
|
|
25
24
|
},
|
|
26
25
|
"dependencies": {
|
|
27
26
|
"@cashu/cashu-ts": "^3.1.1",
|
|
28
|
-
"@routstr/sdk": "^0.
|
|
27
|
+
"@routstr/sdk": "^0.3.0",
|
|
29
28
|
"applesauce-core": "^5.1.0",
|
|
30
29
|
"applesauce-relay": "^5.1.0",
|
|
31
30
|
"commander": "^14.0.2",
|
package/src/cli.ts
CHANGED
|
@@ -59,6 +59,10 @@ function parsePositiveIntOrExit(value: string, fieldName: string): number {
|
|
|
59
59
|
return parsed;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
function isPositiveIntegerString(value: string): boolean {
|
|
63
|
+
return /^[1-9]\d*$/.test(value.trim());
|
|
64
|
+
}
|
|
65
|
+
|
|
62
66
|
async function printLightningInvoice(invoice: string): Promise<void> {
|
|
63
67
|
const paymentUri = `lightning:${invoice}`;
|
|
64
68
|
const qr = await QRCode.toString(paymentUri, {
|
|
@@ -69,27 +73,27 @@ async function printLightningInvoice(invoice: string): Promise<void> {
|
|
|
69
73
|
console.log(`${qr}\nInvoice:\n${invoice}`);
|
|
70
74
|
}
|
|
71
75
|
|
|
72
|
-
async function
|
|
73
|
-
logger.log("
|
|
76
|
+
async function installCocodOrExit(): Promise<void> {
|
|
77
|
+
logger.log("cocod not found. Installing globally with bun...");
|
|
74
78
|
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
const installProc = Bun.spawn(["bun", "install", "--global", "@routstr/cocod"], {
|
|
80
|
+
stdout: "inherit",
|
|
81
|
+
stderr: "inherit",
|
|
82
|
+
});
|
|
77
83
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
84
|
+
const installCode = await installProc.exited;
|
|
85
|
+
if (installCode !== 0 || !(await isCocodInstalled())) {
|
|
86
|
+
logger.error(
|
|
87
|
+
"Failed to install cocod. Please run 'bun install --global @routstr/cocod' manually.",
|
|
88
|
+
);
|
|
89
|
+
throw new Error("cocod installation failed");
|
|
90
|
+
}
|
|
82
91
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
logger.error(
|
|
86
|
-
"Failed to install cocod. Please run 'bun install --global cocod' manually.",
|
|
87
|
-
);
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
92
|
+
logger.log("cocod installed successfully.");
|
|
93
|
+
}
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
async function initDaemon(): Promise<void> {
|
|
96
|
+
logger.log("Initializing routstrd...");
|
|
93
97
|
|
|
94
98
|
// Create config directory
|
|
95
99
|
if (!existsSync(CONFIG_DIR)) {
|
|
@@ -108,7 +112,6 @@ async function initDaemon(): Promise<void> {
|
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
const config = await loadConfig();
|
|
111
|
-
const cocodExecutable = resolveCocodExecutable(config.cocodPath);
|
|
112
115
|
|
|
113
116
|
if (!(await isCocodInstalled(config.cocodPath))) {
|
|
114
117
|
if (config.cocodPath) {
|
|
@@ -118,24 +121,11 @@ async function initDaemon(): Promise<void> {
|
|
|
118
121
|
return;
|
|
119
122
|
}
|
|
120
123
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const installProc = Bun.spawn(["bun", "install", "--global", "cocod"], {
|
|
124
|
-
stdout: "inherit",
|
|
125
|
-
stderr: "inherit",
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
const installCode = await installProc.exited;
|
|
129
|
-
if (installCode !== 0 || !(await isCocodInstalled(config.cocodPath))) {
|
|
130
|
-
logger.error(
|
|
131
|
-
"Failed to install cocod. Please run 'bun install --global cocod' manually.",
|
|
132
|
-
);
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
logger.log("cocod installed successfully.");
|
|
124
|
+
await installCocodOrExit();
|
|
137
125
|
}
|
|
138
126
|
|
|
127
|
+
const cocodExecutable = resolveCocodExecutable(config.cocodPath);
|
|
128
|
+
|
|
139
129
|
console.log(`Database will be stored at: ${DB_PATH}`);
|
|
140
130
|
console.log("\nInitializing cocod...");
|
|
141
131
|
|
|
@@ -202,26 +192,16 @@ async function initDaemon(): Promise<void> {
|
|
|
202
192
|
|
|
203
193
|
logger.log("\nInitialization complete!");
|
|
204
194
|
logger.log(
|
|
205
|
-
"\n use 'routstrd
|
|
195
|
+
"\n use 'routstrd receive <cashu-token>' or 'routstrd receive 2100' to top up your local wallet using Lightning!",
|
|
196
|
+
);
|
|
197
|
+
logger.log(
|
|
198
|
+
"\n full wallet commands still work too, e.g. 'routstrd wallet receive cashu <token>' and 'routstrd wallet receive bolt11 2100'.",
|
|
206
199
|
);
|
|
207
200
|
logger.log(
|
|
208
201
|
"\nTo ensure routstrd persists across system restarts, run: 'routstrd service install'",
|
|
209
202
|
);
|
|
210
203
|
}
|
|
211
204
|
|
|
212
|
-
async function checkCocodInstalled(): Promise<boolean> {
|
|
213
|
-
try {
|
|
214
|
-
const proc = Bun.spawn({
|
|
215
|
-
cmd: ["which", "cocod"],
|
|
216
|
-
stdout: "pipe",
|
|
217
|
-
});
|
|
218
|
-
const code = await proc.exited;
|
|
219
|
-
return code === 0;
|
|
220
|
-
} catch {
|
|
221
|
-
return false;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
205
|
program
|
|
226
206
|
.name("routstrd")
|
|
227
207
|
.description("Routstr daemon - Manage routstr processes")
|
|
@@ -733,6 +713,77 @@ program
|
|
|
733
713
|
await runUsageTui();
|
|
734
714
|
});
|
|
735
715
|
|
|
716
|
+
program
|
|
717
|
+
.command("send <target>")
|
|
718
|
+
.description(
|
|
719
|
+
"Shortcut: numbers send Cashu, non-numbers pay a Lightning invoice",
|
|
720
|
+
)
|
|
721
|
+
.option("--mint-url <url>", "Mint URL to use")
|
|
722
|
+
.action(async (target: string, options: { mintUrl?: string }) => {
|
|
723
|
+
if (isPositiveIntegerString(target)) {
|
|
724
|
+
await handleDaemonCommand("/wallet/send/cashu", {
|
|
725
|
+
method: "POST",
|
|
726
|
+
body: {
|
|
727
|
+
amount: parsePositiveIntOrExit(target, "amount"),
|
|
728
|
+
mintUrl: options.mintUrl,
|
|
729
|
+
},
|
|
730
|
+
});
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
await handleDaemonCommand("/wallet/send/bolt11", {
|
|
735
|
+
method: "POST",
|
|
736
|
+
body: {
|
|
737
|
+
invoice: target,
|
|
738
|
+
mintUrl: options.mintUrl,
|
|
739
|
+
},
|
|
740
|
+
});
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
program
|
|
744
|
+
.command("receive <value>")
|
|
745
|
+
.description(
|
|
746
|
+
"Shortcut: numbers create a Lightning invoice, non-numbers receive a Cashu token",
|
|
747
|
+
)
|
|
748
|
+
.option("--mint-url <url>", "Mint URL to use for bolt11 receive")
|
|
749
|
+
.action(async (value: string, options: { mintUrl?: string }) => {
|
|
750
|
+
if (isPositiveIntegerString(value)) {
|
|
751
|
+
try {
|
|
752
|
+
await ensureDaemonRunning();
|
|
753
|
+
|
|
754
|
+
const result = await callDaemon("/wallet/receive/bolt11", {
|
|
755
|
+
method: "POST",
|
|
756
|
+
body: {
|
|
757
|
+
amount: parsePositiveIntOrExit(value, "amount"),
|
|
758
|
+
mintUrl: options.mintUrl,
|
|
759
|
+
},
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
const output = result.output as
|
|
763
|
+
| { invoice?: string; amount?: number; mintUrl?: string }
|
|
764
|
+
| undefined;
|
|
765
|
+
|
|
766
|
+
if (typeof output?.invoice === "string" && output.invoice) {
|
|
767
|
+
await printLightningInvoice(output.invoice);
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
if (result.output !== undefined) {
|
|
772
|
+
console.log(JSON.stringify(result.output, null, 2));
|
|
773
|
+
}
|
|
774
|
+
} catch (error) {
|
|
775
|
+
console.error((error as Error).message);
|
|
776
|
+
process.exit(1);
|
|
777
|
+
}
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
await handleDaemonCommand("/wallet/receive/cashu", {
|
|
782
|
+
method: "POST",
|
|
783
|
+
body: { token: value },
|
|
784
|
+
});
|
|
785
|
+
});
|
|
786
|
+
|
|
736
787
|
const walletCmd = program.command("wallet").description("Wallet operations");
|
|
737
788
|
|
|
738
789
|
walletCmd
|
package/src/daemon/http/index.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { randomBytes } from "crypto";
|
|
2
2
|
import { type IncomingMessage, type ServerResponse } from "http";
|
|
3
|
+
import { Readable } from "stream";
|
|
3
4
|
import {
|
|
4
|
-
|
|
5
|
+
routeRequests,
|
|
5
6
|
InsufficientBalanceError,
|
|
6
7
|
ProviderManager,
|
|
7
8
|
} from "@routstr/sdk";
|
|
@@ -968,7 +969,8 @@ export function createDaemonRequestHandler(deps: {
|
|
|
968
969
|
try {
|
|
969
970
|
await deps.ensureProvidersBootstrapped();
|
|
970
971
|
logger.log("Routing request with path: ", url.pathname);
|
|
971
|
-
|
|
972
|
+
|
|
973
|
+
const response = await routeRequests({
|
|
972
974
|
modelId,
|
|
973
975
|
requestBody,
|
|
974
976
|
path: url.pathname,
|
|
@@ -984,8 +986,58 @@ export function createDaemonRequestHandler(deps: {
|
|
|
984
986
|
usageTrackingDriver: deps.usageTrackingDriver,
|
|
985
987
|
sdkStore: deps.store,
|
|
986
988
|
providerManager: deps.providerManager,
|
|
987
|
-
res,
|
|
988
989
|
});
|
|
990
|
+
|
|
991
|
+
// Bridge the Web `Response` to the Node `ServerResponse` with no
|
|
992
|
+
// transforms: status + headers + pipe(body → res).
|
|
993
|
+
res.statusCode = response.status;
|
|
994
|
+
response.headers.forEach((value, key) => {
|
|
995
|
+
res.setHeader(key, value);
|
|
996
|
+
});
|
|
997
|
+
|
|
998
|
+
const finalize = (response as any).finalize as
|
|
999
|
+
| (() => Promise<number>)
|
|
1000
|
+
| undefined;
|
|
1001
|
+
|
|
1002
|
+
if (!response.body) {
|
|
1003
|
+
res.end();
|
|
1004
|
+
if (finalize) {
|
|
1005
|
+
try {
|
|
1006
|
+
await finalize();
|
|
1007
|
+
} catch (err) {
|
|
1008
|
+
logger.error(`[daemon] finalize error: ${toErrorMessage(err)}`);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
const nodeReadable = Readable.fromWeb(response.body as any);
|
|
1015
|
+
await new Promise<void>((resolve, reject) => {
|
|
1016
|
+
let settled = false;
|
|
1017
|
+
const finish = () => {
|
|
1018
|
+
if (settled) return;
|
|
1019
|
+
settled = true;
|
|
1020
|
+
resolve();
|
|
1021
|
+
};
|
|
1022
|
+
const fail = (err: unknown) => {
|
|
1023
|
+
if (settled) return;
|
|
1024
|
+
settled = true;
|
|
1025
|
+
reject(err);
|
|
1026
|
+
};
|
|
1027
|
+
res.once("finish", finish);
|
|
1028
|
+
res.once("close", finish);
|
|
1029
|
+
res.once("error", fail);
|
|
1030
|
+
nodeReadable.once("error", fail);
|
|
1031
|
+
nodeReadable.pipe(res);
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
if (finalize) {
|
|
1035
|
+
try {
|
|
1036
|
+
await finalize();
|
|
1037
|
+
} catch (err) {
|
|
1038
|
+
logger.error(`[daemon] finalize error: ${toErrorMessage(err)}`);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
989
1041
|
return;
|
|
990
1042
|
} catch (error) {
|
|
991
1043
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -4,7 +4,7 @@ import { dirname } from "path";
|
|
|
4
4
|
import type { RoutstrdConfig } from "../utils/config";
|
|
5
5
|
import { logger } from "../utils/logger";
|
|
6
6
|
import type { SdkStore } from "@routstr/sdk";
|
|
7
|
-
import type { IntegrationConfig } from "./registry";
|
|
7
|
+
import type { IntegrationConfig, RoutstrModel } from "./registry";
|
|
8
8
|
import { generateApiKey } from "./registry";
|
|
9
9
|
|
|
10
10
|
export async function installClaudeCodeIntegration(
|
|
@@ -61,11 +61,28 @@ export async function installClaudeCodeIntegration(
|
|
|
61
61
|
|
|
62
62
|
settings.env["ANTHROPIC_AUTH_TOKEN"] = apiKey;
|
|
63
63
|
settings.env["ANTHROPIC_BASE_URL"] = `http://localhost:${port}`;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const response = await fetch(`http://localhost:${port}/models`);
|
|
67
|
+
const data = await response.json() as { output?: { models: RoutstrModel[] } };
|
|
68
|
+
const models = data.output?.models || [];
|
|
69
|
+
|
|
70
|
+
if (models.length >= 3) {
|
|
71
|
+
settings.env["ANTHROPIC_DEFAULT_OPUS_MODEL"] = models[0].id;
|
|
72
|
+
settings.env["ANTHROPIC_DEFAULT_SONNET_MODEL"] = models[1].id;
|
|
73
|
+
settings.env["ANTHROPIC_DEFAULT_HAIKU_MODEL"] = models[2].id;
|
|
74
|
+
logger.log(`Set Claude models: Opus=${models[0].id}, Sonnet=${models[1].id}, Haiku=${models[2].id}`);
|
|
75
|
+
} else if (models.length > 0) {
|
|
76
|
+
logger.log(`Only ${models.length} models available, falling back to defaults.`);
|
|
77
|
+
settings.env["ANTHROPIC_DEFAULT_OPUS_MODEL"] = models[0].id;
|
|
78
|
+
settings.env["ANTHROPIC_DEFAULT_SONNET_MODEL"] = models[0].id;
|
|
79
|
+
settings.env["ANTHROPIC_DEFAULT_HAIKU_MODEL"] = models[0].id;
|
|
80
|
+
} else {
|
|
81
|
+
logger.log("No models available from routstr daemon.");
|
|
82
|
+
}
|
|
83
|
+
} catch (error) {
|
|
84
|
+
logger.error("Failed to fetch models for Claude Code integration:", error);
|
|
85
|
+
}
|
|
69
86
|
|
|
70
87
|
try {
|
|
71
88
|
mkdirSync(dirname(configPath), { recursive: true });
|