@alook/cli 0.0.11 → 0.0.12
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 +91 -14
- package/dist/session-runner.js +119 -46
- 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({
|
|
@@ -14052,7 +14053,9 @@ var SendEmailRequestSchema = exports_external.object({
|
|
|
14052
14053
|
htmlBody: exports_external.string().default(""),
|
|
14053
14054
|
inReplyTo: exports_external.string().optional(),
|
|
14054
14055
|
references: exports_external.string().optional(),
|
|
14055
|
-
attachments: exports_external.array(EmailAttachmentSchema).optional()
|
|
14056
|
+
attachments: exports_external.array(EmailAttachmentSchema).optional(),
|
|
14057
|
+
customAccountId: exports_external.string().optional(),
|
|
14058
|
+
from: exports_external.string().email().optional()
|
|
14056
14059
|
});
|
|
14057
14060
|
var UpdateEmailStatusRequestSchema = exports_external.object({
|
|
14058
14061
|
status: exports_external.enum(["unread", "read", "archived"])
|
|
@@ -14070,6 +14073,48 @@ var EmailNotifyRequestSchema = exports_external.object({
|
|
|
14070
14073
|
inReplyTo: exports_external.string().optional().default(""),
|
|
14071
14074
|
references: exports_external.string().optional().default("")
|
|
14072
14075
|
});
|
|
14076
|
+
var CreateEmailAccountSchema = exports_external.object({
|
|
14077
|
+
emailAddress: exports_external.string().email("valid email required"),
|
|
14078
|
+
displayName: exports_external.string().default(""),
|
|
14079
|
+
imapHost: exports_external.string().min(1, "IMAP host is required"),
|
|
14080
|
+
imapPort: exports_external.number().int().min(1).max(65535).default(993),
|
|
14081
|
+
imapUsername: exports_external.string().min(1, "IMAP username is required"),
|
|
14082
|
+
imapPassword: exports_external.string().min(1, "IMAP password is required"),
|
|
14083
|
+
imapTls: exports_external.boolean().default(true),
|
|
14084
|
+
smtpHost: exports_external.string().min(1, "SMTP host is required"),
|
|
14085
|
+
smtpPort: exports_external.number().int().min(1).max(65535).default(587),
|
|
14086
|
+
smtpUsername: exports_external.string().min(1, "SMTP username is required"),
|
|
14087
|
+
smtpPassword: exports_external.string().min(1, "SMTP password is required"),
|
|
14088
|
+
smtpTls: exports_external.number().int().min(0).max(2).default(1),
|
|
14089
|
+
pollIntervalSeconds: exports_external.number().int().min(30).max(3600).default(60)
|
|
14090
|
+
});
|
|
14091
|
+
var UpdateEmailAccountSchema = exports_external.object({
|
|
14092
|
+
emailAddress: exports_external.string().email().optional(),
|
|
14093
|
+
displayName: exports_external.string().optional(),
|
|
14094
|
+
imapHost: exports_external.string().min(1).optional(),
|
|
14095
|
+
imapPort: exports_external.number().int().min(1).max(65535).optional(),
|
|
14096
|
+
imapUsername: exports_external.string().min(1).optional(),
|
|
14097
|
+
imapPassword: exports_external.string().min(1).optional(),
|
|
14098
|
+
imapTls: exports_external.boolean().optional(),
|
|
14099
|
+
smtpHost: exports_external.string().min(1).optional(),
|
|
14100
|
+
smtpPort: exports_external.number().int().min(1).max(65535).optional(),
|
|
14101
|
+
smtpUsername: exports_external.string().min(1).optional(),
|
|
14102
|
+
smtpPassword: exports_external.string().min(1).optional(),
|
|
14103
|
+
smtpTls: exports_external.number().int().min(0).max(2).optional(),
|
|
14104
|
+
pollIntervalSeconds: exports_external.number().int().min(30).max(3600).optional()
|
|
14105
|
+
});
|
|
14106
|
+
var TestEmailConnectionSchema = exports_external.object({
|
|
14107
|
+
imapHost: exports_external.string().min(1),
|
|
14108
|
+
imapPort: exports_external.number().int().min(1).max(65535).default(993),
|
|
14109
|
+
imapUsername: exports_external.string().min(1),
|
|
14110
|
+
imapPassword: exports_external.string().min(1),
|
|
14111
|
+
imapTls: exports_external.boolean().default(true),
|
|
14112
|
+
smtpHost: exports_external.string().min(1),
|
|
14113
|
+
smtpPort: exports_external.number().int().min(1).max(65535).default(587),
|
|
14114
|
+
smtpUsername: exports_external.string().min(1),
|
|
14115
|
+
smtpPassword: exports_external.string().min(1),
|
|
14116
|
+
smtpTls: exports_external.number().int().min(0).max(2).default(1)
|
|
14117
|
+
});
|
|
14073
14118
|
var CreateWorkspaceRequestSchema = exports_external.object({
|
|
14074
14119
|
name: exports_external.string().min(1, "name is required"),
|
|
14075
14120
|
slug: exports_external.string().min(1, "slug is required")
|
|
@@ -15683,6 +15728,37 @@ var artifact = sqliteTable("artifact", {
|
|
|
15683
15728
|
foreignColumns: [agent.id, agent.workspaceId]
|
|
15684
15729
|
}).onDelete("cascade")
|
|
15685
15730
|
]);
|
|
15731
|
+
var agentEmailAccount = sqliteTable("agent_email_account", {
|
|
15732
|
+
id: text("id").primaryKey().$defaultFn(() => "aea_" + nanoid3()),
|
|
15733
|
+
agentId: text("agent_id").notNull(),
|
|
15734
|
+
workspaceId: text("workspace_id").notNull(),
|
|
15735
|
+
emailAddress: text("email_address").notNull(),
|
|
15736
|
+
displayName: text("display_name").notNull().default(""),
|
|
15737
|
+
imapHost: text("imap_host").notNull(),
|
|
15738
|
+
imapPort: integer2("imap_port").notNull().default(993),
|
|
15739
|
+
imapUsername: text("imap_username").notNull(),
|
|
15740
|
+
imapPassword: text("imap_password").notNull(),
|
|
15741
|
+
imapTls: integer2("imap_tls", { mode: "boolean" }).notNull().default(true),
|
|
15742
|
+
smtpHost: text("smtp_host").notNull(),
|
|
15743
|
+
smtpPort: integer2("smtp_port").notNull().default(587),
|
|
15744
|
+
smtpUsername: text("smtp_username").notNull(),
|
|
15745
|
+
smtpPassword: text("smtp_password").notNull(),
|
|
15746
|
+
smtpTls: integer2("smtp_tls").notNull().default(1),
|
|
15747
|
+
pollIntervalSeconds: integer2("poll_interval_seconds").notNull().default(60),
|
|
15748
|
+
lastSyncedUid: text("last_synced_uid").notNull().default("0"),
|
|
15749
|
+
lastSyncedAt: text("last_synced_at"),
|
|
15750
|
+
status: text("status").notNull().default("active"),
|
|
15751
|
+
errorMessage: text("error_message").notNull().default(""),
|
|
15752
|
+
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
|
|
15753
|
+
updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
15754
|
+
}, (t) => [
|
|
15755
|
+
index("idx_email_account_agent_ws").on(t.agentId, t.workspaceId),
|
|
15756
|
+
unique("email_account_agent_email").on(t.agentId, t.emailAddress),
|
|
15757
|
+
foreignKey({
|
|
15758
|
+
columns: [t.agentId, t.workspaceId],
|
|
15759
|
+
foreignColumns: [agent.id, agent.workspaceId]
|
|
15760
|
+
}).onDelete("cascade")
|
|
15761
|
+
]);
|
|
15686
15762
|
var machineToken = sqliteTable("machine_token", {
|
|
15687
15763
|
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
15688
15764
|
userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
@@ -15888,7 +15964,7 @@ function loadDaemonConfig(profile) {
|
|
|
15888
15964
|
codexModel: process.env.ALOOK_CODEX_MODEL || "",
|
|
15889
15965
|
opencodeModel: process.env.ALOOK_OPENCODE_MODEL || "",
|
|
15890
15966
|
pollInterval: parseDuration(process.env.ALOOK_DAEMON_POLL_INTERVAL || "3s"),
|
|
15891
|
-
agentTimeout: parseDuration(process.env.ALOOK_AGENT_TIMEOUT || "
|
|
15967
|
+
agentTimeout: parseDuration(process.env.ALOOK_AGENT_TIMEOUT || "12h"),
|
|
15892
15968
|
maxConcurrentTasks: parseInt(process.env.ALOOK_DAEMON_MAX_CONCURRENT_TASKS || "20"),
|
|
15893
15969
|
daemonId,
|
|
15894
15970
|
deviceName: process.env.ALOOK_DAEMON_DEVICE_NAME || h,
|
|
@@ -15964,7 +16040,7 @@ function fromApiTask(api2) {
|
|
|
15964
16040
|
type: api2.type,
|
|
15965
16041
|
contextKey: api2.context_key ?? null,
|
|
15966
16042
|
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,
|
|
16043
|
+
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
16044
|
repos: undefined,
|
|
15969
16045
|
createdAt: api2.created_at
|
|
15970
16046
|
};
|
|
@@ -16001,10 +16077,13 @@ function useColor() {
|
|
|
16001
16077
|
}
|
|
16002
16078
|
function timestamp() {
|
|
16003
16079
|
const d = new Date;
|
|
16080
|
+
const Y = d.getFullYear();
|
|
16081
|
+
const M = String(d.getMonth() + 1).padStart(2, "0");
|
|
16082
|
+
const D = String(d.getDate()).padStart(2, "0");
|
|
16004
16083
|
const h = String(d.getHours()).padStart(2, "0");
|
|
16005
16084
|
const m = String(d.getMinutes()).padStart(2, "0");
|
|
16006
16085
|
const s = String(d.getSeconds()).padStart(2, "0");
|
|
16007
|
-
return `${h}:${m}:${s}`;
|
|
16086
|
+
return `${Y}-${M}-${D} ${h}:${m}:${s}`;
|
|
16008
16087
|
}
|
|
16009
16088
|
|
|
16010
16089
|
class Logger2 {
|
|
@@ -16193,7 +16272,7 @@ async function handleCliUpdate(version3, onSuccess, profile) {
|
|
|
16193
16272
|
}
|
|
16194
16273
|
|
|
16195
16274
|
// daemon/daemon.ts
|
|
16196
|
-
import { existsSync, mkdirSync as mkdirSync3, openSync, closeSync,
|
|
16275
|
+
import { existsSync, mkdirSync as mkdirSync3, openSync, closeSync, readdirSync, statSync, unlinkSync as unlinkSync3 } from "fs";
|
|
16197
16276
|
import { execSync as execSync3, spawn as spawn2 } from "child_process";
|
|
16198
16277
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
16199
16278
|
import { dirname as dirname3, join as join4 } from "path";
|
|
@@ -16468,21 +16547,18 @@ async function startDaemon(profile, serverUrl) {
|
|
|
16468
16547
|
await pollCycle();
|
|
16469
16548
|
}
|
|
16470
16549
|
function spawnSessionRunner(input) {
|
|
16471
|
-
const encoded = Buffer.from(JSON.stringify(input)).toString("base64");
|
|
16472
16550
|
const logDir = sessionRunnerLogDir();
|
|
16473
16551
|
mkdirSync3(logDir, { recursive: true });
|
|
16474
|
-
const
|
|
16475
|
-
|
|
16552
|
+
const logFilePath = join4(logDir, `${input.task.id}.log`);
|
|
16553
|
+
input.logFilePath = logFilePath;
|
|
16554
|
+
const encoded = Buffer.from(JSON.stringify(input)).toString("base64");
|
|
16555
|
+
const fd = openSync(logFilePath, "a");
|
|
16476
16556
|
const child = spawn2(process.execPath, [sessionRunnerPath, encoded], {
|
|
16477
16557
|
detached: true,
|
|
16478
16558
|
stdio: ["ignore", fd, fd]
|
|
16479
16559
|
});
|
|
16480
16560
|
child.unref();
|
|
16481
16561
|
closeSync(fd);
|
|
16482
|
-
if (child.pid) {
|
|
16483
|
-
const pidLogPath = join4(logDir, `${child.pid}.log`);
|
|
16484
|
-
renameSync(tmpLogPath, pidLogPath);
|
|
16485
|
-
}
|
|
16486
16562
|
return child;
|
|
16487
16563
|
}
|
|
16488
16564
|
async function handleTask(client, config2, runtimeIndex, task, token, activeTasks) {
|
|
@@ -16832,7 +16908,7 @@ function emailCommand() {
|
|
|
16832
16908
|
process.exit(1);
|
|
16833
16909
|
}
|
|
16834
16910
|
});
|
|
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) => {
|
|
16911
|
+
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
16912
|
const { serverUrl, token, workspaceId } = resolveClientOpts(command, {
|
|
16837
16913
|
workspace: opts.workspace,
|
|
16838
16914
|
agentId: opts.agent_id
|
|
@@ -16893,7 +16969,8 @@ function emailCommand() {
|
|
|
16893
16969
|
subject: opts.subject,
|
|
16894
16970
|
htmlBody,
|
|
16895
16971
|
attachments,
|
|
16896
|
-
...inReplyTo ? { inReplyTo, references } : {}
|
|
16972
|
+
...inReplyTo ? { inReplyTo, references } : {},
|
|
16973
|
+
...opts.from ? { from: opts.from } : {}
|
|
16897
16974
|
});
|
|
16898
16975
|
console.log(`Sent email to ${res.to_email} (id: ${res.id})`);
|
|
16899
16976
|
} 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({
|
|
@@ -13770,7 +13770,9 @@ var SendEmailRequestSchema = exports_external.object({
|
|
|
13770
13770
|
htmlBody: exports_external.string().default(""),
|
|
13771
13771
|
inReplyTo: exports_external.string().optional(),
|
|
13772
13772
|
references: exports_external.string().optional(),
|
|
13773
|
-
attachments: exports_external.array(EmailAttachmentSchema).optional()
|
|
13773
|
+
attachments: exports_external.array(EmailAttachmentSchema).optional(),
|
|
13774
|
+
customAccountId: exports_external.string().optional(),
|
|
13775
|
+
from: exports_external.string().email().optional()
|
|
13774
13776
|
});
|
|
13775
13777
|
var UpdateEmailStatusRequestSchema = exports_external.object({
|
|
13776
13778
|
status: exports_external.enum(["unread", "read", "archived"])
|
|
@@ -13788,6 +13790,48 @@ var EmailNotifyRequestSchema = exports_external.object({
|
|
|
13788
13790
|
inReplyTo: exports_external.string().optional().default(""),
|
|
13789
13791
|
references: exports_external.string().optional().default("")
|
|
13790
13792
|
});
|
|
13793
|
+
var CreateEmailAccountSchema = exports_external.object({
|
|
13794
|
+
emailAddress: exports_external.string().email("valid email required"),
|
|
13795
|
+
displayName: exports_external.string().default(""),
|
|
13796
|
+
imapHost: exports_external.string().min(1, "IMAP host is required"),
|
|
13797
|
+
imapPort: exports_external.number().int().min(1).max(65535).default(993),
|
|
13798
|
+
imapUsername: exports_external.string().min(1, "IMAP username is required"),
|
|
13799
|
+
imapPassword: exports_external.string().min(1, "IMAP password is required"),
|
|
13800
|
+
imapTls: exports_external.boolean().default(true),
|
|
13801
|
+
smtpHost: exports_external.string().min(1, "SMTP host is required"),
|
|
13802
|
+
smtpPort: exports_external.number().int().min(1).max(65535).default(587),
|
|
13803
|
+
smtpUsername: exports_external.string().min(1, "SMTP username is required"),
|
|
13804
|
+
smtpPassword: exports_external.string().min(1, "SMTP password is required"),
|
|
13805
|
+
smtpTls: exports_external.number().int().min(0).max(2).default(1),
|
|
13806
|
+
pollIntervalSeconds: exports_external.number().int().min(30).max(3600).default(60)
|
|
13807
|
+
});
|
|
13808
|
+
var UpdateEmailAccountSchema = exports_external.object({
|
|
13809
|
+
emailAddress: exports_external.string().email().optional(),
|
|
13810
|
+
displayName: exports_external.string().optional(),
|
|
13811
|
+
imapHost: exports_external.string().min(1).optional(),
|
|
13812
|
+
imapPort: exports_external.number().int().min(1).max(65535).optional(),
|
|
13813
|
+
imapUsername: exports_external.string().min(1).optional(),
|
|
13814
|
+
imapPassword: exports_external.string().min(1).optional(),
|
|
13815
|
+
imapTls: exports_external.boolean().optional(),
|
|
13816
|
+
smtpHost: exports_external.string().min(1).optional(),
|
|
13817
|
+
smtpPort: exports_external.number().int().min(1).max(65535).optional(),
|
|
13818
|
+
smtpUsername: exports_external.string().min(1).optional(),
|
|
13819
|
+
smtpPassword: exports_external.string().min(1).optional(),
|
|
13820
|
+
smtpTls: exports_external.number().int().min(0).max(2).optional(),
|
|
13821
|
+
pollIntervalSeconds: exports_external.number().int().min(30).max(3600).optional()
|
|
13822
|
+
});
|
|
13823
|
+
var TestEmailConnectionSchema = exports_external.object({
|
|
13824
|
+
imapHost: exports_external.string().min(1),
|
|
13825
|
+
imapPort: exports_external.number().int().min(1).max(65535).default(993),
|
|
13826
|
+
imapUsername: exports_external.string().min(1),
|
|
13827
|
+
imapPassword: exports_external.string().min(1),
|
|
13828
|
+
imapTls: exports_external.boolean().default(true),
|
|
13829
|
+
smtpHost: exports_external.string().min(1),
|
|
13830
|
+
smtpPort: exports_external.number().int().min(1).max(65535).default(587),
|
|
13831
|
+
smtpUsername: exports_external.string().min(1),
|
|
13832
|
+
smtpPassword: exports_external.string().min(1),
|
|
13833
|
+
smtpTls: exports_external.number().int().min(0).max(2).default(1)
|
|
13834
|
+
});
|
|
13791
13835
|
var CreateWorkspaceRequestSchema = exports_external.object({
|
|
13792
13836
|
name: exports_external.string().min(1, "name is required"),
|
|
13793
13837
|
slug: exports_external.string().min(1, "slug is required")
|
|
@@ -15401,6 +15445,37 @@ var artifact = sqliteTable("artifact", {
|
|
|
15401
15445
|
foreignColumns: [agent.id, agent.workspaceId]
|
|
15402
15446
|
}).onDelete("cascade")
|
|
15403
15447
|
]);
|
|
15448
|
+
var agentEmailAccount = sqliteTable("agent_email_account", {
|
|
15449
|
+
id: text("id").primaryKey().$defaultFn(() => "aea_" + nanoid3()),
|
|
15450
|
+
agentId: text("agent_id").notNull(),
|
|
15451
|
+
workspaceId: text("workspace_id").notNull(),
|
|
15452
|
+
emailAddress: text("email_address").notNull(),
|
|
15453
|
+
displayName: text("display_name").notNull().default(""),
|
|
15454
|
+
imapHost: text("imap_host").notNull(),
|
|
15455
|
+
imapPort: integer2("imap_port").notNull().default(993),
|
|
15456
|
+
imapUsername: text("imap_username").notNull(),
|
|
15457
|
+
imapPassword: text("imap_password").notNull(),
|
|
15458
|
+
imapTls: integer2("imap_tls", { mode: "boolean" }).notNull().default(true),
|
|
15459
|
+
smtpHost: text("smtp_host").notNull(),
|
|
15460
|
+
smtpPort: integer2("smtp_port").notNull().default(587),
|
|
15461
|
+
smtpUsername: text("smtp_username").notNull(),
|
|
15462
|
+
smtpPassword: text("smtp_password").notNull(),
|
|
15463
|
+
smtpTls: integer2("smtp_tls").notNull().default(1),
|
|
15464
|
+
pollIntervalSeconds: integer2("poll_interval_seconds").notNull().default(60),
|
|
15465
|
+
lastSyncedUid: text("last_synced_uid").notNull().default("0"),
|
|
15466
|
+
lastSyncedAt: text("last_synced_at"),
|
|
15467
|
+
status: text("status").notNull().default("active"),
|
|
15468
|
+
errorMessage: text("error_message").notNull().default(""),
|
|
15469
|
+
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
|
|
15470
|
+
updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
15471
|
+
}, (t) => [
|
|
15472
|
+
index("idx_email_account_agent_ws").on(t.agentId, t.workspaceId),
|
|
15473
|
+
unique("email_account_agent_email").on(t.agentId, t.emailAddress),
|
|
15474
|
+
foreignKey({
|
|
15475
|
+
columns: [t.agentId, t.workspaceId],
|
|
15476
|
+
foreignColumns: [agent.id, agent.workspaceId]
|
|
15477
|
+
}).onDelete("cascade")
|
|
15478
|
+
]);
|
|
15404
15479
|
var machineToken = sqliteTable("machine_token", {
|
|
15405
15480
|
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
15406
15481
|
userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
@@ -16421,7 +16496,7 @@ function createBackend(provider, cliPath) {
|
|
|
16421
16496
|
|
|
16422
16497
|
// daemon/execenv/index.ts
|
|
16423
16498
|
import { mkdirSync as mkdirSync2 } from "fs";
|
|
16424
|
-
import { join as join3
|
|
16499
|
+
import { join as join3 } from "path";
|
|
16425
16500
|
|
|
16426
16501
|
// daemon/execenv/context.ts
|
|
16427
16502
|
import { createHash } from "crypto";
|
|
@@ -16499,9 +16574,18 @@ ${task.agent.instructions}
|
|
|
16499
16574
|
You can communicate with the world through Alook CLI.
|
|
16500
16575
|
Your alook agent id is '${task.agentId}'. remember this, most of alook cli will requires you input your agent id.
|
|
16501
16576
|
`;
|
|
16502
|
-
|
|
16503
|
-
|
|
16504
|
-
|
|
16577
|
+
const alookAddr = task.agent?.emailHandle ? toAlookAddress(task.agent.emailHandle) : null;
|
|
16578
|
+
const customAddrs = (task.agent?.emailAddresses ?? []).filter((a) => a !== alookAddr);
|
|
16579
|
+
if (alookAddr || customAddrs.length > 0) {
|
|
16580
|
+
const lines = [];
|
|
16581
|
+
if (alookAddr)
|
|
16582
|
+
lines.push(`- '${alookAddr}' (default, Alook platform address)`);
|
|
16583
|
+
for (const a of customAddrs)
|
|
16584
|
+
lines.push(`- '${a}' (custom IMAP/SMTP mailbox)`);
|
|
16585
|
+
content += `Your email addresses:
|
|
16586
|
+
${lines.join(`
|
|
16587
|
+
`)}
|
|
16588
|
+
${task.agent?.userEmail ? `Your owner's email address is '${task.agent.userEmail}'.` : ""}
|
|
16505
16589
|
|
|
16506
16590
|
### Emails
|
|
16507
16591
|
---
|
|
@@ -16519,8 +16603,9 @@ Before starting to process an email, mark it as read:
|
|
|
16519
16603
|
#### Sending a new email
|
|
16520
16604
|
Write the HTML body to a file first, then send it. The body is forwarded as-is (HTML).
|
|
16521
16605
|
- Run 'npx @alook/cli email send --agent_id ${task.agentId} --to <ADDRESS> --subject "<SUBJECT>" --body-file <PATH_TO_HTML>'
|
|
16606
|
+
- To send from a specific mailbox, add '--from <YOUR_EMAIL_ADDRESS>'. Without '--from', the default Alook address is used.
|
|
16522
16607
|
- 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 --
|
|
16608
|
+
- 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
16609
|
|
|
16525
16610
|
#### Replying to an email
|
|
16526
16611
|
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 +16793,13 @@ function useColor() {
|
|
|
16708
16793
|
}
|
|
16709
16794
|
function timestamp() {
|
|
16710
16795
|
const d = new Date;
|
|
16796
|
+
const Y = d.getFullYear();
|
|
16797
|
+
const M = String(d.getMonth() + 1).padStart(2, "0");
|
|
16798
|
+
const D = String(d.getDate()).padStart(2, "0");
|
|
16711
16799
|
const h = String(d.getHours()).padStart(2, "0");
|
|
16712
16800
|
const m = String(d.getMinutes()).padStart(2, "0");
|
|
16713
16801
|
const s = String(d.getSeconds()).padStart(2, "0");
|
|
16714
|
-
return `${h}:${m}:${s}`;
|
|
16802
|
+
return `${Y}-${M}-${D} ${h}:${m}:${s}`;
|
|
16715
16803
|
}
|
|
16716
16804
|
|
|
16717
16805
|
class Logger2 {
|
|
@@ -16896,7 +16984,7 @@ function updateEntry(timelineDir, taskId, updater) {
|
|
|
16896
16984
|
}
|
|
16897
16985
|
log.debug(`Timeline updateEntry: task_id ${taskId} not found in last 7 days`);
|
|
16898
16986
|
}
|
|
16899
|
-
function createTimelineEntry(taskId, prompt, type, sessionId, pid, provider, contextKey) {
|
|
16987
|
+
function createTimelineEntry(taskId, prompt, type, sessionId, pid, provider, contextKey, detailedLog) {
|
|
16900
16988
|
return {
|
|
16901
16989
|
task_id: taskId,
|
|
16902
16990
|
context_key: contextKey ?? null,
|
|
@@ -16908,7 +16996,8 @@ function createTimelineEntry(taskId, prompt, type, sessionId, pid, provider, con
|
|
|
16908
16996
|
prompt,
|
|
16909
16997
|
agent_responses: [],
|
|
16910
16998
|
errmsg: null,
|
|
16911
|
-
provider: provider ?? null
|
|
16999
|
+
provider: provider ?? null,
|
|
17000
|
+
detailed_log: detailedLog ?? null
|
|
16912
17001
|
};
|
|
16913
17002
|
}
|
|
16914
17003
|
var DEFAULT_RESUME_MAX_AGE_MS = 3 * 60 * 60 * 1000;
|
|
@@ -16938,8 +17027,6 @@ function prepare(config2, task) {
|
|
|
16938
17027
|
const timelineDir = join3(workDir, ".context_timeline");
|
|
16939
17028
|
mkdirSync2(timelineDir, { recursive: true });
|
|
16940
17029
|
writeInstructionFileIfChanged(workDir, task);
|
|
16941
|
-
const logFile = join3(config2.workspacesRoot, task.workspaceId, task.agentId, "agent.log");
|
|
16942
|
-
mkdirSync2(dirname(logFile), { recursive: true });
|
|
16943
17030
|
const env = {
|
|
16944
17031
|
ALOOK_WORKSPACE_ID: task.workspaceId,
|
|
16945
17032
|
ALOOK_AGENT_ID: task.agentId,
|
|
@@ -16947,7 +17034,7 @@ function prepare(config2, task) {
|
|
|
16947
17034
|
ALOOK_CONVERSATION_ID: task.conversationId,
|
|
16948
17035
|
ALOOK_HEALTH_PORT: process.env.ALOOK_HEALTH_PORT || "19514"
|
|
16949
17036
|
};
|
|
16950
|
-
return { workDir,
|
|
17037
|
+
return { workDir, timelineDir, env };
|
|
16951
17038
|
}
|
|
16952
17039
|
|
|
16953
17040
|
// daemon/prompt.ts
|
|
@@ -16993,18 +17080,21 @@ async function downloadAttachments(client, token, workspaceId, taskId, attachmen
|
|
|
16993
17080
|
}
|
|
16994
17081
|
async function runSession(input) {
|
|
16995
17082
|
const { task, provider, cliPath, model, serverURL, token, workspacesRoot, agentTimeout } = input;
|
|
17083
|
+
log.info(`starting (task=${task.id}, type=${task.type}, agent=${task.agentId}, provider=${provider}, model=${model || "default"})`);
|
|
16996
17084
|
const client = new DaemonClient(serverURL);
|
|
16997
17085
|
const backend = createBackend(provider, cliPath);
|
|
16998
|
-
const { workDir,
|
|
17086
|
+
const { workDir, timelineDir, env } = prepare({ workspacesRoot }, task);
|
|
16999
17087
|
const attachmentIds = task.context?.attachment_ids ?? [];
|
|
17000
17088
|
let attachments;
|
|
17001
17089
|
if (attachmentIds.length > 0) {
|
|
17090
|
+
log.info(`downloading ${attachmentIds.length} attachment(s)`);
|
|
17002
17091
|
try {
|
|
17003
17092
|
attachments = await downloadAttachments(client, token, task.workspaceId, task.id, attachmentIds);
|
|
17093
|
+
log.info(`attachments ready (${attachments.length} file(s))`);
|
|
17004
17094
|
} catch (e) {
|
|
17005
17095
|
await cleanupAttachments(task.id);
|
|
17006
17096
|
const errMsg = `failed to download attachments: ${e}`;
|
|
17007
|
-
log.error(
|
|
17097
|
+
log.error(errMsg);
|
|
17008
17098
|
await client.failTask(token, task.id, errMsg);
|
|
17009
17099
|
return;
|
|
17010
17100
|
}
|
|
@@ -17012,7 +17102,7 @@ async function runSession(input) {
|
|
|
17012
17102
|
const prompt = buildPrompt(task, attachments);
|
|
17013
17103
|
const resumeSessionId = task.contextKey ? findResumableSessionByContextKey(timelineDir, task.contextKey, provider) ?? undefined : undefined;
|
|
17014
17104
|
if (resumeSessionId) {
|
|
17015
|
-
log.info(`
|
|
17105
|
+
log.info(`resuming session ${resumeSessionId} (context_key: ${task.contextKey})`);
|
|
17016
17106
|
}
|
|
17017
17107
|
const session2 = backend.execute(prompt, {
|
|
17018
17108
|
cwd: workDir,
|
|
@@ -17023,9 +17113,12 @@ async function runSession(input) {
|
|
|
17023
17113
|
});
|
|
17024
17114
|
const agentPid = session2.pid;
|
|
17025
17115
|
const earlySessionId = await session2.sessionId;
|
|
17026
|
-
|
|
17116
|
+
log.info(`agent started (pid=${agentPid ?? "unknown"}, session=${earlySessionId})`);
|
|
17117
|
+
log.info(JSON.stringify({ role: "user", type: "text", content: prompt }));
|
|
17118
|
+
await initEntryAsync(timelineDir, createTimelineEntry(task.id, task.prompt, task.type, earlySessionId, process.pid, provider, task.contextKey, input.logFilePath));
|
|
17027
17119
|
const pendingMessages = [];
|
|
17028
17120
|
let seq = 0;
|
|
17121
|
+
let toolCount = 0;
|
|
17029
17122
|
const BATCH_SIZE = Number(process.env.ALOOK_MESSAGE_BATCH_SIZE) || 20;
|
|
17030
17123
|
const FLUSH_INTERVAL_MS = Number(process.env.ALOOK_MESSAGE_FLUSH_INTERVAL_MS) || 100;
|
|
17031
17124
|
const flushMessages = async () => {
|
|
@@ -17035,29 +17128,16 @@ async function runSession(input) {
|
|
|
17035
17128
|
try {
|
|
17036
17129
|
await client.reportMessages(token, task.id, batch);
|
|
17037
17130
|
} catch (e) {
|
|
17038
|
-
log.debug(
|
|
17131
|
+
log.debug("message report failed", e);
|
|
17039
17132
|
}
|
|
17040
17133
|
};
|
|
17041
17134
|
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
17135
|
let killed = false;
|
|
17056
17136
|
const onKill = async () => {
|
|
17057
17137
|
if (killed)
|
|
17058
17138
|
return;
|
|
17059
17139
|
killed = true;
|
|
17060
|
-
log.info(`
|
|
17140
|
+
log.info(`killed by signal (messages=${seq}, tools=${toolCount})`);
|
|
17061
17141
|
if (agentPid) {
|
|
17062
17142
|
try {
|
|
17063
17143
|
process.kill(agentPid, "SIGTERM");
|
|
@@ -17067,7 +17147,6 @@ async function runSession(input) {
|
|
|
17067
17147
|
try {
|
|
17068
17148
|
await flushMessages();
|
|
17069
17149
|
} catch {}
|
|
17070
|
-
logStream?.end();
|
|
17071
17150
|
await cleanupAttachments(task.id);
|
|
17072
17151
|
updateEntry(timelineDir, task.id, (entry) => {
|
|
17073
17152
|
entry.pid = null;
|
|
@@ -17095,21 +17174,14 @@ async function runSession(input) {
|
|
|
17095
17174
|
input: msg.input,
|
|
17096
17175
|
output: msg.output
|
|
17097
17176
|
});
|
|
17177
|
+
if (msg.type === "tool-use")
|
|
17178
|
+
toolCount++;
|
|
17179
|
+
log.info(JSON.stringify({ role: "assistant", ...msg }));
|
|
17098
17180
|
if (msg.type === "text" && msg.content) {
|
|
17099
17181
|
updateEntry(timelineDir, task.id, (entry) => {
|
|
17100
17182
|
entry.agent_responses.push(msg.content);
|
|
17101
17183
|
});
|
|
17102
17184
|
}
|
|
17103
|
-
if (logStream) {
|
|
17104
|
-
try {
|
|
17105
|
-
logStream.write(JSON.stringify({
|
|
17106
|
-
ts: localISOString(),
|
|
17107
|
-
role: "assistant",
|
|
17108
|
-
...msg
|
|
17109
|
-
}) + `
|
|
17110
|
-
`);
|
|
17111
|
-
} catch {}
|
|
17112
|
-
}
|
|
17113
17185
|
if (pendingMessages.length >= BATCH_SIZE) {
|
|
17114
17186
|
await flushMessages();
|
|
17115
17187
|
}
|
|
@@ -17118,7 +17190,6 @@ async function runSession(input) {
|
|
|
17118
17190
|
await flushMessages();
|
|
17119
17191
|
} finally {
|
|
17120
17192
|
clearInterval(flushTimer);
|
|
17121
|
-
logStream?.end();
|
|
17122
17193
|
process.removeListener("SIGTERM", onKill);
|
|
17123
17194
|
process.removeListener("SIGINT", onKill);
|
|
17124
17195
|
}
|
|
@@ -17152,10 +17223,12 @@ async function runSession(input) {
|
|
|
17152
17223
|
if (result.sessionId)
|
|
17153
17224
|
body.session_id = result.sessionId;
|
|
17154
17225
|
await client.completeTask(token, task.id, body);
|
|
17155
|
-
|
|
17226
|
+
const dur = (result.durationMs / 1000).toFixed(1);
|
|
17227
|
+
log.info(`completed (duration=${dur}s, messages=${seq}, tools=${toolCount})`);
|
|
17156
17228
|
} else {
|
|
17157
17229
|
await client.failTask(token, task.id, result.error || "unknown error");
|
|
17158
|
-
|
|
17230
|
+
const dur = (result.durationMs / 1000).toFixed(1);
|
|
17231
|
+
log.info(`failed (duration=${dur}s, messages=${seq}, tools=${toolCount}) — ${result.error}`);
|
|
17159
17232
|
}
|
|
17160
17233
|
}
|
|
17161
17234
|
async function main() {
|