@alook/cli 0.0.2 → 0.0.3
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 +48 -158
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -97,7 +97,7 @@ function isDev() {
|
|
|
97
97
|
return !!process.env.ALOOK_SERVER_URL;
|
|
98
98
|
}
|
|
99
99
|
function cmdPrefix() {
|
|
100
|
-
return isDev() ? "pnpm dev:cli" : "alook";
|
|
100
|
+
return isDev() ? "pnpm dev:cli" : "npx @alook/cli";
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
// lib/config.ts
|
|
@@ -145,137 +145,6 @@ function saveCLIConfigForProfile(profile, profileConfig) {
|
|
|
145
145
|
saveCLIConfig(cfg);
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
// lib/installer.ts
|
|
149
|
-
import { spawnSync } from "child_process";
|
|
150
|
-
|
|
151
|
-
// lib/version.ts
|
|
152
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
153
|
-
import { join as join2, dirname } from "path";
|
|
154
|
-
import { fileURLToPath } from "url";
|
|
155
|
-
function getCurrentVersion() {
|
|
156
|
-
const __dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
157
|
-
const candidates = [
|
|
158
|
-
join2(__dirname2, "..", "package.json"),
|
|
159
|
-
join2(__dirname2, "..", "..", "package.json")
|
|
160
|
-
];
|
|
161
|
-
for (const candidate of candidates) {
|
|
162
|
-
try {
|
|
163
|
-
const pkg = JSON.parse(readFileSync2(candidate, "utf-8"));
|
|
164
|
-
if (typeof pkg.version === "string")
|
|
165
|
-
return pkg.version;
|
|
166
|
-
} catch {}
|
|
167
|
-
}
|
|
168
|
-
return "unknown";
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// lib/installer.ts
|
|
172
|
-
var PACKAGE = "@alook/cli";
|
|
173
|
-
var REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE}/latest`;
|
|
174
|
-
var FETCH_TIMEOUT_MS = 3000;
|
|
175
|
-
async function fetchLatestVersion() {
|
|
176
|
-
const ctrl = new AbortController;
|
|
177
|
-
const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
|
|
178
|
-
try {
|
|
179
|
-
const res = await fetch(REGISTRY_URL, { signal: ctrl.signal });
|
|
180
|
-
if (!res.ok)
|
|
181
|
-
return null;
|
|
182
|
-
const data = await res.json();
|
|
183
|
-
return typeof data.version === "string" ? data.version : null;
|
|
184
|
-
} catch {
|
|
185
|
-
return null;
|
|
186
|
-
} finally {
|
|
187
|
-
clearTimeout(timer);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
function isNewer(current, latest) {
|
|
191
|
-
const parse = (v) => v.split("-")[0].split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
192
|
-
const [cMaj = 0, cMin = 0, cPatch = 0] = parse(current);
|
|
193
|
-
const [lMaj = 0, lMin = 0, lPatch = 0] = parse(latest);
|
|
194
|
-
if (lMaj !== cMaj)
|
|
195
|
-
return lMaj > cMaj;
|
|
196
|
-
if (lMin !== cMin)
|
|
197
|
-
return lMin > cMin;
|
|
198
|
-
return lPatch > cPatch;
|
|
199
|
-
}
|
|
200
|
-
function isNpx() {
|
|
201
|
-
return process.env.npm_command === "exec" || !!process.env.npm_execpath?.includes("npx-cli");
|
|
202
|
-
}
|
|
203
|
-
function detectPackageManager() {
|
|
204
|
-
const ua = process.env.npm_config_user_agent || "";
|
|
205
|
-
if (ua.startsWith("pnpm/"))
|
|
206
|
-
return "pnpm";
|
|
207
|
-
if (ua.startsWith("yarn/"))
|
|
208
|
-
return "yarn";
|
|
209
|
-
return "npm";
|
|
210
|
-
}
|
|
211
|
-
function installArgs(pm) {
|
|
212
|
-
switch (pm) {
|
|
213
|
-
case "pnpm":
|
|
214
|
-
return ["pnpm", ["add", "-g", PACKAGE]];
|
|
215
|
-
case "yarn":
|
|
216
|
-
return ["yarn", ["global", "add", PACKAGE]];
|
|
217
|
-
case "npm":
|
|
218
|
-
return ["npm", ["install", "-g", `${PACKAGE}@latest`]];
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
function installCmdString(pm) {
|
|
222
|
-
const [bin, args] = installArgs(pm);
|
|
223
|
-
return `${bin} ${args.join(" ")}`;
|
|
224
|
-
}
|
|
225
|
-
function runInstall(pm) {
|
|
226
|
-
const [bin, args] = installArgs(pm);
|
|
227
|
-
const result = spawnSync(bin, args, { stdio: "inherit" });
|
|
228
|
-
return result.status === 0;
|
|
229
|
-
}
|
|
230
|
-
async function ensureInstalled(opts = {}, deps = {}) {
|
|
231
|
-
const fetchLatest = deps.fetchLatest ?? fetchLatestVersion;
|
|
232
|
-
const runInst = deps.runInstall ?? runInstall;
|
|
233
|
-
const getCurrent = deps.getCurrent ?? getCurrentVersion;
|
|
234
|
-
const isNpxFn = deps.isNpxFn ?? isNpx;
|
|
235
|
-
const isDevFn = deps.isDevFn ?? isDev;
|
|
236
|
-
const log = deps.log ?? ((m) => console.log(m));
|
|
237
|
-
const current = getCurrent();
|
|
238
|
-
const pm = detectPackageManager();
|
|
239
|
-
if (isDevFn() || opts.skip) {
|
|
240
|
-
return { skipped: true, action: "none", current, latest: null, pm };
|
|
241
|
-
}
|
|
242
|
-
const latest = await fetchLatest();
|
|
243
|
-
if (!latest) {
|
|
244
|
-
return { skipped: false, action: "none", current, latest: null, pm };
|
|
245
|
-
}
|
|
246
|
-
const runningViaNpx = isNpxFn();
|
|
247
|
-
const needsInstall = runningViaNpx;
|
|
248
|
-
const needsUpdate = !runningViaNpx && isNewer(current, latest);
|
|
249
|
-
if (!needsInstall && !needsUpdate) {
|
|
250
|
-
log(`
|
|
251
|
-
✓ ${PACKAGE} is up to date (${current})`);
|
|
252
|
-
return { skipped: false, action: "none", current, latest, pm };
|
|
253
|
-
}
|
|
254
|
-
const cmdStr = installCmdString(pm);
|
|
255
|
-
if (needsInstall) {
|
|
256
|
-
log(`
|
|
257
|
-
Installing ${PACKAGE} globally (${cmdStr})...`);
|
|
258
|
-
} else {
|
|
259
|
-
log(`
|
|
260
|
-
Updating ${PACKAGE} ${current} → ${latest} (${cmdStr})...`);
|
|
261
|
-
}
|
|
262
|
-
const ok = runInst(pm);
|
|
263
|
-
if (!ok) {
|
|
264
|
-
log(`
|
|
265
|
-
Could not ${needsInstall ? "install" : "update"} ${PACKAGE} automatically.`);
|
|
266
|
-
log(`Install it manually: ${cmdStr}`);
|
|
267
|
-
return { skipped: false, action: "failed", current, latest, pm };
|
|
268
|
-
}
|
|
269
|
-
log(`✓ ${needsInstall ? "Installed" : "Updated"} ${PACKAGE} ${latest}`);
|
|
270
|
-
return {
|
|
271
|
-
skipped: false,
|
|
272
|
-
action: needsInstall ? "installed" : "updated",
|
|
273
|
-
current,
|
|
274
|
-
latest,
|
|
275
|
-
pm
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
|
|
279
148
|
// commands/register.ts
|
|
280
149
|
function isCommandAvailable(cmd) {
|
|
281
150
|
try {
|
|
@@ -299,7 +168,7 @@ function detectRuntimes() {
|
|
|
299
168
|
return found;
|
|
300
169
|
}
|
|
301
170
|
function registerCommand() {
|
|
302
|
-
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").
|
|
171
|
+
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) => {
|
|
303
172
|
const token = opts.token;
|
|
304
173
|
const profile = opts.profile || command.parent?.opts().profile;
|
|
305
174
|
const serverUrl = opts.server || command.parent?.opts().server || process.env.ALOOK_SERVER_URL || "https://alook.ai";
|
|
@@ -380,7 +249,6 @@ Usage: ${cmdPrefix()} register --token <token>`);
|
|
|
380
249
|
Registered as ${me.email}`);
|
|
381
250
|
console.log(`Workspace: ${ws.name} (${ws.id})`);
|
|
382
251
|
console.log(`Runtimes: ${activateResp.runtimes.map((r) => r.provider).join(", ")}`);
|
|
383
|
-
await ensureInstalled({ skip: opts.install === false });
|
|
384
252
|
console.log();
|
|
385
253
|
console.log(`Run '${cmdPrefix()} daemon start --foreground' to start the daemon.`);
|
|
386
254
|
});
|
|
@@ -410,7 +278,7 @@ function statusCommand() {
|
|
|
410
278
|
import { Command as Command3 } from "commander";
|
|
411
279
|
import { spawn as spawn2 } from "child_process";
|
|
412
280
|
import { openSync, closeSync, mkdirSync as mkdirSync3 } from "fs";
|
|
413
|
-
import { dirname as
|
|
281
|
+
import { dirname as dirname3 } from "path";
|
|
414
282
|
|
|
415
283
|
// ../shared/src/constants.ts
|
|
416
284
|
var POLL_INTERVAL_MS = Number(process.env.POLL_INTERVAL_MS) || 3000;
|
|
@@ -14650,7 +14518,7 @@ function sql(strings, ...params) {
|
|
|
14650
14518
|
return new SQL([new StringChunk(str)]);
|
|
14651
14519
|
}
|
|
14652
14520
|
sql2.raw = raw;
|
|
14653
|
-
function
|
|
14521
|
+
function join2(chunks, separator) {
|
|
14654
14522
|
const result = [];
|
|
14655
14523
|
for (const [i, chunk] of chunks.entries()) {
|
|
14656
14524
|
if (i > 0 && separator !== undefined) {
|
|
@@ -14660,7 +14528,7 @@ function sql(strings, ...params) {
|
|
|
14660
14528
|
}
|
|
14661
14529
|
return new SQL(result);
|
|
14662
14530
|
}
|
|
14663
|
-
sql2.join =
|
|
14531
|
+
sql2.join = join2;
|
|
14664
14532
|
function identifier(value) {
|
|
14665
14533
|
return new Name(value);
|
|
14666
14534
|
}
|
|
@@ -15713,19 +15581,19 @@ class DaemonClient {
|
|
|
15713
15581
|
|
|
15714
15582
|
// daemon/config.ts
|
|
15715
15583
|
import { hostname as hostname4 } from "os";
|
|
15716
|
-
import { join as
|
|
15584
|
+
import { join as join2 } from "path";
|
|
15717
15585
|
function pidFilePath(profile) {
|
|
15718
15586
|
const name = profile ? `daemon_${profile}.pid` : "daemon.pid";
|
|
15719
|
-
return
|
|
15587
|
+
return join2(configDir(), name);
|
|
15720
15588
|
}
|
|
15721
15589
|
function daemonLogDir() {
|
|
15722
|
-
return
|
|
15590
|
+
return join2(configDir(), "daemon", "logs");
|
|
15723
15591
|
}
|
|
15724
15592
|
function daemonLogFilePath(date5 = new Date) {
|
|
15725
15593
|
const y = date5.getFullYear();
|
|
15726
15594
|
const m = String(date5.getMonth() + 1).padStart(2, "0");
|
|
15727
15595
|
const d = String(date5.getDate()).padStart(2, "0");
|
|
15728
|
-
return
|
|
15596
|
+
return join2(daemonLogDir(), `${y}-${m}-${d}.log`);
|
|
15729
15597
|
}
|
|
15730
15598
|
function parseDuration(s) {
|
|
15731
15599
|
if (!s)
|
|
@@ -15765,7 +15633,7 @@ function loadDaemonConfig(profile) {
|
|
|
15765
15633
|
if (profile && !daemonId.endsWith(`-${profile}`)) {
|
|
15766
15634
|
daemonId = `${daemonId}-${profile}`;
|
|
15767
15635
|
}
|
|
15768
|
-
const defaultRoot =
|
|
15636
|
+
const defaultRoot = join2(configDir(), profile ? `workspaces_${profile}` : "workspaces");
|
|
15769
15637
|
const workspacesRoot = process.env.ALOOK_WORKSPACES_ROOT || defaultRoot;
|
|
15770
15638
|
return {
|
|
15771
15639
|
serverURL: normalizeServerBaseURL(process.env.ALOOK_SERVER_URL || "https://alook.ai"),
|
|
@@ -15947,8 +15815,8 @@ function createLogger2(level) {
|
|
|
15947
15815
|
var log = createLogger2();
|
|
15948
15816
|
|
|
15949
15817
|
// daemon/pidfile.ts
|
|
15950
|
-
import { readFileSync as
|
|
15951
|
-
import { dirname
|
|
15818
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, unlinkSync, mkdirSync as mkdirSync2 } from "fs";
|
|
15819
|
+
import { dirname } from "path";
|
|
15952
15820
|
function isProcessAlive(pid) {
|
|
15953
15821
|
try {
|
|
15954
15822
|
process.kill(pid, 0);
|
|
@@ -15959,7 +15827,7 @@ function isProcessAlive(pid) {
|
|
|
15959
15827
|
}
|
|
15960
15828
|
function readDaemonPid(profile) {
|
|
15961
15829
|
try {
|
|
15962
|
-
const content =
|
|
15830
|
+
const content = readFileSync2(pidFilePath(profile), "utf-8").trim();
|
|
15963
15831
|
const pid = parseInt(content, 10);
|
|
15964
15832
|
return Number.isNaN(pid) ? null : pid;
|
|
15965
15833
|
} catch {
|
|
@@ -15969,14 +15837,14 @@ function readDaemonPid(profile) {
|
|
|
15969
15837
|
function acquireDaemonPid(profile) {
|
|
15970
15838
|
const pidPath = pidFilePath(profile);
|
|
15971
15839
|
try {
|
|
15972
|
-
const content =
|
|
15840
|
+
const content = readFileSync2(pidPath, "utf-8").trim();
|
|
15973
15841
|
const existingPid = parseInt(content, 10);
|
|
15974
15842
|
if (!isNaN(existingPid) && isProcessAlive(existingPid)) {
|
|
15975
15843
|
log.error(`Another daemon is already running (PID ${existingPid}). ` + `Remove ${pidPath} if this is stale.`);
|
|
15976
15844
|
return false;
|
|
15977
15845
|
}
|
|
15978
15846
|
} catch {}
|
|
15979
|
-
mkdirSync2(
|
|
15847
|
+
mkdirSync2(dirname(pidPath), { recursive: true, mode: 448 });
|
|
15980
15848
|
writeFileSync2(pidPath, String(process.pid), { mode: 384 });
|
|
15981
15849
|
return true;
|
|
15982
15850
|
}
|
|
@@ -15995,8 +15863,8 @@ function releaseDaemonPid(profile) {
|
|
|
15995
15863
|
|
|
15996
15864
|
// daemon/daemon.ts
|
|
15997
15865
|
import { execSync as execSync3, spawn } from "child_process";
|
|
15998
|
-
import { fileURLToPath
|
|
15999
|
-
import { dirname as
|
|
15866
|
+
import { fileURLToPath } from "url";
|
|
15867
|
+
import { dirname as dirname2, join as join3 } from "path";
|
|
16000
15868
|
function isCommandAvailable2(cmd) {
|
|
16001
15869
|
try {
|
|
16002
15870
|
execSync3(`which ${cmd}`, { stdio: "ignore" });
|
|
@@ -16168,7 +16036,7 @@ async function startDaemon(profile, serverUrl) {
|
|
|
16168
16036
|
process.on("SIGINT", shutdown);
|
|
16169
16037
|
await pollCycle();
|
|
16170
16038
|
}
|
|
16171
|
-
var SESSION_RUNNER_PATH =
|
|
16039
|
+
var SESSION_RUNNER_PATH = join3(dirname2(fileURLToPath(import.meta.url)), "session-runner.ts");
|
|
16172
16040
|
function spawnSessionRunner(input) {
|
|
16173
16041
|
const encoded = Buffer.from(JSON.stringify(input)).toString("base64");
|
|
16174
16042
|
const child = spawn("bun", ["run", SESSION_RUNNER_PATH, encoded], {
|
|
@@ -16246,7 +16114,7 @@ async function startInBackground(profile, serverUrl) {
|
|
|
16246
16114
|
return;
|
|
16247
16115
|
}
|
|
16248
16116
|
const logPath = daemonLogFilePath();
|
|
16249
|
-
mkdirSync3(
|
|
16117
|
+
mkdirSync3(dirname3(logPath), { recursive: true, mode: 448 });
|
|
16250
16118
|
const logFd = openSync(logPath, "a", 384);
|
|
16251
16119
|
const child = spawn2(process.execPath, buildChildArgs(profile, serverUrl), {
|
|
16252
16120
|
detached: true,
|
|
@@ -16357,7 +16225,7 @@ function configCommand() {
|
|
|
16357
16225
|
// commands/email.ts
|
|
16358
16226
|
import { Command as Command5 } from "commander";
|
|
16359
16227
|
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync4 } from "fs";
|
|
16360
|
-
import { join as
|
|
16228
|
+
import { join as join4 } from "path";
|
|
16361
16229
|
import PostalMime from "postal-mime";
|
|
16362
16230
|
var VALID_STATUSES = ["unread", "read", "archived"];
|
|
16363
16231
|
var EMAIL_DIR = "/tmp/alook-emails";
|
|
@@ -16407,7 +16275,7 @@ function emailCommand() {
|
|
|
16407
16275
|
mkdirSync4(EMAIL_DIR, { recursive: true });
|
|
16408
16276
|
const downloadedPaths = [];
|
|
16409
16277
|
for (const email3 of emails2) {
|
|
16410
|
-
const emailDir =
|
|
16278
|
+
const emailDir = join4(EMAIL_DIR, email3.id);
|
|
16411
16279
|
mkdirSync4(emailDir, { recursive: true });
|
|
16412
16280
|
const metadata = {
|
|
16413
16281
|
id: email3.id,
|
|
@@ -16417,7 +16285,7 @@ function emailCommand() {
|
|
|
16417
16285
|
date: email3.created_at,
|
|
16418
16286
|
status: email3.status
|
|
16419
16287
|
};
|
|
16420
|
-
const metadataPath =
|
|
16288
|
+
const metadataPath = join4(emailDir, "metadata.json");
|
|
16421
16289
|
writeFileSync3(metadataPath, JSON.stringify(metadata, null, 2));
|
|
16422
16290
|
downloadedPaths.push(metadataPath);
|
|
16423
16291
|
let rawMime;
|
|
@@ -16433,17 +16301,17 @@ function emailCommand() {
|
|
|
16433
16301
|
}
|
|
16434
16302
|
const parsed = await new PostalMime().parse(rawMime);
|
|
16435
16303
|
if (parsed.text) {
|
|
16436
|
-
const bodyPath =
|
|
16304
|
+
const bodyPath = join4(emailDir, "body.txt");
|
|
16437
16305
|
writeFileSync3(bodyPath, parsed.text);
|
|
16438
16306
|
downloadedPaths.push(bodyPath);
|
|
16439
16307
|
}
|
|
16440
16308
|
if (parsed.html) {
|
|
16441
|
-
const htmlPath =
|
|
16309
|
+
const htmlPath = join4(emailDir, "body.html");
|
|
16442
16310
|
writeFileSync3(htmlPath, parsed.html);
|
|
16443
16311
|
downloadedPaths.push(htmlPath);
|
|
16444
16312
|
}
|
|
16445
16313
|
if (parsed.attachments && parsed.attachments.length > 0) {
|
|
16446
|
-
const attDir =
|
|
16314
|
+
const attDir = join4(emailDir, "attachments");
|
|
16447
16315
|
mkdirSync4(attDir, { recursive: true });
|
|
16448
16316
|
const usedFilenames = new Set;
|
|
16449
16317
|
for (let i = 0;i < parsed.attachments.length; i++) {
|
|
@@ -16453,7 +16321,7 @@ function emailCommand() {
|
|
|
16453
16321
|
filename = `${i}-${filename}`;
|
|
16454
16322
|
}
|
|
16455
16323
|
usedFilenames.add(filename);
|
|
16456
|
-
const attPath =
|
|
16324
|
+
const attPath = join4(attDir, filename);
|
|
16457
16325
|
const content = att.content;
|
|
16458
16326
|
let buf;
|
|
16459
16327
|
if (typeof content === "string") {
|
|
@@ -16499,6 +16367,28 @@ function emailCommand() {
|
|
|
16499
16367
|
|
|
16500
16368
|
// commands/version.ts
|
|
16501
16369
|
import { Command as Command6 } from "commander";
|
|
16370
|
+
|
|
16371
|
+
// lib/version.ts
|
|
16372
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
16373
|
+
import { join as join5, dirname as dirname4 } from "path";
|
|
16374
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
16375
|
+
function getCurrentVersion() {
|
|
16376
|
+
const __dirname2 = dirname4(fileURLToPath2(import.meta.url));
|
|
16377
|
+
const candidates = [
|
|
16378
|
+
join5(__dirname2, "..", "package.json"),
|
|
16379
|
+
join5(__dirname2, "..", "..", "package.json")
|
|
16380
|
+
];
|
|
16381
|
+
for (const candidate of candidates) {
|
|
16382
|
+
try {
|
|
16383
|
+
const pkg = JSON.parse(readFileSync3(candidate, "utf-8"));
|
|
16384
|
+
if (typeof pkg.version === "string")
|
|
16385
|
+
return pkg.version;
|
|
16386
|
+
} catch {}
|
|
16387
|
+
}
|
|
16388
|
+
return "unknown";
|
|
16389
|
+
}
|
|
16390
|
+
|
|
16391
|
+
// commands/version.ts
|
|
16502
16392
|
function versionCommand() {
|
|
16503
16393
|
const cmd = new Command6("version").description("Show CLI version").action(() => {
|
|
16504
16394
|
console.log(`alook version ${getCurrentVersion()}`);
|