@alook/cli 0.0.39 → 0.0.41
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 +280 -12
- package/dist/session-runner.js +97 -4
- 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 Command11 } from "commander";
|
|
19
19
|
|
|
20
20
|
// commands/register.ts
|
|
21
21
|
import { Command } from "commander";
|
|
@@ -320,8 +320,29 @@ var TASK_TYPES = {
|
|
|
320
320
|
USER_DM_MESSAGE: "user_dm_message",
|
|
321
321
|
EMAIL_NOTIFICATION: "email_notification",
|
|
322
322
|
CALENDAR_EVENT: "calendar_event",
|
|
323
|
+
ISSUE_EVENT: "issue_event",
|
|
323
324
|
KILL_TASK: "kill_task"
|
|
324
325
|
};
|
|
326
|
+
var IssueStatus = {
|
|
327
|
+
TODO: "todo",
|
|
328
|
+
IN_PROGRESS: "in_progress",
|
|
329
|
+
REVIEW: "review",
|
|
330
|
+
DONE: "done",
|
|
331
|
+
CLOSED: "closed",
|
|
332
|
+
CANCELED: "canceled",
|
|
333
|
+
FAILED: "failed"
|
|
334
|
+
};
|
|
335
|
+
var ACTIVE_ISSUE_STATUSES = [
|
|
336
|
+
IssueStatus.TODO,
|
|
337
|
+
IssueStatus.IN_PROGRESS,
|
|
338
|
+
IssueStatus.REVIEW
|
|
339
|
+
];
|
|
340
|
+
var TERMINAL_ISSUE_STATUSES = [
|
|
341
|
+
IssueStatus.DONE,
|
|
342
|
+
IssueStatus.CLOSED,
|
|
343
|
+
IssueStatus.CANCELED,
|
|
344
|
+
IssueStatus.FAILED
|
|
345
|
+
];
|
|
325
346
|
var POLL_INTERVAL_MS = Number(process.env.POLL_INTERVAL_MS) || 3000;
|
|
326
347
|
var OFFLINE_THRESHOLD_MS = Number(process.env.OFFLINE_THRESHOLD_MS) || 9000;
|
|
327
348
|
var EVENT_POLL_INTERVAL_MS = Number(process.env.EVENT_POLL_INTERVAL_MS) || 2000;
|
|
@@ -14821,6 +14842,42 @@ var CalendarEventApiSchema = exports_external.object({
|
|
|
14821
14842
|
created_at: exports_external.string(),
|
|
14822
14843
|
updated_at: exports_external.string()
|
|
14823
14844
|
});
|
|
14845
|
+
var IssueStatusSchema = exports_external.enum([
|
|
14846
|
+
IssueStatus.TODO,
|
|
14847
|
+
IssueStatus.IN_PROGRESS,
|
|
14848
|
+
IssueStatus.REVIEW,
|
|
14849
|
+
IssueStatus.DONE,
|
|
14850
|
+
IssueStatus.CLOSED,
|
|
14851
|
+
IssueStatus.CANCELED,
|
|
14852
|
+
IssueStatus.FAILED
|
|
14853
|
+
]);
|
|
14854
|
+
var CreateIssueRequestSchema = exports_external.object({
|
|
14855
|
+
agent_id: exports_external.string().min(1, "agent_id is required"),
|
|
14856
|
+
title: exports_external.string().min(1, "title is required").max(200),
|
|
14857
|
+
description: exports_external.string().max(20000).optional().default("")
|
|
14858
|
+
});
|
|
14859
|
+
var UpdateIssueRequestSchema = exports_external.object({
|
|
14860
|
+
title: exports_external.string().min(1).max(200).optional(),
|
|
14861
|
+
description: exports_external.string().max(20000).optional(),
|
|
14862
|
+
status: IssueStatusSchema.optional()
|
|
14863
|
+
}).refine((v) => v.title !== undefined || v.description !== undefined || v.status !== undefined, { message: "at least one field is required" });
|
|
14864
|
+
var CreateIssueCommentRequestSchema = exports_external.object({
|
|
14865
|
+
content: exports_external.string().min(1, "content is required").max(20000)
|
|
14866
|
+
});
|
|
14867
|
+
var IssueApiSchema = exports_external.object({
|
|
14868
|
+
id: exports_external.string(),
|
|
14869
|
+
workspace_id: exports_external.string(),
|
|
14870
|
+
agent_id: exports_external.string(),
|
|
14871
|
+
creator_user_id: exports_external.string(),
|
|
14872
|
+
conversation_id: exports_external.string(),
|
|
14873
|
+
latest_task_id: exports_external.string().nullable(),
|
|
14874
|
+
title: exports_external.string(),
|
|
14875
|
+
description: exports_external.string(),
|
|
14876
|
+
status: IssueStatusSchema,
|
|
14877
|
+
created_at: exports_external.string(),
|
|
14878
|
+
updated_at: exports_external.string(),
|
|
14879
|
+
completed_at: exports_external.string().nullable()
|
|
14880
|
+
});
|
|
14824
14881
|
var CreateAgentLinkRequestSchema = exports_external.object({
|
|
14825
14882
|
source_agent_id: exports_external.string().min(1, "source_agent_id is required"),
|
|
14826
14883
|
target_agent_id: exports_external.string().min(1, "target_agent_id is required"),
|
|
@@ -16603,6 +16660,30 @@ var agentTaskQueue = sqliteTable("agent_task_queue", {
|
|
|
16603
16660
|
foreignColumns: [agent.id, agent.workspaceId]
|
|
16604
16661
|
}).onDelete("cascade")
|
|
16605
16662
|
]);
|
|
16663
|
+
var issue2 = sqliteTable("issue", {
|
|
16664
|
+
id: text("id").primaryKey().$defaultFn(() => "iss_" + nanoid3()),
|
|
16665
|
+
workspaceId: text("workspace_id").notNull().references(() => workspace.id, { onDelete: "cascade" }),
|
|
16666
|
+
agentId: text("agent_id").notNull(),
|
|
16667
|
+
creatorUserId: text("creator_user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
16668
|
+
conversationId: text("conversation_id").notNull().references(() => conversation.id, { onDelete: "cascade" }),
|
|
16669
|
+
latestTaskId: text("latest_task_id").references(() => agentTaskQueue.id, {
|
|
16670
|
+
onDelete: "set null"
|
|
16671
|
+
}),
|
|
16672
|
+
title: text("title").notNull(),
|
|
16673
|
+
description: text("description").notNull().default(""),
|
|
16674
|
+
status: text("status").notNull().default("todo"),
|
|
16675
|
+
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
|
|
16676
|
+
updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString()),
|
|
16677
|
+
completedAt: text("completed_at")
|
|
16678
|
+
}, (t) => [
|
|
16679
|
+
index("idx_issue_workspace_status_agent").on(t.workspaceId, t.status, t.agentId),
|
|
16680
|
+
index("idx_issue_workspace_updated").on(t.workspaceId, t.updatedAt),
|
|
16681
|
+
unique("issue_conversation_unique").on(t.conversationId),
|
|
16682
|
+
foreignKey({
|
|
16683
|
+
columns: [t.agentId, t.workspaceId],
|
|
16684
|
+
foreignColumns: [agent.id, agent.workspaceId]
|
|
16685
|
+
}).onDelete("cascade")
|
|
16686
|
+
]);
|
|
16606
16687
|
var taskMessage = sqliteTable("task_message", {
|
|
16607
16688
|
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
16608
16689
|
taskId: text("task_id").notNull().references(() => agentTaskQueue.id, { onDelete: "cascade" }),
|
|
@@ -17969,7 +18050,11 @@ async function startDaemon(profile, serverUrl) {
|
|
|
17969
18050
|
}
|
|
17970
18051
|
if (pending_rescan) {
|
|
17971
18052
|
log.info("Rescan requested — restarting daemon to re-detect runtimes");
|
|
18053
|
+
for (const id of evictedIds) {
|
|
18054
|
+
evictWorkspace(id);
|
|
18055
|
+
}
|
|
17972
18056
|
requestRestart();
|
|
18057
|
+
return;
|
|
17973
18058
|
}
|
|
17974
18059
|
for (const apiTask of apiTasks) {
|
|
17975
18060
|
const task = fromApiTask(apiTask);
|
|
@@ -19112,19 +19197,201 @@ function calendarCommand() {
|
|
|
19112
19197
|
return cmd;
|
|
19113
19198
|
}
|
|
19114
19199
|
|
|
19115
|
-
// commands/
|
|
19200
|
+
// commands/issue.ts
|
|
19116
19201
|
import { Command as Command7 } from "commander";
|
|
19202
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
19203
|
+
var VALID_STATUSES2 = ["todo", "in_progress", "review", "done", "closed", "canceled", "failed"];
|
|
19204
|
+
function resolveClientOpts3(command, agentId) {
|
|
19205
|
+
let root = command;
|
|
19206
|
+
while (root.parent)
|
|
19207
|
+
root = root.parent;
|
|
19208
|
+
const parentOpts = root.opts() || {};
|
|
19209
|
+
const profile = parentOpts.profile;
|
|
19210
|
+
const cfg = loadCLIConfigForProfile(profile);
|
|
19211
|
+
const serverUrl = parentOpts.server || cfg.server_url;
|
|
19212
|
+
const workspaces = cfg.watched_workspaces || [];
|
|
19213
|
+
const ws = workspaces.find((w) => w.agent_ids?.includes(agentId));
|
|
19214
|
+
if (!ws || !ws.token) {
|
|
19215
|
+
console.error(`Error: no registered workspace contains agent ${agentId}. Run '${cmdPrefix()} register --token <token>' first.`);
|
|
19216
|
+
process.exit(1);
|
|
19217
|
+
}
|
|
19218
|
+
return { serverUrl, token: ws.token, workspaceId: ws.id };
|
|
19219
|
+
}
|
|
19220
|
+
function readBody(opts) {
|
|
19221
|
+
if (opts.body && opts.bodyFile) {
|
|
19222
|
+
console.error("Error: --body and --body-file are mutually exclusive");
|
|
19223
|
+
process.exit(1);
|
|
19224
|
+
}
|
|
19225
|
+
if (opts.bodyFile)
|
|
19226
|
+
return readFileSync8(opts.bodyFile, "utf-8");
|
|
19227
|
+
return opts.body ?? "";
|
|
19228
|
+
}
|
|
19229
|
+
function printIssue(issue3) {
|
|
19230
|
+
console.log(`${issue3.id} ${issue3.status.padEnd(11)} ${issue3.title}`);
|
|
19231
|
+
}
|
|
19232
|
+
function printIssueDetail(issue3, messages) {
|
|
19233
|
+
console.log(`id: ${issue3.id}`);
|
|
19234
|
+
console.log(`agent_id: ${issue3.agent_id}`);
|
|
19235
|
+
console.log(`status: ${issue3.status}`);
|
|
19236
|
+
console.log(`conversation_id: ${issue3.conversation_id}`);
|
|
19237
|
+
if (issue3.latest_task_id)
|
|
19238
|
+
console.log(`latest_task_id: ${issue3.latest_task_id}`);
|
|
19239
|
+
console.log(`title: ${issue3.title}`);
|
|
19240
|
+
console.log("description:");
|
|
19241
|
+
console.log(issue3.description || "(no description)");
|
|
19242
|
+
if (messages && messages.length > 0) {
|
|
19243
|
+
console.log(`
|
|
19244
|
+
conversation:`);
|
|
19245
|
+
for (const m of messages) {
|
|
19246
|
+
console.log(`[${m.role}] ${m.content}`);
|
|
19247
|
+
}
|
|
19248
|
+
}
|
|
19249
|
+
}
|
|
19250
|
+
function issueCommand() {
|
|
19251
|
+
const cmd = new Command7("issue").description("Manage assigned issues");
|
|
19252
|
+
cmd.command("create").description("Create and dispatch an issue to an agent").requiredOption("--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) => {
|
|
19253
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts3(command, opts.agent_id);
|
|
19254
|
+
const client = new APIClient(serverUrl, token, workspaceId);
|
|
19255
|
+
const description = readBody({ body: opts.description, bodyFile: opts.bodyFile });
|
|
19256
|
+
try {
|
|
19257
|
+
const res = await client.postJSON("/api/issues", {
|
|
19258
|
+
agent_id: opts.agent_id,
|
|
19259
|
+
title: opts.title,
|
|
19260
|
+
description
|
|
19261
|
+
});
|
|
19262
|
+
if (opts.json)
|
|
19263
|
+
return printJSON(res);
|
|
19264
|
+
console.log(`Created ${res.issue.id} — ${res.issue.title}`);
|
|
19265
|
+
} catch (err) {
|
|
19266
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
19267
|
+
process.exit(1);
|
|
19268
|
+
}
|
|
19269
|
+
});
|
|
19270
|
+
cmd.command("list").description("List issues for an agent").requiredOption("--agent_id <id>", "Agent ID").option("--status <status>", `Filter by status (${VALID_STATUSES2.join(", ")})`).option("--completed", "Show completed/closed/canceled/failed issues").option("--all", "Show all issues").option("--json", "Output as JSON").action(async (opts, command) => {
|
|
19271
|
+
if (opts.status && !VALID_STATUSES2.includes(opts.status)) {
|
|
19272
|
+
console.error(`Error: invalid status "${opts.status}"`);
|
|
19273
|
+
process.exit(1);
|
|
19274
|
+
}
|
|
19275
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts3(command, opts.agent_id);
|
|
19276
|
+
const client = new APIClient(serverUrl, token, workspaceId);
|
|
19277
|
+
const params = new URLSearchParams({ agentId: opts.agent_id });
|
|
19278
|
+
if (opts.status)
|
|
19279
|
+
params.set("status", opts.status);
|
|
19280
|
+
if (!opts.all && !opts.status)
|
|
19281
|
+
params.set("terminal", opts.completed ? "true" : "false");
|
|
19282
|
+
try {
|
|
19283
|
+
const issues = await client.getJSON(`/api/issues?${params}`);
|
|
19284
|
+
if (opts.json)
|
|
19285
|
+
return printJSON(issues);
|
|
19286
|
+
if (issues.length === 0) {
|
|
19287
|
+
console.log("No issues found.");
|
|
19288
|
+
return;
|
|
19289
|
+
}
|
|
19290
|
+
for (const issue3 of issues)
|
|
19291
|
+
printIssue(issue3);
|
|
19292
|
+
} catch (err) {
|
|
19293
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
19294
|
+
process.exit(1);
|
|
19295
|
+
}
|
|
19296
|
+
});
|
|
19297
|
+
cmd.command("pull").description("Show the next active issue for an agent").requiredOption("--agent_id <id>", "Agent ID").option("--json", "Output as JSON").action(async (opts, command) => {
|
|
19298
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts3(command, opts.agent_id);
|
|
19299
|
+
const client = new APIClient(serverUrl, token, workspaceId);
|
|
19300
|
+
try {
|
|
19301
|
+
const issues = await client.getJSON(`/api/issues?agentId=${encodeURIComponent(opts.agent_id)}&terminal=false`);
|
|
19302
|
+
const issue3 = issues[0] ?? null;
|
|
19303
|
+
if (opts.json)
|
|
19304
|
+
return printJSON(issue3);
|
|
19305
|
+
if (!issue3) {
|
|
19306
|
+
console.log("No active issues.");
|
|
19307
|
+
return;
|
|
19308
|
+
}
|
|
19309
|
+
printIssueDetail(issue3);
|
|
19310
|
+
} catch (err) {
|
|
19311
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
19312
|
+
process.exit(1);
|
|
19313
|
+
}
|
|
19314
|
+
});
|
|
19315
|
+
cmd.command("show").description("Show issue details and conversation").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--issue_id <id>", "Issue ID").option("--json", "Output as JSON").action(async (opts, command) => {
|
|
19316
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts3(command, opts.agent_id);
|
|
19317
|
+
const client = new APIClient(serverUrl, token, workspaceId);
|
|
19318
|
+
try {
|
|
19319
|
+
const res = await client.getJSON(`/api/issues/${opts.issue_id}?agentId=${encodeURIComponent(opts.agent_id)}`);
|
|
19320
|
+
if (res.issue.agent_id !== opts.agent_id) {
|
|
19321
|
+
console.error(`Error: issue ${res.issue.id} does not belong to agent ${opts.agent_id}`);
|
|
19322
|
+
process.exit(1);
|
|
19323
|
+
}
|
|
19324
|
+
if (opts.json)
|
|
19325
|
+
return printJSON(res);
|
|
19326
|
+
printIssueDetail(res.issue, res.messages);
|
|
19327
|
+
} catch (err) {
|
|
19328
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
19329
|
+
process.exit(1);
|
|
19330
|
+
}
|
|
19331
|
+
});
|
|
19332
|
+
cmd.command("update").description("Update issue status or text").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--issue_id <id>", "Issue ID").option("--status <status>", `New status (${VALID_STATUSES2.join(", ")})`).option("--title <title>", "New title").option("--description <text>", "New description").option("--body-file <path>", "Read description from a file").option("--json", "Output as JSON").action(async (opts, command) => {
|
|
19333
|
+
if (opts.status && !VALID_STATUSES2.includes(opts.status)) {
|
|
19334
|
+
console.error(`Error: invalid status "${opts.status}"`);
|
|
19335
|
+
process.exit(1);
|
|
19336
|
+
}
|
|
19337
|
+
const description = readBody({ body: opts.description, bodyFile: opts.bodyFile });
|
|
19338
|
+
const body = {};
|
|
19339
|
+
if (opts.status)
|
|
19340
|
+
body.status = opts.status;
|
|
19341
|
+
if (opts.title)
|
|
19342
|
+
body.title = opts.title;
|
|
19343
|
+
if (description)
|
|
19344
|
+
body.description = description;
|
|
19345
|
+
if (Object.keys(body).length === 0) {
|
|
19346
|
+
console.error("Error: pass at least one of --status, --title, --description, --body-file");
|
|
19347
|
+
process.exit(1);
|
|
19348
|
+
}
|
|
19349
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts3(command, opts.agent_id);
|
|
19350
|
+
const client = new APIClient(serverUrl, token, workspaceId);
|
|
19351
|
+
try {
|
|
19352
|
+
const issue3 = await client.patchJSON(`/api/issues/${opts.issue_id}?agentId=${encodeURIComponent(opts.agent_id)}`, body);
|
|
19353
|
+
if (opts.json)
|
|
19354
|
+
return printJSON(issue3);
|
|
19355
|
+
printIssue(issue3);
|
|
19356
|
+
} catch (err) {
|
|
19357
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
19358
|
+
process.exit(1);
|
|
19359
|
+
}
|
|
19360
|
+
});
|
|
19361
|
+
cmd.command("comment").description("Append a comment to an issue").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--issue_id <id>", "Issue ID").option("--body <text>", "Comment text").option("--body-file <path>", "Read comment from a file").option("--json", "Output as JSON").action(async (opts, command) => {
|
|
19362
|
+
const content = readBody({ body: opts.body, bodyFile: opts.bodyFile }).trim();
|
|
19363
|
+
if (!content) {
|
|
19364
|
+
console.error("Error: pass --body or --body-file");
|
|
19365
|
+
process.exit(1);
|
|
19366
|
+
}
|
|
19367
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts3(command, opts.agent_id);
|
|
19368
|
+
const client = new APIClient(serverUrl, token, workspaceId);
|
|
19369
|
+
try {
|
|
19370
|
+
const res = await client.postJSON(`/api/issues/${opts.issue_id}?agentId=${encodeURIComponent(opts.agent_id)}`, { content });
|
|
19371
|
+
if (opts.json)
|
|
19372
|
+
return printJSON(res);
|
|
19373
|
+
console.log(`Commented on ${opts.issue_id}`);
|
|
19374
|
+
} catch (err) {
|
|
19375
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
19376
|
+
process.exit(1);
|
|
19377
|
+
}
|
|
19378
|
+
});
|
|
19379
|
+
return cmd;
|
|
19380
|
+
}
|
|
19381
|
+
|
|
19382
|
+
// commands/version.ts
|
|
19383
|
+
import { Command as Command8 } from "commander";
|
|
19117
19384
|
function versionCommand() {
|
|
19118
|
-
const cmd = new
|
|
19385
|
+
const cmd = new Command8("version").description("Show CLI version").action(() => {
|
|
19119
19386
|
console.log(`alook version ${getCurrentVersion()}`);
|
|
19120
19387
|
});
|
|
19121
19388
|
return cmd;
|
|
19122
19389
|
}
|
|
19123
19390
|
|
|
19124
19391
|
// commands/update.ts
|
|
19125
|
-
import { Command as
|
|
19392
|
+
import { Command as Command9 } from "commander";
|
|
19126
19393
|
function updateCommand() {
|
|
19127
|
-
const cmd = new
|
|
19394
|
+
const cmd = new Command9("update").description("Update CLI to the latest version").action(async () => {
|
|
19128
19395
|
const current = getCurrentVersion();
|
|
19129
19396
|
console.log(`Current version: ${current}`);
|
|
19130
19397
|
const latest = await fetchLatestVersion();
|
|
@@ -19158,8 +19425,8 @@ ${result.output}`);
|
|
|
19158
19425
|
}
|
|
19159
19426
|
|
|
19160
19427
|
// commands/sync.ts
|
|
19161
|
-
import { Command as
|
|
19162
|
-
import { readFileSync as
|
|
19428
|
+
import { Command as Command10 } from "commander";
|
|
19429
|
+
import { readFileSync as readFileSync9, statSync as statSync5 } from "fs";
|
|
19163
19430
|
import { basename as basename2 } from "path";
|
|
19164
19431
|
var MIME_BY_EXT2 = {
|
|
19165
19432
|
".pdf": "application/pdf",
|
|
@@ -19187,7 +19454,7 @@ function guessContentType2(filename) {
|
|
|
19187
19454
|
const ext = filename.slice(idx).toLowerCase();
|
|
19188
19455
|
return MIME_BY_EXT2[ext] ?? "application/octet-stream";
|
|
19189
19456
|
}
|
|
19190
|
-
function
|
|
19457
|
+
function resolveClientOpts4(command, agentId) {
|
|
19191
19458
|
const parentOpts = command.parent?.parent?.opts() || {};
|
|
19192
19459
|
const profile = parentOpts.profile;
|
|
19193
19460
|
const cfg = loadCLIConfigForProfile(profile);
|
|
@@ -19201,16 +19468,16 @@ function resolveClientOpts3(command, agentId) {
|
|
|
19201
19468
|
return { serverUrl, token: ws.token, workspaceId: ws.id };
|
|
19202
19469
|
}
|
|
19203
19470
|
function syncCommand() {
|
|
19204
|
-
const cmd = new
|
|
19471
|
+
const cmd = new Command10("sync").description("File sync utilities");
|
|
19205
19472
|
cmd.command("upload-artifact").description("Upload a file artifact to a conversation").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--conversation_id <id>", "Conversation ID").requiredOption("--file <path>", "Path to file to upload").action(async (opts, command) => {
|
|
19206
|
-
const { serverUrl, token, workspaceId } =
|
|
19473
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts4(command, opts.agent_id);
|
|
19207
19474
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
19208
19475
|
let bytes;
|
|
19209
19476
|
let size;
|
|
19210
19477
|
try {
|
|
19211
19478
|
const stat2 = statSync5(opts.file);
|
|
19212
19479
|
size = stat2.size;
|
|
19213
|
-
bytes =
|
|
19480
|
+
bytes = readFileSync9(opts.file);
|
|
19214
19481
|
} catch (err) {
|
|
19215
19482
|
console.error(`Error: cannot read file "${opts.file}": ${err.message}`);
|
|
19216
19483
|
process.exit(1);
|
|
@@ -19233,13 +19500,14 @@ function syncCommand() {
|
|
|
19233
19500
|
}
|
|
19234
19501
|
|
|
19235
19502
|
// src/index.ts
|
|
19236
|
-
var program = new
|
|
19503
|
+
var program = new Command11;
|
|
19237
19504
|
program.name("alook").description("Alook CLI").option("--server <url>", "Server URL").option("--profile <name>", "Profile name");
|
|
19238
19505
|
program.addCommand(registerCommand());
|
|
19239
19506
|
program.addCommand(statusCommand());
|
|
19240
19507
|
program.addCommand(daemonCommand());
|
|
19241
19508
|
program.addCommand(emailCommand());
|
|
19242
19509
|
program.addCommand(calendarCommand());
|
|
19510
|
+
program.addCommand(issueCommand());
|
|
19243
19511
|
program.addCommand(configCommand());
|
|
19244
19512
|
program.addCommand(versionCommand());
|
|
19245
19513
|
program.addCommand(updateCommand());
|
package/dist/session-runner.js
CHANGED
|
@@ -37,8 +37,29 @@ var TASK_TYPES = {
|
|
|
37
37
|
USER_DM_MESSAGE: "user_dm_message",
|
|
38
38
|
EMAIL_NOTIFICATION: "email_notification",
|
|
39
39
|
CALENDAR_EVENT: "calendar_event",
|
|
40
|
+
ISSUE_EVENT: "issue_event",
|
|
40
41
|
KILL_TASK: "kill_task"
|
|
41
42
|
};
|
|
43
|
+
var IssueStatus = {
|
|
44
|
+
TODO: "todo",
|
|
45
|
+
IN_PROGRESS: "in_progress",
|
|
46
|
+
REVIEW: "review",
|
|
47
|
+
DONE: "done",
|
|
48
|
+
CLOSED: "closed",
|
|
49
|
+
CANCELED: "canceled",
|
|
50
|
+
FAILED: "failed"
|
|
51
|
+
};
|
|
52
|
+
var ACTIVE_ISSUE_STATUSES = [
|
|
53
|
+
IssueStatus.TODO,
|
|
54
|
+
IssueStatus.IN_PROGRESS,
|
|
55
|
+
IssueStatus.REVIEW
|
|
56
|
+
];
|
|
57
|
+
var TERMINAL_ISSUE_STATUSES = [
|
|
58
|
+
IssueStatus.DONE,
|
|
59
|
+
IssueStatus.CLOSED,
|
|
60
|
+
IssueStatus.CANCELED,
|
|
61
|
+
IssueStatus.FAILED
|
|
62
|
+
];
|
|
42
63
|
var POLL_INTERVAL_MS = Number(process.env.POLL_INTERVAL_MS) || 3000;
|
|
43
64
|
var OFFLINE_THRESHOLD_MS = Number(process.env.OFFLINE_THRESHOLD_MS) || 9000;
|
|
44
65
|
var EVENT_POLL_INTERVAL_MS = Number(process.env.EVENT_POLL_INTERVAL_MS) || 2000;
|
|
@@ -14538,6 +14559,42 @@ var CalendarEventApiSchema = exports_external.object({
|
|
|
14538
14559
|
created_at: exports_external.string(),
|
|
14539
14560
|
updated_at: exports_external.string()
|
|
14540
14561
|
});
|
|
14562
|
+
var IssueStatusSchema = exports_external.enum([
|
|
14563
|
+
IssueStatus.TODO,
|
|
14564
|
+
IssueStatus.IN_PROGRESS,
|
|
14565
|
+
IssueStatus.REVIEW,
|
|
14566
|
+
IssueStatus.DONE,
|
|
14567
|
+
IssueStatus.CLOSED,
|
|
14568
|
+
IssueStatus.CANCELED,
|
|
14569
|
+
IssueStatus.FAILED
|
|
14570
|
+
]);
|
|
14571
|
+
var CreateIssueRequestSchema = exports_external.object({
|
|
14572
|
+
agent_id: exports_external.string().min(1, "agent_id is required"),
|
|
14573
|
+
title: exports_external.string().min(1, "title is required").max(200),
|
|
14574
|
+
description: exports_external.string().max(20000).optional().default("")
|
|
14575
|
+
});
|
|
14576
|
+
var UpdateIssueRequestSchema = exports_external.object({
|
|
14577
|
+
title: exports_external.string().min(1).max(200).optional(),
|
|
14578
|
+
description: exports_external.string().max(20000).optional(),
|
|
14579
|
+
status: IssueStatusSchema.optional()
|
|
14580
|
+
}).refine((v) => v.title !== undefined || v.description !== undefined || v.status !== undefined, { message: "at least one field is required" });
|
|
14581
|
+
var CreateIssueCommentRequestSchema = exports_external.object({
|
|
14582
|
+
content: exports_external.string().min(1, "content is required").max(20000)
|
|
14583
|
+
});
|
|
14584
|
+
var IssueApiSchema = exports_external.object({
|
|
14585
|
+
id: exports_external.string(),
|
|
14586
|
+
workspace_id: exports_external.string(),
|
|
14587
|
+
agent_id: exports_external.string(),
|
|
14588
|
+
creator_user_id: exports_external.string(),
|
|
14589
|
+
conversation_id: exports_external.string(),
|
|
14590
|
+
latest_task_id: exports_external.string().nullable(),
|
|
14591
|
+
title: exports_external.string(),
|
|
14592
|
+
description: exports_external.string(),
|
|
14593
|
+
status: IssueStatusSchema,
|
|
14594
|
+
created_at: exports_external.string(),
|
|
14595
|
+
updated_at: exports_external.string(),
|
|
14596
|
+
completed_at: exports_external.string().nullable()
|
|
14597
|
+
});
|
|
14541
14598
|
var CreateAgentLinkRequestSchema = exports_external.object({
|
|
14542
14599
|
source_agent_id: exports_external.string().min(1, "source_agent_id is required"),
|
|
14543
14600
|
target_agent_id: exports_external.string().min(1, "target_agent_id is required"),
|
|
@@ -16320,6 +16377,30 @@ var agentTaskQueue = sqliteTable("agent_task_queue", {
|
|
|
16320
16377
|
foreignColumns: [agent.id, agent.workspaceId]
|
|
16321
16378
|
}).onDelete("cascade")
|
|
16322
16379
|
]);
|
|
16380
|
+
var issue2 = sqliteTable("issue", {
|
|
16381
|
+
id: text("id").primaryKey().$defaultFn(() => "iss_" + nanoid3()),
|
|
16382
|
+
workspaceId: text("workspace_id").notNull().references(() => workspace.id, { onDelete: "cascade" }),
|
|
16383
|
+
agentId: text("agent_id").notNull(),
|
|
16384
|
+
creatorUserId: text("creator_user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
16385
|
+
conversationId: text("conversation_id").notNull().references(() => conversation.id, { onDelete: "cascade" }),
|
|
16386
|
+
latestTaskId: text("latest_task_id").references(() => agentTaskQueue.id, {
|
|
16387
|
+
onDelete: "set null"
|
|
16388
|
+
}),
|
|
16389
|
+
title: text("title").notNull(),
|
|
16390
|
+
description: text("description").notNull().default(""),
|
|
16391
|
+
status: text("status").notNull().default("todo"),
|
|
16392
|
+
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
|
|
16393
|
+
updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString()),
|
|
16394
|
+
completedAt: text("completed_at")
|
|
16395
|
+
}, (t) => [
|
|
16396
|
+
index("idx_issue_workspace_status_agent").on(t.workspaceId, t.status, t.agentId),
|
|
16397
|
+
index("idx_issue_workspace_updated").on(t.workspaceId, t.updatedAt),
|
|
16398
|
+
unique("issue_conversation_unique").on(t.conversationId),
|
|
16399
|
+
foreignKey({
|
|
16400
|
+
columns: [t.agentId, t.workspaceId],
|
|
16401
|
+
foreignColumns: [agent.id, agent.workspaceId]
|
|
16402
|
+
}).onDelete("cascade")
|
|
16403
|
+
]);
|
|
16323
16404
|
var taskMessage = sqliteTable("task_message", {
|
|
16324
16405
|
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
16325
16406
|
taskId: text("task_id").notNull().references(() => agentTaskQueue.id, { onDelete: "cascade" }),
|
|
@@ -17265,7 +17346,8 @@ class CodexBackend {
|
|
|
17265
17346
|
} else {
|
|
17266
17347
|
const threadParams = {
|
|
17267
17348
|
cwd: options.cwd,
|
|
17268
|
-
|
|
17349
|
+
sandboxPolicy: { type: "dangerFullAccess" },
|
|
17350
|
+
approvalPolicy: "never",
|
|
17269
17351
|
persistExtendedHistory: true,
|
|
17270
17352
|
experimentalRawEvents: false
|
|
17271
17353
|
};
|
|
@@ -17278,7 +17360,9 @@ class CodexBackend {
|
|
|
17278
17360
|
resolveSessionId(sessionId);
|
|
17279
17361
|
await sendRpc("turn/start", {
|
|
17280
17362
|
threadId: sessionId,
|
|
17281
|
-
input: [{ type: "text", text: prompt }]
|
|
17363
|
+
input: [{ type: "text", text: prompt }],
|
|
17364
|
+
sandboxPolicy: { type: "dangerFullAccess" },
|
|
17365
|
+
approvalPolicy: "never"
|
|
17282
17366
|
});
|
|
17283
17367
|
} catch (err) {
|
|
17284
17368
|
const errMsg = err instanceof Error ? err.message : "handshake failed";
|
|
@@ -17698,8 +17782,9 @@ ${task.agent.instructions}
|
|
|
17698
17782
|
## Your Colleagues
|
|
17699
17783
|
Below are your direct colleagues. You can reach them via email.
|
|
17700
17784
|
|
|
17701
|
-
**Important:**
|
|
17702
|
-
- When communicating with a colleague on the
|
|
17785
|
+
**Important:**
|
|
17786
|
+
- 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.
|
|
17787
|
+
- **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.
|
|
17703
17788
|
`;
|
|
17704
17789
|
for (let i = 0;i < task.agent.colleagues.length; i++) {
|
|
17705
17790
|
const c = task.agent.colleagues[i];
|
|
@@ -18234,12 +18319,17 @@ function clearKillIntent(baseDir, taskId) {
|
|
|
18234
18319
|
}
|
|
18235
18320
|
|
|
18236
18321
|
// daemon/prompt.ts
|
|
18322
|
+
var DM_RESPONSE_NOTICE = "IMPORTANT: Only your final text response is visible to the user." + " Tool calls, intermediate reasoning, and mid-process outputs are NOT displayed." + " Put all key information, answers, and conclusions in your final response — that is the only thing the user will read.";
|
|
18237
18323
|
var EMAIL_NOTICE = "This task was triggered automatically by an incoming email. There is no human in this session." + " If you need to communicate with a human, you MUST send an email using the email sending tool." + " If you need more information or confirmation from the human, send them an email asking for it and then exit." + " Do not wait — when the human replies, a new task will be triggered automatically and you will be woken up with their response.";
|
|
18324
|
+
var ISSUE_NOTICE = "This task was triggered by an assigned issue. Use `alook issue show`, `alook issue update`, and `alook issue comment` to inspect and update the issue as you work." + " Move the issue to in_progress when you begin, then to review, done, closed, canceled, or failed when appropriate.";
|
|
18238
18325
|
function buildDmNotice(name, email3) {
|
|
18239
18326
|
return `This task was triggered by an incoming email on a conversation with ${name} (${email3}).` + ` ${name} is present in this session — reply to them directly.` + ` If you need to communicate with anyone else, use the email sending tool.`;
|
|
18240
18327
|
}
|
|
18241
18328
|
function buildPrompt(task, attachments) {
|
|
18242
18329
|
const obj = { type: task.type, instruction: task.prompt };
|
|
18330
|
+
if (task.type === "user_dm_message") {
|
|
18331
|
+
obj.notice = DM_RESPONSE_NOTICE;
|
|
18332
|
+
}
|
|
18243
18333
|
if (task.type === "email_notification") {
|
|
18244
18334
|
const ctx = task.context;
|
|
18245
18335
|
const dmUser = ctx?.dmUser;
|
|
@@ -18249,6 +18339,9 @@ function buildPrompt(task, attachments) {
|
|
|
18249
18339
|
obj.notice = EMAIL_NOTICE;
|
|
18250
18340
|
}
|
|
18251
18341
|
}
|
|
18342
|
+
if (task.type === "issue_event") {
|
|
18343
|
+
obj.notice = ISSUE_NOTICE;
|
|
18344
|
+
}
|
|
18252
18345
|
if (task.sender) {
|
|
18253
18346
|
obj.sender = {
|
|
18254
18347
|
name: task.sender.name,
|