@vellumai/cli 0.4.20 → 0.4.22
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/package.json +1 -1
- package/src/lib/local.ts +26 -36
- package/src/lib/xdg-log.ts +37 -0
package/package.json
CHANGED
package/src/lib/local.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { dirname, join } from "path";
|
|
|
14
14
|
import { loadLatestAssistant } from "./assistant-config.js";
|
|
15
15
|
import { GATEWAY_PORT } from "./constants.js";
|
|
16
16
|
import { stopProcessByPidFile } from "./process.js";
|
|
17
|
-
import { openLogFile,
|
|
17
|
+
import { openLogFile, pipeToLogFile } from "./xdg-log.js";
|
|
18
18
|
|
|
19
19
|
const _require = createRequire(import.meta.url);
|
|
20
20
|
|
|
@@ -513,20 +513,16 @@ export async function startLocalDaemon(): Promise<void> {
|
|
|
513
513
|
}
|
|
514
514
|
}
|
|
515
515
|
|
|
516
|
-
const daemonLogFd = openLogFile("
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
daemonPid = child.pid;
|
|
527
|
-
} finally {
|
|
528
|
-
closeLogFile(daemonLogFd);
|
|
529
|
-
}
|
|
516
|
+
const daemonLogFd = openLogFile("hatch.log");
|
|
517
|
+
const child = spawn(daemonBinary, [], {
|
|
518
|
+
cwd: dirname(daemonBinary),
|
|
519
|
+
detached: true,
|
|
520
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
521
|
+
env: daemonEnv,
|
|
522
|
+
});
|
|
523
|
+
pipeToLogFile(child, daemonLogFd, "daemon");
|
|
524
|
+
child.unref();
|
|
525
|
+
const daemonPid = child.pid;
|
|
530
526
|
|
|
531
527
|
// Write PID file immediately so the health monitor can find the process
|
|
532
528
|
// and concurrent hatch() calls see it as alive.
|
|
@@ -691,30 +687,24 @@ export async function startGateway(assistantId?: string): Promise<string> {
|
|
|
691
687
|
);
|
|
692
688
|
}
|
|
693
689
|
|
|
694
|
-
const gatewayLogFd = openLogFile("
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
} finally {
|
|
702
|
-
closeLogFile(gatewayLogFd);
|
|
703
|
-
}
|
|
690
|
+
const gatewayLogFd = openLogFile("hatch.log");
|
|
691
|
+
gateway = spawn(gatewayBinary, [], {
|
|
692
|
+
detached: true,
|
|
693
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
694
|
+
env: gatewayEnv,
|
|
695
|
+
});
|
|
696
|
+
pipeToLogFile(gateway, gatewayLogFd, "gateway");
|
|
704
697
|
} else {
|
|
705
698
|
// Source tree / bunx: resolve the gateway source directory and run via bun.
|
|
706
699
|
const gatewayDir = resolveGatewayDir();
|
|
707
|
-
const gwLogFd = openLogFile("
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
} finally {
|
|
716
|
-
closeLogFile(gwLogFd);
|
|
717
|
-
}
|
|
700
|
+
const gwLogFd = openLogFile("hatch.log");
|
|
701
|
+
gateway = spawn("bun", ["run", "src/index.ts", "--vellum-gateway"], {
|
|
702
|
+
cwd: gatewayDir,
|
|
703
|
+
detached: true,
|
|
704
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
705
|
+
env: gatewayEnv,
|
|
706
|
+
});
|
|
707
|
+
pipeToLogFile(gateway, gwLogFd, "gateway");
|
|
718
708
|
}
|
|
719
709
|
|
|
720
710
|
gateway.unref();
|
package/src/lib/xdg-log.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { closeSync, mkdirSync, openSync, writeSync } from "fs";
|
|
2
|
+
import type { ChildProcess } from "child_process";
|
|
2
3
|
import { homedir } from "os";
|
|
3
4
|
import { join } from "path";
|
|
4
5
|
|
|
@@ -35,3 +36,39 @@ export function writeToLogFile(fd: number | "ignore", msg: string): void {
|
|
|
35
36
|
try { writeSync(fd, msg); } catch { /* best-effort */ }
|
|
36
37
|
}
|
|
37
38
|
}
|
|
39
|
+
|
|
40
|
+
/** Pipe a child process's stdout/stderr to a shared log file descriptor,
|
|
41
|
+
* prefixing each line with a tag (e.g. "[daemon]" or "[gateway]").
|
|
42
|
+
* Streams are unref'd so they don't prevent the parent from exiting.
|
|
43
|
+
* The fd is closed automatically when both streams end. */
|
|
44
|
+
export function pipeToLogFile(child: ChildProcess, fd: number | "ignore", tag: string): void {
|
|
45
|
+
if (fd === "ignore") return;
|
|
46
|
+
const numFd: number = fd;
|
|
47
|
+
const tagLabel = `[${tag}]`;
|
|
48
|
+
const streams = [child.stdout, child.stderr].filter(Boolean);
|
|
49
|
+
let ended = 0;
|
|
50
|
+
|
|
51
|
+
function onDone() {
|
|
52
|
+
ended++;
|
|
53
|
+
if (ended >= streams.length) {
|
|
54
|
+
try { closeSync(numFd); } catch { /* best-effort */ }
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (const stream of streams) {
|
|
59
|
+
if (!stream) continue;
|
|
60
|
+
(stream as NodeJS.ReadableStream & { unref?: () => void }).unref?.();
|
|
61
|
+
stream.on("data", (chunk: Buffer) => {
|
|
62
|
+
const text = chunk.toString();
|
|
63
|
+
const lines = text.split("\n");
|
|
64
|
+
for (let i = 0; i < lines.length; i++) {
|
|
65
|
+
if (i === lines.length - 1 && lines[i] === "") break;
|
|
66
|
+
const nl = i < lines.length - 1 ? "\n" : "";
|
|
67
|
+
const prefix = `${new Date().toISOString()} ${tagLabel} `;
|
|
68
|
+
try { writeSync(numFd, prefix + lines[i] + nl); } catch { /* best-effort */ }
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
stream.on("end", onDone);
|
|
72
|
+
stream.on("error", onDone);
|
|
73
|
+
}
|
|
74
|
+
}
|