@alook/cli 0.0.98 → 0.0.100
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 +194 -234
- package/dist/session-runner.js +18 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14833,7 +14833,7 @@ var EmailNotifyRequestSchema = exports_external.object({
|
|
|
14833
14833
|
r2Key: exports_external.string().min(1),
|
|
14834
14834
|
from: exports_external.string().min(1),
|
|
14835
14835
|
to: exports_external.string().optional(),
|
|
14836
|
-
subject: exports_external.string()
|
|
14836
|
+
subject: exports_external.string(),
|
|
14837
14837
|
isWhitelisted: exports_external.boolean(),
|
|
14838
14838
|
forwarded: exports_external.boolean().optional().default(false),
|
|
14839
14839
|
messageId: exports_external.string().optional().default(""),
|
|
@@ -14935,6 +14935,7 @@ var SkillItemSchema = exports_external.object({
|
|
|
14935
14935
|
var SkillSyncRequestSchema = exports_external.object({
|
|
14936
14936
|
scope: exports_external.enum(["global", "agent"]),
|
|
14937
14937
|
agent_id: exports_external.string().min(1).optional(),
|
|
14938
|
+
daemon_id: exports_external.string().min(1).optional(),
|
|
14938
14939
|
runtime: exports_external.enum(["claude", "codex", "opencode"]),
|
|
14939
14940
|
skills: exports_external.array(SkillItemSchema)
|
|
14940
14941
|
});
|
|
@@ -16834,12 +16835,13 @@ var agentSkill = sqliteTable("agent_skill", {
|
|
|
16834
16835
|
id: text("id").primaryKey().$defaultFn(() => "as_" + nanoid3()),
|
|
16835
16836
|
workspaceId: text("workspace_id").notNull().references(() => workspace.id, { onDelete: "cascade" }),
|
|
16836
16837
|
agentId: text("agent_id"),
|
|
16838
|
+
daemonId: text("daemon_id"),
|
|
16837
16839
|
runtime: text("runtime").notNull(),
|
|
16838
16840
|
name: text("name").notNull(),
|
|
16839
16841
|
description: text("description").notNull().default(""),
|
|
16840
16842
|
syncedAt: text("synced_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
16841
16843
|
}, (t) => [
|
|
16842
|
-
unique("
|
|
16844
|
+
unique("agent_skill_ws_runtime_name_agent_daemon").on(t.workspaceId, t.runtime, t.name, t.agentId, t.daemonId),
|
|
16843
16845
|
index("idx_as_workspace_runtime").on(t.workspaceId, t.runtime),
|
|
16844
16846
|
index("idx_as_agent_runtime").on(t.agentId, t.runtime),
|
|
16845
16847
|
foreignKey({
|
|
@@ -18728,6 +18730,10 @@ ${task.agent.instructions}
|
|
|
18728
18730
|
`;
|
|
18729
18731
|
}
|
|
18730
18732
|
content += `
|
|
18733
|
+
**Isolated workspaces:**
|
|
18734
|
+
- Each agent runs in its own isolated workspace directory. Colleagues CANNOT read your local files — even in the same workspace.
|
|
18735
|
+
- When sending plans, code, or any file to a colleague, you MUST attach the file to the email (use --attachment). Never reference local file paths expecting them to read it.
|
|
18736
|
+
|
|
18731
18737
|
**Email threading rules:**
|
|
18732
18738
|
- When communicating with a colleague on the **same topic** as an existing email thread, reply to that thread (use --in-reply-to) to keep context together.
|
|
18733
18739
|
- **When starting a NEW topic or task that is unrelated to any previous email thread, you MUST compose a brand new email (do NOT use --in-reply-to). Never hijack an unrelated thread just because you recently emailed that colleague.** Judge by topic/task relevance, not by recency of communication.
|
|
@@ -18753,7 +18759,10 @@ ${lines.join(`
|
|
|
18753
18759
|
|
|
18754
18760
|
### Emails
|
|
18755
18761
|
---
|
|
18756
|
-
|
|
18762
|
+
When your task prompt includes an \`email_id\` field, fetch ONLY that specific email:
|
|
18763
|
+
- Run '${cmdPrefix()} email pull --email_id <EMAIL_ID>' (uses the email_id from the prompt)
|
|
18764
|
+
When no \`email_id\` is present, fall back to listing unread:
|
|
18765
|
+
- Run '${cmdPrefix()} email pull --status unread' to download unread emails from inbox to '${tempDir("alook-emails")}/${task.workspaceId}/${task.agentId}/'.
|
|
18757
18766
|
---
|
|
18758
18767
|
To download sent emails, add '--folder sent': '${cmdPrefix()} email pull --folder sent'
|
|
18759
18768
|
Valid folders: inbox (default), sent, untrust.
|
|
@@ -18940,7 +18949,8 @@ function prepare(config2, task) {
|
|
|
18940
18949
|
ALOOK_CONVERSATION_ID: task.conversationId,
|
|
18941
18950
|
ALOOK_TRACE_ID: task.traceId ?? "",
|
|
18942
18951
|
ALOOK_CHANNEL: task.channel ?? "default",
|
|
18943
|
-
ALOOK_HEALTH_PORT: process.env.ALOOK_HEALTH_PORT || "19514"
|
|
18952
|
+
ALOOK_HEALTH_PORT: process.env.ALOOK_HEALTH_PORT || "19514",
|
|
18953
|
+
...config2.token ? { ALOOK_TOKEN: config2.token } : {}
|
|
18944
18954
|
};
|
|
18945
18955
|
return { workDir, timelineDir, env };
|
|
18946
18956
|
}
|
|
@@ -19265,6 +19275,9 @@ function buildPrompt(task, attachments) {
|
|
|
19265
19275
|
} else {
|
|
19266
19276
|
obj.notice = EMAIL_NOTICE;
|
|
19267
19277
|
}
|
|
19278
|
+
if (ctx?.emailId != null) {
|
|
19279
|
+
obj.email_id = ctx.emailId;
|
|
19280
|
+
}
|
|
19268
19281
|
}
|
|
19269
19282
|
if (task.type === "calendar_event") {
|
|
19270
19283
|
obj.notice = CALENDAR_NOTICE;
|
|
@@ -19412,7 +19425,7 @@ async function runSession(input) {
|
|
|
19412
19425
|
const timelineDir = path.join(agentBaseDir, ".context_timeline").replace(/\\/g, "/");
|
|
19413
19426
|
mkdirSync6(timelineDir, { recursive: true });
|
|
19414
19427
|
await initEntryAsync(timelineDir, createTimelineEntry(task.id, task.prompt, task.type, undefined, process.pid, provider, task.contextKey, input.logFilePath));
|
|
19415
|
-
const { workDir, env } = prepare({ workspacesRoot }, task);
|
|
19428
|
+
const { workDir, env } = prepare({ workspacesRoot, token }, task);
|
|
19416
19429
|
let killed = false;
|
|
19417
19430
|
const earlyOnKill = async () => {
|
|
19418
19431
|
if (killed)
|
|
@@ -20237,8 +20250,8 @@ function scanOpenCodeAgentSkills(workdir) {
|
|
|
20237
20250
|
function computeHash(skills) {
|
|
20238
20251
|
return createHash2("md5").update(JSON.stringify(skills)).digest("hex");
|
|
20239
20252
|
}
|
|
20240
|
-
function globalCachePath(runtime) {
|
|
20241
|
-
return join10(getCacheDir(), "global", `${runtime}.json`);
|
|
20253
|
+
function globalCachePath(daemonId, runtime) {
|
|
20254
|
+
return join10(getCacheDir(), "global", daemonId, `${runtime}.json`);
|
|
20242
20255
|
}
|
|
20243
20256
|
function agentCachePath(agentId, runtime) {
|
|
20244
20257
|
return join10(getCacheDir(), "agents", agentId, `${runtime}.json`);
|
|
@@ -20322,17 +20335,19 @@ function runScan() {
|
|
|
20322
20335
|
try {
|
|
20323
20336
|
const skills = getGlobalScanner(runtime)();
|
|
20324
20337
|
const hash2 = computeHash(skills);
|
|
20325
|
-
const prevHash = readCacheHash(globalCachePath(runtime));
|
|
20338
|
+
const prevHash = readCacheHash(globalCachePath(scannerConfig.daemonId, runtime));
|
|
20326
20339
|
if (prevHash !== hash2) {
|
|
20327
20340
|
const skillItems = skills.map((s) => ({ name: s.name, description: s.description }));
|
|
20328
20341
|
log8.info(`Syncing global ${runtime} — ${skills.length} skills`);
|
|
20342
|
+
const daemonId = scannerConfig.daemonId;
|
|
20329
20343
|
const syncPromises = scannerConfig.workspaces.map((ws) => clientRef.syncSkills(ws.token, {
|
|
20330
20344
|
scope: "global",
|
|
20331
20345
|
runtime,
|
|
20332
|
-
skills: skillItems
|
|
20346
|
+
skills: skillItems,
|
|
20347
|
+
daemon_id: daemonId
|
|
20333
20348
|
}));
|
|
20334
20349
|
Promise.all(syncPromises).then(() => {
|
|
20335
|
-
writeCacheFile(globalCachePath(runtime), hash2, skills);
|
|
20350
|
+
writeCacheFile(globalCachePath(daemonId, runtime), hash2, skills);
|
|
20336
20351
|
}).catch((e) => log8.debug("Global skill sync failed", e));
|
|
20337
20352
|
}
|
|
20338
20353
|
} catch (e) {
|
|
@@ -20935,7 +20950,8 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20935
20950
|
token: ws.token,
|
|
20936
20951
|
agentIds: ws.agent_ids ?? []
|
|
20937
20952
|
})),
|
|
20938
|
-
runtimes: providers.map((p) => p.type)
|
|
20953
|
+
runtimes: providers.map((p) => p.type),
|
|
20954
|
+
daemonId: config2.daemonId
|
|
20939
20955
|
}, 60000);
|
|
20940
20956
|
let shuttingDown = false;
|
|
20941
20957
|
let restartRequested = false;
|
|
@@ -21426,11 +21442,12 @@ function configCommand() {
|
|
|
21426
21442
|
|
|
21427
21443
|
// commands/email.ts
|
|
21428
21444
|
import { Command as Command5 } from "commander";
|
|
21429
|
-
import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync10, readFileSync as
|
|
21430
|
-
import {
|
|
21445
|
+
import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync10, readFileSync as readFileSync11 } from "fs";
|
|
21446
|
+
import { join as join12 } from "path";
|
|
21431
21447
|
import PostalMime from "postal-mime";
|
|
21432
21448
|
|
|
21433
21449
|
// lib/flags.ts
|
|
21450
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
21434
21451
|
function resolveAgentId(opts) {
|
|
21435
21452
|
const id = opts.agent_id || process.env.ALOOK_AGENT_ID;
|
|
21436
21453
|
if (!id) {
|
|
@@ -21439,83 +21456,157 @@ function resolveAgentId(opts) {
|
|
|
21439
21456
|
}
|
|
21440
21457
|
return id;
|
|
21441
21458
|
}
|
|
21442
|
-
|
|
21443
|
-
// commands/email.ts
|
|
21444
|
-
var log10 = createLogger2({ module: "email" });
|
|
21445
|
-
var VALID_STATUSES = ["unread", "read", "archived", "sent"];
|
|
21446
|
-
var VALID_FOLDERS = ["inbox", "sent", "untrust"];
|
|
21447
|
-
var EMAIL_BASE = tempDir("alook-emails");
|
|
21448
|
-
var MIME_BY_EXT = {
|
|
21449
|
-
".pdf": "application/pdf",
|
|
21450
|
-
".png": "image/png",
|
|
21451
|
-
".jpg": "image/jpeg",
|
|
21452
|
-
".jpeg": "image/jpeg",
|
|
21453
|
-
".gif": "image/gif",
|
|
21454
|
-
".webp": "image/webp",
|
|
21455
|
-
".svg": "image/svg+xml",
|
|
21456
|
-
".txt": "text/plain",
|
|
21457
|
-
".html": "text/html",
|
|
21458
|
-
".htm": "text/html",
|
|
21459
|
-
".json": "application/json",
|
|
21460
|
-
".csv": "text/csv",
|
|
21461
|
-
".md": "text/markdown",
|
|
21462
|
-
".zip": "application/zip"
|
|
21463
|
-
};
|
|
21464
|
-
function guessContentType(filename) {
|
|
21465
|
-
const idx = filename.lastIndexOf(".");
|
|
21466
|
-
if (idx < 0)
|
|
21467
|
-
return "application/octet-stream";
|
|
21468
|
-
const ext = filename.slice(idx).toLowerCase();
|
|
21469
|
-
return MIME_BY_EXT[ext] ?? "application/octet-stream";
|
|
21470
|
-
}
|
|
21471
21459
|
function collectRepeated(value, previous) {
|
|
21472
21460
|
return previous.concat([value]);
|
|
21473
21461
|
}
|
|
21474
|
-
function
|
|
21462
|
+
function readBody(opts) {
|
|
21463
|
+
if (opts.body && opts.bodyFile) {
|
|
21464
|
+
console.error("Error: --body and --body-file are mutually exclusive");
|
|
21465
|
+
process.exit(1);
|
|
21466
|
+
}
|
|
21467
|
+
if (opts.bodyFile)
|
|
21468
|
+
return readFileSync9(opts.bodyFile, "utf-8");
|
|
21469
|
+
return opts.body ?? "";
|
|
21470
|
+
}
|
|
21471
|
+
|
|
21472
|
+
// lib/command-utils.ts
|
|
21473
|
+
function getRootOpts(command) {
|
|
21475
21474
|
let root = command;
|
|
21476
21475
|
while (root.parent)
|
|
21477
21476
|
root = root.parent;
|
|
21478
|
-
|
|
21479
|
-
|
|
21480
|
-
|
|
21481
|
-
|
|
21477
|
+
return root.opts() || {};
|
|
21478
|
+
}
|
|
21479
|
+
|
|
21480
|
+
// lib/resolve-client.ts
|
|
21481
|
+
function resolveClientOpts(command, opts = {}) {
|
|
21482
|
+
const parentOpts = getRootOpts(command);
|
|
21483
|
+
const cfg = loadCLIConfigForProfile(parentOpts.profile);
|
|
21484
|
+
const serverUrl = parentOpts.server || process.env.ALOOK_SERVER_URL || cfg.server_url;
|
|
21485
|
+
if (!serverUrl) {
|
|
21486
|
+
console.error("Error: no server URL configured. Set ALOOK_SERVER_URL or run register.");
|
|
21487
|
+
process.exit(1);
|
|
21488
|
+
}
|
|
21482
21489
|
const workspaces = cfg.watched_workspaces || [];
|
|
21483
21490
|
let ws;
|
|
21491
|
+
const envWorkspaceId = process.env.ALOOK_WORKSPACE_ID;
|
|
21484
21492
|
if (opts.workspace) {
|
|
21485
21493
|
ws = workspaces.find((w) => w.id === opts.workspace);
|
|
21486
21494
|
if (!ws) {
|
|
21487
|
-
|
|
21488
|
-
|
|
21495
|
+
if (envWorkspaceId === opts.workspace) {
|
|
21496
|
+
ws = undefined;
|
|
21497
|
+
} else {
|
|
21498
|
+
console.error(`Error: workspace ${opts.workspace} not found in config.`);
|
|
21499
|
+
process.exit(1);
|
|
21500
|
+
}
|
|
21489
21501
|
}
|
|
21490
21502
|
} else if (opts.agentId) {
|
|
21491
21503
|
ws = workspaces.find((w) => w.agent_ids?.includes(opts.agentId));
|
|
21492
21504
|
if (!ws) {
|
|
21493
21505
|
if (workspaces.length === 1) {
|
|
21494
21506
|
ws = workspaces[0];
|
|
21495
|
-
} else {
|
|
21496
|
-
console.error(`Error: agent ${opts.agentId} not found in any registered workspace. Use --workspace to specify.`);
|
|
21497
|
-
process.exit(1);
|
|
21498
21507
|
}
|
|
21499
21508
|
}
|
|
21500
21509
|
} else if (workspaces.length === 1) {
|
|
21501
21510
|
ws = workspaces[0];
|
|
21502
|
-
} else {
|
|
21503
|
-
console.error(`Error: multiple workspaces registered. Use --workspace to specify which one.`);
|
|
21504
|
-
process.exit(1);
|
|
21505
21511
|
}
|
|
21506
|
-
const
|
|
21512
|
+
const envToken = process.env.ALOOK_TOKEN;
|
|
21513
|
+
const token = envToken || ws?.token;
|
|
21507
21514
|
if (!token) {
|
|
21508
21515
|
console.error(`Error: not registered. Run '${cmdPrefix()} register --token <token>' first.`);
|
|
21509
21516
|
process.exit(1);
|
|
21510
21517
|
}
|
|
21511
|
-
|
|
21518
|
+
const workspaceId = ws?.id || envWorkspaceId;
|
|
21519
|
+
if (!workspaceId) {
|
|
21520
|
+
console.error("Error: cannot determine workspace. Set ALOOK_WORKSPACE_ID env var or use --workspace flag.");
|
|
21521
|
+
process.exit(1);
|
|
21522
|
+
}
|
|
21523
|
+
return { serverUrl, token, workspaceId };
|
|
21524
|
+
}
|
|
21525
|
+
|
|
21526
|
+
// lib/file-utils.ts
|
|
21527
|
+
import { readFileSync as readFileSync10, statSync as statSync5 } from "fs";
|
|
21528
|
+
import { basename as basename2 } from "path";
|
|
21529
|
+
var MIME_BY_EXT = {
|
|
21530
|
+
".pdf": "application/pdf",
|
|
21531
|
+
".png": "image/png",
|
|
21532
|
+
".jpg": "image/jpeg",
|
|
21533
|
+
".jpeg": "image/jpeg",
|
|
21534
|
+
".gif": "image/gif",
|
|
21535
|
+
".webp": "image/webp",
|
|
21536
|
+
".svg": "image/svg+xml",
|
|
21537
|
+
".txt": "text/plain",
|
|
21538
|
+
".html": "text/html",
|
|
21539
|
+
".htm": "text/html",
|
|
21540
|
+
".json": "application/json",
|
|
21541
|
+
".csv": "text/csv",
|
|
21542
|
+
".md": "text/markdown",
|
|
21543
|
+
".ts": "text/typescript",
|
|
21544
|
+
".js": "text/javascript",
|
|
21545
|
+
".yaml": "text/yaml",
|
|
21546
|
+
".yml": "text/yaml",
|
|
21547
|
+
".xml": "application/xml",
|
|
21548
|
+
".zip": "application/zip"
|
|
21549
|
+
};
|
|
21550
|
+
function guessContentType(filename) {
|
|
21551
|
+
const idx = filename.lastIndexOf(".");
|
|
21552
|
+
if (idx < 0)
|
|
21553
|
+
return "application/octet-stream";
|
|
21554
|
+
const ext = filename.slice(idx).toLowerCase();
|
|
21555
|
+
return MIME_BY_EXT[ext] ?? "application/octet-stream";
|
|
21556
|
+
}
|
|
21557
|
+
function contentToBuffer(content) {
|
|
21558
|
+
if (typeof content === "string") {
|
|
21559
|
+
return Buffer.from(content, "base64");
|
|
21560
|
+
} else if (content instanceof ArrayBuffer) {
|
|
21561
|
+
return Buffer.from(new Uint8Array(content));
|
|
21562
|
+
}
|
|
21563
|
+
return Buffer.from(content);
|
|
21512
21564
|
}
|
|
21565
|
+
async function uploadFile(client, filePath, endpoint) {
|
|
21566
|
+
let bytes;
|
|
21567
|
+
let size;
|
|
21568
|
+
try {
|
|
21569
|
+
bytes = readFileSync10(filePath);
|
|
21570
|
+
size = statSync5(filePath).size;
|
|
21571
|
+
} catch (err) {
|
|
21572
|
+
throw new Error(`cannot read file "${filePath}": ${err instanceof Error ? err.message : err}`);
|
|
21573
|
+
}
|
|
21574
|
+
const filename = basename2(filePath);
|
|
21575
|
+
const contentType = guessContentType(filename);
|
|
21576
|
+
const form = new FormData;
|
|
21577
|
+
form.append("file", new Blob([new Uint8Array(bytes)], { type: contentType }), filename);
|
|
21578
|
+
const uploaded = await client.postMultipart(endpoint, form);
|
|
21579
|
+
return {
|
|
21580
|
+
key: uploaded.key,
|
|
21581
|
+
filename: uploaded.filename,
|
|
21582
|
+
size: uploaded.size ?? size,
|
|
21583
|
+
contentType: uploaded.contentType ?? contentType
|
|
21584
|
+
};
|
|
21585
|
+
}
|
|
21586
|
+
|
|
21587
|
+
// lib/context-env.ts
|
|
21588
|
+
function gatherContextEnvVars() {
|
|
21589
|
+
const conversationId = process.env.ALOOK_CONVERSATION_ID || undefined;
|
|
21590
|
+
const traceId = process.env.ALOOK_TRACE_ID || undefined;
|
|
21591
|
+
const sourceTaskId = process.env.ALOOK_TASK_ID || undefined;
|
|
21592
|
+
return { conversationId, traceId, sourceTaskId };
|
|
21593
|
+
}
|
|
21594
|
+
|
|
21595
|
+
// commands/email.ts
|
|
21596
|
+
var log10 = createLogger2({ module: "email" });
|
|
21597
|
+
var VALID_STATUSES = ["unread", "read", "archived", "sent"];
|
|
21598
|
+
var VALID_FOLDERS = ["inbox", "sent", "untrust"];
|
|
21599
|
+
var EMAIL_BASE = tempDir("alook-emails");
|
|
21513
21600
|
function emailCommand() {
|
|
21514
21601
|
const cmd = new Command5("email").description("Manage agent emails");
|
|
21515
|
-
cmd.command("pull").description("Download and parse emails to /tmp/alook-emails/{workspaceId}/{agentId}/").option("--agent_id <id>", "Agent ID").option("--status <status>", "Filter by status (unread, read, archived)").option("--folder <folder>", "Email folder (inbox, sent, untrust)").option("--limit <n>", "Maximum number of emails to download").option("--offset <n>", "Number of emails to skip").option("--workspace <id>", "Workspace ID").option("--json", "Output as JSON instead of files").action(async (opts, command) => {
|
|
21602
|
+
cmd.command("pull").description("Download and parse emails to /tmp/alook-emails/{workspaceId}/{agentId}/").option("--agent_id <id>", "Agent ID").option("--email_id <id>", "Fetch a single email by ID (mutually exclusive with --status/--folder/--limit/--offset)").option("--status <status>", "Filter by status (unread, read, archived)").option("--folder <folder>", "Email folder (inbox, sent, untrust)").option("--limit <n>", "Maximum number of emails to download").option("--offset <n>", "Number of emails to skip").option("--workspace <id>", "Workspace ID").option("--json", "Output as JSON instead of files").action(async (opts, command) => {
|
|
21516
21603
|
const agentId = resolveAgentId(opts);
|
|
21517
21604
|
const { serverUrl, token, workspaceId } = resolveClientOpts(command, { workspace: opts.workspace, agentId });
|
|
21518
21605
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
21606
|
+
if (opts.email_id && (opts.status || opts.folder || opts.limit || opts.offset)) {
|
|
21607
|
+
console.error("Error: --email_id cannot be combined with --status, --folder, --limit, or --offset");
|
|
21608
|
+
process.exit(1);
|
|
21609
|
+
}
|
|
21519
21610
|
if (opts.status && !VALID_STATUSES.includes(opts.status)) {
|
|
21520
21611
|
console.error(`Error: invalid status "${opts.status}", must be one of: ${VALID_STATUSES.join(", ")}`);
|
|
21521
21612
|
process.exit(1);
|
|
@@ -21540,16 +21631,22 @@ function emailCommand() {
|
|
|
21540
21631
|
}
|
|
21541
21632
|
const emailDir_base = join12(EMAIL_BASE, workspaceId, agentId);
|
|
21542
21633
|
try {
|
|
21543
|
-
let
|
|
21544
|
-
if (opts.
|
|
21545
|
-
|
|
21546
|
-
|
|
21547
|
-
|
|
21548
|
-
|
|
21549
|
-
|
|
21550
|
-
|
|
21551
|
-
|
|
21552
|
-
|
|
21634
|
+
let emails2;
|
|
21635
|
+
if (opts.email_id) {
|
|
21636
|
+
const single = await client.getJSON(`/api/email/${opts.email_id}`);
|
|
21637
|
+
emails2 = [single];
|
|
21638
|
+
} else {
|
|
21639
|
+
let query = `/api/email?agentId=${agentId}`;
|
|
21640
|
+
if (opts.status)
|
|
21641
|
+
query += `&status=${opts.status}`;
|
|
21642
|
+
if (opts.folder)
|
|
21643
|
+
query += `&folder=${opts.folder}`;
|
|
21644
|
+
if (opts.limit)
|
|
21645
|
+
query += `&limit=${opts.limit}`;
|
|
21646
|
+
if (opts.offset)
|
|
21647
|
+
query += `&offset=${opts.offset}`;
|
|
21648
|
+
emails2 = await client.getJSON(query);
|
|
21649
|
+
}
|
|
21553
21650
|
if (!emails2.length) {
|
|
21554
21651
|
console.log("No emails found.");
|
|
21555
21652
|
return;
|
|
@@ -21611,16 +21708,7 @@ function emailCommand() {
|
|
|
21611
21708
|
}
|
|
21612
21709
|
usedFilenames.add(filename);
|
|
21613
21710
|
const attPath = join12(attDir, filename);
|
|
21614
|
-
|
|
21615
|
-
let buf;
|
|
21616
|
-
if (typeof content === "string") {
|
|
21617
|
-
buf = Buffer.from(content, "base64");
|
|
21618
|
-
} else if (content instanceof ArrayBuffer) {
|
|
21619
|
-
buf = Buffer.from(new Uint8Array(content));
|
|
21620
|
-
} else {
|
|
21621
|
-
buf = Buffer.from(content);
|
|
21622
|
-
}
|
|
21623
|
-
writeFileSync8(attPath, buf);
|
|
21711
|
+
writeFileSync8(attPath, contentToBuffer(att.content));
|
|
21624
21712
|
downloadedPaths.push(attPath);
|
|
21625
21713
|
}
|
|
21626
21714
|
}
|
|
@@ -21661,7 +21749,7 @@ function emailCommand() {
|
|
|
21661
21749
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
21662
21750
|
let htmlBody;
|
|
21663
21751
|
try {
|
|
21664
|
-
htmlBody =
|
|
21752
|
+
htmlBody = readFileSync11(opts.bodyFile, "utf-8");
|
|
21665
21753
|
} catch (err) {
|
|
21666
21754
|
console.error(`Error: cannot read body file "${opts.bodyFile}": ${err instanceof Error ? err.message : err}`);
|
|
21667
21755
|
process.exit(1);
|
|
@@ -21673,27 +21761,8 @@ function emailCommand() {
|
|
|
21673
21761
|
const attachmentPaths = opts.attachment ?? [];
|
|
21674
21762
|
const attachments = [];
|
|
21675
21763
|
try {
|
|
21676
|
-
for (const
|
|
21677
|
-
|
|
21678
|
-
let size;
|
|
21679
|
-
try {
|
|
21680
|
-
bytes = readFileSync9(path2);
|
|
21681
|
-
size = statSync5(path2).size;
|
|
21682
|
-
} catch (err) {
|
|
21683
|
-
console.error(`Error: cannot read attachment "${path2}": ${err instanceof Error ? err.message : err}`);
|
|
21684
|
-
process.exit(1);
|
|
21685
|
-
}
|
|
21686
|
-
const filename = basename2(path2);
|
|
21687
|
-
const contentType = guessContentType(filename);
|
|
21688
|
-
const form = new FormData;
|
|
21689
|
-
form.append("file", new Blob([new Uint8Array(bytes)], { type: contentType }), filename);
|
|
21690
|
-
const uploaded = await client.postMultipart("/api/email/upload", form);
|
|
21691
|
-
attachments.push({
|
|
21692
|
-
key: uploaded.key,
|
|
21693
|
-
filename: uploaded.filename,
|
|
21694
|
-
size: uploaded.size ?? size,
|
|
21695
|
-
contentType: uploaded.contentType ?? contentType
|
|
21696
|
-
});
|
|
21764
|
+
for (const filePath of attachmentPaths) {
|
|
21765
|
+
attachments.push(await uploadFile(client, filePath, "/api/email/upload"));
|
|
21697
21766
|
}
|
|
21698
21767
|
let inReplyTo;
|
|
21699
21768
|
let references;
|
|
@@ -21708,9 +21777,7 @@ function emailCommand() {
|
|
|
21708
21777
|
log10.warn(`could not fetch parent email ${opts.inReplyTo}, sending without threading`);
|
|
21709
21778
|
}
|
|
21710
21779
|
}
|
|
21711
|
-
const
|
|
21712
|
-
const traceId = process.env.ALOOK_TRACE_ID;
|
|
21713
|
-
const sourceTaskId = process.env.ALOOK_TASK_ID;
|
|
21780
|
+
const ctx = gatherContextEnvVars();
|
|
21714
21781
|
const res = await client.postJSON("/api/email/send", {
|
|
21715
21782
|
agentId,
|
|
21716
21783
|
to: opts.to,
|
|
@@ -21719,9 +21786,9 @@ function emailCommand() {
|
|
|
21719
21786
|
attachments,
|
|
21720
21787
|
...inReplyTo ? { inReplyTo, references } : {},
|
|
21721
21788
|
...opts.from ? { from: opts.from } : {},
|
|
21722
|
-
...conversationId ? { conversationId } : {},
|
|
21723
|
-
...traceId ? { traceId } : {},
|
|
21724
|
-
...sourceTaskId ? { sourceTaskId } : {}
|
|
21789
|
+
...ctx.conversationId ? { conversationId: ctx.conversationId } : {},
|
|
21790
|
+
...ctx.traceId ? { traceId: ctx.traceId } : {},
|
|
21791
|
+
...ctx.sourceTaskId ? { sourceTaskId: ctx.sourceTaskId } : {}
|
|
21725
21792
|
});
|
|
21726
21793
|
console.log(`Sent email to ${res.to_email} (id: ${res.id})`);
|
|
21727
21794
|
} catch (err) {
|
|
@@ -21765,15 +21832,7 @@ function emailCommand() {
|
|
|
21765
21832
|
for (const att of parsed.attachments) {
|
|
21766
21833
|
const filename = att.filename || "attachment.bin";
|
|
21767
21834
|
const contentType = att.mimeType || "application/octet-stream";
|
|
21768
|
-
const
|
|
21769
|
-
let buf;
|
|
21770
|
-
if (typeof content === "string") {
|
|
21771
|
-
buf = Buffer.from(content, "base64");
|
|
21772
|
-
} else if (content instanceof ArrayBuffer) {
|
|
21773
|
-
buf = Buffer.from(new Uint8Array(content));
|
|
21774
|
-
} else {
|
|
21775
|
-
buf = Buffer.from(content);
|
|
21776
|
-
}
|
|
21835
|
+
const buf = contentToBuffer(att.content);
|
|
21777
21836
|
const form = new FormData;
|
|
21778
21837
|
form.append("file", new Blob([new Uint8Array(buf)], { type: contentType }), filename);
|
|
21779
21838
|
const uploaded = await client.postMultipart("/api/email/upload", form);
|
|
@@ -21786,27 +21845,8 @@ function emailCommand() {
|
|
|
21786
21845
|
}
|
|
21787
21846
|
}
|
|
21788
21847
|
const extraPaths = opts.attachment ?? [];
|
|
21789
|
-
for (const
|
|
21790
|
-
|
|
21791
|
-
let size;
|
|
21792
|
-
try {
|
|
21793
|
-
bytes = readFileSync9(path2);
|
|
21794
|
-
size = statSync5(path2).size;
|
|
21795
|
-
} catch (err) {
|
|
21796
|
-
console.error(`Error: cannot read attachment "${path2}": ${err instanceof Error ? err.message : err}`);
|
|
21797
|
-
process.exit(1);
|
|
21798
|
-
}
|
|
21799
|
-
const filename = basename2(path2);
|
|
21800
|
-
const contentType = guessContentType(filename);
|
|
21801
|
-
const form = new FormData;
|
|
21802
|
-
form.append("file", new Blob([new Uint8Array(bytes)], { type: contentType }), filename);
|
|
21803
|
-
const uploaded = await client.postMultipart("/api/email/upload", form);
|
|
21804
|
-
attachments.push({
|
|
21805
|
-
key: uploaded.key,
|
|
21806
|
-
filename: uploaded.filename,
|
|
21807
|
-
size: uploaded.size ?? size,
|
|
21808
|
-
contentType: uploaded.contentType ?? contentType
|
|
21809
|
-
});
|
|
21848
|
+
for (const filePath of extraPaths) {
|
|
21849
|
+
attachments.push(await uploadFile(client, filePath, "/api/email/upload"));
|
|
21810
21850
|
}
|
|
21811
21851
|
let htmlBody = "";
|
|
21812
21852
|
if (opts.note) {
|
|
@@ -21823,9 +21863,7 @@ function emailCommand() {
|
|
|
21823
21863
|
htmlBody += `<pre>${parsed.text}</pre>`;
|
|
21824
21864
|
}
|
|
21825
21865
|
const subject = /^fwd:/i.test(original.subject) ? original.subject : `Fwd: ${original.subject}`;
|
|
21826
|
-
const
|
|
21827
|
-
const traceId = process.env.ALOOK_TRACE_ID;
|
|
21828
|
-
const sourceTaskId = process.env.ALOOK_TASK_ID;
|
|
21866
|
+
const ctx = gatherContextEnvVars();
|
|
21829
21867
|
const res = await client.postJSON("/api/email/send", {
|
|
21830
21868
|
agentId,
|
|
21831
21869
|
to: opts.to,
|
|
@@ -21833,9 +21871,9 @@ function emailCommand() {
|
|
|
21833
21871
|
htmlBody,
|
|
21834
21872
|
attachments,
|
|
21835
21873
|
...opts.from ? { from: opts.from } : {},
|
|
21836
|
-
...conversationId ? { conversationId } : {},
|
|
21837
|
-
...traceId ? { traceId } : {},
|
|
21838
|
-
...sourceTaskId ? { sourceTaskId } : {}
|
|
21874
|
+
...ctx.conversationId ? { conversationId: ctx.conversationId } : {},
|
|
21875
|
+
...ctx.traceId ? { traceId: ctx.traceId } : {},
|
|
21876
|
+
...ctx.sourceTaskId ? { sourceTaskId: ctx.sourceTaskId } : {}
|
|
21839
21877
|
});
|
|
21840
21878
|
console.log(`Forwarded email to ${res.to_email} (id: ${res.id})`);
|
|
21841
21879
|
} catch (err) {
|
|
@@ -21921,19 +21959,6 @@ function emailCommand() {
|
|
|
21921
21959
|
|
|
21922
21960
|
// commands/calendar.ts
|
|
21923
21961
|
import { Command as Command6 } from "commander";
|
|
21924
|
-
function resolveClientOpts2(command, agentId) {
|
|
21925
|
-
const parentOpts = command.parent?.parent?.opts() || {};
|
|
21926
|
-
const profile = parentOpts.profile;
|
|
21927
|
-
const cfg = loadCLIConfigForProfile(profile);
|
|
21928
|
-
const serverUrl = parentOpts.server || cfg.server_url;
|
|
21929
|
-
const workspaces = cfg.watched_workspaces || [];
|
|
21930
|
-
const ws = workspaces.find((w) => w.agent_ids?.includes(agentId));
|
|
21931
|
-
if (!ws || !ws.token) {
|
|
21932
|
-
console.error(`Error: no registered workspace contains agent ${agentId}. Run '${cmdPrefix()} register --token <token>' first.`);
|
|
21933
|
-
process.exit(1);
|
|
21934
|
-
}
|
|
21935
|
-
return { serverUrl, token: ws.token, workspaceId: ws.id };
|
|
21936
|
-
}
|
|
21937
21962
|
function parseLocalDatetime(input) {
|
|
21938
21963
|
const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?$/.exec(input);
|
|
21939
21964
|
if (!match) {
|
|
@@ -21967,7 +21992,7 @@ function calendarCommand() {
|
|
|
21967
21992
|
const cmd = new Command6("calendar").description("Manage scheduled agent events");
|
|
21968
21993
|
cmd.command("set").description("Create a calendar event").option("--agent_id <id>", "Agent ID").requiredOption("--event_title <title>", "Event title (used as the task prompt)").requiredOption("--datetime <iso>", "Scheduled datetime (YYYY-MM-DDTHH:MM, local time)").option("--description <text>", "Optional longer-form notes for the event").option("--repeat <interval>", "Repeat interval, e.g. 1day, 2hour, 1month").option("--repeat_stop_date <date>", "Stop repeating on or after this date (YYYY-MM-DD, local time)").option("--json", "Output as JSON").action(async (opts, command) => {
|
|
21969
21994
|
const agentId = resolveAgentId(opts);
|
|
21970
|
-
const { serverUrl, token, workspaceId } =
|
|
21995
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts(command, { agentId });
|
|
21971
21996
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
21972
21997
|
let scheduledAt;
|
|
21973
21998
|
try {
|
|
@@ -22011,7 +22036,7 @@ function calendarCommand() {
|
|
|
22011
22036
|
});
|
|
22012
22037
|
cmd.command("list").description("List calendar events for an agent").option("--agent_id <id>", "Agent ID").option("--future_days <n>", "Include events scheduled in the next N days", "30").option("--past_days <n>", "Include events scheduled in the past N days", "0").option("--json", "Output as JSON").action(async (opts, command) => {
|
|
22013
22038
|
const agentId = resolveAgentId(opts);
|
|
22014
|
-
const { serverUrl, token, workspaceId } =
|
|
22039
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts(command, { agentId });
|
|
22015
22040
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
22016
22041
|
const now = Date.now();
|
|
22017
22042
|
const from = new Date(now - Number(opts.past_days) * 86400000).toISOString();
|
|
@@ -22038,7 +22063,7 @@ function calendarCommand() {
|
|
|
22038
22063
|
});
|
|
22039
22064
|
cmd.command("show").description("Show the full detail of a single calendar event").option("--agent_id <id>", "Agent ID").requiredOption("--event_id <id>", "Event ID").option("--json", "Output as JSON").action(async (opts, command) => {
|
|
22040
22065
|
const agentId = resolveAgentId(opts);
|
|
22041
|
-
const { serverUrl, token, workspaceId } =
|
|
22066
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts(command, { agentId });
|
|
22042
22067
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
22043
22068
|
try {
|
|
22044
22069
|
const ev = await client.getJSON(`/api/calendar/${opts.event_id}`);
|
|
@@ -22102,7 +22127,7 @@ function calendarCommand() {
|
|
|
22102
22127
|
process.exit(1);
|
|
22103
22128
|
}
|
|
22104
22129
|
const agentId = resolveAgentId(opts);
|
|
22105
|
-
const { serverUrl, token, workspaceId } =
|
|
22130
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts(command, { agentId });
|
|
22106
22131
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
22107
22132
|
try {
|
|
22108
22133
|
const updated = await client.patchJSON(`/api/calendar/${opts.event_id}`, body);
|
|
@@ -22122,7 +22147,7 @@ function calendarCommand() {
|
|
|
22122
22147
|
});
|
|
22123
22148
|
cmd.command("delete").description("Delete a calendar event").option("--agent_id <id>", "Agent ID").requiredOption("--event_id <id>", "Event ID").action(async (opts, command) => {
|
|
22124
22149
|
const agentId = resolveAgentId(opts);
|
|
22125
|
-
const { serverUrl, token, workspaceId } =
|
|
22150
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts(command, { agentId });
|
|
22126
22151
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
22127
22152
|
try {
|
|
22128
22153
|
await client.deleteJSON(`/api/calendar/${opts.event_id}`);
|
|
@@ -22137,33 +22162,7 @@ function calendarCommand() {
|
|
|
22137
22162
|
|
|
22138
22163
|
// commands/issue.ts
|
|
22139
22164
|
import { Command as Command7 } from "commander";
|
|
22140
|
-
import { readFileSync as readFileSync10 } from "fs";
|
|
22141
22165
|
var VALID_STATUSES2 = ["todo", "in_progress", "review", "done", "closed", "canceled", "failed"];
|
|
22142
|
-
function resolveClientOpts3(command, agentId) {
|
|
22143
|
-
let root = command;
|
|
22144
|
-
while (root.parent)
|
|
22145
|
-
root = root.parent;
|
|
22146
|
-
const parentOpts = root.opts() || {};
|
|
22147
|
-
const profile = parentOpts.profile;
|
|
22148
|
-
const cfg = loadCLIConfigForProfile(profile);
|
|
22149
|
-
const serverUrl = parentOpts.server || cfg.server_url;
|
|
22150
|
-
const workspaces = cfg.watched_workspaces || [];
|
|
22151
|
-
const ws = workspaces.find((w) => w.agent_ids?.includes(agentId));
|
|
22152
|
-
if (!ws || !ws.token) {
|
|
22153
|
-
console.error(`Error: no registered workspace contains agent ${agentId}. Run '${cmdPrefix()} register --token <token>' first.`);
|
|
22154
|
-
process.exit(1);
|
|
22155
|
-
}
|
|
22156
|
-
return { serverUrl, token: ws.token, workspaceId: ws.id };
|
|
22157
|
-
}
|
|
22158
|
-
function readBody(opts) {
|
|
22159
|
-
if (opts.body && opts.bodyFile) {
|
|
22160
|
-
console.error("Error: --body and --body-file are mutually exclusive");
|
|
22161
|
-
process.exit(1);
|
|
22162
|
-
}
|
|
22163
|
-
if (opts.bodyFile)
|
|
22164
|
-
return readFileSync10(opts.bodyFile, "utf-8");
|
|
22165
|
-
return opts.body ?? "";
|
|
22166
|
-
}
|
|
22167
22166
|
function printIssue(issue3) {
|
|
22168
22167
|
console.log(`${issue3.id} ${issue3.status.padEnd(11)} ${issue3.title}`);
|
|
22169
22168
|
}
|
|
@@ -22197,7 +22196,7 @@ function issueCommand() {
|
|
|
22197
22196
|
const cmd = new Command7("issue").description("Manage assigned issues");
|
|
22198
22197
|
cmd.command("create").description("Create and dispatch an issue to an agent").option("--agent_id <id>", "Agent ID").requiredOption("--title <title>", "Issue title").option("--description <text>", "Issue description").option("--body-file <path>", "Read issue description from a file").option("--json", "Output as JSON").action(async (opts, command) => {
|
|
22199
22198
|
const agentId = resolveAgentId(opts);
|
|
22200
|
-
const { serverUrl, token, workspaceId } =
|
|
22199
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts(command, { agentId });
|
|
22201
22200
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
22202
22201
|
const description = readBody({ body: opts.description, bodyFile: opts.bodyFile });
|
|
22203
22202
|
try {
|
|
@@ -22220,7 +22219,7 @@ function issueCommand() {
|
|
|
22220
22219
|
process.exit(1);
|
|
22221
22220
|
}
|
|
22222
22221
|
const agentId = resolveAgentId(opts);
|
|
22223
|
-
const { serverUrl, token, workspaceId } =
|
|
22222
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts(command, { agentId });
|
|
22224
22223
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
22225
22224
|
const params = new URLSearchParams({ agentId });
|
|
22226
22225
|
if (opts.status)
|
|
@@ -22244,7 +22243,7 @@ function issueCommand() {
|
|
|
22244
22243
|
});
|
|
22245
22244
|
cmd.command("show").description("Show issue details and conversation").option("--agent_id <id>", "Agent ID").requiredOption("--issue_id <id>", "Issue ID").option("--json", "Output as JSON").action(async (opts, command) => {
|
|
22246
22245
|
const agentId = resolveAgentId(opts);
|
|
22247
|
-
const { serverUrl, token, workspaceId } =
|
|
22246
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts(command, { agentId });
|
|
22248
22247
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
22249
22248
|
try {
|
|
22250
22249
|
const res = await client.getJSON(`/api/issues/${opts.issue_id}?agentId=${encodeURIComponent(agentId)}`);
|
|
@@ -22278,7 +22277,7 @@ function issueCommand() {
|
|
|
22278
22277
|
process.exit(1);
|
|
22279
22278
|
}
|
|
22280
22279
|
const agentId = resolveAgentId(opts);
|
|
22281
|
-
const { serverUrl, token, workspaceId } =
|
|
22280
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts(command, { agentId });
|
|
22282
22281
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
22283
22282
|
try {
|
|
22284
22283
|
const issue3 = await client.patchJSON(`/api/issues/${opts.issue_id}?agentId=${encodeURIComponent(agentId)}`, body);
|
|
@@ -22297,7 +22296,7 @@ function issueCommand() {
|
|
|
22297
22296
|
process.exit(1);
|
|
22298
22297
|
}
|
|
22299
22298
|
const agentId = resolveAgentId(opts);
|
|
22300
|
-
const { serverUrl, token, workspaceId } =
|
|
22299
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts(command, { agentId });
|
|
22301
22300
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
22302
22301
|
try {
|
|
22303
22302
|
const res = await client.postJSON(`/api/issues/${opts.issue_id}/comments?agentId=${encodeURIComponent(agentId)}`, { content });
|
|
@@ -22359,62 +22358,23 @@ ${result.output}`);
|
|
|
22359
22358
|
|
|
22360
22359
|
// commands/sync.ts
|
|
22361
22360
|
import { Command as Command10 } from "commander";
|
|
22362
|
-
import { readFileSync as
|
|
22361
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
22363
22362
|
import { basename as basename3 } from "path";
|
|
22364
|
-
var MIME_BY_EXT2 = {
|
|
22365
|
-
".pdf": "application/pdf",
|
|
22366
|
-
".png": "image/png",
|
|
22367
|
-
".jpg": "image/jpeg",
|
|
22368
|
-
".jpeg": "image/jpeg",
|
|
22369
|
-
".gif": "image/gif",
|
|
22370
|
-
".txt": "text/plain",
|
|
22371
|
-
".html": "text/html",
|
|
22372
|
-
".json": "application/json",
|
|
22373
|
-
".csv": "text/csv",
|
|
22374
|
-
".md": "text/markdown",
|
|
22375
|
-
".ts": "text/typescript",
|
|
22376
|
-
".js": "text/javascript",
|
|
22377
|
-
".yaml": "text/yaml",
|
|
22378
|
-
".yml": "text/yaml",
|
|
22379
|
-
".svg": "image/svg+xml",
|
|
22380
|
-
".xml": "application/xml",
|
|
22381
|
-
".zip": "application/zip"
|
|
22382
|
-
};
|
|
22383
|
-
function guessContentType2(filename) {
|
|
22384
|
-
const idx = filename.lastIndexOf(".");
|
|
22385
|
-
if (idx < 0)
|
|
22386
|
-
return "application/octet-stream";
|
|
22387
|
-
const ext = filename.slice(idx).toLowerCase();
|
|
22388
|
-
return MIME_BY_EXT2[ext] ?? "application/octet-stream";
|
|
22389
|
-
}
|
|
22390
|
-
function resolveClientOpts4(command, agentId) {
|
|
22391
|
-
const parentOpts = command.parent?.parent?.opts() || {};
|
|
22392
|
-
const profile = parentOpts.profile;
|
|
22393
|
-
const cfg = loadCLIConfigForProfile(profile);
|
|
22394
|
-
const serverUrl = parentOpts.server || cfg.server_url;
|
|
22395
|
-
const workspaces = cfg.watched_workspaces || [];
|
|
22396
|
-
const ws = workspaces.find((w) => w.agent_ids?.includes(agentId));
|
|
22397
|
-
if (!ws || !ws.token) {
|
|
22398
|
-
console.error(`Error: no registered workspace contains agent ${agentId}. Run '${cmdPrefix()} register --token <token>' first.`);
|
|
22399
|
-
process.exit(1);
|
|
22400
|
-
}
|
|
22401
|
-
return { serverUrl, token: ws.token, workspaceId: ws.id };
|
|
22402
|
-
}
|
|
22403
22363
|
function syncCommand() {
|
|
22404
22364
|
const cmd = new Command10("sync").description("File sync utilities");
|
|
22405
22365
|
cmd.command("upload-artifact").description("Upload a file artifact to a conversation").option("--agent_id <id>", "Agent ID").requiredOption("--conversation_id <id>", "Conversation ID").requiredOption("--file <path>", "Path to file to upload").action(async (opts, command) => {
|
|
22406
22366
|
const agentId = resolveAgentId(opts);
|
|
22407
|
-
const { serverUrl, token, workspaceId } =
|
|
22367
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts(command, { agentId });
|
|
22408
22368
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
22409
22369
|
let bytes;
|
|
22410
22370
|
try {
|
|
22411
|
-
bytes =
|
|
22371
|
+
bytes = readFileSync12(opts.file);
|
|
22412
22372
|
} catch (err) {
|
|
22413
22373
|
console.error(`Error: cannot read file "${opts.file}": ${err.message}`);
|
|
22414
22374
|
process.exit(1);
|
|
22415
22375
|
}
|
|
22416
22376
|
const filename = basename3(opts.file);
|
|
22417
|
-
const contentType =
|
|
22377
|
+
const contentType = guessContentType(filename);
|
|
22418
22378
|
const form = new FormData;
|
|
22419
22379
|
form.append("file", new Blob([new Uint8Array(bytes)], { type: contentType }), filename);
|
|
22420
22380
|
form.append("agent_id", agentId);
|
package/dist/session-runner.js
CHANGED
|
@@ -14700,7 +14700,7 @@ var EmailNotifyRequestSchema = exports_external.object({
|
|
|
14700
14700
|
r2Key: exports_external.string().min(1),
|
|
14701
14701
|
from: exports_external.string().min(1),
|
|
14702
14702
|
to: exports_external.string().optional(),
|
|
14703
|
-
subject: exports_external.string()
|
|
14703
|
+
subject: exports_external.string(),
|
|
14704
14704
|
isWhitelisted: exports_external.boolean(),
|
|
14705
14705
|
forwarded: exports_external.boolean().optional().default(false),
|
|
14706
14706
|
messageId: exports_external.string().optional().default(""),
|
|
@@ -14802,6 +14802,7 @@ var SkillItemSchema = exports_external.object({
|
|
|
14802
14802
|
var SkillSyncRequestSchema = exports_external.object({
|
|
14803
14803
|
scope: exports_external.enum(["global", "agent"]),
|
|
14804
14804
|
agent_id: exports_external.string().min(1).optional(),
|
|
14805
|
+
daemon_id: exports_external.string().min(1).optional(),
|
|
14805
14806
|
runtime: exports_external.enum(["claude", "codex", "opencode"]),
|
|
14806
14807
|
skills: exports_external.array(SkillItemSchema)
|
|
14807
14808
|
});
|
|
@@ -16701,12 +16702,13 @@ var agentSkill = sqliteTable("agent_skill", {
|
|
|
16701
16702
|
id: text("id").primaryKey().$defaultFn(() => "as_" + nanoid3()),
|
|
16702
16703
|
workspaceId: text("workspace_id").notNull().references(() => workspace.id, { onDelete: "cascade" }),
|
|
16703
16704
|
agentId: text("agent_id"),
|
|
16705
|
+
daemonId: text("daemon_id"),
|
|
16704
16706
|
runtime: text("runtime").notNull(),
|
|
16705
16707
|
name: text("name").notNull(),
|
|
16706
16708
|
description: text("description").notNull().default(""),
|
|
16707
16709
|
syncedAt: text("synced_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
16708
16710
|
}, (t) => [
|
|
16709
|
-
unique("
|
|
16711
|
+
unique("agent_skill_ws_runtime_name_agent_daemon").on(t.workspaceId, t.runtime, t.name, t.agentId, t.daemonId),
|
|
16710
16712
|
index("idx_as_workspace_runtime").on(t.workspaceId, t.runtime),
|
|
16711
16713
|
index("idx_as_agent_runtime").on(t.agentId, t.runtime),
|
|
16712
16714
|
foreignKey({
|
|
@@ -18066,6 +18068,10 @@ ${task.agent.instructions}
|
|
|
18066
18068
|
`;
|
|
18067
18069
|
}
|
|
18068
18070
|
content += `
|
|
18071
|
+
**Isolated workspaces:**
|
|
18072
|
+
- Each agent runs in its own isolated workspace directory. Colleagues CANNOT read your local files — even in the same workspace.
|
|
18073
|
+
- When sending plans, code, or any file to a colleague, you MUST attach the file to the email (use --attachment). Never reference local file paths expecting them to read it.
|
|
18074
|
+
|
|
18069
18075
|
**Email threading rules:**
|
|
18070
18076
|
- When communicating with a colleague on the **same topic** as an existing email thread, reply to that thread (use --in-reply-to) to keep context together.
|
|
18071
18077
|
- **When starting a NEW topic or task that is unrelated to any previous email thread, you MUST compose a brand new email (do NOT use --in-reply-to). Never hijack an unrelated thread just because you recently emailed that colleague.** Judge by topic/task relevance, not by recency of communication.
|
|
@@ -18091,7 +18097,10 @@ ${lines.join(`
|
|
|
18091
18097
|
|
|
18092
18098
|
### Emails
|
|
18093
18099
|
---
|
|
18094
|
-
|
|
18100
|
+
When your task prompt includes an \`email_id\` field, fetch ONLY that specific email:
|
|
18101
|
+
- Run '${cmdPrefix()} email pull --email_id <EMAIL_ID>' (uses the email_id from the prompt)
|
|
18102
|
+
When no \`email_id\` is present, fall back to listing unread:
|
|
18103
|
+
- Run '${cmdPrefix()} email pull --status unread' to download unread emails from inbox to '${tempDir("alook-emails")}/${task.workspaceId}/${task.agentId}/'.
|
|
18095
18104
|
---
|
|
18096
18105
|
To download sent emails, add '--folder sent': '${cmdPrefix()} email pull --folder sent'
|
|
18097
18106
|
Valid folders: inbox (default), sent, untrust.
|
|
@@ -18278,7 +18287,8 @@ function prepare(config2, task) {
|
|
|
18278
18287
|
ALOOK_CONVERSATION_ID: task.conversationId,
|
|
18279
18288
|
ALOOK_TRACE_ID: task.traceId ?? "",
|
|
18280
18289
|
ALOOK_CHANNEL: task.channel ?? "default",
|
|
18281
|
-
ALOOK_HEALTH_PORT: process.env.ALOOK_HEALTH_PORT || "19514"
|
|
18290
|
+
ALOOK_HEALTH_PORT: process.env.ALOOK_HEALTH_PORT || "19514",
|
|
18291
|
+
...config2.token ? { ALOOK_TOKEN: config2.token } : {}
|
|
18282
18292
|
};
|
|
18283
18293
|
return { workDir, timelineDir, env };
|
|
18284
18294
|
}
|
|
@@ -18651,6 +18661,9 @@ function buildPrompt(task, attachments) {
|
|
|
18651
18661
|
} else {
|
|
18652
18662
|
obj.notice = EMAIL_NOTICE;
|
|
18653
18663
|
}
|
|
18664
|
+
if (ctx?.emailId != null) {
|
|
18665
|
+
obj.email_id = ctx.emailId;
|
|
18666
|
+
}
|
|
18654
18667
|
}
|
|
18655
18668
|
if (task.type === "calendar_event") {
|
|
18656
18669
|
obj.notice = CALENDAR_NOTICE;
|
|
@@ -18798,7 +18811,7 @@ async function runSession(input) {
|
|
|
18798
18811
|
const timelineDir = path.join(agentBaseDir, ".context_timeline").replace(/\\/g, "/");
|
|
18799
18812
|
mkdirSync4(timelineDir, { recursive: true });
|
|
18800
18813
|
await initEntryAsync(timelineDir, createTimelineEntry(task.id, task.prompt, task.type, undefined, process.pid, provider, task.contextKey, input.logFilePath));
|
|
18801
|
-
const { workDir, env } = prepare({ workspacesRoot }, task);
|
|
18814
|
+
const { workDir, env } = prepare({ workspacesRoot, token }, task);
|
|
18802
18815
|
let killed = false;
|
|
18803
18816
|
const earlyOnKill = async () => {
|
|
18804
18817
|
if (killed)
|