@alook/cli 0.0.60 → 0.0.62
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/README.md +118 -17
- package/dist/index.js +554 -502
- package/dist/meeting-runner.js +219 -23
- package/dist/session-runner.js +69 -24
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -20,7 +20,7 @@ import { Command as Command11 } from "commander";
|
|
|
20
20
|
// commands/register.ts
|
|
21
21
|
import { Command } from "commander";
|
|
22
22
|
import { execSync } from "child_process";
|
|
23
|
-
import { hostname as
|
|
23
|
+
import { hostname as hostname4 } from "os";
|
|
24
24
|
|
|
25
25
|
// lib/client.ts
|
|
26
26
|
class APIClient {
|
|
@@ -110,485 +110,46 @@ class APIClient {
|
|
|
110
110
|
import { readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
111
111
|
import { join } from "path";
|
|
112
112
|
import { homedir } from "os";
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
function isDev() {
|
|
116
|
-
return !!process.env.ALOOK_SERVER_URL;
|
|
117
|
-
}
|
|
118
|
-
function cmdPrefix() {
|
|
119
|
-
return isDev() ? "pnpm dev:cli" : "npx @alook/cli";
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// lib/config.ts
|
|
123
|
-
function configDir() {
|
|
124
|
-
if (isDev() && process.env.ALOOK_PROJECT_ROOT) {
|
|
125
|
-
return join(process.env.ALOOK_PROJECT_ROOT, ".alook");
|
|
126
|
-
}
|
|
127
|
-
return join(homedir(), ".alook");
|
|
128
|
-
}
|
|
129
|
-
function configPath() {
|
|
130
|
-
return join(configDir(), "config.json");
|
|
131
|
-
}
|
|
132
|
-
function loadCLIConfig() {
|
|
133
|
-
try {
|
|
134
|
-
return JSON.parse(readFileSync(configPath(), "utf-8"));
|
|
135
|
-
} catch {
|
|
136
|
-
return {};
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
function loadCLIConfigForProfile(profile) {
|
|
140
|
-
const cfg = loadCLIConfig();
|
|
141
|
-
const profileName = profile || cfg.default_profile;
|
|
142
|
-
if (profileName && cfg.profiles?.[profileName]) {
|
|
143
|
-
return cfg.profiles[profileName];
|
|
144
|
-
}
|
|
145
|
-
return {
|
|
146
|
-
server_url: cfg.server_url || "",
|
|
147
|
-
watched_workspaces: cfg.watched_workspaces || []
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
function saveCLIConfig(cfg) {
|
|
151
|
-
mkdirSync(configDir(), { recursive: true, mode: 448 });
|
|
152
|
-
writeFileSync(configPath(), JSON.stringify(cfg, null, 2), { mode: 384 });
|
|
153
|
-
}
|
|
154
|
-
function saveCLIConfigForProfile(profile, profileConfig) {
|
|
155
|
-
const cfg = loadCLIConfig();
|
|
156
|
-
if (profile) {
|
|
157
|
-
if (!cfg.profiles)
|
|
158
|
-
cfg.profiles = {};
|
|
159
|
-
cfg.profiles[profile] = profileConfig;
|
|
160
|
-
} else {
|
|
161
|
-
cfg.server_url = profileConfig.server_url;
|
|
162
|
-
cfg.watched_workspaces = profileConfig.watched_workspaces;
|
|
163
|
-
}
|
|
164
|
-
saveCLIConfig(cfg);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// daemon/pidfile.ts
|
|
168
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, unlinkSync, mkdirSync as mkdirSync2 } from "fs";
|
|
169
|
-
import { dirname as dirname2 } from "path";
|
|
170
|
-
|
|
171
|
-
// daemon/config.ts
|
|
172
|
-
import { hostname } from "os";
|
|
173
|
-
import { join as join3 } from "path";
|
|
174
|
-
|
|
175
|
-
// lib/version.ts
|
|
176
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
177
|
-
import { join as join2, dirname } from "path";
|
|
178
|
-
import { fileURLToPath } from "url";
|
|
179
|
-
function getCurrentVersion() {
|
|
180
|
-
const __dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
181
|
-
const candidates = [
|
|
182
|
-
join2(__dirname2, "..", "package.json"),
|
|
183
|
-
join2(__dirname2, "..", "..", "package.json")
|
|
184
|
-
];
|
|
185
|
-
for (const candidate of candidates) {
|
|
186
|
-
try {
|
|
187
|
-
const pkg = JSON.parse(readFileSync2(candidate, "utf-8"));
|
|
188
|
-
if (typeof pkg.version === "string")
|
|
189
|
-
return pkg.version;
|
|
190
|
-
} catch {}
|
|
191
|
-
}
|
|
192
|
-
return "unknown";
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// daemon/config.ts
|
|
196
|
-
function pidFilePath(profile) {
|
|
197
|
-
const name = profile ? `daemon_${profile}.pid` : "daemon.pid";
|
|
198
|
-
return join3(configDir(), name);
|
|
199
|
-
}
|
|
200
|
-
function lastUpdateMarkerPath(profile) {
|
|
201
|
-
const name = profile ? `last_update_${profile}` : "last_update";
|
|
202
|
-
return join3(configDir(), name);
|
|
203
|
-
}
|
|
204
|
-
function daemonLogDir() {
|
|
205
|
-
return join3(configDir(), "daemon", "logs");
|
|
206
|
-
}
|
|
207
|
-
function sessionRunnerLogDir() {
|
|
208
|
-
return join3(configDir(), "daemon", "session-runners");
|
|
209
|
-
}
|
|
210
|
-
function daemonLogFilePath(date = new Date) {
|
|
211
|
-
const y = date.getFullYear();
|
|
212
|
-
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
213
|
-
const d = String(date.getDate()).padStart(2, "0");
|
|
214
|
-
return join3(daemonLogDir(), `${y}-${m}-${d}.log`);
|
|
215
|
-
}
|
|
216
|
-
function parseDuration(s) {
|
|
217
|
-
if (!s)
|
|
218
|
-
return 0;
|
|
219
|
-
let total = 0;
|
|
220
|
-
const regex = /(\d+(?:\.\d+)?)(ns|us|µs|ms|s|m|h)/g;
|
|
221
|
-
let match;
|
|
222
|
-
while ((match = regex.exec(s)) !== null) {
|
|
223
|
-
const val = parseFloat(match[1]);
|
|
224
|
-
switch (match[2]) {
|
|
225
|
-
case "ns":
|
|
226
|
-
total += val / 1e6;
|
|
227
|
-
break;
|
|
228
|
-
case "us":
|
|
229
|
-
case "µs":
|
|
230
|
-
total += val / 1000;
|
|
231
|
-
break;
|
|
232
|
-
case "ms":
|
|
233
|
-
total += val;
|
|
234
|
-
break;
|
|
235
|
-
case "s":
|
|
236
|
-
total += val * 1000;
|
|
237
|
-
break;
|
|
238
|
-
case "m":
|
|
239
|
-
total += val * 60000;
|
|
240
|
-
break;
|
|
241
|
-
case "h":
|
|
242
|
-
total += val * 3600000;
|
|
243
|
-
break;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
return total;
|
|
247
|
-
}
|
|
248
|
-
function loadDaemonConfig(profile) {
|
|
249
|
-
const h = hostname();
|
|
250
|
-
let daemonId = process.env.ALOOK_DAEMON_ID || h;
|
|
251
|
-
if (profile && !daemonId.endsWith(`-${profile}`)) {
|
|
252
|
-
daemonId = `${daemonId}-${profile}`;
|
|
253
|
-
}
|
|
254
|
-
const defaultRoot = join3(configDir(), profile ? `workspaces_${profile}` : "workspaces");
|
|
255
|
-
const workspacesRoot = process.env.ALOOK_WORKSPACES_ROOT || defaultRoot;
|
|
256
|
-
return {
|
|
257
|
-
serverURL: normalizeServerBaseURL(process.env.ALOOK_SERVER_URL || "https://alook.ai"),
|
|
258
|
-
claudePath: process.env.ALOOK_CLAUDE_PATH || "claude",
|
|
259
|
-
codexPath: process.env.ALOOK_CODEX_PATH || "codex",
|
|
260
|
-
opencodePath: process.env.ALOOK_OPENCODE_PATH || "opencode",
|
|
261
|
-
claudeModel: process.env.ALOOK_CLAUDE_MODEL || "",
|
|
262
|
-
codexModel: process.env.ALOOK_CODEX_MODEL || "",
|
|
263
|
-
opencodeModel: process.env.ALOOK_OPENCODE_MODEL || "",
|
|
264
|
-
pollInterval: parseDuration(process.env.ALOOK_DAEMON_POLL_INTERVAL || "3s"),
|
|
265
|
-
agentTimeout: parseDuration(process.env.ALOOK_AGENT_TIMEOUT || "12h"),
|
|
266
|
-
messageInactivityTimeout: parseDuration(process.env.ALOOK_MESSAGE_INACTIVITY_TIMEOUT || "20m"),
|
|
267
|
-
maxConcurrentTasks: parseInt(process.env.ALOOK_DAEMON_MAX_CONCURRENT_TASKS || "20"),
|
|
268
|
-
daemonId,
|
|
269
|
-
deviceName: process.env.ALOOK_DAEMON_DEVICE_NAME || h,
|
|
270
|
-
workspacesRoot,
|
|
271
|
-
cliVersion: getCurrentVersion()
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
function normalizeServerBaseURL(url) {
|
|
275
|
-
return url.replace(/^ws:\/\//, "http://").replace(/^wss:\/\//, "https://").replace(/\/ws$/, "");
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// lib/logger.ts
|
|
279
|
-
var LEVELS = {
|
|
280
|
-
debug: 0,
|
|
281
|
-
info: 1,
|
|
282
|
-
warn: 2,
|
|
283
|
-
error: 3,
|
|
284
|
-
silent: 4
|
|
285
|
-
};
|
|
286
|
-
var LABELS = {
|
|
287
|
-
debug: "DEBUG",
|
|
288
|
-
info: "INFO ",
|
|
289
|
-
warn: "WARN ",
|
|
290
|
-
error: "ERROR"
|
|
291
|
-
};
|
|
292
|
-
var COLORS = {
|
|
293
|
-
debug: "\x1B[90m",
|
|
294
|
-
info: "\x1B[36m",
|
|
295
|
-
warn: "\x1B[33m",
|
|
296
|
-
error: "\x1B[31m"
|
|
297
|
-
};
|
|
298
|
-
var RESET = "\x1B[0m";
|
|
299
|
-
var DIM = "\x1B[2m";
|
|
300
|
-
var BOLD = "\x1B[1m";
|
|
301
|
-
function useColor() {
|
|
302
|
-
if (process.env.NO_COLOR !== undefined)
|
|
303
|
-
return false;
|
|
304
|
-
if (process.env.FORCE_COLOR !== undefined)
|
|
305
|
-
return true;
|
|
306
|
-
return process.stdout.isTTY === true;
|
|
307
|
-
}
|
|
308
|
-
function timestamp() {
|
|
309
|
-
const d = new Date;
|
|
310
|
-
const Y = d.getFullYear();
|
|
311
|
-
const M = String(d.getMonth() + 1).padStart(2, "0");
|
|
312
|
-
const D = String(d.getDate()).padStart(2, "0");
|
|
313
|
-
const h = String(d.getHours()).padStart(2, "0");
|
|
314
|
-
const m = String(d.getMinutes()).padStart(2, "0");
|
|
315
|
-
const s = String(d.getSeconds()).padStart(2, "0");
|
|
316
|
-
return `${Y}-${M}-${D} ${h}:${m}:${s}`;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
class Logger {
|
|
320
|
-
level;
|
|
321
|
-
color;
|
|
322
|
-
module;
|
|
323
|
-
constructor(opts = {}) {
|
|
324
|
-
const envLevel = process.env.ALOOK_LOG_LEVEL;
|
|
325
|
-
this.level = LEVELS[opts.level ?? envLevel ?? "info"];
|
|
326
|
-
this.color = useColor();
|
|
327
|
-
this.module = opts.module;
|
|
328
|
-
}
|
|
329
|
-
setLevel(level) {
|
|
330
|
-
this.level = LEVELS[level];
|
|
331
|
-
}
|
|
332
|
-
child(module) {
|
|
333
|
-
const child = new Logger({ level: this.levelName(), module });
|
|
334
|
-
return child;
|
|
335
|
-
}
|
|
336
|
-
debug(msg, ...args) {
|
|
337
|
-
this.write("debug", msg, args);
|
|
338
|
-
}
|
|
339
|
-
info(msg, ...args) {
|
|
340
|
-
this.write("info", msg, args);
|
|
341
|
-
}
|
|
342
|
-
warn(msg, ...args) {
|
|
343
|
-
this.write("warn", msg, args);
|
|
344
|
-
}
|
|
345
|
-
error(msg, ...args) {
|
|
346
|
-
this.write("error", msg, args);
|
|
347
|
-
}
|
|
348
|
-
levelName() {
|
|
349
|
-
for (const [name, num] of Object.entries(LEVELS)) {
|
|
350
|
-
if (num === this.level)
|
|
351
|
-
return name;
|
|
352
|
-
}
|
|
353
|
-
return "info";
|
|
354
|
-
}
|
|
355
|
-
write(level, msg, args) {
|
|
356
|
-
if (LEVELS[level] < this.level)
|
|
357
|
-
return;
|
|
358
|
-
const ts = timestamp();
|
|
359
|
-
const label = LABELS[level];
|
|
360
|
-
const mod = this.module ? `[${this.module}]` : "";
|
|
361
|
-
let line;
|
|
362
|
-
if (this.color) {
|
|
363
|
-
const c = COLORS[level];
|
|
364
|
-
const modStr = mod ? ` ${BOLD}${mod}${RESET}` : "";
|
|
365
|
-
line = `${DIM}${ts}${RESET} ${c}${label}${RESET}${modStr} ${msg}`;
|
|
366
|
-
} else {
|
|
367
|
-
const modStr = mod ? ` ${mod}` : "";
|
|
368
|
-
line = `${ts} ${label}${modStr} ${msg}`;
|
|
369
|
-
}
|
|
370
|
-
const dest = level === "error" ? process.stderr : process.stdout;
|
|
371
|
-
dest.write(line + `
|
|
372
|
-
`);
|
|
373
|
-
for (const a of args) {
|
|
374
|
-
if (a instanceof Error) {
|
|
375
|
-
dest.write(` ${a.message}
|
|
376
|
-
`);
|
|
377
|
-
if (a.stack && this.level <= LEVELS.debug) {
|
|
378
|
-
dest.write(` ${a.stack}
|
|
379
|
-
`);
|
|
380
|
-
}
|
|
381
|
-
} else if (a !== null && typeof a === "object") {
|
|
382
|
-
const pairs = Object.entries(a).map(([k, v]) => `${k}=${typeof v === "object" ? JSON.stringify(v) : v}`).join(" ");
|
|
383
|
-
if (pairs)
|
|
384
|
-
dest.write(` ${pairs}
|
|
385
|
-
`);
|
|
386
|
-
} else if (a !== undefined) {
|
|
387
|
-
dest.write(` ${String(a)}
|
|
388
|
-
`);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
function createLogger(opts) {
|
|
394
|
-
return new Logger(opts);
|
|
395
|
-
}
|
|
396
|
-
var log = createLogger();
|
|
397
|
-
|
|
398
|
-
// daemon/pidfile.ts
|
|
399
|
-
var log2 = createLogger({ module: "pidfile" });
|
|
400
|
-
function isProcessAlive(pid) {
|
|
401
|
-
try {
|
|
402
|
-
process.kill(pid, 0);
|
|
403
|
-
return true;
|
|
404
|
-
} catch {
|
|
405
|
-
return false;
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
function readDaemonPid(profile) {
|
|
409
|
-
try {
|
|
410
|
-
const content = readFileSync3(pidFilePath(profile), "utf-8").trim();
|
|
411
|
-
const pid = parseInt(content, 10);
|
|
412
|
-
return Number.isNaN(pid) ? null : pid;
|
|
413
|
-
} catch {
|
|
414
|
-
return null;
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
function acquireDaemonPid(profile) {
|
|
418
|
-
const pidPath = pidFilePath(profile);
|
|
419
|
-
try {
|
|
420
|
-
const content = readFileSync3(pidPath, "utf-8").trim();
|
|
421
|
-
const existingPid = parseInt(content, 10);
|
|
422
|
-
if (!isNaN(existingPid) && isProcessAlive(existingPid)) {
|
|
423
|
-
log2.error(`Another daemon is already running (PID ${existingPid}). ` + `Remove ${pidPath} if this is stale.`);
|
|
424
|
-
return false;
|
|
425
|
-
}
|
|
426
|
-
} catch {}
|
|
427
|
-
mkdirSync2(dirname2(pidPath), { recursive: true, mode: 448 });
|
|
428
|
-
writeFileSync2(pidPath, String(process.pid), { mode: 384 });
|
|
429
|
-
return true;
|
|
430
|
-
}
|
|
431
|
-
function removePidFileIfMatches(pid, profile) {
|
|
432
|
-
const pidPath = pidFilePath(profile);
|
|
433
|
-
const onDisk = readDaemonPid(profile);
|
|
434
|
-
if (onDisk !== pid)
|
|
435
|
-
return;
|
|
436
|
-
try {
|
|
437
|
-
unlinkSync(pidPath);
|
|
438
|
-
} catch {}
|
|
439
|
-
}
|
|
440
|
-
function releaseDaemonPid(profile) {
|
|
441
|
-
removePidFileIfMatches(process.pid, profile);
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// commands/register.ts
|
|
445
|
-
function isCommandAvailable(cmd) {
|
|
446
|
-
try {
|
|
447
|
-
const check = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
|
|
448
|
-
execSync(check, { stdio: "ignore" });
|
|
449
|
-
return true;
|
|
450
|
-
} catch {
|
|
451
|
-
return false;
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
function detectRuntimes() {
|
|
455
|
-
const found = [];
|
|
456
|
-
for (const type of ["claude", "codex", "opencode"]) {
|
|
457
|
-
if (isCommandAvailable(type)) {
|
|
458
|
-
let version = "";
|
|
459
|
-
try {
|
|
460
|
-
version = execSync(`${type} --version`, { encoding: "utf-8" }).trim();
|
|
461
|
-
} catch {}
|
|
462
|
-
found.push({ type, version });
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
return found;
|
|
466
|
-
}
|
|
467
|
-
function registerCommand() {
|
|
468
|
-
const cmd = new Command("register").description("Register CLI with your Alook account").requiredOption("--token <token>", "API token (starts with al_)").option("--server <url>", "Server URL").option("--profile <name>", "Profile name").action(async (opts, command) => {
|
|
469
|
-
const token = opts.token;
|
|
470
|
-
const profile = opts.profile || command.parent?.opts().profile;
|
|
471
|
-
const serverUrl = opts.server || command.parent?.opts().server || process.env.ALOOK_SERVER_URL || "https://alook.ai";
|
|
472
|
-
if (!token) {
|
|
473
|
-
console.error(`Error: --token is required
|
|
474
|
-
Usage: ${cmdPrefix()} register --token <token>`);
|
|
475
|
-
process.exit(1);
|
|
476
|
-
}
|
|
477
|
-
if (!token.startsWith("al_")) {
|
|
478
|
-
console.error("Error: invalid token format: must start with 'al_'");
|
|
479
|
-
process.exit(1);
|
|
480
|
-
}
|
|
481
|
-
const client = new APIClient(serverUrl, token);
|
|
482
|
-
let me;
|
|
483
|
-
try {
|
|
484
|
-
me = await client.getJSON("/api/me");
|
|
485
|
-
} catch (err) {
|
|
486
|
-
console.error(`Error: failed to verify token: ${err instanceof Error ? err.message : err}`);
|
|
487
|
-
process.exit(1);
|
|
488
|
-
}
|
|
489
|
-
console.log("Scanning for AI runtimes...");
|
|
490
|
-
const runtimes = detectRuntimes();
|
|
491
|
-
if (runtimes.length === 0) {
|
|
492
|
-
console.error("Error: no runtimes found. Install claude, codex, or opencode first.");
|
|
493
|
-
process.exit(1);
|
|
494
|
-
}
|
|
495
|
-
console.log(`Found: ${runtimes.map((r) => r.type).join(", ")}`);
|
|
496
|
-
const host = hostname2();
|
|
497
|
-
console.log("Registering runtime...");
|
|
498
|
-
let activateResp;
|
|
499
|
-
try {
|
|
500
|
-
const res = await fetch(`${serverUrl}/api/machine-tokens/activate`, {
|
|
501
|
-
method: "POST",
|
|
502
|
-
headers: { "Content-Type": "application/json" },
|
|
503
|
-
body: JSON.stringify({ token, hostname: host, runtimes })
|
|
504
|
-
});
|
|
505
|
-
if (!res.ok) {
|
|
506
|
-
const text = await res.text();
|
|
507
|
-
console.error(`Error: registration failed (${res.status}): ${text}`);
|
|
508
|
-
process.exit(1);
|
|
509
|
-
}
|
|
510
|
-
activateResp = await res.json();
|
|
511
|
-
} catch (err) {
|
|
512
|
-
console.error(`Error: failed to activate: ${err instanceof Error ? err.message : err}`);
|
|
513
|
-
process.exit(1);
|
|
514
|
-
}
|
|
515
|
-
let workspaces;
|
|
516
|
-
try {
|
|
517
|
-
workspaces = await client.getJSON("/api/workspaces");
|
|
518
|
-
} catch (err) {
|
|
519
|
-
console.error(`Error: failed to fetch workspaces: ${err instanceof Error ? err.message : err}`);
|
|
520
|
-
process.exit(1);
|
|
521
|
-
}
|
|
522
|
-
if (!workspaces.length) {
|
|
523
|
-
console.error("Error: no workspaces found for this user");
|
|
524
|
-
process.exit(1);
|
|
525
|
-
}
|
|
526
|
-
const ws = workspaces.find((w) => w.id === activateResp.workspace_id) || workspaces[0];
|
|
527
|
-
const wsClient = new APIClient(serverUrl, token, ws.id);
|
|
528
|
-
let agentIds = [];
|
|
529
|
-
try {
|
|
530
|
-
const agents = await wsClient.getJSON(`/api/agents?workspace_id=${ws.id}`);
|
|
531
|
-
agentIds = agents.map((a) => a.id);
|
|
532
|
-
} catch {}
|
|
533
|
-
const existing = loadCLIConfigForProfile(profile);
|
|
534
|
-
const watched = existing.watched_workspaces || [];
|
|
535
|
-
const idx = watched.findIndex((w) => w.id === ws.id);
|
|
536
|
-
if (idx >= 0) {
|
|
537
|
-
watched[idx] = { id: ws.id, name: ws.name, token, agent_ids: agentIds };
|
|
538
|
-
} else {
|
|
539
|
-
watched.push({ id: ws.id, name: ws.name, token, agent_ids: agentIds });
|
|
540
|
-
}
|
|
541
|
-
saveCLIConfigForProfile(profile, {
|
|
542
|
-
server_url: serverUrl,
|
|
543
|
-
watched_workspaces: watched
|
|
544
|
-
});
|
|
545
|
-
console.log(`
|
|
546
|
-
Registered as ${me.email}`);
|
|
547
|
-
console.log(`Workspace: ${ws.name} (${ws.id})`);
|
|
548
|
-
console.log(`Runtimes: ${activateResp.runtimes.map((r) => r.provider).join(", ")}`);
|
|
549
|
-
const daemonPid = readDaemonPid(profile);
|
|
550
|
-
if (daemonPid && isProcessAlive(daemonPid)) {
|
|
551
|
-
try {
|
|
552
|
-
process.kill(daemonPid, "SIGHUP");
|
|
553
|
-
console.log(`
|
|
554
|
-
Daemon (pid ${daemonPid}) notified — workspace will be active shortly.`);
|
|
555
|
-
} catch {
|
|
556
|
-
console.log(`
|
|
557
|
-
Daemon is running but could not be notified. Restart it to pick up the new workspace.`);
|
|
558
|
-
}
|
|
559
|
-
} else {
|
|
560
|
-
const startCmd = isDev() ? `${cmdPrefix()} daemon start --foreground` : `${cmdPrefix()} daemon start`;
|
|
561
|
-
console.log();
|
|
562
|
-
console.log(`Run '${startCmd}' to start the daemon.`);
|
|
563
|
-
}
|
|
564
|
-
});
|
|
565
|
-
return cmd;
|
|
113
|
+
function configDir() {
|
|
114
|
+
return process.env.ALOOK_PROJECT_ROOT || join(homedir(), ".alook");
|
|
566
115
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
function
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
116
|
+
function configPath() {
|
|
117
|
+
return join(configDir(), "config.json");
|
|
118
|
+
}
|
|
119
|
+
function loadCLIConfig() {
|
|
120
|
+
try {
|
|
121
|
+
return JSON.parse(readFileSync(configPath(), "utf-8"));
|
|
122
|
+
} catch {
|
|
123
|
+
return {};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function loadCLIConfigForProfile(profile) {
|
|
127
|
+
const cfg = loadCLIConfig();
|
|
128
|
+
const profileName = profile || cfg.default_profile;
|
|
129
|
+
if (profileName && cfg.profiles?.[profileName]) {
|
|
130
|
+
return cfg.profiles[profileName];
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
server_url: cfg.server_url || "",
|
|
134
|
+
watched_workspaces: cfg.watched_workspaces || []
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function saveCLIConfig(cfg) {
|
|
138
|
+
mkdirSync(configDir(), { recursive: true, mode: 448 });
|
|
139
|
+
writeFileSync(configPath(), JSON.stringify(cfg, null, 2), { mode: 384 });
|
|
140
|
+
}
|
|
141
|
+
function saveCLIConfigForProfile(profile, profileConfig) {
|
|
142
|
+
const cfg = loadCLIConfig();
|
|
143
|
+
if (profile) {
|
|
144
|
+
if (!cfg.profiles)
|
|
145
|
+
cfg.profiles = {};
|
|
146
|
+
cfg.profiles[profile] = profileConfig;
|
|
147
|
+
} else {
|
|
148
|
+
cfg.server_url = profileConfig.server_url;
|
|
149
|
+
cfg.watched_workspaces = profileConfig.watched_workspaces;
|
|
150
|
+
}
|
|
151
|
+
saveCLIConfig(cfg);
|
|
585
152
|
}
|
|
586
|
-
|
|
587
|
-
// commands/daemon.ts
|
|
588
|
-
import { Command as Command3 } from "commander";
|
|
589
|
-
import { spawn as spawn3 } from "child_process";
|
|
590
|
-
import { openSync as openSync2, closeSync as closeSync2, mkdirSync as mkdirSync6 } from "fs";
|
|
591
|
-
import { dirname as dirname4 } from "path";
|
|
592
153
|
|
|
593
154
|
// ../shared/src/constants.ts
|
|
594
155
|
var TaskStatus = {
|
|
@@ -761,7 +322,7 @@ __export(exports_external, {
|
|
|
761
322
|
instanceof: () => _instanceof,
|
|
762
323
|
includes: () => _includes,
|
|
763
324
|
httpUrl: () => httpUrl,
|
|
764
|
-
hostname: () =>
|
|
325
|
+
hostname: () => hostname2,
|
|
765
326
|
hex: () => hex2,
|
|
766
327
|
hash: () => hash,
|
|
767
328
|
guid: () => guid2,
|
|
@@ -2212,7 +1773,7 @@ __export(exports_regexes, {
|
|
|
2212
1773
|
idnEmail: () => idnEmail,
|
|
2213
1774
|
httpProtocol: () => httpProtocol,
|
|
2214
1775
|
html5Email: () => html5Email,
|
|
2215
|
-
hostname: () =>
|
|
1776
|
+
hostname: () => hostname,
|
|
2216
1777
|
hex: () => hex,
|
|
2217
1778
|
guid: () => guid,
|
|
2218
1779
|
extendedDuration: () => extendedDuration,
|
|
@@ -2270,7 +1831,7 @@ var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]
|
|
|
2270
1831
|
var cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/;
|
|
2271
1832
|
var base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/;
|
|
2272
1833
|
var base64url = /^[A-Za-z0-9_-]*$/;
|
|
2273
|
-
var
|
|
1834
|
+
var hostname = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/;
|
|
2274
1835
|
var domain = /^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
2275
1836
|
var httpProtocol = /^https?$/;
|
|
2276
1837
|
var e164 = /^\+[1-9]\d{6,14}$/;
|
|
@@ -12115,7 +11676,7 @@ function finalize(ctx, schema) {
|
|
|
12115
11676
|
result.$schema = "http://json-schema.org/draft-07/schema#";
|
|
12116
11677
|
} else if (ctx.target === "draft-04") {
|
|
12117
11678
|
result.$schema = "http://json-schema.org/draft-04/schema#";
|
|
12118
|
-
} else if (ctx.target === "openapi-3.0") {}
|
|
11679
|
+
} else if (ctx.target === "openapi-3.0") {}
|
|
12119
11680
|
if (ctx.external?.uri) {
|
|
12120
11681
|
const id = ctx.external.registry.get(schema)?.id;
|
|
12121
11682
|
if (!id)
|
|
@@ -12359,7 +11920,7 @@ var literalProcessor = (schema, ctx, json, _params) => {
|
|
|
12359
11920
|
if (val === undefined) {
|
|
12360
11921
|
if (ctx.unrepresentable === "throw") {
|
|
12361
11922
|
throw new Error("Literal `undefined` cannot be represented in JSON Schema");
|
|
12362
|
-
}
|
|
11923
|
+
}
|
|
12363
11924
|
} else if (typeof val === "bigint") {
|
|
12364
11925
|
if (ctx.unrepresentable === "throw") {
|
|
12365
11926
|
throw new Error("BigInt literals cannot be represented in JSON Schema");
|
|
@@ -12894,7 +12455,7 @@ __export(exports_schemas2, {
|
|
|
12894
12455
|
int: () => int,
|
|
12895
12456
|
instanceof: () => _instanceof,
|
|
12896
12457
|
httpUrl: () => httpUrl,
|
|
12897
|
-
hostname: () =>
|
|
12458
|
+
hostname: () => hostname2,
|
|
12898
12459
|
hex: () => hex2,
|
|
12899
12460
|
hash: () => hash,
|
|
12900
12461
|
guid: () => guid2,
|
|
@@ -13546,7 +13107,7 @@ var ZodCustomStringFormat = /* @__PURE__ */ $constructor("ZodCustomStringFormat"
|
|
|
13546
13107
|
function stringFormat(format, fnOrRegex, _params = {}) {
|
|
13547
13108
|
return _stringFormat(ZodCustomStringFormat, format, fnOrRegex, _params);
|
|
13548
13109
|
}
|
|
13549
|
-
function
|
|
13110
|
+
function hostname2(_params) {
|
|
13550
13111
|
return _stringFormat(ZodCustomStringFormat, "hostname", exports_regexes.hostname, _params);
|
|
13551
13112
|
}
|
|
13552
13113
|
function hex2(_params) {
|
|
@@ -15022,7 +14583,9 @@ var PollMeetingItemSchema = exports_external.object({
|
|
|
15022
14583
|
meeting_url: exports_external.string(),
|
|
15023
14584
|
participants: exports_external.array(exports_external.string()),
|
|
15024
14585
|
workspace_id: exports_external.string(),
|
|
15025
|
-
|
|
14586
|
+
agent_id: exports_external.string(),
|
|
14587
|
+
agent_name: exports_external.string(),
|
|
14588
|
+
title: exports_external.string().optional()
|
|
15026
14589
|
});
|
|
15027
14590
|
var PollResponseSchema = exports_external.object({
|
|
15028
14591
|
tasks: exports_external.array(TaskApiSchema),
|
|
@@ -15057,6 +14620,7 @@ var RegisterDaemonRequestSchema = exports_external.object({
|
|
|
15057
14620
|
daemon_id: exports_external.string().min(1),
|
|
15058
14621
|
device_name: exports_external.string().optional().default(""),
|
|
15059
14622
|
cli_version: exports_external.string().optional().default(""),
|
|
14623
|
+
workspaces_root: exports_external.string().optional().default(""),
|
|
15060
14624
|
runtimes: exports_external.array(DaemonRuntimeItemSchema).min(1)
|
|
15061
14625
|
});
|
|
15062
14626
|
var DeregisterRequestSchema = exports_external.object({
|
|
@@ -15265,7 +14829,8 @@ var EmailNotifyRequestSchema = exports_external.object({
|
|
|
15265
14829
|
meetingInfo: MeetingInfoSchema.nullable().optional(),
|
|
15266
14830
|
attachments: exports_external.string().optional(),
|
|
15267
14831
|
traceId: exports_external.string().optional(),
|
|
15268
|
-
sourceTaskId: exports_external.string().optional()
|
|
14832
|
+
sourceTaskId: exports_external.string().optional(),
|
|
14833
|
+
isInternal: exports_external.boolean().optional().default(false)
|
|
15269
14834
|
});
|
|
15270
14835
|
var CreateEmailAccountSchema = exports_external.object({
|
|
15271
14836
|
emailAddress: exports_external.string().email("valid email required"),
|
|
@@ -15946,7 +15511,7 @@ function sql(strings, ...params) {
|
|
|
15946
15511
|
return new SQL([new StringChunk(str)]);
|
|
15947
15512
|
}
|
|
15948
15513
|
sql2.raw = raw;
|
|
15949
|
-
function
|
|
15514
|
+
function join2(chunks, separator) {
|
|
15950
15515
|
const result = [];
|
|
15951
15516
|
for (const [i, chunk] of chunks.entries()) {
|
|
15952
15517
|
if (i > 0 && separator !== undefined) {
|
|
@@ -15956,7 +15521,7 @@ function sql(strings, ...params) {
|
|
|
15956
15521
|
}
|
|
15957
15522
|
return new SQL(result);
|
|
15958
15523
|
}
|
|
15959
|
-
sql2.join =
|
|
15524
|
+
sql2.join = join2;
|
|
15960
15525
|
function identifier(value) {
|
|
15961
15526
|
return new Name(value);
|
|
15962
15527
|
}
|
|
@@ -17164,6 +16729,17 @@ var machineToken = sqliteTable("machine_token", {
|
|
|
17164
16729
|
lastUsedAt: text("last_used_at"),
|
|
17165
16730
|
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
17166
16731
|
}, (t) => [index("idx_machine_token").on(t.token)]);
|
|
16732
|
+
var messageFlag = sqliteTable("message_flag", {
|
|
16733
|
+
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
16734
|
+
messageId: text("message_id").notNull().references(() => message.id, { onDelete: "cascade" }),
|
|
16735
|
+
userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
16736
|
+
workspaceId: text("workspace_id").notNull().references(() => workspace.id, { onDelete: "cascade" }),
|
|
16737
|
+
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
16738
|
+
}, (t) => [
|
|
16739
|
+
unique("message_flag_message_user").on(t.messageId, t.userId),
|
|
16740
|
+
index("idx_message_flag_ws_user_created").on(t.workspaceId, t.userId, t.createdAt),
|
|
16741
|
+
index("idx_message_flag_message_user").on(t.messageId, t.userId)
|
|
16742
|
+
]);
|
|
17167
16743
|
var conversationMap = sqliteTable("conversation_map", {
|
|
17168
16744
|
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
17169
16745
|
key: text("key").notNull(),
|
|
@@ -17255,6 +16831,468 @@ function semverGte(a, b) {
|
|
|
17255
16831
|
}
|
|
17256
16832
|
return true;
|
|
17257
16833
|
}
|
|
16834
|
+
// ../shared/src/mode.ts
|
|
16835
|
+
function resolveMode(signals) {
|
|
16836
|
+
if (signals.nodeEnv === "development" && !signals.cmdPrefix)
|
|
16837
|
+
return "dev";
|
|
16838
|
+
if (signals.serverUrl && !signals.cmdPrefix)
|
|
16839
|
+
return "dev";
|
|
16840
|
+
if (signals.cmdPrefix)
|
|
16841
|
+
return "app";
|
|
16842
|
+
if (signals.hostname && ["localhost", "127.0.0.1"].includes(signals.hostname))
|
|
16843
|
+
return "app";
|
|
16844
|
+
return "production";
|
|
16845
|
+
}
|
|
16846
|
+
function cliCommand(mode) {
|
|
16847
|
+
switch (mode) {
|
|
16848
|
+
case "dev":
|
|
16849
|
+
return "pnpm dev:cli";
|
|
16850
|
+
case "app":
|
|
16851
|
+
return "npx @alook/app cli";
|
|
16852
|
+
case "production":
|
|
16853
|
+
return "npx @alook/cli";
|
|
16854
|
+
}
|
|
16855
|
+
}
|
|
16856
|
+
// lib/env.ts
|
|
16857
|
+
function isDev() {
|
|
16858
|
+
return resolveMode({
|
|
16859
|
+
serverUrl: process.env.ALOOK_SERVER_URL,
|
|
16860
|
+
cmdPrefix: process.env.ALOOK_CMD_PREFIX
|
|
16861
|
+
}) === "dev";
|
|
16862
|
+
}
|
|
16863
|
+
function cmdPrefix() {
|
|
16864
|
+
return process.env.ALOOK_CMD_PREFIX || cliCommand(resolveMode({
|
|
16865
|
+
serverUrl: process.env.ALOOK_SERVER_URL,
|
|
16866
|
+
cmdPrefix: process.env.ALOOK_CMD_PREFIX
|
|
16867
|
+
}));
|
|
16868
|
+
}
|
|
16869
|
+
|
|
16870
|
+
// daemon/pidfile.ts
|
|
16871
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, unlinkSync, mkdirSync as mkdirSync2 } from "fs";
|
|
16872
|
+
import { dirname as dirname2 } from "path";
|
|
16873
|
+
|
|
16874
|
+
// daemon/config.ts
|
|
16875
|
+
import { hostname as hostname3 } from "os";
|
|
16876
|
+
import { join as join3 } from "path";
|
|
16877
|
+
|
|
16878
|
+
// lib/version.ts
|
|
16879
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
16880
|
+
import { join as join2, dirname } from "path";
|
|
16881
|
+
import { fileURLToPath } from "url";
|
|
16882
|
+
function getCurrentVersion() {
|
|
16883
|
+
const __dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
16884
|
+
const candidates = [
|
|
16885
|
+
join2(__dirname2, "..", "package.json"),
|
|
16886
|
+
join2(__dirname2, "..", "..", "package.json")
|
|
16887
|
+
];
|
|
16888
|
+
for (const candidate of candidates) {
|
|
16889
|
+
try {
|
|
16890
|
+
const pkg = JSON.parse(readFileSync2(candidate, "utf-8"));
|
|
16891
|
+
if (typeof pkg.version === "string")
|
|
16892
|
+
return pkg.version;
|
|
16893
|
+
} catch {}
|
|
16894
|
+
}
|
|
16895
|
+
return "unknown";
|
|
16896
|
+
}
|
|
16897
|
+
|
|
16898
|
+
// daemon/config.ts
|
|
16899
|
+
function pidFilePath(profile) {
|
|
16900
|
+
const name = profile ? `daemon_${profile}.pid` : "daemon.pid";
|
|
16901
|
+
return join3(configDir(), name);
|
|
16902
|
+
}
|
|
16903
|
+
function lastUpdateMarkerPath(profile) {
|
|
16904
|
+
const name = profile ? `last_update_${profile}` : "last_update";
|
|
16905
|
+
return join3(configDir(), name);
|
|
16906
|
+
}
|
|
16907
|
+
function daemonLogDir() {
|
|
16908
|
+
return join3(configDir(), "daemon", "logs");
|
|
16909
|
+
}
|
|
16910
|
+
function sessionRunnerLogDir() {
|
|
16911
|
+
return join3(configDir(), "daemon", "session-runners");
|
|
16912
|
+
}
|
|
16913
|
+
function daemonLogFilePath(date5 = new Date) {
|
|
16914
|
+
const y = date5.getFullYear();
|
|
16915
|
+
const m = String(date5.getMonth() + 1).padStart(2, "0");
|
|
16916
|
+
const d = String(date5.getDate()).padStart(2, "0");
|
|
16917
|
+
return join3(daemonLogDir(), `${y}-${m}-${d}.log`);
|
|
16918
|
+
}
|
|
16919
|
+
function parseDuration(s) {
|
|
16920
|
+
if (!s)
|
|
16921
|
+
return 0;
|
|
16922
|
+
let total = 0;
|
|
16923
|
+
const regex = /(\d+(?:\.\d+)?)(ns|us|µs|ms|s|m|h)/g;
|
|
16924
|
+
let match;
|
|
16925
|
+
while ((match = regex.exec(s)) !== null) {
|
|
16926
|
+
const val = parseFloat(match[1]);
|
|
16927
|
+
switch (match[2]) {
|
|
16928
|
+
case "ns":
|
|
16929
|
+
total += val / 1e6;
|
|
16930
|
+
break;
|
|
16931
|
+
case "us":
|
|
16932
|
+
case "µs":
|
|
16933
|
+
total += val / 1000;
|
|
16934
|
+
break;
|
|
16935
|
+
case "ms":
|
|
16936
|
+
total += val;
|
|
16937
|
+
break;
|
|
16938
|
+
case "s":
|
|
16939
|
+
total += val * 1000;
|
|
16940
|
+
break;
|
|
16941
|
+
case "m":
|
|
16942
|
+
total += val * 60000;
|
|
16943
|
+
break;
|
|
16944
|
+
case "h":
|
|
16945
|
+
total += val * 3600000;
|
|
16946
|
+
break;
|
|
16947
|
+
}
|
|
16948
|
+
}
|
|
16949
|
+
return total;
|
|
16950
|
+
}
|
|
16951
|
+
function loadDaemonConfig(profile) {
|
|
16952
|
+
const h = hostname3();
|
|
16953
|
+
let daemonId = process.env.ALOOK_DAEMON_ID || h;
|
|
16954
|
+
if (profile && !daemonId.endsWith(`-${profile}`)) {
|
|
16955
|
+
daemonId = `${daemonId}-${profile}`;
|
|
16956
|
+
}
|
|
16957
|
+
const defaultRoot = join3(configDir(), profile ? `workspaces_${profile}` : "workspaces");
|
|
16958
|
+
const workspacesRoot = process.env.ALOOK_WORKSPACES_ROOT || defaultRoot;
|
|
16959
|
+
return {
|
|
16960
|
+
serverURL: normalizeServerBaseURL(process.env.ALOOK_SERVER_URL || "https://alook.ai"),
|
|
16961
|
+
claudePath: process.env.ALOOK_CLAUDE_PATH || "claude",
|
|
16962
|
+
codexPath: process.env.ALOOK_CODEX_PATH || "codex",
|
|
16963
|
+
opencodePath: process.env.ALOOK_OPENCODE_PATH || "opencode",
|
|
16964
|
+
claudeModel: process.env.ALOOK_CLAUDE_MODEL || "",
|
|
16965
|
+
codexModel: process.env.ALOOK_CODEX_MODEL || "",
|
|
16966
|
+
opencodeModel: process.env.ALOOK_OPENCODE_MODEL || "",
|
|
16967
|
+
pollInterval: parseDuration(process.env.ALOOK_DAEMON_POLL_INTERVAL || "3s"),
|
|
16968
|
+
agentTimeout: parseDuration(process.env.ALOOK_AGENT_TIMEOUT || "12h"),
|
|
16969
|
+
messageInactivityTimeout: parseDuration(process.env.ALOOK_MESSAGE_INACTIVITY_TIMEOUT || "20m"),
|
|
16970
|
+
maxConcurrentTasks: parseInt(process.env.ALOOK_DAEMON_MAX_CONCURRENT_TASKS || "20"),
|
|
16971
|
+
daemonId,
|
|
16972
|
+
deviceName: process.env.ALOOK_DAEMON_DEVICE_NAME || h,
|
|
16973
|
+
workspacesRoot,
|
|
16974
|
+
cliVersion: getCurrentVersion()
|
|
16975
|
+
};
|
|
16976
|
+
}
|
|
16977
|
+
function normalizeServerBaseURL(url2) {
|
|
16978
|
+
return url2.replace(/^ws:\/\//, "http://").replace(/^wss:\/\//, "https://").replace(/\/ws$/, "");
|
|
16979
|
+
}
|
|
16980
|
+
|
|
16981
|
+
// lib/logger.ts
|
|
16982
|
+
var LEVELS = {
|
|
16983
|
+
debug: 0,
|
|
16984
|
+
info: 1,
|
|
16985
|
+
warn: 2,
|
|
16986
|
+
error: 3,
|
|
16987
|
+
silent: 4
|
|
16988
|
+
};
|
|
16989
|
+
var LABELS = {
|
|
16990
|
+
debug: "DEBUG",
|
|
16991
|
+
info: "INFO ",
|
|
16992
|
+
warn: "WARN ",
|
|
16993
|
+
error: "ERROR"
|
|
16994
|
+
};
|
|
16995
|
+
var COLORS = {
|
|
16996
|
+
debug: "\x1B[90m",
|
|
16997
|
+
info: "\x1B[36m",
|
|
16998
|
+
warn: "\x1B[33m",
|
|
16999
|
+
error: "\x1B[31m"
|
|
17000
|
+
};
|
|
17001
|
+
var RESET = "\x1B[0m";
|
|
17002
|
+
var DIM = "\x1B[2m";
|
|
17003
|
+
var BOLD = "\x1B[1m";
|
|
17004
|
+
function useColor() {
|
|
17005
|
+
if (process.env.NO_COLOR !== undefined)
|
|
17006
|
+
return false;
|
|
17007
|
+
if (process.env.FORCE_COLOR !== undefined)
|
|
17008
|
+
return true;
|
|
17009
|
+
return process.stdout.isTTY === true;
|
|
17010
|
+
}
|
|
17011
|
+
function timestamp() {
|
|
17012
|
+
const d = new Date;
|
|
17013
|
+
const Y = d.getFullYear();
|
|
17014
|
+
const M = String(d.getMonth() + 1).padStart(2, "0");
|
|
17015
|
+
const D = String(d.getDate()).padStart(2, "0");
|
|
17016
|
+
const h = String(d.getHours()).padStart(2, "0");
|
|
17017
|
+
const m = String(d.getMinutes()).padStart(2, "0");
|
|
17018
|
+
const s = String(d.getSeconds()).padStart(2, "0");
|
|
17019
|
+
return `${Y}-${M}-${D} ${h}:${m}:${s}`;
|
|
17020
|
+
}
|
|
17021
|
+
|
|
17022
|
+
class Logger2 {
|
|
17023
|
+
level;
|
|
17024
|
+
color;
|
|
17025
|
+
module;
|
|
17026
|
+
constructor(opts = {}) {
|
|
17027
|
+
const envLevel = process.env.ALOOK_LOG_LEVEL;
|
|
17028
|
+
this.level = LEVELS[opts.level ?? envLevel ?? "info"];
|
|
17029
|
+
this.color = useColor();
|
|
17030
|
+
this.module = opts.module;
|
|
17031
|
+
}
|
|
17032
|
+
setLevel(level) {
|
|
17033
|
+
this.level = LEVELS[level];
|
|
17034
|
+
}
|
|
17035
|
+
child(module) {
|
|
17036
|
+
const child = new Logger2({ level: this.levelName(), module });
|
|
17037
|
+
return child;
|
|
17038
|
+
}
|
|
17039
|
+
debug(msg, ...args) {
|
|
17040
|
+
this.write("debug", msg, args);
|
|
17041
|
+
}
|
|
17042
|
+
info(msg, ...args) {
|
|
17043
|
+
this.write("info", msg, args);
|
|
17044
|
+
}
|
|
17045
|
+
warn(msg, ...args) {
|
|
17046
|
+
this.write("warn", msg, args);
|
|
17047
|
+
}
|
|
17048
|
+
error(msg, ...args) {
|
|
17049
|
+
this.write("error", msg, args);
|
|
17050
|
+
}
|
|
17051
|
+
levelName() {
|
|
17052
|
+
for (const [name, num] of Object.entries(LEVELS)) {
|
|
17053
|
+
if (num === this.level)
|
|
17054
|
+
return name;
|
|
17055
|
+
}
|
|
17056
|
+
return "info";
|
|
17057
|
+
}
|
|
17058
|
+
write(level, msg, args) {
|
|
17059
|
+
if (LEVELS[level] < this.level)
|
|
17060
|
+
return;
|
|
17061
|
+
const ts = timestamp();
|
|
17062
|
+
const label = LABELS[level];
|
|
17063
|
+
const mod = this.module ? `[${this.module}]` : "";
|
|
17064
|
+
let line;
|
|
17065
|
+
if (this.color) {
|
|
17066
|
+
const c = COLORS[level];
|
|
17067
|
+
const modStr = mod ? ` ${BOLD}${mod}${RESET}` : "";
|
|
17068
|
+
line = `${DIM}${ts}${RESET} ${c}${label}${RESET}${modStr} ${msg}`;
|
|
17069
|
+
} else {
|
|
17070
|
+
const modStr = mod ? ` ${mod}` : "";
|
|
17071
|
+
line = `${ts} ${label}${modStr} ${msg}`;
|
|
17072
|
+
}
|
|
17073
|
+
const dest = level === "error" ? process.stderr : process.stdout;
|
|
17074
|
+
dest.write(line + `
|
|
17075
|
+
`);
|
|
17076
|
+
for (const a of args) {
|
|
17077
|
+
if (a instanceof Error) {
|
|
17078
|
+
dest.write(` ${a.message}
|
|
17079
|
+
`);
|
|
17080
|
+
if (a.stack && this.level <= LEVELS.debug) {
|
|
17081
|
+
dest.write(` ${a.stack}
|
|
17082
|
+
`);
|
|
17083
|
+
}
|
|
17084
|
+
} else if (a !== null && typeof a === "object") {
|
|
17085
|
+
const pairs = Object.entries(a).map(([k, v]) => `${k}=${typeof v === "object" ? JSON.stringify(v) : v}`).join(" ");
|
|
17086
|
+
if (pairs)
|
|
17087
|
+
dest.write(` ${pairs}
|
|
17088
|
+
`);
|
|
17089
|
+
} else if (a !== undefined) {
|
|
17090
|
+
dest.write(` ${String(a)}
|
|
17091
|
+
`);
|
|
17092
|
+
}
|
|
17093
|
+
}
|
|
17094
|
+
}
|
|
17095
|
+
}
|
|
17096
|
+
function createLogger2(opts) {
|
|
17097
|
+
return new Logger2(opts);
|
|
17098
|
+
}
|
|
17099
|
+
var log = createLogger2();
|
|
17100
|
+
|
|
17101
|
+
// daemon/pidfile.ts
|
|
17102
|
+
var log2 = createLogger2({ module: "pidfile" });
|
|
17103
|
+
function isProcessAlive(pid) {
|
|
17104
|
+
try {
|
|
17105
|
+
process.kill(pid, 0);
|
|
17106
|
+
return true;
|
|
17107
|
+
} catch {
|
|
17108
|
+
return false;
|
|
17109
|
+
}
|
|
17110
|
+
}
|
|
17111
|
+
function readDaemonPid(profile) {
|
|
17112
|
+
try {
|
|
17113
|
+
const content = readFileSync3(pidFilePath(profile), "utf-8").trim();
|
|
17114
|
+
const pid = parseInt(content, 10);
|
|
17115
|
+
return Number.isNaN(pid) ? null : pid;
|
|
17116
|
+
} catch {
|
|
17117
|
+
return null;
|
|
17118
|
+
}
|
|
17119
|
+
}
|
|
17120
|
+
function acquireDaemonPid(profile) {
|
|
17121
|
+
const pidPath = pidFilePath(profile);
|
|
17122
|
+
try {
|
|
17123
|
+
const content = readFileSync3(pidPath, "utf-8").trim();
|
|
17124
|
+
const existingPid = parseInt(content, 10);
|
|
17125
|
+
if (!isNaN(existingPid) && isProcessAlive(existingPid)) {
|
|
17126
|
+
log2.error(`Another daemon is already running (PID ${existingPid}). ` + `Remove ${pidPath} if this is stale.`);
|
|
17127
|
+
return false;
|
|
17128
|
+
}
|
|
17129
|
+
} catch {}
|
|
17130
|
+
mkdirSync2(dirname2(pidPath), { recursive: true, mode: 448 });
|
|
17131
|
+
writeFileSync2(pidPath, String(process.pid), { mode: 384 });
|
|
17132
|
+
return true;
|
|
17133
|
+
}
|
|
17134
|
+
function removePidFileIfMatches(pid, profile) {
|
|
17135
|
+
const pidPath = pidFilePath(profile);
|
|
17136
|
+
const onDisk = readDaemonPid(profile);
|
|
17137
|
+
if (onDisk !== pid)
|
|
17138
|
+
return;
|
|
17139
|
+
try {
|
|
17140
|
+
unlinkSync(pidPath);
|
|
17141
|
+
} catch {}
|
|
17142
|
+
}
|
|
17143
|
+
function releaseDaemonPid(profile) {
|
|
17144
|
+
removePidFileIfMatches(process.pid, profile);
|
|
17145
|
+
}
|
|
17146
|
+
|
|
17147
|
+
// commands/register.ts
|
|
17148
|
+
function isCommandAvailable(cmd) {
|
|
17149
|
+
try {
|
|
17150
|
+
const check2 = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
|
|
17151
|
+
execSync(check2, { stdio: "ignore" });
|
|
17152
|
+
return true;
|
|
17153
|
+
} catch {
|
|
17154
|
+
return false;
|
|
17155
|
+
}
|
|
17156
|
+
}
|
|
17157
|
+
function detectRuntimes() {
|
|
17158
|
+
const found = [];
|
|
17159
|
+
for (const type of ["claude", "codex", "opencode"]) {
|
|
17160
|
+
if (isCommandAvailable(type)) {
|
|
17161
|
+
let version3 = "";
|
|
17162
|
+
try {
|
|
17163
|
+
version3 = execSync(`${type} --version`, { encoding: "utf-8" }).trim();
|
|
17164
|
+
} catch {}
|
|
17165
|
+
found.push({ type, version: version3 });
|
|
17166
|
+
}
|
|
17167
|
+
}
|
|
17168
|
+
return found;
|
|
17169
|
+
}
|
|
17170
|
+
function registerCommand() {
|
|
17171
|
+
const cmd = new Command("register").description("Register CLI with your Alook account").requiredOption("--token <token>", "API token (starts with al_)").option("--server <url>", "Server URL").option("--profile <name>", "Profile name").action(async (opts, command) => {
|
|
17172
|
+
const token = opts.token;
|
|
17173
|
+
const profile = opts.profile || command.parent?.opts().profile;
|
|
17174
|
+
const serverUrl = opts.server || command.parent?.opts().server || process.env.ALOOK_SERVER_URL || "https://alook.ai";
|
|
17175
|
+
if (!token) {
|
|
17176
|
+
console.error(`Error: --token is required
|
|
17177
|
+
Usage: ${cmdPrefix()} register --token <token>`);
|
|
17178
|
+
process.exit(1);
|
|
17179
|
+
}
|
|
17180
|
+
if (!token.startsWith("al_")) {
|
|
17181
|
+
console.error("Error: invalid token format: must start with 'al_'");
|
|
17182
|
+
process.exit(1);
|
|
17183
|
+
}
|
|
17184
|
+
const client = new APIClient(serverUrl, token);
|
|
17185
|
+
let me;
|
|
17186
|
+
try {
|
|
17187
|
+
me = await client.getJSON("/api/me");
|
|
17188
|
+
} catch (err) {
|
|
17189
|
+
console.error(`Error: failed to verify token: ${err instanceof Error ? err.message : err}`);
|
|
17190
|
+
process.exit(1);
|
|
17191
|
+
}
|
|
17192
|
+
console.log("Scanning for AI runtimes...");
|
|
17193
|
+
const runtimes = detectRuntimes();
|
|
17194
|
+
if (runtimes.length === 0) {
|
|
17195
|
+
console.error("Error: no runtimes found. Install claude, codex, or opencode first.");
|
|
17196
|
+
process.exit(1);
|
|
17197
|
+
}
|
|
17198
|
+
console.log(`Found: ${runtimes.map((r) => r.type).join(", ")}`);
|
|
17199
|
+
const host = hostname4();
|
|
17200
|
+
console.log("Registering runtime...");
|
|
17201
|
+
let activateResp;
|
|
17202
|
+
try {
|
|
17203
|
+
const res = await fetch(`${serverUrl}/api/machine-tokens/activate`, {
|
|
17204
|
+
method: "POST",
|
|
17205
|
+
headers: { "Content-Type": "application/json" },
|
|
17206
|
+
body: JSON.stringify({ token, hostname: host, runtimes })
|
|
17207
|
+
});
|
|
17208
|
+
if (!res.ok) {
|
|
17209
|
+
const text2 = await res.text();
|
|
17210
|
+
console.error(`Error: registration failed (${res.status}): ${text2}`);
|
|
17211
|
+
process.exit(1);
|
|
17212
|
+
}
|
|
17213
|
+
activateResp = await res.json();
|
|
17214
|
+
} catch (err) {
|
|
17215
|
+
console.error(`Error: failed to activate: ${err instanceof Error ? err.message : err}`);
|
|
17216
|
+
process.exit(1);
|
|
17217
|
+
}
|
|
17218
|
+
let workspaces;
|
|
17219
|
+
try {
|
|
17220
|
+
workspaces = await client.getJSON("/api/workspaces");
|
|
17221
|
+
} catch (err) {
|
|
17222
|
+
console.error(`Error: failed to fetch workspaces: ${err instanceof Error ? err.message : err}`);
|
|
17223
|
+
process.exit(1);
|
|
17224
|
+
}
|
|
17225
|
+
if (!workspaces.length) {
|
|
17226
|
+
console.error("Error: no workspaces found for this user");
|
|
17227
|
+
process.exit(1);
|
|
17228
|
+
}
|
|
17229
|
+
const ws = workspaces.find((w) => w.id === activateResp.workspace_id) || workspaces[0];
|
|
17230
|
+
const wsClient = new APIClient(serverUrl, token, ws.id);
|
|
17231
|
+
let agentIds = [];
|
|
17232
|
+
try {
|
|
17233
|
+
const agents = await wsClient.getJSON(`/api/agents?workspace_id=${ws.id}`);
|
|
17234
|
+
agentIds = agents.map((a) => a.id);
|
|
17235
|
+
} catch {}
|
|
17236
|
+
const existing = loadCLIConfigForProfile(profile);
|
|
17237
|
+
const watched = existing.watched_workspaces || [];
|
|
17238
|
+
const idx = watched.findIndex((w) => w.id === ws.id);
|
|
17239
|
+
if (idx >= 0) {
|
|
17240
|
+
watched[idx] = { id: ws.id, name: ws.name, token, agent_ids: agentIds };
|
|
17241
|
+
} else {
|
|
17242
|
+
watched.push({ id: ws.id, name: ws.name, token, agent_ids: agentIds });
|
|
17243
|
+
}
|
|
17244
|
+
saveCLIConfigForProfile(profile, {
|
|
17245
|
+
server_url: serverUrl,
|
|
17246
|
+
watched_workspaces: watched
|
|
17247
|
+
});
|
|
17248
|
+
console.log(`
|
|
17249
|
+
Registered as ${me.email}`);
|
|
17250
|
+
console.log(`Workspace: ${ws.name} (${ws.id})`);
|
|
17251
|
+
console.log(`Runtimes: ${activateResp.runtimes.map((r) => r.provider).join(", ")}`);
|
|
17252
|
+
const daemonPid = readDaemonPid(profile);
|
|
17253
|
+
if (daemonPid && isProcessAlive(daemonPid)) {
|
|
17254
|
+
try {
|
|
17255
|
+
process.kill(daemonPid, "SIGHUP");
|
|
17256
|
+
console.log(`
|
|
17257
|
+
Daemon (pid ${daemonPid}) notified — workspace will be active shortly.`);
|
|
17258
|
+
} catch {
|
|
17259
|
+
console.log(`
|
|
17260
|
+
Daemon is running but could not be notified. Restart it to pick up the new workspace.`);
|
|
17261
|
+
}
|
|
17262
|
+
} else {
|
|
17263
|
+
const startCmd = isDev() ? `${cmdPrefix()} daemon start --foreground` : `${cmdPrefix()} daemon start`;
|
|
17264
|
+
console.log();
|
|
17265
|
+
console.log(`Run '${startCmd}' to start the daemon.`);
|
|
17266
|
+
}
|
|
17267
|
+
});
|
|
17268
|
+
return cmd;
|
|
17269
|
+
}
|
|
17270
|
+
|
|
17271
|
+
// commands/status.ts
|
|
17272
|
+
import { Command as Command2 } from "commander";
|
|
17273
|
+
function statusCommand() {
|
|
17274
|
+
const cmd = new Command2("status").description("Show registration status").action((_opts, command) => {
|
|
17275
|
+
const profile = command.parent?.opts().profile;
|
|
17276
|
+
const cfg = loadCLIConfigForProfile(profile);
|
|
17277
|
+
const ws = cfg.watched_workspaces?.[0];
|
|
17278
|
+
if (!ws?.token) {
|
|
17279
|
+
console.log("Not registered");
|
|
17280
|
+
console.log(`Run '${cmdPrefix()} register --token <token>' to register.`);
|
|
17281
|
+
return;
|
|
17282
|
+
}
|
|
17283
|
+
console.log("Status: Registered");
|
|
17284
|
+
console.log(`Server: ${cfg.server_url}`);
|
|
17285
|
+
console.log(`Workspace: ${ws.name} (${ws.id})`);
|
|
17286
|
+
});
|
|
17287
|
+
return cmd;
|
|
17288
|
+
}
|
|
17289
|
+
|
|
17290
|
+
// commands/daemon.ts
|
|
17291
|
+
import { Command as Command3 } from "commander";
|
|
17292
|
+
import { spawn as spawn3 } from "child_process";
|
|
17293
|
+
import { openSync as openSync2, closeSync as closeSync2, mkdirSync as mkdirSync6 } from "fs";
|
|
17294
|
+
import { dirname as dirname4 } from "path";
|
|
17295
|
+
|
|
17258
17296
|
// daemon/client.ts
|
|
17259
17297
|
class DaemonClient {
|
|
17260
17298
|
baseURL;
|
|
@@ -17482,7 +17520,7 @@ function runNpmUpdate(targetVersion) {
|
|
|
17482
17520
|
}
|
|
17483
17521
|
|
|
17484
17522
|
// daemon/update-handler.ts
|
|
17485
|
-
var log3 =
|
|
17523
|
+
var log3 = createLogger2({ module: "updater" });
|
|
17486
17524
|
var updating = false;
|
|
17487
17525
|
var retryCount = 0;
|
|
17488
17526
|
var MAX_RETRIES = 3;
|
|
@@ -17511,6 +17549,10 @@ async function handleCliUpdate(version3, onSuccess, profile) {
|
|
|
17511
17549
|
return;
|
|
17512
17550
|
if (retryCount >= MAX_RETRIES)
|
|
17513
17551
|
return;
|
|
17552
|
+
if (process.env.ALOOK_CMD_PREFIX) {
|
|
17553
|
+
log3.info(`Skipping auto-update in app mode — user should run: npx @alook/app@latest update`);
|
|
17554
|
+
return;
|
|
17555
|
+
}
|
|
17514
17556
|
const marker = readUpdateMarker(profile);
|
|
17515
17557
|
if (marker === version3) {
|
|
17516
17558
|
log3.info(`Skipping update to v${version3} — already attempted (marker exists)`);
|
|
@@ -17577,7 +17619,7 @@ function releaseLock(lockPath) {
|
|
|
17577
17619
|
}
|
|
17578
17620
|
|
|
17579
17621
|
// daemon/execenv/timeline.ts
|
|
17580
|
-
var log4 =
|
|
17622
|
+
var log4 = createLogger2({ module: "timeline" });
|
|
17581
17623
|
function readJsonl(filePath) {
|
|
17582
17624
|
let content;
|
|
17583
17625
|
try {
|
|
@@ -17640,7 +17682,7 @@ function findRunningEntryByContextKey(timelineDir, contextKey, provider) {
|
|
|
17640
17682
|
// daemon/execenv/steering.ts
|
|
17641
17683
|
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, readFileSync as readFileSync6, unlinkSync as unlinkSync3, readdirSync, statSync as statSync2 } from "fs";
|
|
17642
17684
|
import { join as join5 } from "path";
|
|
17643
|
-
var log5 =
|
|
17685
|
+
var log5 = createLogger2({ module: "steering" });
|
|
17644
17686
|
var INTENT_DIR_NAME = ".kill_intents";
|
|
17645
17687
|
var STEERING_LOCK_DIR = ".steering_locks";
|
|
17646
17688
|
var INTENT_STALE_MS = 10 * 60 * 1000;
|
|
@@ -17806,6 +17848,7 @@ function tempDir(subdir) {
|
|
|
17806
17848
|
}
|
|
17807
17849
|
|
|
17808
17850
|
// lib/shell-env.ts
|
|
17851
|
+
var PASSTHROUGH_VARS = ["ALOOK_PROJECT_ROOT", "ALOOK_SERVER_URL", "ALOOK_CMD_PREFIX", "ALOOK_HEALTH_PORT"];
|
|
17809
17852
|
function resolveLoginShellEnv() {
|
|
17810
17853
|
if (isWindows) {
|
|
17811
17854
|
return { ...process.env };
|
|
@@ -17825,8 +17868,13 @@ function resolveLoginShellEnv() {
|
|
|
17825
17868
|
env[line.slice(0, idx)] = line.slice(idx + 1);
|
|
17826
17869
|
}
|
|
17827
17870
|
}
|
|
17828
|
-
if (env.PATH)
|
|
17871
|
+
if (env.PATH) {
|
|
17872
|
+
for (const key of PASSTHROUGH_VARS) {
|
|
17873
|
+
if (process.env[key])
|
|
17874
|
+
env[key] = process.env[key];
|
|
17875
|
+
}
|
|
17829
17876
|
return env;
|
|
17877
|
+
}
|
|
17830
17878
|
} catch {}
|
|
17831
17879
|
return { ...process.env };
|
|
17832
17880
|
}
|
|
@@ -17837,7 +17885,7 @@ import { readdir as readdir2, readFile as readFile2, unlink, stat as fsStat } fr
|
|
|
17837
17885
|
import { execSync as execSync4, spawn as spawn2 } from "child_process";
|
|
17838
17886
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
17839
17887
|
import { dirname as dirname3, join as join8 } from "path";
|
|
17840
|
-
var log6 =
|
|
17888
|
+
var log6 = createLogger2({ module: "daemon" });
|
|
17841
17889
|
var _dir = dirname3(fileURLToPath2(import.meta.url));
|
|
17842
17890
|
var sessionRunnerPath = existsSync(join8(_dir, "session-runner.js")) ? join8(_dir, "session-runner.js") : join8(_dir, "session-runner.ts");
|
|
17843
17891
|
var meetingRunnerPath = existsSync(join8(_dir, "meeting-runner.js")) ? join8(_dir, "meeting-runner.js") : join8(_dir, "meeting-runner.ts");
|
|
@@ -18066,6 +18114,7 @@ async function startDaemon(profile, serverUrl) {
|
|
|
18066
18114
|
daemon_id: config2.daemonId,
|
|
18067
18115
|
device_name: config2.deviceName,
|
|
18068
18116
|
cli_version: config2.cliVersion,
|
|
18117
|
+
workspaces_root: config2.workspacesRoot,
|
|
18069
18118
|
runtimes
|
|
18070
18119
|
});
|
|
18071
18120
|
} catch (e) {
|
|
@@ -18179,6 +18228,8 @@ async function startDaemon(profile, serverUrl) {
|
|
|
18179
18228
|
}
|
|
18180
18229
|
if (meetings) {
|
|
18181
18230
|
for (const m of meetings) {
|
|
18231
|
+
const agentBaseDir = join8(config2.workspacesRoot, m.workspace_id, m.agent_id, "workdir");
|
|
18232
|
+
const timelineDir = join8(agentBaseDir, ".context_timeline");
|
|
18182
18233
|
spawnMeetingRunner({
|
|
18183
18234
|
meetingId: m.id,
|
|
18184
18235
|
meetingUrl: m.meeting_url,
|
|
@@ -18186,7 +18237,10 @@ async function startDaemon(profile, serverUrl) {
|
|
|
18186
18237
|
workspaceId: m.workspace_id,
|
|
18187
18238
|
callbackUrl: config2.serverURL,
|
|
18188
18239
|
authToken: ws.token,
|
|
18189
|
-
agentName: m.agent_name
|
|
18240
|
+
agentName: m.agent_name,
|
|
18241
|
+
agentId: m.agent_id,
|
|
18242
|
+
timelineDir,
|
|
18243
|
+
title: m.title
|
|
18190
18244
|
});
|
|
18191
18245
|
}
|
|
18192
18246
|
}
|
|
@@ -18282,6 +18336,7 @@ async function startDaemon(profile, serverUrl) {
|
|
|
18282
18336
|
daemon_id: config2.daemonId,
|
|
18283
18337
|
device_name: config2.deviceName,
|
|
18284
18338
|
cli_version: config2.cliVersion,
|
|
18339
|
+
workspaces_root: config2.workspacesRoot,
|
|
18285
18340
|
runtimes
|
|
18286
18341
|
});
|
|
18287
18342
|
const runtimeIds = resp.runtimes.map((r) => r.id);
|
|
@@ -18611,7 +18666,7 @@ async function stopCommand(profile) {
|
|
|
18611
18666
|
removePidFileIfMatches(pid, profile);
|
|
18612
18667
|
console.log("Daemon stopped.");
|
|
18613
18668
|
}
|
|
18614
|
-
function
|
|
18669
|
+
function daemonCommand2() {
|
|
18615
18670
|
const cmd = new Command3("daemon").description("Manage the Alook daemon");
|
|
18616
18671
|
cmd.command("start").description("Start the daemon").option("--foreground", "Run in foreground").option("--server <url>", "Server URL override").action(async (opts, command) => {
|
|
18617
18672
|
const parentOpts = command.parent?.parent?.opts() || {};
|
|
@@ -18668,7 +18723,7 @@ import { Command as Command5 } from "commander";
|
|
|
18668
18723
|
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync7, readFileSync as readFileSync7, statSync as statSync4 } from "fs";
|
|
18669
18724
|
import { basename, join as join9 } from "path";
|
|
18670
18725
|
import PostalMime from "postal-mime";
|
|
18671
|
-
var log7 =
|
|
18726
|
+
var log7 = createLogger2({ module: "email" });
|
|
18672
18727
|
var VALID_STATUSES = ["unread", "read", "archived", "sent"];
|
|
18673
18728
|
var VALID_FOLDERS = ["inbox", "sent", "untrust"];
|
|
18674
18729
|
var EMAIL_BASE = tempDir("alook-emails");
|
|
@@ -19567,7 +19622,7 @@ ${result.output}`);
|
|
|
19567
19622
|
|
|
19568
19623
|
// commands/sync.ts
|
|
19569
19624
|
import { Command as Command10 } from "commander";
|
|
19570
|
-
import { readFileSync as readFileSync9
|
|
19625
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
19571
19626
|
import { basename as basename2 } from "path";
|
|
19572
19627
|
var MIME_BY_EXT2 = {
|
|
19573
19628
|
".pdf": "application/pdf",
|
|
@@ -19614,10 +19669,7 @@ function syncCommand() {
|
|
|
19614
19669
|
const { serverUrl, token, workspaceId } = resolveClientOpts4(command, opts.agent_id);
|
|
19615
19670
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
19616
19671
|
let bytes;
|
|
19617
|
-
let size;
|
|
19618
19672
|
try {
|
|
19619
|
-
const stat2 = statSync5(opts.file);
|
|
19620
|
-
size = stat2.size;
|
|
19621
19673
|
bytes = readFileSync9(opts.file);
|
|
19622
19674
|
} catch (err) {
|
|
19623
19675
|
console.error(`Error: cannot read file "${opts.file}": ${err.message}`);
|
|
@@ -19645,7 +19697,7 @@ var program = new Command11;
|
|
|
19645
19697
|
program.name("alook").description("Alook CLI").option("--server <url>", "Server URL").option("--profile <name>", "Profile name");
|
|
19646
19698
|
program.addCommand(registerCommand());
|
|
19647
19699
|
program.addCommand(statusCommand());
|
|
19648
|
-
program.addCommand(
|
|
19700
|
+
program.addCommand(daemonCommand2());
|
|
19649
19701
|
program.addCommand(emailCommand());
|
|
19650
19702
|
program.addCommand(calendarCommand());
|
|
19651
19703
|
program.addCommand(issueCommand());
|