routstrd 0.4.0 → 0.4.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/COCO-2.0.0-MIGRATION-PLAN.md +1191 -0
- package/README.md +5 -0
- package/dist/daemon/index.js +1096 -143
- package/dist/index.js +572 -124
- package/package.json +1 -1
- package/src/cli.ts +160 -26
- package/src/daemon/fatal-error.test.ts +104 -0
- package/src/daemon/fatal-error.ts +48 -0
- package/src/daemon/wallet/auto-refill.ts +4 -6
- package/src/daemon/wallet/cleanup.test.ts +168 -0
- package/src/daemon/wallet/cleanup.ts +104 -0
- package/src/daemon/wallet/coco-client.test.ts +191 -30
- package/src/daemon/wallet/coco-client.ts +867 -74
- package/src/daemon/wallet/cocod-client.ts +49 -1
- package/src/daemon/wallet/diagnostics.test.ts +378 -0
- package/src/daemon/wallet/diagnostics.ts +471 -0
- package/src/daemon/wallet/migration.test.ts +30 -6
- package/src/daemon/wallet/migration.ts +30 -85
- package/src/daemon/wallet/receive-dedup.test.ts +238 -0
- package/src/daemon/wallet/receive-dedup.ts +384 -0
- package/src/daemon/wallet/wallet-state.ts +75 -0
- package/src/start-daemon.ts +21 -1
- package/tests/integrations/hermes.test.ts +42 -5
package/src/start-daemon.ts
CHANGED
|
@@ -170,6 +170,22 @@ async function startDaemonUnlocked(
|
|
|
170
170
|
|
|
171
171
|
proc.unref();
|
|
172
172
|
|
|
173
|
+
// The daemon must outlive a successful start, but a start we give up on must not
|
|
174
|
+
// leave a detached process holding the wallet locks. `detached` makes it a group leader.
|
|
175
|
+
const killSpawnedDaemon = (): void => {
|
|
176
|
+
try {
|
|
177
|
+
process.kill(-proc.pid, "SIGTERM");
|
|
178
|
+
} catch {
|
|
179
|
+
// Already exited.
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
const abandonOnSignal = (): void => {
|
|
183
|
+
killSpawnedDaemon();
|
|
184
|
+
process.exit(1);
|
|
185
|
+
};
|
|
186
|
+
process.once("SIGINT", abandonOnSignal);
|
|
187
|
+
process.once("SIGTERM", abandonOnSignal);
|
|
188
|
+
|
|
173
189
|
let exitCode: number | null = null;
|
|
174
190
|
proc.exited.then((code) => {
|
|
175
191
|
exitCode = code;
|
|
@@ -212,6 +228,8 @@ async function startDaemonUnlocked(
|
|
|
212
228
|
}
|
|
213
229
|
|
|
214
230
|
if (await healthyDaemonHost(port, host)) {
|
|
231
|
+
process.off("SIGINT", abandonOnSignal);
|
|
232
|
+
process.off("SIGTERM", abandonOnSignal);
|
|
215
233
|
printStartupProgress(progressLogOffset);
|
|
216
234
|
console.log(
|
|
217
235
|
`Routstr daemon started (PID: ${proc.pid}, ${formatElapsed(Date.now() - startedAt)}).`,
|
|
@@ -220,8 +238,10 @@ async function startDaemonUnlocked(
|
|
|
220
238
|
}
|
|
221
239
|
}
|
|
222
240
|
|
|
241
|
+
killSpawnedDaemon();
|
|
223
242
|
throw new Error(
|
|
224
|
-
`Daemon
|
|
243
|
+
`Daemon did not become healthy within ${Math.round(startupTimeoutMs / 1000)} seconds; ` +
|
|
244
|
+
`the incomplete daemon (PID ${proc.pid}) was stopped. Check logs in ${LOGS_DIR}`,
|
|
225
245
|
);
|
|
226
246
|
}
|
|
227
247
|
|
|
@@ -66,7 +66,7 @@ other_setting: true
|
|
|
66
66
|
});
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
it("
|
|
69
|
+
it("updates an existing Routstr provider in place without duplicating it", () => {
|
|
70
70
|
const existing = `custom_providers:
|
|
71
71
|
- name: Routstr (old-host:8008)
|
|
72
72
|
base_url: http://old-host:8008/v1
|
|
@@ -83,14 +83,51 @@ other_setting: true
|
|
|
83
83
|
|
|
84
84
|
expect(routstrProviders).toHaveLength(1);
|
|
85
85
|
expect(routstrProviders[0]).toEqual({
|
|
86
|
-
name: "Routstr (
|
|
87
|
-
base_url:
|
|
88
|
-
api_key:
|
|
89
|
-
model:
|
|
86
|
+
name: "Routstr (localhost:8008)",
|
|
87
|
+
base_url: ROUTSTR.baseUrl,
|
|
88
|
+
api_key: ROUTSTR.apiKey,
|
|
89
|
+
model: ROUTSTR.defaultModel,
|
|
90
90
|
});
|
|
91
91
|
expect(twice).toBe(once);
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
+
it("repoints model.provider when the Routstr provider is renamed", () => {
|
|
95
|
+
const existing = `model:
|
|
96
|
+
default: old-model
|
|
97
|
+
provider: custom:routstr-(old-host:8008)
|
|
98
|
+
|
|
99
|
+
custom_providers:
|
|
100
|
+
- name: Routstr (old-host:8008)
|
|
101
|
+
base_url: http://old-host:8008/v1
|
|
102
|
+
api_key: old-key
|
|
103
|
+
model: old-model
|
|
104
|
+
`;
|
|
105
|
+
|
|
106
|
+
const merged = parse(mergeHermesConfig(existing, ROUTSTR));
|
|
107
|
+
|
|
108
|
+
expect(merged.model).toEqual({
|
|
109
|
+
default: "old-model",
|
|
110
|
+
provider: "custom:routstr-(localhost:8008)",
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("leaves model.provider alone when it does not reference the Routstr provider", () => {
|
|
115
|
+
const existing = `model:
|
|
116
|
+
default: user-model
|
|
117
|
+
provider: custom:user-provider
|
|
118
|
+
|
|
119
|
+
custom_providers:
|
|
120
|
+
- name: Routstr (old-host:8008)
|
|
121
|
+
base_url: http://old-host:8008/v1
|
|
122
|
+
api_key: old-key
|
|
123
|
+
model: old-model
|
|
124
|
+
`;
|
|
125
|
+
|
|
126
|
+
const merged = parse(mergeHermesConfig(existing, ROUTSTR));
|
|
127
|
+
|
|
128
|
+
expect(merged.model.provider).toBe("custom:user-provider");
|
|
129
|
+
});
|
|
130
|
+
|
|
94
131
|
it("rejects malformed YAML instead of replacing it", () => {
|
|
95
132
|
expect(() => mergeHermesConfig("model: [unterminated", ROUTSTR)).toThrow();
|
|
96
133
|
});
|