@alook/cli 0.0.11 → 0.0.13
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 +98 -15
- package/dist/session-runner.js +128 -49
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13878,6 +13878,7 @@ var TaskAgentDataApiSchema = exports_external.object({
|
|
|
13878
13878
|
name: exports_external.string(),
|
|
13879
13879
|
runtime_config: exports_external.record(exports_external.string(), exports_external.unknown()).default({}),
|
|
13880
13880
|
email_handle: exports_external.string().nullable().optional(),
|
|
13881
|
+
email_addresses: exports_external.array(exports_external.string()).default([]),
|
|
13881
13882
|
user_email: exports_external.string().nullable().optional()
|
|
13882
13883
|
});
|
|
13883
13884
|
var TaskApiBaseSchema = exports_external.object({
|
|
@@ -14039,6 +14040,9 @@ var CreateConversationRequestSchema = exports_external.object({
|
|
|
14039
14040
|
var CreateMessageRequestSchema = exports_external.object({
|
|
14040
14041
|
content: exports_external.string().min(1, "content is required")
|
|
14041
14042
|
});
|
|
14043
|
+
var CreateBufferedMessageRequestSchema = exports_external.object({
|
|
14044
|
+
content: exports_external.string().min(1, "content is required")
|
|
14045
|
+
});
|
|
14042
14046
|
var EmailAttachmentSchema = exports_external.object({
|
|
14043
14047
|
key: exports_external.string().min(1),
|
|
14044
14048
|
filename: exports_external.string().min(1),
|
|
@@ -14052,7 +14056,9 @@ var SendEmailRequestSchema = exports_external.object({
|
|
|
14052
14056
|
htmlBody: exports_external.string().default(""),
|
|
14053
14057
|
inReplyTo: exports_external.string().optional(),
|
|
14054
14058
|
references: exports_external.string().optional(),
|
|
14055
|
-
attachments: exports_external.array(EmailAttachmentSchema).optional()
|
|
14059
|
+
attachments: exports_external.array(EmailAttachmentSchema).optional(),
|
|
14060
|
+
customAccountId: exports_external.string().optional(),
|
|
14061
|
+
from: exports_external.string().email().optional()
|
|
14056
14062
|
});
|
|
14057
14063
|
var UpdateEmailStatusRequestSchema = exports_external.object({
|
|
14058
14064
|
status: exports_external.enum(["unread", "read", "archived"])
|
|
@@ -14070,6 +14076,48 @@ var EmailNotifyRequestSchema = exports_external.object({
|
|
|
14070
14076
|
inReplyTo: exports_external.string().optional().default(""),
|
|
14071
14077
|
references: exports_external.string().optional().default("")
|
|
14072
14078
|
});
|
|
14079
|
+
var CreateEmailAccountSchema = exports_external.object({
|
|
14080
|
+
emailAddress: exports_external.string().email("valid email required"),
|
|
14081
|
+
displayName: exports_external.string().default(""),
|
|
14082
|
+
imapHost: exports_external.string().min(1, "IMAP host is required"),
|
|
14083
|
+
imapPort: exports_external.number().int().min(1).max(65535).default(993),
|
|
14084
|
+
imapUsername: exports_external.string().min(1, "IMAP username is required"),
|
|
14085
|
+
imapPassword: exports_external.string().min(1, "IMAP password is required"),
|
|
14086
|
+
imapTls: exports_external.boolean().default(true),
|
|
14087
|
+
smtpHost: exports_external.string().min(1, "SMTP host is required"),
|
|
14088
|
+
smtpPort: exports_external.number().int().min(1).max(65535).default(587),
|
|
14089
|
+
smtpUsername: exports_external.string().min(1, "SMTP username is required"),
|
|
14090
|
+
smtpPassword: exports_external.string().min(1, "SMTP password is required"),
|
|
14091
|
+
smtpTls: exports_external.number().int().min(0).max(2).default(1),
|
|
14092
|
+
pollIntervalSeconds: exports_external.number().int().min(30).max(3600).default(60)
|
|
14093
|
+
});
|
|
14094
|
+
var UpdateEmailAccountSchema = exports_external.object({
|
|
14095
|
+
emailAddress: exports_external.string().email().optional(),
|
|
14096
|
+
displayName: exports_external.string().optional(),
|
|
14097
|
+
imapHost: exports_external.string().min(1).optional(),
|
|
14098
|
+
imapPort: exports_external.number().int().min(1).max(65535).optional(),
|
|
14099
|
+
imapUsername: exports_external.string().min(1).optional(),
|
|
14100
|
+
imapPassword: exports_external.string().min(1).optional(),
|
|
14101
|
+
imapTls: exports_external.boolean().optional(),
|
|
14102
|
+
smtpHost: exports_external.string().min(1).optional(),
|
|
14103
|
+
smtpPort: exports_external.number().int().min(1).max(65535).optional(),
|
|
14104
|
+
smtpUsername: exports_external.string().min(1).optional(),
|
|
14105
|
+
smtpPassword: exports_external.string().min(1).optional(),
|
|
14106
|
+
smtpTls: exports_external.number().int().min(0).max(2).optional(),
|
|
14107
|
+
pollIntervalSeconds: exports_external.number().int().min(30).max(3600).optional()
|
|
14108
|
+
});
|
|
14109
|
+
var TestEmailConnectionSchema = exports_external.object({
|
|
14110
|
+
imapHost: exports_external.string().min(1),
|
|
14111
|
+
imapPort: exports_external.number().int().min(1).max(65535).default(993),
|
|
14112
|
+
imapUsername: exports_external.string().min(1),
|
|
14113
|
+
imapPassword: exports_external.string().min(1),
|
|
14114
|
+
imapTls: exports_external.boolean().default(true),
|
|
14115
|
+
smtpHost: exports_external.string().min(1),
|
|
14116
|
+
smtpPort: exports_external.number().int().min(1).max(65535).default(587),
|
|
14117
|
+
smtpUsername: exports_external.string().min(1),
|
|
14118
|
+
smtpPassword: exports_external.string().min(1),
|
|
14119
|
+
smtpTls: exports_external.number().int().min(0).max(2).default(1)
|
|
14120
|
+
});
|
|
14073
14121
|
var CreateWorkspaceRequestSchema = exports_external.object({
|
|
14074
14122
|
name: exports_external.string().min(1, "name is required"),
|
|
14075
14123
|
slug: exports_external.string().min(1, "slug is required")
|
|
@@ -15581,8 +15629,11 @@ var message = sqliteTable("message", {
|
|
|
15581
15629
|
content: text("content").notNull().default(""),
|
|
15582
15630
|
taskId: text("task_id"),
|
|
15583
15631
|
attachmentIds: text("attachment_ids"),
|
|
15632
|
+
status: text("status").notNull().default("active"),
|
|
15584
15633
|
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
15585
|
-
})
|
|
15634
|
+
}, (t) => [
|
|
15635
|
+
index("idx_message_conversation_status").on(t.conversationId, t.status)
|
|
15636
|
+
]);
|
|
15586
15637
|
var agentTaskQueue = sqliteTable("agent_task_queue", {
|
|
15587
15638
|
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
15588
15639
|
agentId: text("agent_id").notNull(),
|
|
@@ -15683,6 +15734,37 @@ var artifact = sqliteTable("artifact", {
|
|
|
15683
15734
|
foreignColumns: [agent.id, agent.workspaceId]
|
|
15684
15735
|
}).onDelete("cascade")
|
|
15685
15736
|
]);
|
|
15737
|
+
var agentEmailAccount = sqliteTable("agent_email_account", {
|
|
15738
|
+
id: text("id").primaryKey().$defaultFn(() => "aea_" + nanoid3()),
|
|
15739
|
+
agentId: text("agent_id").notNull(),
|
|
15740
|
+
workspaceId: text("workspace_id").notNull(),
|
|
15741
|
+
emailAddress: text("email_address").notNull(),
|
|
15742
|
+
displayName: text("display_name").notNull().default(""),
|
|
15743
|
+
imapHost: text("imap_host").notNull(),
|
|
15744
|
+
imapPort: integer2("imap_port").notNull().default(993),
|
|
15745
|
+
imapUsername: text("imap_username").notNull(),
|
|
15746
|
+
imapPassword: text("imap_password").notNull(),
|
|
15747
|
+
imapTls: integer2("imap_tls", { mode: "boolean" }).notNull().default(true),
|
|
15748
|
+
smtpHost: text("smtp_host").notNull(),
|
|
15749
|
+
smtpPort: integer2("smtp_port").notNull().default(587),
|
|
15750
|
+
smtpUsername: text("smtp_username").notNull(),
|
|
15751
|
+
smtpPassword: text("smtp_password").notNull(),
|
|
15752
|
+
smtpTls: integer2("smtp_tls").notNull().default(1),
|
|
15753
|
+
pollIntervalSeconds: integer2("poll_interval_seconds").notNull().default(60),
|
|
15754
|
+
lastSyncedUid: text("last_synced_uid").notNull().default("0"),
|
|
15755
|
+
lastSyncedAt: text("last_synced_at"),
|
|
15756
|
+
status: text("status").notNull().default("active"),
|
|
15757
|
+
errorMessage: text("error_message").notNull().default(""),
|
|
15758
|
+
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
|
|
15759
|
+
updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
15760
|
+
}, (t) => [
|
|
15761
|
+
index("idx_email_account_agent_ws").on(t.agentId, t.workspaceId),
|
|
15762
|
+
unique("email_account_agent_email").on(t.agentId, t.emailAddress),
|
|
15763
|
+
foreignKey({
|
|
15764
|
+
columns: [t.agentId, t.workspaceId],
|
|
15765
|
+
foreignColumns: [agent.id, agent.workspaceId]
|
|
15766
|
+
}).onDelete("cascade")
|
|
15767
|
+
]);
|
|
15686
15768
|
var machineToken = sqliteTable("machine_token", {
|
|
15687
15769
|
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
15688
15770
|
userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
@@ -15888,7 +15970,7 @@ function loadDaemonConfig(profile) {
|
|
|
15888
15970
|
codexModel: process.env.ALOOK_CODEX_MODEL || "",
|
|
15889
15971
|
opencodeModel: process.env.ALOOK_OPENCODE_MODEL || "",
|
|
15890
15972
|
pollInterval: parseDuration(process.env.ALOOK_DAEMON_POLL_INTERVAL || "3s"),
|
|
15891
|
-
agentTimeout: parseDuration(process.env.ALOOK_AGENT_TIMEOUT || "
|
|
15973
|
+
agentTimeout: parseDuration(process.env.ALOOK_AGENT_TIMEOUT || "12h"),
|
|
15892
15974
|
maxConcurrentTasks: parseInt(process.env.ALOOK_DAEMON_MAX_CONCURRENT_TASKS || "20"),
|
|
15893
15975
|
daemonId,
|
|
15894
15976
|
deviceName: process.env.ALOOK_DAEMON_DEVICE_NAME || h,
|
|
@@ -15964,7 +16046,7 @@ function fromApiTask(api2) {
|
|
|
15964
16046
|
type: api2.type,
|
|
15965
16047
|
contextKey: api2.context_key ?? null,
|
|
15966
16048
|
context: api2.context ?? undefined,
|
|
15967
|
-
agent: api2.agent ? { name: api2.agent.name, instructions: api2.agent.instructions, emailHandle: api2.agent.email_handle ?? undefined, userEmail: api2.agent.user_email ?? undefined, runtimeConfig: api2.agent.runtime_config ?? undefined } : undefined,
|
|
16049
|
+
agent: api2.agent ? { name: api2.agent.name, instructions: api2.agent.instructions, emailHandle: api2.agent.email_handle ?? undefined, emailAddresses: api2.agent.email_addresses ?? [], userEmail: api2.agent.user_email ?? undefined, runtimeConfig: api2.agent.runtime_config ?? undefined } : undefined,
|
|
15968
16050
|
repos: undefined,
|
|
15969
16051
|
createdAt: api2.created_at
|
|
15970
16052
|
};
|
|
@@ -16001,10 +16083,13 @@ function useColor() {
|
|
|
16001
16083
|
}
|
|
16002
16084
|
function timestamp() {
|
|
16003
16085
|
const d = new Date;
|
|
16086
|
+
const Y = d.getFullYear();
|
|
16087
|
+
const M = String(d.getMonth() + 1).padStart(2, "0");
|
|
16088
|
+
const D = String(d.getDate()).padStart(2, "0");
|
|
16004
16089
|
const h = String(d.getHours()).padStart(2, "0");
|
|
16005
16090
|
const m = String(d.getMinutes()).padStart(2, "0");
|
|
16006
16091
|
const s = String(d.getSeconds()).padStart(2, "0");
|
|
16007
|
-
return `${h}:${m}:${s}`;
|
|
16092
|
+
return `${Y}-${M}-${D} ${h}:${m}:${s}`;
|
|
16008
16093
|
}
|
|
16009
16094
|
|
|
16010
16095
|
class Logger2 {
|
|
@@ -16193,7 +16278,7 @@ async function handleCliUpdate(version3, onSuccess, profile) {
|
|
|
16193
16278
|
}
|
|
16194
16279
|
|
|
16195
16280
|
// daemon/daemon.ts
|
|
16196
|
-
import { existsSync, mkdirSync as mkdirSync3, openSync, closeSync,
|
|
16281
|
+
import { existsSync, mkdirSync as mkdirSync3, openSync, closeSync, readdirSync, statSync, unlinkSync as unlinkSync3 } from "fs";
|
|
16197
16282
|
import { execSync as execSync3, spawn as spawn2 } from "child_process";
|
|
16198
16283
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
16199
16284
|
import { dirname as dirname3, join as join4 } from "path";
|
|
@@ -16468,21 +16553,18 @@ async function startDaemon(profile, serverUrl) {
|
|
|
16468
16553
|
await pollCycle();
|
|
16469
16554
|
}
|
|
16470
16555
|
function spawnSessionRunner(input) {
|
|
16471
|
-
const encoded = Buffer.from(JSON.stringify(input)).toString("base64");
|
|
16472
16556
|
const logDir = sessionRunnerLogDir();
|
|
16473
16557
|
mkdirSync3(logDir, { recursive: true });
|
|
16474
|
-
const
|
|
16475
|
-
|
|
16558
|
+
const logFilePath = join4(logDir, `${input.task.id}.log`);
|
|
16559
|
+
input.logFilePath = logFilePath;
|
|
16560
|
+
const encoded = Buffer.from(JSON.stringify(input)).toString("base64");
|
|
16561
|
+
const fd = openSync(logFilePath, "a");
|
|
16476
16562
|
const child = spawn2(process.execPath, [sessionRunnerPath, encoded], {
|
|
16477
16563
|
detached: true,
|
|
16478
16564
|
stdio: ["ignore", fd, fd]
|
|
16479
16565
|
});
|
|
16480
16566
|
child.unref();
|
|
16481
16567
|
closeSync(fd);
|
|
16482
|
-
if (child.pid) {
|
|
16483
|
-
const pidLogPath = join4(logDir, `${child.pid}.log`);
|
|
16484
|
-
renameSync(tmpLogPath, pidLogPath);
|
|
16485
|
-
}
|
|
16486
16568
|
return child;
|
|
16487
16569
|
}
|
|
16488
16570
|
async function handleTask(client, config2, runtimeIndex, task, token, activeTasks) {
|
|
@@ -16832,7 +16914,7 @@ function emailCommand() {
|
|
|
16832
16914
|
process.exit(1);
|
|
16833
16915
|
}
|
|
16834
16916
|
});
|
|
16835
|
-
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("--in-reply-to <emailId>", "Email ID to reply to (sets threading headers)").option("--attachment <path>", "Path to a file to attach (repeatable)", collectRepeated, []).option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
|
|
16917
|
+
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("--from <addr>", "Send from a specific email address (custom mailbox)").option("--in-reply-to <emailId>", "Email ID to reply to (sets threading headers)").option("--attachment <path>", "Path to a file to attach (repeatable)", collectRepeated, []).option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
|
|
16836
16918
|
const { serverUrl, token, workspaceId } = resolveClientOpts(command, {
|
|
16837
16919
|
workspace: opts.workspace,
|
|
16838
16920
|
agentId: opts.agent_id
|
|
@@ -16893,7 +16975,8 @@ function emailCommand() {
|
|
|
16893
16975
|
subject: opts.subject,
|
|
16894
16976
|
htmlBody,
|
|
16895
16977
|
attachments,
|
|
16896
|
-
...inReplyTo ? { inReplyTo, references } : {}
|
|
16978
|
+
...inReplyTo ? { inReplyTo, references } : {},
|
|
16979
|
+
...opts.from ? { from: opts.from } : {}
|
|
16897
16980
|
});
|
|
16898
16981
|
console.log(`Sent email to ${res.to_email} (id: ${res.id})`);
|
|
16899
16982
|
} catch (err) {
|
package/dist/session-runner.js
CHANGED
|
@@ -14,7 +14,6 @@ var __export = (target, all) => {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
// daemon/session-runner.ts
|
|
17
|
-
import { createWriteStream } from "fs";
|
|
18
17
|
import { mkdir, writeFile, rm } from "fs/promises";
|
|
19
18
|
import path from "path";
|
|
20
19
|
|
|
@@ -13596,6 +13595,7 @@ var TaskAgentDataApiSchema = exports_external.object({
|
|
|
13596
13595
|
name: exports_external.string(),
|
|
13597
13596
|
runtime_config: exports_external.record(exports_external.string(), exports_external.unknown()).default({}),
|
|
13598
13597
|
email_handle: exports_external.string().nullable().optional(),
|
|
13598
|
+
email_addresses: exports_external.array(exports_external.string()).default([]),
|
|
13599
13599
|
user_email: exports_external.string().nullable().optional()
|
|
13600
13600
|
});
|
|
13601
13601
|
var TaskApiBaseSchema = exports_external.object({
|
|
@@ -13757,6 +13757,9 @@ var CreateConversationRequestSchema = exports_external.object({
|
|
|
13757
13757
|
var CreateMessageRequestSchema = exports_external.object({
|
|
13758
13758
|
content: exports_external.string().min(1, "content is required")
|
|
13759
13759
|
});
|
|
13760
|
+
var CreateBufferedMessageRequestSchema = exports_external.object({
|
|
13761
|
+
content: exports_external.string().min(1, "content is required")
|
|
13762
|
+
});
|
|
13760
13763
|
var EmailAttachmentSchema = exports_external.object({
|
|
13761
13764
|
key: exports_external.string().min(1),
|
|
13762
13765
|
filename: exports_external.string().min(1),
|
|
@@ -13770,7 +13773,9 @@ var SendEmailRequestSchema = exports_external.object({
|
|
|
13770
13773
|
htmlBody: exports_external.string().default(""),
|
|
13771
13774
|
inReplyTo: exports_external.string().optional(),
|
|
13772
13775
|
references: exports_external.string().optional(),
|
|
13773
|
-
attachments: exports_external.array(EmailAttachmentSchema).optional()
|
|
13776
|
+
attachments: exports_external.array(EmailAttachmentSchema).optional(),
|
|
13777
|
+
customAccountId: exports_external.string().optional(),
|
|
13778
|
+
from: exports_external.string().email().optional()
|
|
13774
13779
|
});
|
|
13775
13780
|
var UpdateEmailStatusRequestSchema = exports_external.object({
|
|
13776
13781
|
status: exports_external.enum(["unread", "read", "archived"])
|
|
@@ -13788,6 +13793,48 @@ var EmailNotifyRequestSchema = exports_external.object({
|
|
|
13788
13793
|
inReplyTo: exports_external.string().optional().default(""),
|
|
13789
13794
|
references: exports_external.string().optional().default("")
|
|
13790
13795
|
});
|
|
13796
|
+
var CreateEmailAccountSchema = exports_external.object({
|
|
13797
|
+
emailAddress: exports_external.string().email("valid email required"),
|
|
13798
|
+
displayName: exports_external.string().default(""),
|
|
13799
|
+
imapHost: exports_external.string().min(1, "IMAP host is required"),
|
|
13800
|
+
imapPort: exports_external.number().int().min(1).max(65535).default(993),
|
|
13801
|
+
imapUsername: exports_external.string().min(1, "IMAP username is required"),
|
|
13802
|
+
imapPassword: exports_external.string().min(1, "IMAP password is required"),
|
|
13803
|
+
imapTls: exports_external.boolean().default(true),
|
|
13804
|
+
smtpHost: exports_external.string().min(1, "SMTP host is required"),
|
|
13805
|
+
smtpPort: exports_external.number().int().min(1).max(65535).default(587),
|
|
13806
|
+
smtpUsername: exports_external.string().min(1, "SMTP username is required"),
|
|
13807
|
+
smtpPassword: exports_external.string().min(1, "SMTP password is required"),
|
|
13808
|
+
smtpTls: exports_external.number().int().min(0).max(2).default(1),
|
|
13809
|
+
pollIntervalSeconds: exports_external.number().int().min(30).max(3600).default(60)
|
|
13810
|
+
});
|
|
13811
|
+
var UpdateEmailAccountSchema = exports_external.object({
|
|
13812
|
+
emailAddress: exports_external.string().email().optional(),
|
|
13813
|
+
displayName: exports_external.string().optional(),
|
|
13814
|
+
imapHost: exports_external.string().min(1).optional(),
|
|
13815
|
+
imapPort: exports_external.number().int().min(1).max(65535).optional(),
|
|
13816
|
+
imapUsername: exports_external.string().min(1).optional(),
|
|
13817
|
+
imapPassword: exports_external.string().min(1).optional(),
|
|
13818
|
+
imapTls: exports_external.boolean().optional(),
|
|
13819
|
+
smtpHost: exports_external.string().min(1).optional(),
|
|
13820
|
+
smtpPort: exports_external.number().int().min(1).max(65535).optional(),
|
|
13821
|
+
smtpUsername: exports_external.string().min(1).optional(),
|
|
13822
|
+
smtpPassword: exports_external.string().min(1).optional(),
|
|
13823
|
+
smtpTls: exports_external.number().int().min(0).max(2).optional(),
|
|
13824
|
+
pollIntervalSeconds: exports_external.number().int().min(30).max(3600).optional()
|
|
13825
|
+
});
|
|
13826
|
+
var TestEmailConnectionSchema = exports_external.object({
|
|
13827
|
+
imapHost: exports_external.string().min(1),
|
|
13828
|
+
imapPort: exports_external.number().int().min(1).max(65535).default(993),
|
|
13829
|
+
imapUsername: exports_external.string().min(1),
|
|
13830
|
+
imapPassword: exports_external.string().min(1),
|
|
13831
|
+
imapTls: exports_external.boolean().default(true),
|
|
13832
|
+
smtpHost: exports_external.string().min(1),
|
|
13833
|
+
smtpPort: exports_external.number().int().min(1).max(65535).default(587),
|
|
13834
|
+
smtpUsername: exports_external.string().min(1),
|
|
13835
|
+
smtpPassword: exports_external.string().min(1),
|
|
13836
|
+
smtpTls: exports_external.number().int().min(0).max(2).default(1)
|
|
13837
|
+
});
|
|
13791
13838
|
var CreateWorkspaceRequestSchema = exports_external.object({
|
|
13792
13839
|
name: exports_external.string().min(1, "name is required"),
|
|
13793
13840
|
slug: exports_external.string().min(1, "slug is required")
|
|
@@ -15299,8 +15346,11 @@ var message = sqliteTable("message", {
|
|
|
15299
15346
|
content: text("content").notNull().default(""),
|
|
15300
15347
|
taskId: text("task_id"),
|
|
15301
15348
|
attachmentIds: text("attachment_ids"),
|
|
15349
|
+
status: text("status").notNull().default("active"),
|
|
15302
15350
|
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
15303
|
-
})
|
|
15351
|
+
}, (t) => [
|
|
15352
|
+
index("idx_message_conversation_status").on(t.conversationId, t.status)
|
|
15353
|
+
]);
|
|
15304
15354
|
var agentTaskQueue = sqliteTable("agent_task_queue", {
|
|
15305
15355
|
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
15306
15356
|
agentId: text("agent_id").notNull(),
|
|
@@ -15401,6 +15451,37 @@ var artifact = sqliteTable("artifact", {
|
|
|
15401
15451
|
foreignColumns: [agent.id, agent.workspaceId]
|
|
15402
15452
|
}).onDelete("cascade")
|
|
15403
15453
|
]);
|
|
15454
|
+
var agentEmailAccount = sqliteTable("agent_email_account", {
|
|
15455
|
+
id: text("id").primaryKey().$defaultFn(() => "aea_" + nanoid3()),
|
|
15456
|
+
agentId: text("agent_id").notNull(),
|
|
15457
|
+
workspaceId: text("workspace_id").notNull(),
|
|
15458
|
+
emailAddress: text("email_address").notNull(),
|
|
15459
|
+
displayName: text("display_name").notNull().default(""),
|
|
15460
|
+
imapHost: text("imap_host").notNull(),
|
|
15461
|
+
imapPort: integer2("imap_port").notNull().default(993),
|
|
15462
|
+
imapUsername: text("imap_username").notNull(),
|
|
15463
|
+
imapPassword: text("imap_password").notNull(),
|
|
15464
|
+
imapTls: integer2("imap_tls", { mode: "boolean" }).notNull().default(true),
|
|
15465
|
+
smtpHost: text("smtp_host").notNull(),
|
|
15466
|
+
smtpPort: integer2("smtp_port").notNull().default(587),
|
|
15467
|
+
smtpUsername: text("smtp_username").notNull(),
|
|
15468
|
+
smtpPassword: text("smtp_password").notNull(),
|
|
15469
|
+
smtpTls: integer2("smtp_tls").notNull().default(1),
|
|
15470
|
+
pollIntervalSeconds: integer2("poll_interval_seconds").notNull().default(60),
|
|
15471
|
+
lastSyncedUid: text("last_synced_uid").notNull().default("0"),
|
|
15472
|
+
lastSyncedAt: text("last_synced_at"),
|
|
15473
|
+
status: text("status").notNull().default("active"),
|
|
15474
|
+
errorMessage: text("error_message").notNull().default(""),
|
|
15475
|
+
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
|
|
15476
|
+
updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
15477
|
+
}, (t) => [
|
|
15478
|
+
index("idx_email_account_agent_ws").on(t.agentId, t.workspaceId),
|
|
15479
|
+
unique("email_account_agent_email").on(t.agentId, t.emailAddress),
|
|
15480
|
+
foreignKey({
|
|
15481
|
+
columns: [t.agentId, t.workspaceId],
|
|
15482
|
+
foreignColumns: [agent.id, agent.workspaceId]
|
|
15483
|
+
}).onDelete("cascade")
|
|
15484
|
+
]);
|
|
15404
15485
|
var machineToken = sqliteTable("machine_token", {
|
|
15405
15486
|
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
15406
15487
|
userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
@@ -16421,7 +16502,7 @@ function createBackend(provider, cliPath) {
|
|
|
16421
16502
|
|
|
16422
16503
|
// daemon/execenv/index.ts
|
|
16423
16504
|
import { mkdirSync as mkdirSync2 } from "fs";
|
|
16424
|
-
import { join as join3
|
|
16505
|
+
import { join as join3 } from "path";
|
|
16425
16506
|
|
|
16426
16507
|
// daemon/execenv/context.ts
|
|
16427
16508
|
import { createHash } from "crypto";
|
|
@@ -16499,13 +16580,22 @@ ${task.agent.instructions}
|
|
|
16499
16580
|
You can communicate with the world through Alook CLI.
|
|
16500
16581
|
Your alook agent id is '${task.agentId}'. remember this, most of alook cli will requires you input your agent id.
|
|
16501
16582
|
`;
|
|
16502
|
-
|
|
16503
|
-
|
|
16504
|
-
|
|
16583
|
+
const alookAddr = task.agent?.emailHandle ? toAlookAddress(task.agent.emailHandle) : null;
|
|
16584
|
+
const customAddrs = (task.agent?.emailAddresses ?? []).filter((a) => a !== alookAddr);
|
|
16585
|
+
if (alookAddr || customAddrs.length > 0) {
|
|
16586
|
+
const lines = [];
|
|
16587
|
+
if (alookAddr)
|
|
16588
|
+
lines.push(`- '${alookAddr}' (default, Alook platform address)`);
|
|
16589
|
+
for (const a of customAddrs)
|
|
16590
|
+
lines.push(`- '${a}' (custom IMAP/SMTP mailbox)`);
|
|
16591
|
+
content += `Your email addresses:
|
|
16592
|
+
${lines.join(`
|
|
16593
|
+
`)}
|
|
16594
|
+
${task.agent?.userEmail ? `Your owner's email address is '${task.agent.userEmail}'.` : ""}
|
|
16505
16595
|
|
|
16506
16596
|
### Emails
|
|
16507
16597
|
---
|
|
16508
|
-
Run 'npx @alook/cli pull --agent_id ${task.agentId} --status unread' to download unread emails to '/tmp/alook-emails/'.
|
|
16598
|
+
Run 'npx @alook/cli email pull --agent_id ${task.agentId} --status unread' to download unread emails to '/tmp/alook-emails/'.
|
|
16509
16599
|
Each email is saved to '/tmp/alook-emails/<emailId>/' with:
|
|
16510
16600
|
- 'metadata.json' — sender, recipient, subject, date, status, message_id, in_reply_to, references
|
|
16511
16601
|
- 'body.txt' — plain text body
|
|
@@ -16513,14 +16603,15 @@ Each email is saved to '/tmp/alook-emails/<emailId>/' with:
|
|
|
16513
16603
|
- 'attachments/' — extracted attachment files (if any)
|
|
16514
16604
|
---
|
|
16515
16605
|
Before starting to process an email, mark it as read:
|
|
16516
|
-
- Run 'npx @alook/cli set --agent_id ${task.agentId} --email_id <EMAIL_ID> --status read'
|
|
16606
|
+
- Run 'npx @alook/cli email set --agent_id ${task.agentId} --email_id <EMAIL_ID> --status read'
|
|
16517
16607
|
---
|
|
16518
16608
|
|
|
16519
16609
|
#### Sending a new email
|
|
16520
16610
|
Write the HTML body to a file first, then send it. The body is forwarded as-is (HTML).
|
|
16521
16611
|
- Run 'npx @alook/cli email send --agent_id ${task.agentId} --to <ADDRESS> --subject "<SUBJECT>" --body-file <PATH_TO_HTML>'
|
|
16612
|
+
- To send from a specific mailbox, add '--from <YOUR_EMAIL_ADDRESS>'. Without '--from', the default Alook address is used.
|
|
16522
16613
|
- Attach files with '--attachment <PATH>' — repeat the flag for multiple attachments. Each file is uploaded before sending.
|
|
16523
|
-
- Example: 'npx @alook/cli email send --agent_id ${task.agentId} --to foo@bar.com --subject "Weekly report" --body-file /tmp/body.html --
|
|
16614
|
+
- Example: 'npx @alook/cli email send --agent_id ${task.agentId} --to foo@bar.com --subject "Weekly report" --body-file /tmp/body.html --from alice@company.com --attachment /tmp/report.pdf'
|
|
16524
16615
|
|
|
16525
16616
|
#### Replying to an email
|
|
16526
16617
|
To reply to an email, add '--in-reply-to <EMAIL_ID>' to the send command. This sets the correct email threading headers so the recipient's email client groups the reply into the same conversation thread.
|
|
@@ -16708,10 +16799,13 @@ function useColor() {
|
|
|
16708
16799
|
}
|
|
16709
16800
|
function timestamp() {
|
|
16710
16801
|
const d = new Date;
|
|
16802
|
+
const Y = d.getFullYear();
|
|
16803
|
+
const M = String(d.getMonth() + 1).padStart(2, "0");
|
|
16804
|
+
const D = String(d.getDate()).padStart(2, "0");
|
|
16711
16805
|
const h = String(d.getHours()).padStart(2, "0");
|
|
16712
16806
|
const m = String(d.getMinutes()).padStart(2, "0");
|
|
16713
16807
|
const s = String(d.getSeconds()).padStart(2, "0");
|
|
16714
|
-
return `${h}:${m}:${s}`;
|
|
16808
|
+
return `${Y}-${M}-${D} ${h}:${m}:${s}`;
|
|
16715
16809
|
}
|
|
16716
16810
|
|
|
16717
16811
|
class Logger2 {
|
|
@@ -16896,7 +16990,7 @@ function updateEntry(timelineDir, taskId, updater) {
|
|
|
16896
16990
|
}
|
|
16897
16991
|
log.debug(`Timeline updateEntry: task_id ${taskId} not found in last 7 days`);
|
|
16898
16992
|
}
|
|
16899
|
-
function createTimelineEntry(taskId, prompt, type, sessionId, pid, provider, contextKey) {
|
|
16993
|
+
function createTimelineEntry(taskId, prompt, type, sessionId, pid, provider, contextKey, detailedLog) {
|
|
16900
16994
|
return {
|
|
16901
16995
|
task_id: taskId,
|
|
16902
16996
|
context_key: contextKey ?? null,
|
|
@@ -16908,7 +17002,8 @@ function createTimelineEntry(taskId, prompt, type, sessionId, pid, provider, con
|
|
|
16908
17002
|
prompt,
|
|
16909
17003
|
agent_responses: [],
|
|
16910
17004
|
errmsg: null,
|
|
16911
|
-
provider: provider ?? null
|
|
17005
|
+
provider: provider ?? null,
|
|
17006
|
+
detailed_log: detailedLog ?? null
|
|
16912
17007
|
};
|
|
16913
17008
|
}
|
|
16914
17009
|
var DEFAULT_RESUME_MAX_AGE_MS = 3 * 60 * 60 * 1000;
|
|
@@ -16938,8 +17033,6 @@ function prepare(config2, task) {
|
|
|
16938
17033
|
const timelineDir = join3(workDir, ".context_timeline");
|
|
16939
17034
|
mkdirSync2(timelineDir, { recursive: true });
|
|
16940
17035
|
writeInstructionFileIfChanged(workDir, task);
|
|
16941
|
-
const logFile = join3(config2.workspacesRoot, task.workspaceId, task.agentId, "agent.log");
|
|
16942
|
-
mkdirSync2(dirname(logFile), { recursive: true });
|
|
16943
17036
|
const env = {
|
|
16944
17037
|
ALOOK_WORKSPACE_ID: task.workspaceId,
|
|
16945
17038
|
ALOOK_AGENT_ID: task.agentId,
|
|
@@ -16947,7 +17040,7 @@ function prepare(config2, task) {
|
|
|
16947
17040
|
ALOOK_CONVERSATION_ID: task.conversationId,
|
|
16948
17041
|
ALOOK_HEALTH_PORT: process.env.ALOOK_HEALTH_PORT || "19514"
|
|
16949
17042
|
};
|
|
16950
|
-
return { workDir,
|
|
17043
|
+
return { workDir, timelineDir, env };
|
|
16951
17044
|
}
|
|
16952
17045
|
|
|
16953
17046
|
// daemon/prompt.ts
|
|
@@ -16993,18 +17086,21 @@ async function downloadAttachments(client, token, workspaceId, taskId, attachmen
|
|
|
16993
17086
|
}
|
|
16994
17087
|
async function runSession(input) {
|
|
16995
17088
|
const { task, provider, cliPath, model, serverURL, token, workspacesRoot, agentTimeout } = input;
|
|
17089
|
+
log.info(`starting (task=${task.id}, type=${task.type}, agent=${task.agentId}, provider=${provider}, model=${model || "default"})`);
|
|
16996
17090
|
const client = new DaemonClient(serverURL);
|
|
16997
17091
|
const backend = createBackend(provider, cliPath);
|
|
16998
|
-
const { workDir,
|
|
17092
|
+
const { workDir, timelineDir, env } = prepare({ workspacesRoot }, task);
|
|
16999
17093
|
const attachmentIds = task.context?.attachment_ids ?? [];
|
|
17000
17094
|
let attachments;
|
|
17001
17095
|
if (attachmentIds.length > 0) {
|
|
17096
|
+
log.info(`downloading ${attachmentIds.length} attachment(s)`);
|
|
17002
17097
|
try {
|
|
17003
17098
|
attachments = await downloadAttachments(client, token, task.workspaceId, task.id, attachmentIds);
|
|
17099
|
+
log.info(`attachments ready (${attachments.length} file(s))`);
|
|
17004
17100
|
} catch (e) {
|
|
17005
17101
|
await cleanupAttachments(task.id);
|
|
17006
17102
|
const errMsg = `failed to download attachments: ${e}`;
|
|
17007
|
-
log.error(
|
|
17103
|
+
log.error(errMsg);
|
|
17008
17104
|
await client.failTask(token, task.id, errMsg);
|
|
17009
17105
|
return;
|
|
17010
17106
|
}
|
|
@@ -17012,7 +17108,7 @@ async function runSession(input) {
|
|
|
17012
17108
|
const prompt = buildPrompt(task, attachments);
|
|
17013
17109
|
const resumeSessionId = task.contextKey ? findResumableSessionByContextKey(timelineDir, task.contextKey, provider) ?? undefined : undefined;
|
|
17014
17110
|
if (resumeSessionId) {
|
|
17015
|
-
log.info(`
|
|
17111
|
+
log.info(`resuming session ${resumeSessionId} (context_key: ${task.contextKey})`);
|
|
17016
17112
|
}
|
|
17017
17113
|
const session2 = backend.execute(prompt, {
|
|
17018
17114
|
cwd: workDir,
|
|
@@ -17023,9 +17119,12 @@ async function runSession(input) {
|
|
|
17023
17119
|
});
|
|
17024
17120
|
const agentPid = session2.pid;
|
|
17025
17121
|
const earlySessionId = await session2.sessionId;
|
|
17026
|
-
|
|
17122
|
+
log.info(`agent started (pid=${agentPid ?? "unknown"}, session=${earlySessionId})`);
|
|
17123
|
+
log.info(JSON.stringify({ role: "user", type: "text", content: prompt }));
|
|
17124
|
+
await initEntryAsync(timelineDir, createTimelineEntry(task.id, task.prompt, task.type, earlySessionId, process.pid, provider, task.contextKey, input.logFilePath));
|
|
17027
17125
|
const pendingMessages = [];
|
|
17028
17126
|
let seq = 0;
|
|
17127
|
+
let toolCount = 0;
|
|
17029
17128
|
const BATCH_SIZE = Number(process.env.ALOOK_MESSAGE_BATCH_SIZE) || 20;
|
|
17030
17129
|
const FLUSH_INTERVAL_MS = Number(process.env.ALOOK_MESSAGE_FLUSH_INTERVAL_MS) || 100;
|
|
17031
17130
|
const flushMessages = async () => {
|
|
@@ -17035,29 +17134,16 @@ async function runSession(input) {
|
|
|
17035
17134
|
try {
|
|
17036
17135
|
await client.reportMessages(token, task.id, batch);
|
|
17037
17136
|
} catch (e) {
|
|
17038
|
-
log.debug(
|
|
17137
|
+
log.debug("message report failed", e);
|
|
17039
17138
|
}
|
|
17040
17139
|
};
|
|
17041
17140
|
const flushTimer = setInterval(flushMessages, FLUSH_INTERVAL_MS);
|
|
17042
|
-
let logStream;
|
|
17043
|
-
try {
|
|
17044
|
-
logStream = createWriteStream(logFile, { flags: "a" });
|
|
17045
|
-
logStream.write(JSON.stringify({
|
|
17046
|
-
ts: localISOString(),
|
|
17047
|
-
type: "text",
|
|
17048
|
-
role: "user",
|
|
17049
|
-
content: prompt
|
|
17050
|
-
}) + `
|
|
17051
|
-
`);
|
|
17052
|
-
} catch {
|
|
17053
|
-
logStream = undefined;
|
|
17054
|
-
}
|
|
17055
17141
|
let killed = false;
|
|
17056
17142
|
const onKill = async () => {
|
|
17057
17143
|
if (killed)
|
|
17058
17144
|
return;
|
|
17059
17145
|
killed = true;
|
|
17060
|
-
log.info(`
|
|
17146
|
+
log.info(`killed by signal (messages=${seq}, tools=${toolCount})`);
|
|
17061
17147
|
if (agentPid) {
|
|
17062
17148
|
try {
|
|
17063
17149
|
process.kill(agentPid, "SIGTERM");
|
|
@@ -17067,7 +17153,6 @@ async function runSession(input) {
|
|
|
17067
17153
|
try {
|
|
17068
17154
|
await flushMessages();
|
|
17069
17155
|
} catch {}
|
|
17070
|
-
logStream?.end();
|
|
17071
17156
|
await cleanupAttachments(task.id);
|
|
17072
17157
|
updateEntry(timelineDir, task.id, (entry) => {
|
|
17073
17158
|
entry.pid = null;
|
|
@@ -17095,21 +17180,14 @@ async function runSession(input) {
|
|
|
17095
17180
|
input: msg.input,
|
|
17096
17181
|
output: msg.output
|
|
17097
17182
|
});
|
|
17183
|
+
if (msg.type === "tool-use")
|
|
17184
|
+
toolCount++;
|
|
17185
|
+
log.info(JSON.stringify({ role: "assistant", ...msg }));
|
|
17098
17186
|
if (msg.type === "text" && msg.content) {
|
|
17099
17187
|
updateEntry(timelineDir, task.id, (entry) => {
|
|
17100
17188
|
entry.agent_responses.push(msg.content);
|
|
17101
17189
|
});
|
|
17102
17190
|
}
|
|
17103
|
-
if (logStream) {
|
|
17104
|
-
try {
|
|
17105
|
-
logStream.write(JSON.stringify({
|
|
17106
|
-
ts: localISOString(),
|
|
17107
|
-
role: "assistant",
|
|
17108
|
-
...msg
|
|
17109
|
-
}) + `
|
|
17110
|
-
`);
|
|
17111
|
-
} catch {}
|
|
17112
|
-
}
|
|
17113
17191
|
if (pendingMessages.length >= BATCH_SIZE) {
|
|
17114
17192
|
await flushMessages();
|
|
17115
17193
|
}
|
|
@@ -17118,7 +17196,6 @@ async function runSession(input) {
|
|
|
17118
17196
|
await flushMessages();
|
|
17119
17197
|
} finally {
|
|
17120
17198
|
clearInterval(flushTimer);
|
|
17121
|
-
logStream?.end();
|
|
17122
17199
|
process.removeListener("SIGTERM", onKill);
|
|
17123
17200
|
process.removeListener("SIGINT", onKill);
|
|
17124
17201
|
}
|
|
@@ -17152,10 +17229,12 @@ async function runSession(input) {
|
|
|
17152
17229
|
if (result.sessionId)
|
|
17153
17230
|
body.session_id = result.sessionId;
|
|
17154
17231
|
await client.completeTask(token, task.id, body);
|
|
17155
|
-
|
|
17232
|
+
const dur = (result.durationMs / 1000).toFixed(1);
|
|
17233
|
+
log.info(`completed (duration=${dur}s, messages=${seq}, tools=${toolCount})`);
|
|
17156
17234
|
} else {
|
|
17157
17235
|
await client.failTask(token, task.id, result.error || "unknown error");
|
|
17158
|
-
|
|
17236
|
+
const dur = (result.durationMs / 1000).toFixed(1);
|
|
17237
|
+
log.info(`failed (duration=${dur}s, messages=${seq}, tools=${toolCount}) — ${result.error}`);
|
|
17159
17238
|
}
|
|
17160
17239
|
}
|
|
17161
17240
|
async function main() {
|