@lightcone-ai/daemon 0.23.7 → 0.23.8
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/cli.js +53 -15
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn } from 'node:child_process';
|
|
3
|
-
import {
|
|
3
|
+
import { closeSync, existsSync, openSync, readFileSync, readSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import os from 'node:os';
|
|
6
6
|
import path from 'node:path';
|
|
@@ -20,9 +20,9 @@ function parseArgs(raw) {
|
|
|
20
20
|
const opts = { _: [] };
|
|
21
21
|
for (let i = 0; i < raw.length; i += 1) {
|
|
22
22
|
const arg = raw[i];
|
|
23
|
-
if (arg.startsWith('
|
|
23
|
+
if (arg.startsWith('-') && arg !== '-') {
|
|
24
24
|
const next = raw[i + 1];
|
|
25
|
-
if (next && !next.startsWith('
|
|
25
|
+
if (next !== undefined && !next.startsWith('-')) {
|
|
26
26
|
opts[arg] = next;
|
|
27
27
|
i += 1;
|
|
28
28
|
} else {
|
|
@@ -45,7 +45,7 @@ function printUsage() {
|
|
|
45
45
|
lightcone daemon status
|
|
46
46
|
lightcone status
|
|
47
47
|
lightcone doctor [--json]
|
|
48
|
-
lightcone logs [--lines 100]
|
|
48
|
+
lightcone logs [--lines 100] [-f|--follow]
|
|
49
49
|
|
|
50
50
|
Notes:
|
|
51
51
|
Use --code for normal onboarding, or --api-key for advanced/server installs.`);
|
|
@@ -121,16 +121,24 @@ function startDaemon({ foreground = false } = {}) {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
const logPath = resolveDaemonLogPath();
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
124
|
+
// Open the log file synchronously and pass its numeric fd: a lazily-opened
|
|
125
|
+
// WriteStream still has fd=null when spawn() runs, which Node rejects as
|
|
126
|
+
// invalid stdio. The child inherits a dup, so the parent closes its copy.
|
|
127
|
+
const logFd = openSync(logPath, 'a');
|
|
128
|
+
let child;
|
|
129
|
+
try {
|
|
130
|
+
child = spawn(process.execPath, args, {
|
|
131
|
+
detached: true,
|
|
132
|
+
stdio: ['ignore', logFd, logFd],
|
|
133
|
+
env: {
|
|
134
|
+
...process.env,
|
|
135
|
+
SERVER_URL: config.serverUrl,
|
|
136
|
+
MACHINE_API_KEY: config.machineApiKey,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
} finally {
|
|
140
|
+
closeSync(logFd);
|
|
141
|
+
}
|
|
134
142
|
child.unref();
|
|
135
143
|
writeFileSync(resolveDaemonPidPath(), `${child.pid}\n`, 'utf8');
|
|
136
144
|
console.log(`Daemon started pid=${child.pid}`);
|
|
@@ -165,6 +173,35 @@ function tailLogs(lines = 100) {
|
|
|
165
173
|
console.log(raw.split(/\r?\n/).slice(-(Number.isFinite(count) && count > 0 ? count : 100)).join('\n'));
|
|
166
174
|
}
|
|
167
175
|
|
|
176
|
+
function followLogs(lines = 100) {
|
|
177
|
+
const logPath = resolveDaemonLogPath();
|
|
178
|
+
if (existsSync(logPath)) {
|
|
179
|
+
tailLogs(lines);
|
|
180
|
+
} else {
|
|
181
|
+
console.log(`Waiting for ${logPath} to appear ... (Ctrl+C to stop)`);
|
|
182
|
+
}
|
|
183
|
+
let offset = existsSync(logPath) ? statSync(logPath).size : 0;
|
|
184
|
+
setInterval(() => {
|
|
185
|
+
try {
|
|
186
|
+
if (!existsSync(logPath)) return;
|
|
187
|
+
const size = statSync(logPath).size;
|
|
188
|
+
if (size < offset) offset = 0; // truncated or rotated
|
|
189
|
+
if (size <= offset) return;
|
|
190
|
+
const fd = openSync(logPath, 'r');
|
|
191
|
+
try {
|
|
192
|
+
const buf = Buffer.alloc(size - offset);
|
|
193
|
+
readSync(fd, buf, 0, buf.length, offset);
|
|
194
|
+
process.stdout.write(buf.toString('utf8'));
|
|
195
|
+
} finally {
|
|
196
|
+
closeSync(fd);
|
|
197
|
+
}
|
|
198
|
+
offset = size;
|
|
199
|
+
} catch {
|
|
200
|
+
// transient fs errors during rotation — retry on next tick
|
|
201
|
+
}
|
|
202
|
+
}, 500);
|
|
203
|
+
}
|
|
204
|
+
|
|
168
205
|
async function main() {
|
|
169
206
|
const opts = parseArgs(process.argv.slice(2));
|
|
170
207
|
const [command, subcommand] = opts._;
|
|
@@ -226,7 +263,8 @@ async function main() {
|
|
|
226
263
|
}
|
|
227
264
|
|
|
228
265
|
if (command === 'logs') {
|
|
229
|
-
|
|
266
|
+
if (opts['-f'] || opts['--follow']) followLogs(opts['--lines']);
|
|
267
|
+
else tailLogs(opts['--lines']);
|
|
230
268
|
return;
|
|
231
269
|
}
|
|
232
270
|
|