@alook/cli 0.0.7 → 0.0.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/dist/index.js +212 -71
- package/dist/session-runner.js +15 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ var __export = (target, all) => {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
// src/index.ts
|
|
18
|
-
import { Command as
|
|
18
|
+
import { Command as Command9 } from "commander";
|
|
19
19
|
|
|
20
20
|
// commands/register.ts
|
|
21
21
|
import { Command } from "commander";
|
|
@@ -295,9 +295,9 @@ function statusCommand() {
|
|
|
295
295
|
|
|
296
296
|
// commands/daemon.ts
|
|
297
297
|
import { Command as Command3 } from "commander";
|
|
298
|
-
import { spawn as
|
|
298
|
+
import { spawn as spawn3 } from "child_process";
|
|
299
299
|
import { openSync as openSync2, closeSync as closeSync2, mkdirSync as mkdirSync4 } from "fs";
|
|
300
|
-
import { dirname as
|
|
300
|
+
import { dirname as dirname4 } from "path";
|
|
301
301
|
|
|
302
302
|
// ../shared/src/constants.ts
|
|
303
303
|
var TASK_TYPES = {
|
|
@@ -13900,11 +13900,13 @@ var TaskApiSchema = TaskApiBaseSchema.extend({
|
|
|
13900
13900
|
});
|
|
13901
13901
|
var PollRequestSchema = exports_external.object({
|
|
13902
13902
|
daemon_id: exports_external.string().min(1),
|
|
13903
|
-
max_tasks: exports_external.number().int().min(1).default(1)
|
|
13903
|
+
max_tasks: exports_external.number().int().min(1).default(1),
|
|
13904
|
+
cli_version: exports_external.string().optional()
|
|
13904
13905
|
});
|
|
13905
13906
|
var PollResponseSchema = exports_external.object({
|
|
13906
13907
|
tasks: exports_external.array(TaskApiSchema),
|
|
13907
|
-
evicted: exports_external.boolean().optional()
|
|
13908
|
+
evicted: exports_external.boolean().optional(),
|
|
13909
|
+
pending_update: exports_external.object({ version: exports_external.string() }).optional()
|
|
13908
13910
|
});
|
|
13909
13911
|
var RegisterResponseSchema = exports_external.object({
|
|
13910
13912
|
runtimes: exports_external.array(exports_external.object({ id: exports_external.string() }))
|
|
@@ -14007,6 +14009,9 @@ var CalendarEventApiSchema = exports_external.object({
|
|
|
14007
14009
|
created_at: exports_external.string(),
|
|
14008
14010
|
updated_at: exports_external.string()
|
|
14009
14011
|
});
|
|
14012
|
+
var AddWhitelistRequestSchema = exports_external.object({
|
|
14013
|
+
email: exports_external.string().email()
|
|
14014
|
+
});
|
|
14010
14015
|
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260418.1_@opentelemetry+api@1.9.1_bun-types@1.3.12_kysely@0.28.16/node_modules/drizzle-orm/entity.js
|
|
14011
14016
|
var entityKind = Symbol.for("drizzle:entityKind");
|
|
14012
14017
|
var hasOwnEntityKind = Symbol.for("drizzle:hasOwnEntityKind");
|
|
@@ -15443,6 +15448,7 @@ var machine = sqliteTable("machine", {
|
|
|
15443
15448
|
deviceInfo: text("device_info").notNull().default(""),
|
|
15444
15449
|
lastSeenAt: text("last_seen_at"),
|
|
15445
15450
|
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
|
|
15451
|
+
pendingUpdateVersion: text("pending_update_version"),
|
|
15446
15452
|
updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
15447
15453
|
}, (t) => [primaryKey({ columns: [t.workspaceId, t.daemonId] })]);
|
|
15448
15454
|
var agentRuntime = sqliteTable("agent_runtime", {
|
|
@@ -15626,6 +15632,20 @@ var RESERVED_HANDLES = new Set([
|
|
|
15626
15632
|
"system",
|
|
15627
15633
|
"alook"
|
|
15628
15634
|
]);
|
|
15635
|
+
// ../shared/src/semver.ts
|
|
15636
|
+
function semverGte(a, b) {
|
|
15637
|
+
const pa = a.split(".").map(Number);
|
|
15638
|
+
const pb = b.split(".").map(Number);
|
|
15639
|
+
for (let i = 0;i < Math.max(pa.length, pb.length); i++) {
|
|
15640
|
+
const sa = pa[i] ?? 0;
|
|
15641
|
+
const sb = pb[i] ?? 0;
|
|
15642
|
+
if (sa > sb)
|
|
15643
|
+
return true;
|
|
15644
|
+
if (sa < sb)
|
|
15645
|
+
return false;
|
|
15646
|
+
}
|
|
15647
|
+
return true;
|
|
15648
|
+
}
|
|
15629
15649
|
// daemon/client.ts
|
|
15630
15650
|
class DaemonClient {
|
|
15631
15651
|
baseURL;
|
|
@@ -15657,10 +15677,14 @@ class DaemonClient {
|
|
|
15657
15677
|
daemon_id: daemonId
|
|
15658
15678
|
});
|
|
15659
15679
|
}
|
|
15660
|
-
async poll(token, daemonId, maxTasks) {
|
|
15661
|
-
const raw = await this.request("POST", "/api/daemon/tasks/poll", token, { daemon_id: daemonId, max_tasks: maxTasks });
|
|
15680
|
+
async poll(token, daemonId, maxTasks, cliVersion) {
|
|
15681
|
+
const raw = await this.request("POST", "/api/daemon/tasks/poll", token, { daemon_id: daemonId, max_tasks: maxTasks, ...cliVersion && { cli_version: cliVersion } });
|
|
15662
15682
|
const resp = PollResponseSchema.parse(raw);
|
|
15663
|
-
return {
|
|
15683
|
+
return {
|
|
15684
|
+
tasks: resp.tasks,
|
|
15685
|
+
evicted: resp.evicted ?? false,
|
|
15686
|
+
pending_update: resp.pending_update
|
|
15687
|
+
};
|
|
15664
15688
|
}
|
|
15665
15689
|
startTask(token, taskId) {
|
|
15666
15690
|
return this.request("POST", `/api/daemon/tasks/${taskId}/start`, token);
|
|
@@ -15680,22 +15704,44 @@ class DaemonClient {
|
|
|
15680
15704
|
|
|
15681
15705
|
// daemon/config.ts
|
|
15682
15706
|
import { hostname as hostname4 } from "os";
|
|
15683
|
-
import { join as
|
|
15707
|
+
import { join as join3 } from "path";
|
|
15708
|
+
|
|
15709
|
+
// lib/version.ts
|
|
15710
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
15711
|
+
import { join as join2, dirname } from "path";
|
|
15712
|
+
import { fileURLToPath } from "url";
|
|
15713
|
+
function getCurrentVersion() {
|
|
15714
|
+
const __dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
15715
|
+
const candidates = [
|
|
15716
|
+
join2(__dirname2, "..", "package.json"),
|
|
15717
|
+
join2(__dirname2, "..", "..", "package.json")
|
|
15718
|
+
];
|
|
15719
|
+
for (const candidate of candidates) {
|
|
15720
|
+
try {
|
|
15721
|
+
const pkg = JSON.parse(readFileSync2(candidate, "utf-8"));
|
|
15722
|
+
if (typeof pkg.version === "string")
|
|
15723
|
+
return pkg.version;
|
|
15724
|
+
} catch {}
|
|
15725
|
+
}
|
|
15726
|
+
return "unknown";
|
|
15727
|
+
}
|
|
15728
|
+
|
|
15729
|
+
// daemon/config.ts
|
|
15684
15730
|
function pidFilePath(profile) {
|
|
15685
15731
|
const name = profile ? `daemon_${profile}.pid` : "daemon.pid";
|
|
15686
|
-
return
|
|
15732
|
+
return join3(configDir(), name);
|
|
15687
15733
|
}
|
|
15688
15734
|
function daemonLogDir() {
|
|
15689
|
-
return
|
|
15735
|
+
return join3(configDir(), "daemon", "logs");
|
|
15690
15736
|
}
|
|
15691
15737
|
function sessionRunnerLogDir() {
|
|
15692
|
-
return
|
|
15738
|
+
return join3(configDir(), "daemon", "session-runners");
|
|
15693
15739
|
}
|
|
15694
15740
|
function daemonLogFilePath(date5 = new Date) {
|
|
15695
15741
|
const y = date5.getFullYear();
|
|
15696
15742
|
const m = String(date5.getMonth() + 1).padStart(2, "0");
|
|
15697
15743
|
const d = String(date5.getDate()).padStart(2, "0");
|
|
15698
|
-
return
|
|
15744
|
+
return join3(daemonLogDir(), `${y}-${m}-${d}.log`);
|
|
15699
15745
|
}
|
|
15700
15746
|
function parseDuration(s) {
|
|
15701
15747
|
if (!s)
|
|
@@ -15735,7 +15781,7 @@ function loadDaemonConfig(profile) {
|
|
|
15735
15781
|
if (profile && !daemonId.endsWith(`-${profile}`)) {
|
|
15736
15782
|
daemonId = `${daemonId}-${profile}`;
|
|
15737
15783
|
}
|
|
15738
|
-
const defaultRoot =
|
|
15784
|
+
const defaultRoot = join3(configDir(), profile ? `workspaces_${profile}` : "workspaces");
|
|
15739
15785
|
const workspacesRoot = process.env.ALOOK_WORKSPACES_ROOT || defaultRoot;
|
|
15740
15786
|
return {
|
|
15741
15787
|
serverURL: normalizeServerBaseURL(process.env.ALOOK_SERVER_URL || "https://alook.ai"),
|
|
@@ -15752,7 +15798,7 @@ function loadDaemonConfig(profile) {
|
|
|
15752
15798
|
deviceName: process.env.ALOOK_DAEMON_DEVICE_NAME || h,
|
|
15753
15799
|
runtimeName: process.env.ALOOK_AGENT_RUNTIME_NAME || "Local Agent",
|
|
15754
15800
|
workspacesRoot,
|
|
15755
|
-
cliVersion:
|
|
15801
|
+
cliVersion: getCurrentVersion()
|
|
15756
15802
|
};
|
|
15757
15803
|
}
|
|
15758
15804
|
function normalizeServerBaseURL(url2) {
|
|
@@ -15918,8 +15964,8 @@ function createLogger2(level) {
|
|
|
15918
15964
|
var log = createLogger2();
|
|
15919
15965
|
|
|
15920
15966
|
// daemon/pidfile.ts
|
|
15921
|
-
import { readFileSync as
|
|
15922
|
-
import { dirname } from "path";
|
|
15967
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, unlinkSync, mkdirSync as mkdirSync2 } from "fs";
|
|
15968
|
+
import { dirname as dirname2 } from "path";
|
|
15923
15969
|
function isProcessAlive(pid) {
|
|
15924
15970
|
try {
|
|
15925
15971
|
process.kill(pid, 0);
|
|
@@ -15930,7 +15976,7 @@ function isProcessAlive(pid) {
|
|
|
15930
15976
|
}
|
|
15931
15977
|
function readDaemonPid(profile) {
|
|
15932
15978
|
try {
|
|
15933
|
-
const content =
|
|
15979
|
+
const content = readFileSync3(pidFilePath(profile), "utf-8").trim();
|
|
15934
15980
|
const pid = parseInt(content, 10);
|
|
15935
15981
|
return Number.isNaN(pid) ? null : pid;
|
|
15936
15982
|
} catch {
|
|
@@ -15940,14 +15986,14 @@ function readDaemonPid(profile) {
|
|
|
15940
15986
|
function acquireDaemonPid(profile) {
|
|
15941
15987
|
const pidPath = pidFilePath(profile);
|
|
15942
15988
|
try {
|
|
15943
|
-
const content =
|
|
15989
|
+
const content = readFileSync3(pidPath, "utf-8").trim();
|
|
15944
15990
|
const existingPid = parseInt(content, 10);
|
|
15945
15991
|
if (!isNaN(existingPid) && isProcessAlive(existingPid)) {
|
|
15946
15992
|
log.error(`Another daemon is already running (PID ${existingPid}). ` + `Remove ${pidPath} if this is stale.`);
|
|
15947
15993
|
return false;
|
|
15948
15994
|
}
|
|
15949
15995
|
} catch {}
|
|
15950
|
-
mkdirSync2(
|
|
15996
|
+
mkdirSync2(dirname2(pidPath), { recursive: true, mode: 448 });
|
|
15951
15997
|
writeFileSync2(pidPath, String(process.pid), { mode: 384 });
|
|
15952
15998
|
return true;
|
|
15953
15999
|
}
|
|
@@ -15964,13 +16010,71 @@ function releaseDaemonPid(profile) {
|
|
|
15964
16010
|
removePidFileIfMatches(process.pid, profile);
|
|
15965
16011
|
}
|
|
15966
16012
|
|
|
16013
|
+
// lib/update.ts
|
|
16014
|
+
import { spawn } from "child_process";
|
|
16015
|
+
function fetchLatestVersion() {
|
|
16016
|
+
return fetch("https://registry.npmjs.org/@alook/cli/latest").then((res) => {
|
|
16017
|
+
if (!res.ok)
|
|
16018
|
+
return null;
|
|
16019
|
+
return res.json();
|
|
16020
|
+
}).then((data) => data?.version ?? null).catch(() => null);
|
|
16021
|
+
}
|
|
16022
|
+
function runNpmUpdate(targetVersion) {
|
|
16023
|
+
return new Promise((resolve) => {
|
|
16024
|
+
const chunks = [];
|
|
16025
|
+
const child = spawn("npm", ["install", "-g", `@alook/cli@${targetVersion}`], {
|
|
16026
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
16027
|
+
});
|
|
16028
|
+
child.stdout?.on("data", (d) => chunks.push(d));
|
|
16029
|
+
child.stderr?.on("data", (d) => chunks.push(d));
|
|
16030
|
+
child.on("error", (err) => {
|
|
16031
|
+
resolve({ success: false, output: err.message });
|
|
16032
|
+
});
|
|
16033
|
+
child.on("close", (code) => {
|
|
16034
|
+
const output = Buffer.concat(chunks).toString();
|
|
16035
|
+
resolve({ success: code === 0, output });
|
|
16036
|
+
});
|
|
16037
|
+
});
|
|
16038
|
+
}
|
|
16039
|
+
|
|
16040
|
+
// daemon/update-handler.ts
|
|
16041
|
+
var updating = false;
|
|
16042
|
+
var retryCount = 0;
|
|
16043
|
+
var MAX_RETRIES = 3;
|
|
16044
|
+
function isUpdating() {
|
|
16045
|
+
return updating;
|
|
16046
|
+
}
|
|
16047
|
+
async function handleCliUpdate(version3, onSuccess) {
|
|
16048
|
+
if (updating)
|
|
16049
|
+
return;
|
|
16050
|
+
if (retryCount >= MAX_RETRIES)
|
|
16051
|
+
return;
|
|
16052
|
+
updating = true;
|
|
16053
|
+
try {
|
|
16054
|
+
log.info(`Updating CLI to v${version3}...`);
|
|
16055
|
+
const result = await runNpmUpdate(version3);
|
|
16056
|
+
if (result.success) {
|
|
16057
|
+
log.info(`CLI updated to v${version3} — restarting`);
|
|
16058
|
+
onSuccess();
|
|
16059
|
+
} else {
|
|
16060
|
+
retryCount++;
|
|
16061
|
+
log.error(`CLI update failed (attempt ${retryCount}/${MAX_RETRIES}): ${result.output}`);
|
|
16062
|
+
}
|
|
16063
|
+
} catch (e) {
|
|
16064
|
+
retryCount++;
|
|
16065
|
+
log.error(`CLI update error (attempt ${retryCount}/${MAX_RETRIES})`, e);
|
|
16066
|
+
} finally {
|
|
16067
|
+
updating = false;
|
|
16068
|
+
}
|
|
16069
|
+
}
|
|
16070
|
+
|
|
15967
16071
|
// daemon/daemon.ts
|
|
15968
16072
|
import { existsSync, mkdirSync as mkdirSync3, openSync, closeSync, renameSync, readdirSync, statSync, unlinkSync as unlinkSync2 } from "fs";
|
|
15969
|
-
import { execSync as execSync3, spawn } from "child_process";
|
|
15970
|
-
import { fileURLToPath } from "url";
|
|
15971
|
-
import { dirname as
|
|
15972
|
-
var _dir =
|
|
15973
|
-
var sessionRunnerPath = existsSync(
|
|
16073
|
+
import { execSync as execSync3, spawn as spawn2 } from "child_process";
|
|
16074
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
16075
|
+
import { dirname as dirname3, join as join4 } from "path";
|
|
16076
|
+
var _dir = dirname3(fileURLToPath2(import.meta.url));
|
|
16077
|
+
var sessionRunnerPath = existsSync(join4(_dir, "session-runner.js")) ? join4(_dir, "session-runner.js") : join4(_dir, "session-runner.ts");
|
|
15974
16078
|
function isCommandAvailable2(cmd) {
|
|
15975
16079
|
try {
|
|
15976
16080
|
execSync3(`which ${cmd}`, { stdio: "ignore" });
|
|
@@ -15991,7 +16095,7 @@ function pruneSessionRunnerLogs() {
|
|
|
15991
16095
|
if (entries.length <= MAX_SESSION_RUNNER_LOGS)
|
|
15992
16096
|
return;
|
|
15993
16097
|
const withMtime = entries.map((name) => {
|
|
15994
|
-
const full =
|
|
16098
|
+
const full = join4(logDir, name);
|
|
15995
16099
|
try {
|
|
15996
16100
|
return { name, mtime: statSync(full).mtimeMs };
|
|
15997
16101
|
} catch {
|
|
@@ -16001,7 +16105,7 @@ function pruneSessionRunnerLogs() {
|
|
|
16001
16105
|
withMtime.sort((a, b) => b.mtime - a.mtime);
|
|
16002
16106
|
for (const entry of withMtime.slice(MAX_SESSION_RUNNER_LOGS)) {
|
|
16003
16107
|
try {
|
|
16004
|
-
unlinkSync2(
|
|
16108
|
+
unlinkSync2(join4(logDir, entry.name));
|
|
16005
16109
|
} catch {}
|
|
16006
16110
|
}
|
|
16007
16111
|
}
|
|
@@ -16147,11 +16251,14 @@ async function startDaemon(profile, serverUrl) {
|
|
|
16147
16251
|
await new Promise((r) => setTimeout(r, staggerMs));
|
|
16148
16252
|
}
|
|
16149
16253
|
try {
|
|
16150
|
-
const { tasks: apiTasks, evicted } = await client.poll(ws.token, config2.daemonId, remaining);
|
|
16254
|
+
const { tasks: apiTasks, evicted, pending_update } = await client.poll(ws.token, config2.daemonId, remaining, config2.cliVersion);
|
|
16151
16255
|
if (evicted) {
|
|
16152
16256
|
evictedIds.push(ws.workspaceId);
|
|
16153
16257
|
continue;
|
|
16154
16258
|
}
|
|
16259
|
+
if (pending_update && !isUpdating()) {
|
|
16260
|
+
handleCliUpdate(pending_update.version, () => requestRestart());
|
|
16261
|
+
}
|
|
16155
16262
|
for (const apiTask of apiTasks) {
|
|
16156
16263
|
const task = fromApiTask(apiTask);
|
|
16157
16264
|
syncAgentId(task.agentId, ws.workspaceId);
|
|
@@ -16176,23 +16283,42 @@ async function startDaemon(profile, serverUrl) {
|
|
|
16176
16283
|
};
|
|
16177
16284
|
const pollTimer = setInterval(pollCycle, config2.pollInterval);
|
|
16178
16285
|
let shuttingDown = false;
|
|
16286
|
+
let restartRequested = false;
|
|
16287
|
+
const requestRestart = () => {
|
|
16288
|
+
restartRequested = true;
|
|
16289
|
+
shutdown();
|
|
16290
|
+
};
|
|
16179
16291
|
const shutdown = async () => {
|
|
16180
16292
|
if (shuttingDown)
|
|
16181
16293
|
return;
|
|
16182
16294
|
shuttingDown = true;
|
|
16183
|
-
log.info("Shutting down...");
|
|
16295
|
+
log.info(restartRequested ? "Restarting..." : "Shutting down...");
|
|
16184
16296
|
clearInterval(pollTimer);
|
|
16185
|
-
const shutdownMs = Number(process.env.ALOOK_SHUTDOWN_TIMEOUT_MS) || 5000;
|
|
16297
|
+
const shutdownMs = restartRequested ? 30000 : Number(process.env.ALOOK_SHUTDOWN_TIMEOUT_MS) || 5000;
|
|
16186
16298
|
const timeout = setTimeout(() => process.exit(1), shutdownMs);
|
|
16187
16299
|
try {
|
|
16188
16300
|
for (const ws of workspaceStates) {
|
|
16189
16301
|
await client.deregister(ws.token, config2.daemonId);
|
|
16190
16302
|
}
|
|
16191
16303
|
} catch {}
|
|
16192
|
-
clearTimeout(timeout);
|
|
16193
16304
|
releaseDaemonPid(profile);
|
|
16194
|
-
health.server.close()
|
|
16195
|
-
|
|
16305
|
+
health.server.close(() => {
|
|
16306
|
+
if (restartRequested) {
|
|
16307
|
+
const args = ["daemon", "start", "--foreground"];
|
|
16308
|
+
if (profile)
|
|
16309
|
+
args.push("--profile", profile);
|
|
16310
|
+
if (serverUrl)
|
|
16311
|
+
args.push("--server", serverUrl);
|
|
16312
|
+
const child = spawn2("alook", args, {
|
|
16313
|
+
detached: true,
|
|
16314
|
+
stdio: ["ignore", "ignore", "ignore"]
|
|
16315
|
+
});
|
|
16316
|
+
child.unref();
|
|
16317
|
+
log.info(`Spawned new daemon (pid=${child.pid})`);
|
|
16318
|
+
}
|
|
16319
|
+
clearTimeout(timeout);
|
|
16320
|
+
process.exit(0);
|
|
16321
|
+
});
|
|
16196
16322
|
};
|
|
16197
16323
|
process.on("SIGTERM", shutdown);
|
|
16198
16324
|
process.on("SIGINT", shutdown);
|
|
@@ -16202,16 +16328,16 @@ function spawnSessionRunner(input) {
|
|
|
16202
16328
|
const encoded = Buffer.from(JSON.stringify(input)).toString("base64");
|
|
16203
16329
|
const logDir = sessionRunnerLogDir();
|
|
16204
16330
|
mkdirSync3(logDir, { recursive: true });
|
|
16205
|
-
const tmpLogPath =
|
|
16331
|
+
const tmpLogPath = join4(logDir, `${input.task.id}.log`);
|
|
16206
16332
|
const fd = openSync(tmpLogPath, "a");
|
|
16207
|
-
const child =
|
|
16333
|
+
const child = spawn2(process.execPath, [sessionRunnerPath, encoded], {
|
|
16208
16334
|
detached: true,
|
|
16209
16335
|
stdio: ["ignore", fd, fd]
|
|
16210
16336
|
});
|
|
16211
16337
|
child.unref();
|
|
16212
16338
|
closeSync(fd);
|
|
16213
16339
|
if (child.pid) {
|
|
16214
|
-
const pidLogPath =
|
|
16340
|
+
const pidLogPath = join4(logDir, `${child.pid}.log`);
|
|
16215
16341
|
renameSync(tmpLogPath, pidLogPath);
|
|
16216
16342
|
}
|
|
16217
16343
|
return child;
|
|
@@ -16286,9 +16412,9 @@ async function startInBackground(profile, serverUrl) {
|
|
|
16286
16412
|
return;
|
|
16287
16413
|
}
|
|
16288
16414
|
const logPath = daemonLogFilePath();
|
|
16289
|
-
mkdirSync4(
|
|
16415
|
+
mkdirSync4(dirname4(logPath), { recursive: true, mode: 448 });
|
|
16290
16416
|
const logFd = openSync2(logPath, "a", 384);
|
|
16291
|
-
const child =
|
|
16417
|
+
const child = spawn3(process.execPath, buildChildArgs(profile, serverUrl), {
|
|
16292
16418
|
detached: true,
|
|
16293
16419
|
stdio: ["ignore", logFd, logFd]
|
|
16294
16420
|
});
|
|
@@ -16396,8 +16522,8 @@ function configCommand() {
|
|
|
16396
16522
|
|
|
16397
16523
|
// commands/email.ts
|
|
16398
16524
|
import { Command as Command5 } from "commander";
|
|
16399
|
-
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync5, readFileSync as
|
|
16400
|
-
import { basename, join as
|
|
16525
|
+
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync5, readFileSync as readFileSync4, statSync as statSync2 } from "fs";
|
|
16526
|
+
import { basename, join as join5 } from "path";
|
|
16401
16527
|
import PostalMime from "postal-mime";
|
|
16402
16528
|
var VALID_STATUSES = ["unread", "read", "archived"];
|
|
16403
16529
|
var EMAIL_DIR = "/tmp/alook-emails";
|
|
@@ -16473,7 +16599,7 @@ function emailCommand() {
|
|
|
16473
16599
|
mkdirSync5(EMAIL_DIR, { recursive: true });
|
|
16474
16600
|
const downloadedPaths = [];
|
|
16475
16601
|
for (const email3 of emails2) {
|
|
16476
|
-
const emailDir =
|
|
16602
|
+
const emailDir = join5(EMAIL_DIR, email3.id);
|
|
16477
16603
|
mkdirSync5(emailDir, { recursive: true });
|
|
16478
16604
|
const metadata = {
|
|
16479
16605
|
id: email3.id,
|
|
@@ -16486,7 +16612,7 @@ function emailCommand() {
|
|
|
16486
16612
|
in_reply_to: email3.in_reply_to || "",
|
|
16487
16613
|
references: email3.references || ""
|
|
16488
16614
|
};
|
|
16489
|
-
const metadataPath =
|
|
16615
|
+
const metadataPath = join5(emailDir, "metadata.json");
|
|
16490
16616
|
writeFileSync3(metadataPath, JSON.stringify(metadata, null, 2));
|
|
16491
16617
|
downloadedPaths.push(metadataPath);
|
|
16492
16618
|
let rawMime;
|
|
@@ -16502,17 +16628,17 @@ function emailCommand() {
|
|
|
16502
16628
|
}
|
|
16503
16629
|
const parsed = await new PostalMime().parse(rawMime);
|
|
16504
16630
|
if (parsed.text) {
|
|
16505
|
-
const bodyPath =
|
|
16631
|
+
const bodyPath = join5(emailDir, "body.txt");
|
|
16506
16632
|
writeFileSync3(bodyPath, parsed.text);
|
|
16507
16633
|
downloadedPaths.push(bodyPath);
|
|
16508
16634
|
}
|
|
16509
16635
|
if (parsed.html) {
|
|
16510
|
-
const htmlPath =
|
|
16636
|
+
const htmlPath = join5(emailDir, "body.html");
|
|
16511
16637
|
writeFileSync3(htmlPath, parsed.html);
|
|
16512
16638
|
downloadedPaths.push(htmlPath);
|
|
16513
16639
|
}
|
|
16514
16640
|
if (parsed.attachments && parsed.attachments.length > 0) {
|
|
16515
|
-
const attDir =
|
|
16641
|
+
const attDir = join5(emailDir, "attachments");
|
|
16516
16642
|
mkdirSync5(attDir, { recursive: true });
|
|
16517
16643
|
const usedFilenames = new Set;
|
|
16518
16644
|
for (let i = 0;i < parsed.attachments.length; i++) {
|
|
@@ -16522,7 +16648,7 @@ function emailCommand() {
|
|
|
16522
16648
|
filename = `${i}-${filename}`;
|
|
16523
16649
|
}
|
|
16524
16650
|
usedFilenames.add(filename);
|
|
16525
|
-
const attPath =
|
|
16651
|
+
const attPath = join5(attDir, filename);
|
|
16526
16652
|
const content = att.content;
|
|
16527
16653
|
let buf;
|
|
16528
16654
|
if (typeof content === "string") {
|
|
@@ -16571,7 +16697,7 @@ function emailCommand() {
|
|
|
16571
16697
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
16572
16698
|
let htmlBody;
|
|
16573
16699
|
try {
|
|
16574
|
-
htmlBody =
|
|
16700
|
+
htmlBody = readFileSync4(opts.bodyFile, "utf-8");
|
|
16575
16701
|
} catch (err) {
|
|
16576
16702
|
console.error(`Error: cannot read body file "${opts.bodyFile}": ${err instanceof Error ? err.message : err}`);
|
|
16577
16703
|
process.exit(1);
|
|
@@ -16587,7 +16713,7 @@ function emailCommand() {
|
|
|
16587
16713
|
let bytes;
|
|
16588
16714
|
let size;
|
|
16589
16715
|
try {
|
|
16590
|
-
bytes =
|
|
16716
|
+
bytes = readFileSync4(path);
|
|
16591
16717
|
size = statSync2(path).size;
|
|
16592
16718
|
} catch (err) {
|
|
16593
16719
|
console.error(`Error: cannot read attachment "${path}": ${err instanceof Error ? err.message : err}`);
|
|
@@ -16846,28 +16972,6 @@ function calendarCommand() {
|
|
|
16846
16972
|
|
|
16847
16973
|
// commands/version.ts
|
|
16848
16974
|
import { Command as Command7 } from "commander";
|
|
16849
|
-
|
|
16850
|
-
// lib/version.ts
|
|
16851
|
-
import { readFileSync as readFileSync4 } from "fs";
|
|
16852
|
-
import { join as join5, dirname as dirname4 } from "path";
|
|
16853
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
16854
|
-
function getCurrentVersion() {
|
|
16855
|
-
const __dirname2 = dirname4(fileURLToPath2(import.meta.url));
|
|
16856
|
-
const candidates = [
|
|
16857
|
-
join5(__dirname2, "..", "package.json"),
|
|
16858
|
-
join5(__dirname2, "..", "..", "package.json")
|
|
16859
|
-
];
|
|
16860
|
-
for (const candidate of candidates) {
|
|
16861
|
-
try {
|
|
16862
|
-
const pkg = JSON.parse(readFileSync4(candidate, "utf-8"));
|
|
16863
|
-
if (typeof pkg.version === "string")
|
|
16864
|
-
return pkg.version;
|
|
16865
|
-
} catch {}
|
|
16866
|
-
}
|
|
16867
|
-
return "unknown";
|
|
16868
|
-
}
|
|
16869
|
-
|
|
16870
|
-
// commands/version.ts
|
|
16871
16975
|
function versionCommand() {
|
|
16872
16976
|
const cmd = new Command7("version").description("Show CLI version").action(() => {
|
|
16873
16977
|
console.log(`alook version ${getCurrentVersion()}`);
|
|
@@ -16875,8 +16979,44 @@ function versionCommand() {
|
|
|
16875
16979
|
return cmd;
|
|
16876
16980
|
}
|
|
16877
16981
|
|
|
16982
|
+
// commands/update.ts
|
|
16983
|
+
import { Command as Command8 } from "commander";
|
|
16984
|
+
function updateCommand() {
|
|
16985
|
+
const cmd = new Command8("update").description("Update CLI to the latest version").action(async () => {
|
|
16986
|
+
const current = getCurrentVersion();
|
|
16987
|
+
console.log(`Current version: ${current}`);
|
|
16988
|
+
const latest = await fetchLatestVersion();
|
|
16989
|
+
if (!latest) {
|
|
16990
|
+
console.error("Failed to fetch latest version from npm registry.");
|
|
16991
|
+
process.exit(1);
|
|
16992
|
+
return;
|
|
16993
|
+
}
|
|
16994
|
+
if (semverGte(current, latest)) {
|
|
16995
|
+
console.log(`Already up to date (v${current}).`);
|
|
16996
|
+
return;
|
|
16997
|
+
}
|
|
16998
|
+
const healthPort = Number(process.env.ALOOK_HEALTH_PORT) || 19514;
|
|
16999
|
+
try {
|
|
17000
|
+
const res = await fetch(`http://127.0.0.1:${healthPort}/health`);
|
|
17001
|
+
if (res.ok) {
|
|
17002
|
+
console.warn("Warning: daemon is running on the old version. After update, restart with: alook daemon restart");
|
|
17003
|
+
}
|
|
17004
|
+
} catch {}
|
|
17005
|
+
console.log(`Updating to v${latest}...`);
|
|
17006
|
+
const result = await runNpmUpdate(latest);
|
|
17007
|
+
if (result.success) {
|
|
17008
|
+
console.log(`Updated successfully: v${current} → v${latest}`);
|
|
17009
|
+
} else {
|
|
17010
|
+
console.error(`Update failed:
|
|
17011
|
+
${result.output}`);
|
|
17012
|
+
process.exit(1);
|
|
17013
|
+
}
|
|
17014
|
+
});
|
|
17015
|
+
return cmd;
|
|
17016
|
+
}
|
|
17017
|
+
|
|
16878
17018
|
// src/index.ts
|
|
16879
|
-
var program = new
|
|
17019
|
+
var program = new Command9;
|
|
16880
17020
|
program.name("alook").description("Alook CLI").option("--server <url>", "Server URL").option("--profile <name>", "Profile name");
|
|
16881
17021
|
program.addCommand(registerCommand());
|
|
16882
17022
|
program.addCommand(statusCommand());
|
|
@@ -16885,4 +17025,5 @@ program.addCommand(emailCommand());
|
|
|
16885
17025
|
program.addCommand(calendarCommand());
|
|
16886
17026
|
program.addCommand(configCommand());
|
|
16887
17027
|
program.addCommand(versionCommand());
|
|
17028
|
+
program.addCommand(updateCommand());
|
|
16888
17029
|
program.parse();
|
package/dist/session-runner.js
CHANGED
|
@@ -13617,11 +13617,13 @@ var TaskApiSchema = TaskApiBaseSchema.extend({
|
|
|
13617
13617
|
});
|
|
13618
13618
|
var PollRequestSchema = exports_external.object({
|
|
13619
13619
|
daemon_id: exports_external.string().min(1),
|
|
13620
|
-
max_tasks: exports_external.number().int().min(1).default(1)
|
|
13620
|
+
max_tasks: exports_external.number().int().min(1).default(1),
|
|
13621
|
+
cli_version: exports_external.string().optional()
|
|
13621
13622
|
});
|
|
13622
13623
|
var PollResponseSchema = exports_external.object({
|
|
13623
13624
|
tasks: exports_external.array(TaskApiSchema),
|
|
13624
|
-
evicted: exports_external.boolean().optional()
|
|
13625
|
+
evicted: exports_external.boolean().optional(),
|
|
13626
|
+
pending_update: exports_external.object({ version: exports_external.string() }).optional()
|
|
13625
13627
|
});
|
|
13626
13628
|
var RegisterResponseSchema = exports_external.object({
|
|
13627
13629
|
runtimes: exports_external.array(exports_external.object({ id: exports_external.string() }))
|
|
@@ -13724,6 +13726,9 @@ var CalendarEventApiSchema = exports_external.object({
|
|
|
13724
13726
|
created_at: exports_external.string(),
|
|
13725
13727
|
updated_at: exports_external.string()
|
|
13726
13728
|
});
|
|
13729
|
+
var AddWhitelistRequestSchema = exports_external.object({
|
|
13730
|
+
email: exports_external.string().email()
|
|
13731
|
+
});
|
|
13727
13732
|
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260418.1_@opentelemetry+api@1.9.1_bun-types@1.3.12_kysely@0.28.16/node_modules/drizzle-orm/entity.js
|
|
13728
13733
|
var entityKind = Symbol.for("drizzle:entityKind");
|
|
13729
13734
|
var hasOwnEntityKind = Symbol.for("drizzle:hasOwnEntityKind");
|
|
@@ -15160,6 +15165,7 @@ var machine = sqliteTable("machine", {
|
|
|
15160
15165
|
deviceInfo: text("device_info").notNull().default(""),
|
|
15161
15166
|
lastSeenAt: text("last_seen_at"),
|
|
15162
15167
|
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
|
|
15168
|
+
pendingUpdateVersion: text("pending_update_version"),
|
|
15163
15169
|
updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
15164
15170
|
}, (t) => [primaryKey({ columns: [t.workspaceId, t.daemonId] })]);
|
|
15165
15171
|
var agentRuntime = sqliteTable("agent_runtime", {
|
|
@@ -15377,10 +15383,14 @@ class DaemonClient {
|
|
|
15377
15383
|
daemon_id: daemonId
|
|
15378
15384
|
});
|
|
15379
15385
|
}
|
|
15380
|
-
async poll(token, daemonId, maxTasks) {
|
|
15381
|
-
const raw = await this.request("POST", "/api/daemon/tasks/poll", token, { daemon_id: daemonId, max_tasks: maxTasks });
|
|
15386
|
+
async poll(token, daemonId, maxTasks, cliVersion) {
|
|
15387
|
+
const raw = await this.request("POST", "/api/daemon/tasks/poll", token, { daemon_id: daemonId, max_tasks: maxTasks, ...cliVersion && { cli_version: cliVersion } });
|
|
15382
15388
|
const resp = PollResponseSchema.parse(raw);
|
|
15383
|
-
return {
|
|
15389
|
+
return {
|
|
15390
|
+
tasks: resp.tasks,
|
|
15391
|
+
evicted: resp.evicted ?? false,
|
|
15392
|
+
pending_update: resp.pending_update
|
|
15393
|
+
};
|
|
15384
15394
|
}
|
|
15385
15395
|
startTask(token, taskId) {
|
|
15386
15396
|
return this.request("POST", `/api/daemon/tasks/${taskId}/start`, token);
|