@alook/cli 0.0.3 → 0.0.4
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 +391 -10
- 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 Command8 } from "commander";
|
|
19
19
|
|
|
20
20
|
// commands/register.ts
|
|
21
21
|
import { Command } from "commander";
|
|
@@ -64,6 +64,25 @@ class APIClient {
|
|
|
64
64
|
patchJSON(path, body) {
|
|
65
65
|
return this.request("PATCH", path, body);
|
|
66
66
|
}
|
|
67
|
+
async postMultipart(path, form) {
|
|
68
|
+
const headers = {
|
|
69
|
+
Authorization: `Bearer ${this.token}`
|
|
70
|
+
};
|
|
71
|
+
if (this.workspaceId)
|
|
72
|
+
headers["X-Workspace-ID"] = this.workspaceId;
|
|
73
|
+
const res = await fetch(this.baseURL + path, {
|
|
74
|
+
method: "POST",
|
|
75
|
+
headers,
|
|
76
|
+
body: form
|
|
77
|
+
});
|
|
78
|
+
if (!res.ok) {
|
|
79
|
+
const text = await res.text();
|
|
80
|
+
throw new Error(`HTTP ${res.status}: ${text}`);
|
|
81
|
+
}
|
|
82
|
+
if (res.status === 204)
|
|
83
|
+
return;
|
|
84
|
+
return res.json();
|
|
85
|
+
}
|
|
67
86
|
async getText(path) {
|
|
68
87
|
const headers = {
|
|
69
88
|
Authorization: `Bearer ${this.token}`
|
|
@@ -281,6 +300,11 @@ import { openSync, closeSync, mkdirSync as mkdirSync3 } from "fs";
|
|
|
281
300
|
import { dirname as dirname3 } from "path";
|
|
282
301
|
|
|
283
302
|
// ../shared/src/constants.ts
|
|
303
|
+
var TASK_TYPES = {
|
|
304
|
+
USER_DM_MESSAGE: "user_dm_message",
|
|
305
|
+
EMAIL_NOTIFICATION: "email_notification",
|
|
306
|
+
CALENDAR_EVENT: "calendar_event"
|
|
307
|
+
};
|
|
284
308
|
var POLL_INTERVAL_MS = Number(process.env.POLL_INTERVAL_MS) || 3000;
|
|
285
309
|
var OFFLINE_THRESHOLD_MS = Number(process.env.OFFLINE_THRESHOLD_MS) || 9000;
|
|
286
310
|
var EVENT_POLL_INTERVAL_MS = Number(process.env.EVENT_POLL_INTERVAL_MS) || 2000;
|
|
@@ -13839,7 +13863,7 @@ var ClaimedTaskRowSchema = exports_external.object({
|
|
|
13839
13863
|
priority: exports_external.coerce.number(),
|
|
13840
13864
|
result: exports_external.unknown().nullable(),
|
|
13841
13865
|
context: exports_external.unknown().nullable(),
|
|
13842
|
-
type: exports_external.string().default(
|
|
13866
|
+
type: exports_external.string().default(TASK_TYPES.USER_DM_MESSAGE),
|
|
13843
13867
|
sessionId: exports_external.string().nullable(),
|
|
13844
13868
|
createdAt: exports_external.coerce.date(),
|
|
13845
13869
|
dispatchedAt: exports_external.coerce.date().nullable(),
|
|
@@ -13932,6 +13956,50 @@ var MessageItemSchema = exports_external.object({
|
|
|
13932
13956
|
var ReportMessagesRequestSchema = exports_external.object({
|
|
13933
13957
|
messages: exports_external.array(MessageItemSchema)
|
|
13934
13958
|
});
|
|
13959
|
+
var RepeatIntervalSchema = exports_external.string().regex(/^\d+(min|hour|day|week|month)$/, {
|
|
13960
|
+
message: "repeat_interval must match <positive_integer><min|hour|day|week|month>"
|
|
13961
|
+
});
|
|
13962
|
+
var CreateCalendarEventRequestSchema = exports_external.object({
|
|
13963
|
+
agent_id: exports_external.string().min(1),
|
|
13964
|
+
title: exports_external.string().min(1),
|
|
13965
|
+
description: exports_external.string().max(20000).optional(),
|
|
13966
|
+
scheduled_at: exports_external.string().min(1).refine((s) => !Number.isNaN(Date.parse(s)), {
|
|
13967
|
+
message: "scheduled_at must be a valid ISO datetime"
|
|
13968
|
+
}),
|
|
13969
|
+
repeat_interval: RepeatIntervalSchema.optional(),
|
|
13970
|
+
repeat_stop_date: exports_external.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional()
|
|
13971
|
+
}).refine((data) => !data.repeat_stop_date || !!data.repeat_interval, {
|
|
13972
|
+
message: "repeat_stop_date requires repeat_interval",
|
|
13973
|
+
path: ["repeat_stop_date"]
|
|
13974
|
+
});
|
|
13975
|
+
var UpdateCalendarEventRequestSchema = exports_external.object({
|
|
13976
|
+
title: exports_external.string().min(1).optional(),
|
|
13977
|
+
description: exports_external.string().max(20000).nullable().optional(),
|
|
13978
|
+
agent_id: exports_external.string().min(1).optional(),
|
|
13979
|
+
scheduled_at: exports_external.string().min(1).refine((s) => !Number.isNaN(Date.parse(s)), {
|
|
13980
|
+
message: "scheduled_at must be a valid ISO datetime"
|
|
13981
|
+
}).optional(),
|
|
13982
|
+
repeat_interval: RepeatIntervalSchema.nullable().optional(),
|
|
13983
|
+
repeat_stop_date: exports_external.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional(),
|
|
13984
|
+
scope: exports_external.enum(["this", "following"]).optional(),
|
|
13985
|
+
occurrence_at: exports_external.string().min(1).refine((s) => !Number.isNaN(Date.parse(s)), {
|
|
13986
|
+
message: "occurrence_at must be a valid ISO datetime"
|
|
13987
|
+
}).optional()
|
|
13988
|
+
}).refine((v) => v.title !== undefined || v.description !== undefined || v.agent_id !== undefined || v.scheduled_at !== undefined || v.repeat_interval !== undefined || v.repeat_stop_date !== undefined, { message: "at least one field is required" });
|
|
13989
|
+
var CalendarEventApiSchema = exports_external.object({
|
|
13990
|
+
id: exports_external.string(),
|
|
13991
|
+
agent_id: exports_external.string(),
|
|
13992
|
+
workspace_id: exports_external.string(),
|
|
13993
|
+
title: exports_external.string(),
|
|
13994
|
+
description: exports_external.string().nullable(),
|
|
13995
|
+
scheduled_at: exports_external.string(),
|
|
13996
|
+
occurrence_at: exports_external.string(),
|
|
13997
|
+
repeat_interval: exports_external.string().nullable(),
|
|
13998
|
+
repeat_stop_at: exports_external.string().nullable(),
|
|
13999
|
+
last_triggered_at: exports_external.string().nullable(),
|
|
14000
|
+
created_at: exports_external.string(),
|
|
14001
|
+
updated_at: exports_external.string()
|
|
14002
|
+
});
|
|
13935
14003
|
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260414.1_@opentelemetry+api@1.9.1_bun-types@1.3.12_kysely@0.28.15/node_modules/drizzle-orm/entity.js
|
|
13936
14004
|
var entityKind = Symbol.for("drizzle:entityKind");
|
|
13937
14005
|
var hasOwnEntityKind = Symbol.for("drizzle:hasOwnEntityKind");
|
|
@@ -15424,6 +15492,7 @@ var conversation = sqliteTable("conversation", {
|
|
|
15424
15492
|
agentId: text("agent_id").notNull(),
|
|
15425
15493
|
userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
15426
15494
|
title: text("title").notNull().default(""),
|
|
15495
|
+
type: text("type").notNull().default(TASK_TYPES.USER_DM_MESSAGE),
|
|
15427
15496
|
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
15428
15497
|
}, (t) => [
|
|
15429
15498
|
foreignKey({
|
|
@@ -15446,7 +15515,7 @@ var agentTaskQueue = sqliteTable("agent_task_queue", {
|
|
|
15446
15515
|
workspaceId: text("workspace_id").notNull().references(() => workspace.id),
|
|
15447
15516
|
conversationId: text("conversation_id").notNull().references(() => conversation.id),
|
|
15448
15517
|
prompt: text("prompt").notNull(),
|
|
15449
|
-
type: text("type").notNull().default(
|
|
15518
|
+
type: text("type").notNull().default(TASK_TYPES.USER_DM_MESSAGE),
|
|
15450
15519
|
status: text("status").notNull().default("queued"),
|
|
15451
15520
|
priority: integer2("priority").notNull().default(0),
|
|
15452
15521
|
result: text("result", { mode: "json" }),
|
|
@@ -15496,6 +15565,27 @@ var emails = sqliteTable("emails", {
|
|
|
15496
15565
|
foreignColumns: [agent.id, agent.workspaceId]
|
|
15497
15566
|
}).onDelete("cascade")
|
|
15498
15567
|
]);
|
|
15568
|
+
var calendarEvent = sqliteTable("calendar_event", {
|
|
15569
|
+
id: text("id").primaryKey().$defaultFn(() => "ce_" + nanoid3()),
|
|
15570
|
+
agentId: text("agent_id").notNull(),
|
|
15571
|
+
workspaceId: text("workspace_id").notNull(),
|
|
15572
|
+
title: text("title").notNull(),
|
|
15573
|
+
description: text("description"),
|
|
15574
|
+
scheduledAt: text("scheduled_at").notNull(),
|
|
15575
|
+
repeatInterval: text("repeat_interval"),
|
|
15576
|
+
repeatStopAt: text("repeat_stop_at"),
|
|
15577
|
+
lastTriggeredAt: text("last_triggered_at"),
|
|
15578
|
+
exceptions: text("exceptions", { mode: "json" }).$type().notNull().default(sql`'[]'`),
|
|
15579
|
+
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
|
|
15580
|
+
updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
15581
|
+
}, (t) => [
|
|
15582
|
+
index("idx_calendar_event_agent_ws").on(t.agentId, t.workspaceId),
|
|
15583
|
+
index("idx_calendar_event_ws_scheduled").on(t.workspaceId, t.scheduledAt),
|
|
15584
|
+
foreignKey({
|
|
15585
|
+
columns: [t.agentId, t.workspaceId],
|
|
15586
|
+
foreignColumns: [agent.id, agent.workspaceId]
|
|
15587
|
+
}).onDelete("cascade")
|
|
15588
|
+
]);
|
|
15499
15589
|
var machineToken = sqliteTable("machine_token", {
|
|
15500
15590
|
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
15501
15591
|
userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
@@ -16224,11 +16314,37 @@ function configCommand() {
|
|
|
16224
16314
|
|
|
16225
16315
|
// commands/email.ts
|
|
16226
16316
|
import { Command as Command5 } from "commander";
|
|
16227
|
-
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync4 } from "fs";
|
|
16228
|
-
import { join as join4 } from "path";
|
|
16317
|
+
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync3, statSync } from "fs";
|
|
16318
|
+
import { basename, join as join4 } from "path";
|
|
16229
16319
|
import PostalMime from "postal-mime";
|
|
16230
16320
|
var VALID_STATUSES = ["unread", "read", "archived"];
|
|
16231
16321
|
var EMAIL_DIR = "/tmp/alook-emails";
|
|
16322
|
+
var MIME_BY_EXT = {
|
|
16323
|
+
".pdf": "application/pdf",
|
|
16324
|
+
".png": "image/png",
|
|
16325
|
+
".jpg": "image/jpeg",
|
|
16326
|
+
".jpeg": "image/jpeg",
|
|
16327
|
+
".gif": "image/gif",
|
|
16328
|
+
".webp": "image/webp",
|
|
16329
|
+
".svg": "image/svg+xml",
|
|
16330
|
+
".txt": "text/plain",
|
|
16331
|
+
".html": "text/html",
|
|
16332
|
+
".htm": "text/html",
|
|
16333
|
+
".json": "application/json",
|
|
16334
|
+
".csv": "text/csv",
|
|
16335
|
+
".md": "text/markdown",
|
|
16336
|
+
".zip": "application/zip"
|
|
16337
|
+
};
|
|
16338
|
+
function guessContentType(filename) {
|
|
16339
|
+
const idx = filename.lastIndexOf(".");
|
|
16340
|
+
if (idx < 0)
|
|
16341
|
+
return "application/octet-stream";
|
|
16342
|
+
const ext = filename.slice(idx).toLowerCase();
|
|
16343
|
+
return MIME_BY_EXT[ext] ?? "application/octet-stream";
|
|
16344
|
+
}
|
|
16345
|
+
function collectRepeated(value, previous) {
|
|
16346
|
+
return previous.concat([value]);
|
|
16347
|
+
}
|
|
16232
16348
|
function resolveClientOpts(command, opts) {
|
|
16233
16349
|
const parentOpts = command.parent?.parent?.opts() || {};
|
|
16234
16350
|
const profile = parentOpts.profile;
|
|
@@ -16362,14 +16478,278 @@ function emailCommand() {
|
|
|
16362
16478
|
process.exit(1);
|
|
16363
16479
|
}
|
|
16364
16480
|
});
|
|
16481
|
+
cmd.command("send").description("Send an email from the agent").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--to <addr>", "Recipient email address").requiredOption("--subject <s>", "Subject line").requiredOption("--body-file <path>", "Path to HTML body file").option("--attachment <path>", "Path to a file to attach (repeatable)", collectRepeated, []).option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
|
|
16482
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts(command, {
|
|
16483
|
+
workspace: opts.workspace,
|
|
16484
|
+
agentId: opts.agent_id
|
|
16485
|
+
});
|
|
16486
|
+
const client = new APIClient(serverUrl, token, workspaceId);
|
|
16487
|
+
let htmlBody;
|
|
16488
|
+
try {
|
|
16489
|
+
htmlBody = readFileSync3(opts.bodyFile, "utf-8");
|
|
16490
|
+
} catch (err) {
|
|
16491
|
+
console.error(`Error: cannot read body file "${opts.bodyFile}": ${err instanceof Error ? err.message : err}`);
|
|
16492
|
+
process.exit(1);
|
|
16493
|
+
}
|
|
16494
|
+
if (!htmlBody) {
|
|
16495
|
+
console.error(`Error: body file "${opts.bodyFile}" is empty`);
|
|
16496
|
+
process.exit(1);
|
|
16497
|
+
}
|
|
16498
|
+
const attachmentPaths = opts.attachment ?? [];
|
|
16499
|
+
const attachments = [];
|
|
16500
|
+
try {
|
|
16501
|
+
for (const path of attachmentPaths) {
|
|
16502
|
+
let bytes;
|
|
16503
|
+
let size;
|
|
16504
|
+
try {
|
|
16505
|
+
bytes = readFileSync3(path);
|
|
16506
|
+
size = statSync(path).size;
|
|
16507
|
+
} catch (err) {
|
|
16508
|
+
console.error(`Error: cannot read attachment "${path}": ${err instanceof Error ? err.message : err}`);
|
|
16509
|
+
process.exit(1);
|
|
16510
|
+
}
|
|
16511
|
+
const filename = basename(path);
|
|
16512
|
+
const contentType = guessContentType(filename);
|
|
16513
|
+
const form = new FormData;
|
|
16514
|
+
form.append("file", new Blob([new Uint8Array(bytes)], { type: contentType }), filename);
|
|
16515
|
+
const uploaded = await client.postMultipart("/api/email/upload", form);
|
|
16516
|
+
attachments.push({
|
|
16517
|
+
key: uploaded.key,
|
|
16518
|
+
filename: uploaded.filename,
|
|
16519
|
+
size: uploaded.size ?? size,
|
|
16520
|
+
contentType: uploaded.contentType ?? contentType
|
|
16521
|
+
});
|
|
16522
|
+
}
|
|
16523
|
+
const res = await client.postJSON("/api/email/send", {
|
|
16524
|
+
agentId: opts.agent_id,
|
|
16525
|
+
to: opts.to,
|
|
16526
|
+
subject: opts.subject,
|
|
16527
|
+
htmlBody,
|
|
16528
|
+
attachments
|
|
16529
|
+
});
|
|
16530
|
+
console.log(`Sent email to ${res.to_email} (id: ${res.id})`);
|
|
16531
|
+
} catch (err) {
|
|
16532
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
16533
|
+
process.exit(1);
|
|
16534
|
+
}
|
|
16535
|
+
});
|
|
16365
16536
|
return cmd;
|
|
16366
16537
|
}
|
|
16367
16538
|
|
|
16368
|
-
// commands/
|
|
16539
|
+
// commands/calendar.ts
|
|
16369
16540
|
import { Command as Command6 } from "commander";
|
|
16541
|
+
function resolveClientOpts2(command, agentId) {
|
|
16542
|
+
const parentOpts = command.parent?.parent?.opts() || {};
|
|
16543
|
+
const profile = parentOpts.profile;
|
|
16544
|
+
const cfg = loadCLIConfigForProfile(profile);
|
|
16545
|
+
const serverUrl = parentOpts.server || cfg.server_url;
|
|
16546
|
+
const workspaces = cfg.watched_workspaces || [];
|
|
16547
|
+
const ws = workspaces.find((w) => w.agent_ids?.includes(agentId));
|
|
16548
|
+
if (!ws || !ws.token) {
|
|
16549
|
+
console.error(`Error: no registered workspace contains agent ${agentId}. Run '${cmdPrefix()} register --token <token>' first.`);
|
|
16550
|
+
process.exit(1);
|
|
16551
|
+
}
|
|
16552
|
+
return { serverUrl, token: ws.token, workspaceId: ws.id };
|
|
16553
|
+
}
|
|
16554
|
+
function parseLocalDatetime(input) {
|
|
16555
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?$/.exec(input);
|
|
16556
|
+
if (!match) {
|
|
16557
|
+
throw new Error(`invalid --datetime "${input}" — expected YYYY-MM-DDTHH:MM`);
|
|
16558
|
+
}
|
|
16559
|
+
const [, y, mo, d, h, mi, s] = match;
|
|
16560
|
+
const date5 = new Date(Number(y), Number(mo) - 1, Number(d), Number(h), Number(mi), s ? Number(s) : 0);
|
|
16561
|
+
return date5.toISOString();
|
|
16562
|
+
}
|
|
16563
|
+
function formatLocalDatetime(iso) {
|
|
16564
|
+
const d = new Date(iso);
|
|
16565
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
16566
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
|
16567
|
+
}
|
|
16568
|
+
function printEventDetail(ev) {
|
|
16569
|
+
console.log(`id: ${ev.id}`);
|
|
16570
|
+
console.log(`agent_id: ${ev.agent_id}`);
|
|
16571
|
+
console.log(`title: ${ev.title}`);
|
|
16572
|
+
console.log(`scheduled_at: ${formatLocalDatetime(ev.scheduled_at)}`);
|
|
16573
|
+
if (ev.repeat_interval) {
|
|
16574
|
+
const until = ev.repeat_stop_at ? ` until ${formatLocalDatetime(ev.repeat_stop_at)}` : "";
|
|
16575
|
+
console.log(`repeat: every ${ev.repeat_interval}${until}`);
|
|
16576
|
+
} else {
|
|
16577
|
+
console.log(`repeat: (none)`);
|
|
16578
|
+
}
|
|
16579
|
+
console.log(`last_fired_at: ${ev.last_triggered_at ? formatLocalDatetime(ev.last_triggered_at) : "(never)"}`);
|
|
16580
|
+
console.log("description:");
|
|
16581
|
+
console.log(ev.description ?? "(no description)");
|
|
16582
|
+
}
|
|
16583
|
+
function calendarCommand() {
|
|
16584
|
+
const cmd = new Command6("calendar").description("Manage scheduled agent events");
|
|
16585
|
+
cmd.command("set").description("Create a calendar event").requiredOption("--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) => {
|
|
16586
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts2(command, opts.agent_id);
|
|
16587
|
+
const client = new APIClient(serverUrl, token, workspaceId);
|
|
16588
|
+
let scheduledAt;
|
|
16589
|
+
try {
|
|
16590
|
+
scheduledAt = parseLocalDatetime(opts.datetime);
|
|
16591
|
+
} catch (err) {
|
|
16592
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
16593
|
+
process.exit(1);
|
|
16594
|
+
}
|
|
16595
|
+
if (opts.repeat_stop_date && !opts.repeat) {
|
|
16596
|
+
console.error("Error: --repeat_stop_date requires --repeat");
|
|
16597
|
+
process.exit(1);
|
|
16598
|
+
}
|
|
16599
|
+
if (opts.repeat_stop_date && !/^\d{4}-\d{2}-\d{2}$/.test(opts.repeat_stop_date)) {
|
|
16600
|
+
console.error("Error: --repeat_stop_date must be YYYY-MM-DD");
|
|
16601
|
+
process.exit(1);
|
|
16602
|
+
}
|
|
16603
|
+
const body = {
|
|
16604
|
+
agent_id: opts.agent_id,
|
|
16605
|
+
title: opts.event_title,
|
|
16606
|
+
scheduled_at: scheduledAt
|
|
16607
|
+
};
|
|
16608
|
+
if (opts.description)
|
|
16609
|
+
body.description = opts.description;
|
|
16610
|
+
if (opts.repeat)
|
|
16611
|
+
body.repeat_interval = opts.repeat;
|
|
16612
|
+
if (opts.repeat_stop_date)
|
|
16613
|
+
body.repeat_stop_date = opts.repeat_stop_date;
|
|
16614
|
+
try {
|
|
16615
|
+
const created = await client.postJSON("/api/calendar", body);
|
|
16616
|
+
if (opts.json) {
|
|
16617
|
+
printJSON(created);
|
|
16618
|
+
return;
|
|
16619
|
+
}
|
|
16620
|
+
console.log(`Created ${created.id} — ${created.title} @ ${formatLocalDatetime(created.scheduled_at)}${created.repeat_interval ? ` (every ${created.repeat_interval})` : ""}`);
|
|
16621
|
+
} catch (err) {
|
|
16622
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
16623
|
+
process.exit(1);
|
|
16624
|
+
}
|
|
16625
|
+
});
|
|
16626
|
+
cmd.command("list").description("List calendar events for an agent").requiredOption("--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) => {
|
|
16627
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts2(command, opts.agent_id);
|
|
16628
|
+
const client = new APIClient(serverUrl, token, workspaceId);
|
|
16629
|
+
const now = Date.now();
|
|
16630
|
+
const from = new Date(now - Number(opts.past_days) * 86400000).toISOString();
|
|
16631
|
+
const to = new Date(now + Number(opts.future_days) * 86400000).toISOString();
|
|
16632
|
+
try {
|
|
16633
|
+
const events = await client.getJSON(`/api/calendar?agentId=${encodeURIComponent(opts.agent_id)}&from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`);
|
|
16634
|
+
if (opts.json) {
|
|
16635
|
+
printJSON(events);
|
|
16636
|
+
return;
|
|
16637
|
+
}
|
|
16638
|
+
if (events.length === 0) {
|
|
16639
|
+
console.log("No calendar events.");
|
|
16640
|
+
return;
|
|
16641
|
+
}
|
|
16642
|
+
for (const ev of events) {
|
|
16643
|
+
const repeatBadge = ev.repeat_interval ? ` [every ${ev.repeat_interval}${ev.repeat_stop_at ? ` until ${formatLocalDatetime(ev.repeat_stop_at)}` : ""}]` : "";
|
|
16644
|
+
const descBadge = ev.description ? " [has description]" : "";
|
|
16645
|
+
console.log(`${ev.id} ${formatLocalDatetime(ev.scheduled_at)} ${ev.title}${repeatBadge}${descBadge}`);
|
|
16646
|
+
}
|
|
16647
|
+
} catch (err) {
|
|
16648
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
16649
|
+
process.exit(1);
|
|
16650
|
+
}
|
|
16651
|
+
});
|
|
16652
|
+
cmd.command("show").description("Show the full detail of a single calendar event").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--event_id <id>", "Event ID").option("--json", "Output as JSON").action(async (opts, command) => {
|
|
16653
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts2(command, opts.agent_id);
|
|
16654
|
+
const client = new APIClient(serverUrl, token, workspaceId);
|
|
16655
|
+
try {
|
|
16656
|
+
const ev = await client.getJSON(`/api/calendar/${opts.event_id}`);
|
|
16657
|
+
if (ev.agent_id !== opts.agent_id) {
|
|
16658
|
+
console.error(`Error: event ${ev.id} does not belong to agent ${opts.agent_id}`);
|
|
16659
|
+
process.exit(1);
|
|
16660
|
+
}
|
|
16661
|
+
if (opts.json) {
|
|
16662
|
+
printJSON(ev);
|
|
16663
|
+
return;
|
|
16664
|
+
}
|
|
16665
|
+
printEventDetail(ev);
|
|
16666
|
+
} catch (err) {
|
|
16667
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
16668
|
+
process.exit(1);
|
|
16669
|
+
}
|
|
16670
|
+
});
|
|
16671
|
+
cmd.command("update").description("Update fields on an existing calendar event").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--event_id <id>", "Event ID").option("--event_title <title>", "New event title (task prompt)").option("--description <text>", "New description text").option("--clear_description", "Remove the description (sets to null)").option("--datetime <iso>", "New scheduled datetime (YYYY-MM-DDTHH:MM, local time)").option("--repeat <interval>", "New repeat interval, e.g. 1day, 2hour").option("--clear_repeat", "Convert a repeating event into a one-off").option("--repeat_stop_date <date>", "New stop date (YYYY-MM-DD, local time)").option("--clear_repeat_stop_date", "Remove the repeat stop date").option("--json", "Output as JSON").action(async (opts, command) => {
|
|
16672
|
+
if (opts.description && opts.clear_description) {
|
|
16673
|
+
console.error("Error: --description and --clear_description are mutually exclusive");
|
|
16674
|
+
process.exit(1);
|
|
16675
|
+
}
|
|
16676
|
+
if (opts.repeat && opts.clear_repeat) {
|
|
16677
|
+
console.error("Error: --repeat and --clear_repeat are mutually exclusive");
|
|
16678
|
+
process.exit(1);
|
|
16679
|
+
}
|
|
16680
|
+
if (opts.repeat_stop_date && opts.clear_repeat_stop_date) {
|
|
16681
|
+
console.error("Error: --repeat_stop_date and --clear_repeat_stop_date are mutually exclusive");
|
|
16682
|
+
process.exit(1);
|
|
16683
|
+
}
|
|
16684
|
+
const body = {};
|
|
16685
|
+
if (opts.event_title)
|
|
16686
|
+
body.title = opts.event_title;
|
|
16687
|
+
if (opts.description)
|
|
16688
|
+
body.description = opts.description;
|
|
16689
|
+
if (opts.clear_description)
|
|
16690
|
+
body.description = null;
|
|
16691
|
+
if (opts.datetime) {
|
|
16692
|
+
try {
|
|
16693
|
+
body.scheduled_at = parseLocalDatetime(opts.datetime);
|
|
16694
|
+
} catch (err) {
|
|
16695
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
16696
|
+
process.exit(1);
|
|
16697
|
+
}
|
|
16698
|
+
}
|
|
16699
|
+
if (opts.repeat)
|
|
16700
|
+
body.repeat_interval = opts.repeat;
|
|
16701
|
+
if (opts.clear_repeat)
|
|
16702
|
+
body.repeat_interval = null;
|
|
16703
|
+
if (opts.repeat_stop_date) {
|
|
16704
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(opts.repeat_stop_date)) {
|
|
16705
|
+
console.error("Error: --repeat_stop_date must be YYYY-MM-DD");
|
|
16706
|
+
process.exit(1);
|
|
16707
|
+
}
|
|
16708
|
+
body.repeat_stop_date = opts.repeat_stop_date;
|
|
16709
|
+
}
|
|
16710
|
+
if (opts.clear_repeat_stop_date)
|
|
16711
|
+
body.repeat_stop_date = null;
|
|
16712
|
+
if (Object.keys(body).length === 0) {
|
|
16713
|
+
console.error("Error: no fields to update — pass at least one of --event_title, --description, --clear_description, --datetime, --repeat, --clear_repeat, --repeat_stop_date, --clear_repeat_stop_date");
|
|
16714
|
+
process.exit(1);
|
|
16715
|
+
}
|
|
16716
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts2(command, opts.agent_id);
|
|
16717
|
+
const client = new APIClient(serverUrl, token, workspaceId);
|
|
16718
|
+
try {
|
|
16719
|
+
const updated = await client.patchJSON(`/api/calendar/${opts.event_id}`, body);
|
|
16720
|
+
if (updated.agent_id !== opts.agent_id) {
|
|
16721
|
+
console.error(`Error: event ${updated.id} does not belong to agent ${opts.agent_id}`);
|
|
16722
|
+
process.exit(1);
|
|
16723
|
+
}
|
|
16724
|
+
if (opts.json) {
|
|
16725
|
+
printJSON(updated);
|
|
16726
|
+
return;
|
|
16727
|
+
}
|
|
16728
|
+
printEventDetail(updated);
|
|
16729
|
+
} catch (err) {
|
|
16730
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
16731
|
+
process.exit(1);
|
|
16732
|
+
}
|
|
16733
|
+
});
|
|
16734
|
+
cmd.command("delete").description("Delete a calendar event").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--event_id <id>", "Event ID").action(async (opts, command) => {
|
|
16735
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts2(command, opts.agent_id);
|
|
16736
|
+
const client = new APIClient(serverUrl, token, workspaceId);
|
|
16737
|
+
try {
|
|
16738
|
+
await client.deleteJSON(`/api/calendar/${opts.event_id}`);
|
|
16739
|
+
console.log(`Deleted ${opts.event_id}`);
|
|
16740
|
+
} catch (err) {
|
|
16741
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
16742
|
+
process.exit(1);
|
|
16743
|
+
}
|
|
16744
|
+
});
|
|
16745
|
+
return cmd;
|
|
16746
|
+
}
|
|
16747
|
+
|
|
16748
|
+
// commands/version.ts
|
|
16749
|
+
import { Command as Command7 } from "commander";
|
|
16370
16750
|
|
|
16371
16751
|
// lib/version.ts
|
|
16372
|
-
import { readFileSync as
|
|
16752
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
16373
16753
|
import { join as join5, dirname as dirname4 } from "path";
|
|
16374
16754
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
16375
16755
|
function getCurrentVersion() {
|
|
@@ -16380,7 +16760,7 @@ function getCurrentVersion() {
|
|
|
16380
16760
|
];
|
|
16381
16761
|
for (const candidate of candidates) {
|
|
16382
16762
|
try {
|
|
16383
|
-
const pkg = JSON.parse(
|
|
16763
|
+
const pkg = JSON.parse(readFileSync4(candidate, "utf-8"));
|
|
16384
16764
|
if (typeof pkg.version === "string")
|
|
16385
16765
|
return pkg.version;
|
|
16386
16766
|
} catch {}
|
|
@@ -16390,19 +16770,20 @@ function getCurrentVersion() {
|
|
|
16390
16770
|
|
|
16391
16771
|
// commands/version.ts
|
|
16392
16772
|
function versionCommand() {
|
|
16393
|
-
const cmd = new
|
|
16773
|
+
const cmd = new Command7("version").description("Show CLI version").action(() => {
|
|
16394
16774
|
console.log(`alook version ${getCurrentVersion()}`);
|
|
16395
16775
|
});
|
|
16396
16776
|
return cmd;
|
|
16397
16777
|
}
|
|
16398
16778
|
|
|
16399
16779
|
// src/index.ts
|
|
16400
|
-
var program = new
|
|
16780
|
+
var program = new Command8;
|
|
16401
16781
|
program.name("alook").description("Alook CLI").option("--server <url>", "Server URL").option("--profile <name>", "Profile name");
|
|
16402
16782
|
program.addCommand(registerCommand());
|
|
16403
16783
|
program.addCommand(statusCommand());
|
|
16404
16784
|
program.addCommand(daemonCommand());
|
|
16405
16785
|
program.addCommand(emailCommand());
|
|
16786
|
+
program.addCommand(calendarCommand());
|
|
16406
16787
|
program.addCommand(configCommand());
|
|
16407
16788
|
program.addCommand(versionCommand());
|
|
16408
16789
|
program.parse();
|