@alook/app 0.0.79 → 0.0.81
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/bundled/email-worker/index.js +33 -2
- package/bundled/web/.open-next/.build/durable-objects/queue.js +5 -5
- package/bundled/web/.open-next/assets/BUILD_ID +1 -1
- package/bundled/web/.open-next/assets/_next/static/chunks/{1816-z_y9qndk.js → 068.hh6m2g-gl.js} +1 -1
- package/bundled/web/.open-next/assets/_next/static/chunks/{0kcuw_83491vk.js → 0j2~fioc-ekva.js} +15 -15
- package/bundled/web/.open-next/assets/_next/static/chunks/{0ie.u1iu3pwrm.js → 0my5rezp-sbw3.js} +1 -1
- package/bundled/web/.open-next/cache/{3zHg2EwefkGKUXp1h2jId → grlt3qzClfRM3yvBh9bW4}/_global-error.cache +1 -1
- package/bundled/web/.open-next/cache/{3zHg2EwefkGKUXp1h2jId → grlt3qzClfRM3yvBh9bW4}/_not-found.cache +1 -1
- package/bundled/web/.open-next/cache/{3zHg2EwefkGKUXp1h2jId → grlt3qzClfRM3yvBh9bW4}/sitemap.xml.cache +1 -1
- package/bundled/web/.open-next/cloudflare/cache-assets-manifest.sql +1 -1
- package/bundled/web/.open-next/cloudflare/init.js +1 -1
- package/bundled/web/.open-next/dynamodb-provider/dynamodb-cache.json +1 -1
- package/bundled/web/.open-next/middleware/handler.mjs +7 -7
- package/bundled/web/.open-next/server-functions/default/src/web/.next/BUILD_ID +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/app-path-routes-manifest.json +2 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/build-manifest.json +3 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/prerender-manifest.json +3 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/routes-manifest.json +12 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/invite/[token]/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/studio/new/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/[id]/activity/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/[id]/chat/[convId]/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/[id]/chat/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/[id]/email/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/[id]/files/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/[id]/meetings/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/[id]/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/new/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/calendar/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/flags/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/help/email-setup/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/home/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/issues/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/runtimes/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/settings/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/threads/[traceId]/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/threads/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/unread/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/workspaces/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(auth)/sign-in/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/chat-init/route.js +4 -4
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/whitelist/route.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/workspace/browse/route.js +4 -4
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/route.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/conversations/[id]/active-task/route.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/conversations/[id]/buffered-messages/route.js +2 -2
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/conversations/[id]/init/route.js +4 -4
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/conversations/[id]/messages/route.js +2 -2
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/heartbeat/route.js +14 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/heartbeat/route_client-reference-manifest.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/sweep/route.js +15 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/sweep/route_client-reference-manifest.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/tasks/[taskId]/complete/route.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/tasks/[taskId]/fail/route.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/tasks/[taskId]/start/route.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/tasks/[taskId]/supersede/route.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/tasks/poll/route.js +6 -7
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/email/notify/route.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/issues/[id]/comments/route.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/issues/[id]/route.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/issues/route.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/studios/route.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/tasks/[id]/retry/route.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/templates/[id]/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/templates/page_client-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app-paths-manifest.json +2 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__04maj_8._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0_.051i._.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0ko5xa_._.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0kruv9u._.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0l91rwj._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0m5a1_f._.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0ntc1ld._.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0om99x0._.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[turbopack]_runtime.js +25 -23
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0-7a9se._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_007pf4f._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0266t8u._.js +6 -6
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_037ndoa._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_04gp_km._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_05zp0zn._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_05~18bk._.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_08z6pkf._.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_091mubc._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_09j_99x._.js +6 -6
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0aveiot._.js +5 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0cji8yc._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0exm5_w._.js +6 -6
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0f.tk9k._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0g1_3hn._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0h3guve._.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0h_dgb9._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0hxvvdy._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0ke5r~m._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0l0biq~._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0oyl16-._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0pt9vvp._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0s~hhx-._.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0w6dw.t._.js +6 -6
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_12gxjds._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_13hlohp._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/src_0mko5ir._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/src_web__next-internal_server_app_api_daemon_heartbeat_route_actions_059pb-t.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/src_web__next-internal_server_app_api_daemon_sweep_route_actions_00h1~h1.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/[turbopack]_runtime.js +25 -23
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_063q-hj._.js +2 -2
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_0ilz5db._.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_0st8pau._.js +3 -0
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_12e18r-._.js +2 -2
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/src_web_src_components_home_home-page_tsx_0to84tv._.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/middleware-build-manifest.js +3 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/middleware-manifest.json +5 -5
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/server-reference-manifest.js +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/server-reference-manifest.json +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/handler.mjs +94 -58
- package/bundled/web/.open-next/server-functions/default/src/web/handler.mjs.meta.json +498 -327
- package/bundled/web/.open-next/server-functions/default/src/web/index.mjs +5 -5
- package/bundled/web/wrangler.toml +1 -1
- package/bundled/ws-do/index.js +72 -4
- package/dist/cli/index.js +380 -72
- package/dist/cli/session-runner.js +23 -1
- package/dist/index.js +31 -1
- package/package.json +1 -1
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0y4q15f._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0--kvw_._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0-r4t0g._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_02t7kem._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_05_d3df._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_06.am62._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_07-798_._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_07zxhb2._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_08mdiy6._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0csh82a._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0j.pt~7._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0j1t6f2._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0lmedw9._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0ns9.qo._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0piy2kq._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0tarogd._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0u3tu2x._.js +0 -5
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0x0qvxd._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_12wxdg1._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/src_0q3gvkd._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_07q6-kr._.js +0 -3
- package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/src_web_src_0j12j81._.js +0 -3
- /package/bundled/web/.open-next/assets/_next/static/{3zHg2EwefkGKUXp1h2jId → grlt3qzClfRM3yvBh9bW4}/_buildManifest.js +0 -0
- /package/bundled/web/.open-next/assets/_next/static/{3zHg2EwefkGKUXp1h2jId → grlt3qzClfRM3yvBh9bW4}/_clientMiddlewareManifest.js +0 -0
- /package/bundled/web/.open-next/assets/_next/static/{3zHg2EwefkGKUXp1h2jId → grlt3qzClfRM3yvBh9bW4}/_ssgManifest.js +0 -0
- /package/bundled/web/.open-next/cache/{3zHg2EwefkGKUXp1h2jId → grlt3qzClfRM3yvBh9bW4}/robots.txt.cache +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -195,7 +195,7 @@ var TERMINAL_ISSUE_STATUSES = [
|
|
|
195
195
|
IssueStatus.FAILED
|
|
196
196
|
];
|
|
197
197
|
var POLL_INTERVAL_MS = Number(process.env.POLL_INTERVAL_MS) || 3000;
|
|
198
|
-
var OFFLINE_THRESHOLD_MS = Number(process.env.OFFLINE_THRESHOLD_MS) ||
|
|
198
|
+
var OFFLINE_THRESHOLD_MS = Number(process.env.OFFLINE_THRESHOLD_MS) || 30000;
|
|
199
199
|
var EVENT_POLL_INTERVAL_MS = Number(process.env.EVENT_POLL_INTERVAL_MS) || 2000;
|
|
200
200
|
var MeetingStatus = {
|
|
201
201
|
PENDING: "pending",
|
|
@@ -14567,6 +14567,9 @@ var TaskApiSchema = TaskApiBaseSchema.extend({
|
|
|
14567
14567
|
agent: TaskAgentDataApiSchema.nullable().optional(),
|
|
14568
14568
|
sender: TaskSenderApiSchema.nullable().optional()
|
|
14569
14569
|
});
|
|
14570
|
+
var HeartbeatRequestSchema = exports_external.object({
|
|
14571
|
+
daemon_id: exports_external.string().min(1)
|
|
14572
|
+
});
|
|
14570
14573
|
var PollRequestSchema = exports_external.object({
|
|
14571
14574
|
daemon_id: exports_external.string().min(1),
|
|
14572
14575
|
max_tasks: exports_external.number().int().min(1).default(1),
|
|
@@ -14595,6 +14598,15 @@ var PollResponseSchema = exports_external.object({
|
|
|
14595
14598
|
file_requests: exports_external.array(FileRequestItemSchema).optional(),
|
|
14596
14599
|
meetings: exports_external.array(PollMeetingItemSchema).optional()
|
|
14597
14600
|
});
|
|
14601
|
+
var DaemonPushMessageSchema = exports_external.discriminatedUnion("type", [
|
|
14602
|
+
exports_external.object({ type: exports_external.literal("daemon.tasks"), tasks: exports_external.array(TaskApiSchema) }),
|
|
14603
|
+
exports_external.object({ type: exports_external.literal("daemon.file_requests"), workspaceId: exports_external.string(), requests: exports_external.array(FileRequestItemSchema) }),
|
|
14604
|
+
exports_external.object({ type: exports_external.literal("daemon.meetings"), meetings: exports_external.array(PollMeetingItemSchema) }),
|
|
14605
|
+
exports_external.object({ type: exports_external.literal("daemon.evict"), workspaceId: exports_external.string() }),
|
|
14606
|
+
exports_external.object({ type: exports_external.literal("daemon.update"), version: exports_external.string() }),
|
|
14607
|
+
exports_external.object({ type: exports_external.literal("daemon.rescan") }),
|
|
14608
|
+
exports_external.object({ type: exports_external.literal("daemon.kill"), workspaceId: exports_external.string(), taskId: exports_external.string(), targetTaskId: exports_external.string() })
|
|
14609
|
+
]);
|
|
14598
14610
|
var RegisterResponseSchema = exports_external.object({
|
|
14599
14611
|
runtimes: exports_external.array(exports_external.object({ id: exports_external.string() }))
|
|
14600
14612
|
});
|
|
@@ -16979,6 +16991,9 @@ function loadDaemonConfig(profile) {
|
|
|
16979
16991
|
codexModel: process.env.ALOOK_CODEX_MODEL || "",
|
|
16980
16992
|
opencodeModel: process.env.ALOOK_OPENCODE_MODEL || "",
|
|
16981
16993
|
pollInterval: parseDuration(process.env.ALOOK_DAEMON_POLL_INTERVAL || "3s"),
|
|
16994
|
+
wsPollInterval: parseDuration(process.env.ALOOK_DAEMON_WS_POLL_INTERVAL || "60s"),
|
|
16995
|
+
heartbeatInterval: parseDuration(process.env.ALOOK_DAEMON_HEARTBEAT_INTERVAL || "15s"),
|
|
16996
|
+
sweepInterval: parseDuration(process.env.ALOOK_DAEMON_SWEEP_INTERVAL || "60s"),
|
|
16982
16997
|
agentTimeout: parseDuration(process.env.ALOOK_AGENT_TIMEOUT || "12h"),
|
|
16983
16998
|
messageInactivityTimeout: parseDuration(process.env.ALOOK_MESSAGE_INACTIVITY_TIMEOUT || "20m"),
|
|
16984
16999
|
maxConcurrentTasks: parseInt(process.env.ALOOK_DAEMON_MAX_CONCURRENT_TASKS || "20"),
|
|
@@ -17350,6 +17365,16 @@ class DaemonClient {
|
|
|
17350
17365
|
const raw = await this.request("POST", "/api/daemon/register", token, body);
|
|
17351
17366
|
return RegisterResponseSchema.parse(raw);
|
|
17352
17367
|
}
|
|
17368
|
+
heartbeat(token, daemonId) {
|
|
17369
|
+
return this.request("POST", "/api/daemon/heartbeat", token, {
|
|
17370
|
+
daemon_id: daemonId
|
|
17371
|
+
});
|
|
17372
|
+
}
|
|
17373
|
+
sweep(token, daemonId) {
|
|
17374
|
+
return this.request("POST", "/api/daemon/sweep", token, {
|
|
17375
|
+
daemon_id: daemonId
|
|
17376
|
+
});
|
|
17377
|
+
}
|
|
17353
17378
|
deregister(token, daemonId) {
|
|
17354
17379
|
return this.request("POST", "/api/daemon/deregister", token, {
|
|
17355
17380
|
daemon_id: daemonId
|
|
@@ -19615,6 +19640,155 @@ if (isDirectExecution) {
|
|
|
19615
19640
|
main();
|
|
19616
19641
|
}
|
|
19617
19642
|
|
|
19643
|
+
// daemon/ws-client.ts
|
|
19644
|
+
var log6 = createLogger2({ module: "ws-client" });
|
|
19645
|
+
var WS_RECONNECT_INIT = 1000;
|
|
19646
|
+
var WS_RECONNECT_MAX = 30000;
|
|
19647
|
+
var WS_PING_INTERVAL = 25000;
|
|
19648
|
+
var WS_LIVENESS_TIMEOUT = 50000;
|
|
19649
|
+
var WS_DO_DEV_PORT = 8789;
|
|
19650
|
+
|
|
19651
|
+
class DaemonWsClient {
|
|
19652
|
+
opts;
|
|
19653
|
+
ws = null;
|
|
19654
|
+
reconnectDelay = WS_RECONNECT_INIT;
|
|
19655
|
+
reconnectTimer = null;
|
|
19656
|
+
pingInterval = null;
|
|
19657
|
+
livenessInterval = null;
|
|
19658
|
+
lastMessageAt = 0;
|
|
19659
|
+
connected = false;
|
|
19660
|
+
closed = false;
|
|
19661
|
+
constructor(opts) {
|
|
19662
|
+
this.opts = opts;
|
|
19663
|
+
}
|
|
19664
|
+
getUrl() {
|
|
19665
|
+
const url2 = new URL(this.opts.serverURL);
|
|
19666
|
+
const isLocal = url2.hostname === "localhost" || url2.hostname === "127.0.0.1";
|
|
19667
|
+
if (isLocal) {
|
|
19668
|
+
return `ws://localhost:${WS_DO_DEV_PORT}/?daemonId=${this.opts.daemonId}`;
|
|
19669
|
+
}
|
|
19670
|
+
const protocol = url2.protocol === "https:" ? "wss:" : "ws:";
|
|
19671
|
+
return `${protocol}//${url2.host}/api/ws/daemon?daemonId=${this.opts.daemonId}`;
|
|
19672
|
+
}
|
|
19673
|
+
isConnected() {
|
|
19674
|
+
return this.connected;
|
|
19675
|
+
}
|
|
19676
|
+
connect() {
|
|
19677
|
+
if (this.closed)
|
|
19678
|
+
return;
|
|
19679
|
+
this.cleanup();
|
|
19680
|
+
const wsUrl = this.getUrl();
|
|
19681
|
+
log6.info("connecting", { url: wsUrl });
|
|
19682
|
+
try {
|
|
19683
|
+
this.ws = new WebSocket(wsUrl);
|
|
19684
|
+
} catch (err) {
|
|
19685
|
+
log6.warn("ws creation failed", { err: String(err) });
|
|
19686
|
+
this.scheduleReconnect();
|
|
19687
|
+
return;
|
|
19688
|
+
}
|
|
19689
|
+
this.ws.addEventListener("open", () => {
|
|
19690
|
+
this.reconnectDelay = WS_RECONNECT_INIT;
|
|
19691
|
+
this.ws.send(JSON.stringify({
|
|
19692
|
+
type: "auth",
|
|
19693
|
+
machineToken: this.opts.machineToken,
|
|
19694
|
+
daemonId: this.opts.daemonId
|
|
19695
|
+
}));
|
|
19696
|
+
this.lastMessageAt = Date.now();
|
|
19697
|
+
this.startHeartbeat();
|
|
19698
|
+
});
|
|
19699
|
+
this.ws.addEventListener("message", (event) => {
|
|
19700
|
+
this.lastMessageAt = Date.now();
|
|
19701
|
+
const str = typeof event.data === "string" ? event.data : "";
|
|
19702
|
+
if (str === "pong")
|
|
19703
|
+
return;
|
|
19704
|
+
try {
|
|
19705
|
+
const msg = JSON.parse(str);
|
|
19706
|
+
if (msg.type === "auth.ok") {
|
|
19707
|
+
log6.info("authenticated");
|
|
19708
|
+
this.connected = true;
|
|
19709
|
+
this.opts.onConnected();
|
|
19710
|
+
return;
|
|
19711
|
+
}
|
|
19712
|
+
const parsed = DaemonPushMessageSchema.safeParse(msg);
|
|
19713
|
+
if (!parsed.success) {
|
|
19714
|
+
log6.warn("invalid push message", { err: parsed.error.message });
|
|
19715
|
+
return;
|
|
19716
|
+
}
|
|
19717
|
+
this.opts.onMessage(parsed.data);
|
|
19718
|
+
} catch (err) {
|
|
19719
|
+
log6.debug("message parse error", { err: String(err) });
|
|
19720
|
+
}
|
|
19721
|
+
});
|
|
19722
|
+
this.ws.addEventListener("error", () => {
|
|
19723
|
+
log6.debug("ws error");
|
|
19724
|
+
});
|
|
19725
|
+
this.ws.addEventListener("close", () => {
|
|
19726
|
+
const wasConnected = this.connected;
|
|
19727
|
+
this.connected = false;
|
|
19728
|
+
this.stopHeartbeat();
|
|
19729
|
+
if (wasConnected) {
|
|
19730
|
+
this.opts.onDisconnected();
|
|
19731
|
+
}
|
|
19732
|
+
if (!this.closed) {
|
|
19733
|
+
this.scheduleReconnect();
|
|
19734
|
+
}
|
|
19735
|
+
});
|
|
19736
|
+
}
|
|
19737
|
+
close() {
|
|
19738
|
+
this.closed = true;
|
|
19739
|
+
this.cleanup();
|
|
19740
|
+
if (this.reconnectTimer) {
|
|
19741
|
+
clearTimeout(this.reconnectTimer);
|
|
19742
|
+
this.reconnectTimer = null;
|
|
19743
|
+
}
|
|
19744
|
+
}
|
|
19745
|
+
cleanup() {
|
|
19746
|
+
this.stopHeartbeat();
|
|
19747
|
+
if (this.ws) {
|
|
19748
|
+
try {
|
|
19749
|
+
this.ws.close();
|
|
19750
|
+
} catch {}
|
|
19751
|
+
this.ws = null;
|
|
19752
|
+
}
|
|
19753
|
+
this.connected = false;
|
|
19754
|
+
}
|
|
19755
|
+
scheduleReconnect() {
|
|
19756
|
+
if (this.closed)
|
|
19757
|
+
return;
|
|
19758
|
+
const delay = Math.min(this.reconnectDelay, WS_RECONNECT_MAX);
|
|
19759
|
+
this.reconnectDelay = Math.min(delay * 2, WS_RECONNECT_MAX);
|
|
19760
|
+
const jitter = Math.random() * 500;
|
|
19761
|
+
log6.debug("reconnecting", { delayMs: Math.round(delay + jitter) });
|
|
19762
|
+
this.reconnectTimer = setTimeout(() => {
|
|
19763
|
+
this.reconnectTimer = null;
|
|
19764
|
+
this.connect();
|
|
19765
|
+
}, delay + jitter);
|
|
19766
|
+
}
|
|
19767
|
+
startHeartbeat() {
|
|
19768
|
+
this.pingInterval = setInterval(() => {
|
|
19769
|
+
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
19770
|
+
this.ws.send("ping");
|
|
19771
|
+
}
|
|
19772
|
+
}, WS_PING_INTERVAL);
|
|
19773
|
+
this.livenessInterval = setInterval(() => {
|
|
19774
|
+
if (Date.now() - this.lastMessageAt > WS_LIVENESS_TIMEOUT) {
|
|
19775
|
+
log6.warn("liveness timeout, closing");
|
|
19776
|
+
this.ws?.close();
|
|
19777
|
+
}
|
|
19778
|
+
}, 5000);
|
|
19779
|
+
}
|
|
19780
|
+
stopHeartbeat() {
|
|
19781
|
+
if (this.pingInterval) {
|
|
19782
|
+
clearInterval(this.pingInterval);
|
|
19783
|
+
this.pingInterval = null;
|
|
19784
|
+
}
|
|
19785
|
+
if (this.livenessInterval) {
|
|
19786
|
+
clearInterval(this.livenessInterval);
|
|
19787
|
+
this.livenessInterval = null;
|
|
19788
|
+
}
|
|
19789
|
+
}
|
|
19790
|
+
}
|
|
19791
|
+
|
|
19618
19792
|
// daemon/update-handler.ts
|
|
19619
19793
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync6, unlinkSync as unlinkSync4 } from "fs";
|
|
19620
19794
|
|
|
@@ -19646,7 +19820,7 @@ function runNpmUpdate(targetVersion) {
|
|
|
19646
19820
|
}
|
|
19647
19821
|
|
|
19648
19822
|
// daemon/update-handler.ts
|
|
19649
|
-
var
|
|
19823
|
+
var log7 = createLogger2({ module: "updater" });
|
|
19650
19824
|
var updating = false;
|
|
19651
19825
|
var retryCount = 0;
|
|
19652
19826
|
var MAX_RETRIES = 3;
|
|
@@ -19676,29 +19850,29 @@ async function handleCliUpdate(version3, onSuccess, profile) {
|
|
|
19676
19850
|
if (retryCount >= MAX_RETRIES)
|
|
19677
19851
|
return;
|
|
19678
19852
|
if (process.env.ALOOK_CMD_PREFIX) {
|
|
19679
|
-
|
|
19853
|
+
log7.info(`Skipping auto-update in app mode — user should run: npx @alook/app@latest update`);
|
|
19680
19854
|
return;
|
|
19681
19855
|
}
|
|
19682
19856
|
const marker = readUpdateMarker(profile);
|
|
19683
19857
|
if (marker === version3) {
|
|
19684
|
-
|
|
19858
|
+
log7.info(`Skipping update to v${version3} — already attempted (marker exists)`);
|
|
19685
19859
|
return;
|
|
19686
19860
|
}
|
|
19687
19861
|
updating = true;
|
|
19688
19862
|
try {
|
|
19689
|
-
|
|
19863
|
+
log7.info(`Updating CLI to v${version3}...`);
|
|
19690
19864
|
const result = await runNpmUpdate(version3);
|
|
19691
19865
|
if (result.success) {
|
|
19692
19866
|
writeUpdateMarker(version3, profile);
|
|
19693
|
-
|
|
19867
|
+
log7.info(`CLI updated to v${version3} — restarting`);
|
|
19694
19868
|
onSuccess();
|
|
19695
19869
|
} else {
|
|
19696
19870
|
retryCount++;
|
|
19697
|
-
|
|
19871
|
+
log7.error(`CLI update failed (attempt ${retryCount}/${MAX_RETRIES}): ${result.output}`);
|
|
19698
19872
|
}
|
|
19699
19873
|
} catch (e) {
|
|
19700
19874
|
retryCount++;
|
|
19701
|
-
|
|
19875
|
+
log7.error(`CLI update error (attempt ${retryCount}/${MAX_RETRIES})`, e);
|
|
19702
19876
|
} finally {
|
|
19703
19877
|
updating = false;
|
|
19704
19878
|
}
|
|
@@ -19841,7 +20015,7 @@ import { readdir as readdir2, readFile as readFile2, unlink, stat as fsStat } fr
|
|
|
19841
20015
|
import { execSync as execSync4, spawn as spawn5 } from "child_process";
|
|
19842
20016
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
19843
20017
|
import { dirname as dirname3, join as join10 } from "path";
|
|
19844
|
-
var
|
|
20018
|
+
var log8 = createLogger2({ module: "daemon" });
|
|
19845
20019
|
var _dir = dirname3(fileURLToPath2(import.meta.url));
|
|
19846
20020
|
var sessionRunnerPath = existsSync2(join10(_dir, "session-runner.js")) ? join10(_dir, "session-runner.js") : join10(_dir, "session-runner.ts");
|
|
19847
20021
|
var meetingRunnerPath = existsSync2(join10(_dir, "meeting-runner.js")) ? join10(_dir, "meeting-runner.js") : join10(_dir, "meeting-runner.ts");
|
|
@@ -19948,14 +20122,14 @@ async function reconcilePendingCompletions(workspacesRoot) {
|
|
|
19948
20122
|
try {
|
|
19949
20123
|
parsed = JSON.parse(raw);
|
|
19950
20124
|
} catch {
|
|
19951
|
-
|
|
20125
|
+
log8.warn(`reconcile: malformed marker ${name}, deleting`);
|
|
19952
20126
|
try {
|
|
19953
20127
|
await unlink(filePath);
|
|
19954
20128
|
} catch {}
|
|
19955
20129
|
continue;
|
|
19956
20130
|
}
|
|
19957
20131
|
if (!isValidMarker(parsed)) {
|
|
19958
|
-
|
|
20132
|
+
log8.warn(`reconcile: invalid marker structure ${name}, deleting`);
|
|
19959
20133
|
try {
|
|
19960
20134
|
await unlink(filePath);
|
|
19961
20135
|
} catch {}
|
|
@@ -19964,7 +20138,7 @@ async function reconcilePendingCompletions(workspacesRoot) {
|
|
|
19964
20138
|
const marker = parsed;
|
|
19965
20139
|
const age = Date.now() - new Date(marker.createdAt).getTime();
|
|
19966
20140
|
if (age > MARKER_STALE_MS) {
|
|
19967
|
-
|
|
20141
|
+
log8.warn(`reconcile: stale marker ${name} (${Math.round(age / 3600000)}h old), deleting`);
|
|
19968
20142
|
try {
|
|
19969
20143
|
await unlink(filePath);
|
|
19970
20144
|
} catch {}
|
|
@@ -19980,7 +20154,7 @@ async function reconcilePendingCompletions(workspacesRoot) {
|
|
|
19980
20154
|
try {
|
|
19981
20155
|
await unlink(filePath);
|
|
19982
20156
|
} catch (delErr) {
|
|
19983
|
-
|
|
20157
|
+
log8.warn(`reconcile: delivered marker ${name} but failed to delete: ${delErr}`);
|
|
19984
20158
|
}
|
|
19985
20159
|
} catch (deliverErr) {
|
|
19986
20160
|
if (isClientError2(deliverErr)) {
|
|
@@ -19988,11 +20162,11 @@ async function reconcilePendingCompletions(workspacesRoot) {
|
|
|
19988
20162
|
await unlink(filePath);
|
|
19989
20163
|
} catch {}
|
|
19990
20164
|
} else {
|
|
19991
|
-
|
|
20165
|
+
log8.debug(`reconcile: delivery failed for ${name}, will retry next cycle`);
|
|
19992
20166
|
}
|
|
19993
20167
|
}
|
|
19994
20168
|
} catch (e) {
|
|
19995
|
-
|
|
20169
|
+
log8.debug(`reconcile: error processing ${name}`, e);
|
|
19996
20170
|
}
|
|
19997
20171
|
}
|
|
19998
20172
|
}
|
|
@@ -20003,7 +20177,7 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20003
20177
|
}
|
|
20004
20178
|
process.once("exit", () => releaseDaemonPid(profile));
|
|
20005
20179
|
const bailOnUnexpected = (label, err) => {
|
|
20006
|
-
|
|
20180
|
+
log8.error(`${label} — shutting down`, err);
|
|
20007
20181
|
releaseDaemonPid(profile);
|
|
20008
20182
|
process.exit(1);
|
|
20009
20183
|
};
|
|
@@ -20016,21 +20190,21 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20016
20190
|
if (marker) {
|
|
20017
20191
|
clearUpdateMarker(profile);
|
|
20018
20192
|
if (marker === config2.cliVersion) {
|
|
20019
|
-
|
|
20193
|
+
log8.info(`Cleared update marker — now running v${config2.cliVersion}`);
|
|
20020
20194
|
} else {
|
|
20021
|
-
|
|
20195
|
+
log8.info(`Cleared stale update marker (was v${marker}, running v${config2.cliVersion}) — update will be retried`);
|
|
20022
20196
|
}
|
|
20023
20197
|
}
|
|
20024
20198
|
const cliConfig = loadCLIConfigForProfile(profile);
|
|
20025
20199
|
const workspaces = cliConfig.watched_workspaces || [];
|
|
20026
20200
|
if (workspaces.length === 0) {
|
|
20027
|
-
|
|
20201
|
+
log8.error("No watched workspaces configured.");
|
|
20028
20202
|
process.exit(1);
|
|
20029
20203
|
return;
|
|
20030
20204
|
}
|
|
20031
20205
|
const hasPerWorkspaceTokens = workspaces.every((ws) => !!ws.token);
|
|
20032
20206
|
if (!hasPerWorkspaceTokens) {
|
|
20033
|
-
|
|
20207
|
+
log8.error(`Config uses old format. Run '${cmdPrefix()} register --token <token>' for each workspace to upgrade.`);
|
|
20034
20208
|
process.exit(1);
|
|
20035
20209
|
return;
|
|
20036
20210
|
}
|
|
@@ -20050,11 +20224,11 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20050
20224
|
}
|
|
20051
20225
|
}
|
|
20052
20226
|
if (providers.length === 0) {
|
|
20053
|
-
|
|
20227
|
+
log8.error("No agent CLI tools found on PATH.");
|
|
20054
20228
|
process.exit(1);
|
|
20055
20229
|
return;
|
|
20056
20230
|
}
|
|
20057
|
-
|
|
20231
|
+
log8.info(`Detected providers: ${providers.map((p) => `${p.type}@${p.version}`).join(", ")}`);
|
|
20058
20232
|
const workspaceStates = [];
|
|
20059
20233
|
const runtimeIndex = new Map;
|
|
20060
20234
|
for (const ws of workspaces) {
|
|
@@ -20062,7 +20236,7 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20062
20236
|
type: p.type,
|
|
20063
20237
|
version: p.version
|
|
20064
20238
|
}));
|
|
20065
|
-
|
|
20239
|
+
log8.info(`Registering workspace ${ws.id} (${ws.name ?? "unnamed"}) with ${runtimes.length} runtime(s)...`);
|
|
20066
20240
|
let resp;
|
|
20067
20241
|
try {
|
|
20068
20242
|
resp = await client.register(ws.token, {
|
|
@@ -20075,13 +20249,13 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20075
20249
|
});
|
|
20076
20250
|
} catch (e) {
|
|
20077
20251
|
if (e instanceof Error && e.message.startsWith("HTTP 401")) {
|
|
20078
|
-
|
|
20252
|
+
log8.warn(`Workspace ${ws.id} token invalid — skipping (run '${cmdPrefix()} register --token <token>' to fix)`);
|
|
20079
20253
|
} else {
|
|
20080
|
-
|
|
20254
|
+
log8.error(`Failed to register workspace ${ws.id}, skipping`, e);
|
|
20081
20255
|
}
|
|
20082
20256
|
continue;
|
|
20083
20257
|
}
|
|
20084
|
-
|
|
20258
|
+
log8.info(`Workspace ${ws.id} registered — ${resp.runtimes.length} runtime(s)`);
|
|
20085
20259
|
const runtimeIds = resp.runtimes.map((r) => r.id);
|
|
20086
20260
|
workspaceStates.push({ workspaceId: ws.id, token: ws.token, runtimeIds });
|
|
20087
20261
|
for (let i = 0;i < runtimeIds.length; i++) {
|
|
@@ -20093,13 +20267,13 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20093
20267
|
}
|
|
20094
20268
|
}
|
|
20095
20269
|
if (workspaceStates.length === 0) {
|
|
20096
|
-
|
|
20270
|
+
log8.error("No workspaces registered successfully.");
|
|
20097
20271
|
process.exit(1);
|
|
20098
20272
|
return;
|
|
20099
20273
|
}
|
|
20100
20274
|
const allRuntimeIds = workspaceStates.flatMap((ws) => ws.runtimeIds);
|
|
20101
20275
|
health.setRuntimeCount(allRuntimeIds.length);
|
|
20102
|
-
|
|
20276
|
+
log8.info(`Daemon started — ${allRuntimeIds.length} runtime(s) across ${workspaceStates.length} workspace(s)`);
|
|
20103
20277
|
const activeTasks = new Set;
|
|
20104
20278
|
const knownAgentIds = new Set(workspaces.flatMap((ws) => ws.agent_ids ?? []));
|
|
20105
20279
|
function syncAgentId(agentId, workspaceId) {
|
|
@@ -20134,7 +20308,7 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20134
20308
|
cfg.watched_workspaces = (cfg.watched_workspaces || []).filter((w) => w.id !== workspaceId);
|
|
20135
20309
|
saveCLIConfigForProfile(profile, cfg);
|
|
20136
20310
|
} catch {}
|
|
20137
|
-
|
|
20311
|
+
log8.info(`Workspace ${workspaceId} deleted server-side — removed from config`);
|
|
20138
20312
|
}
|
|
20139
20313
|
const pollCycle = async () => {
|
|
20140
20314
|
let remaining = config2.maxConcurrentTasks - activeTasks.size;
|
|
@@ -20160,7 +20334,7 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20160
20334
|
handleCliUpdate(pending_update.version, () => requestRestart(), profile);
|
|
20161
20335
|
}
|
|
20162
20336
|
if (pending_rescan) {
|
|
20163
|
-
|
|
20337
|
+
log8.info("Rescan requested — restarting daemon to re-detect runtimes");
|
|
20164
20338
|
for (const id of evictedIds) {
|
|
20165
20339
|
evictWorkspace(id);
|
|
20166
20340
|
}
|
|
@@ -20173,13 +20347,13 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20173
20347
|
activeTasks.add(task.id);
|
|
20174
20348
|
remaining--;
|
|
20175
20349
|
handleTask(client, config2, runtimeIndex, task, ws.token, activeTasks).catch((e) => {
|
|
20176
|
-
|
|
20350
|
+
log8.error("Task error", e);
|
|
20177
20351
|
activeTasks.delete(task.id);
|
|
20178
20352
|
});
|
|
20179
20353
|
}
|
|
20180
20354
|
if (file_requests) {
|
|
20181
20355
|
for (const req of file_requests) {
|
|
20182
|
-
handleFileRequest(client, config2, ws.workspaceId, req, ws.token).catch((e) =>
|
|
20356
|
+
handleFileRequest(client, config2, ws.workspaceId, req, ws.token).catch((e) => log8.debug("File request error", e));
|
|
20183
20357
|
}
|
|
20184
20358
|
}
|
|
20185
20359
|
if (meetings) {
|
|
@@ -20202,26 +20376,157 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20202
20376
|
}
|
|
20203
20377
|
} catch (e) {
|
|
20204
20378
|
if (e instanceof Error && e.message.startsWith("HTTP 401")) {
|
|
20205
|
-
|
|
20379
|
+
log8.warn(`Workspace ${ws.workspaceId} poll returned 401 — will retry next cycle`);
|
|
20206
20380
|
} else {
|
|
20207
|
-
|
|
20381
|
+
log8.debug("Poll error", e);
|
|
20208
20382
|
}
|
|
20209
20383
|
}
|
|
20210
20384
|
}
|
|
20211
20385
|
for (const id of evictedIds) {
|
|
20212
20386
|
evictWorkspace(id);
|
|
20213
20387
|
}
|
|
20388
|
+
if (workspaceStates.length === 0) {
|
|
20389
|
+
log8.info("All workspaces evicted — shutting down");
|
|
20390
|
+
shutdown();
|
|
20391
|
+
}
|
|
20392
|
+
};
|
|
20393
|
+
let pollTimer = setInterval(pollCycle, config2.pollInterval);
|
|
20394
|
+
const heartbeatPing = () => {
|
|
20395
|
+
for (const ws of workspaceStates) {
|
|
20396
|
+
client.heartbeat(ws.token, config2.daemonId).catch((e) => {
|
|
20397
|
+
log8.debug("heartbeat failed", { workspaceId: ws.workspaceId, err: String(e) });
|
|
20398
|
+
});
|
|
20399
|
+
}
|
|
20400
|
+
};
|
|
20401
|
+
const heartbeatTimer = setInterval(heartbeatPing, config2.heartbeatInterval);
|
|
20402
|
+
const firstToken = workspaceStates[0]?.token;
|
|
20403
|
+
function updatePollInterval(newInterval) {
|
|
20404
|
+
clearInterval(pollTimer);
|
|
20405
|
+
pollTimer = setInterval(pollCycle, newInterval);
|
|
20406
|
+
}
|
|
20407
|
+
function handleWsPush(msg) {
|
|
20408
|
+
switch (msg.type) {
|
|
20409
|
+
case "daemon.tasks":
|
|
20410
|
+
for (const apiTask of msg.tasks) {
|
|
20411
|
+
if (activeTasks.size >= config2.maxConcurrentTasks)
|
|
20412
|
+
break;
|
|
20413
|
+
const task = fromApiTask(apiTask);
|
|
20414
|
+
if (activeTasks.has(task.id))
|
|
20415
|
+
continue;
|
|
20416
|
+
const ws = workspaceStates.find((w) => w.workspaceId === task.workspaceId);
|
|
20417
|
+
if (!ws)
|
|
20418
|
+
continue;
|
|
20419
|
+
syncAgentId(task.agentId, ws.workspaceId);
|
|
20420
|
+
activeTasks.add(task.id);
|
|
20421
|
+
handleTask(client, config2, runtimeIndex, task, ws.token, activeTasks).catch((e) => {
|
|
20422
|
+
log8.error("WS task error", e);
|
|
20423
|
+
activeTasks.delete(task.id);
|
|
20424
|
+
});
|
|
20425
|
+
}
|
|
20426
|
+
break;
|
|
20427
|
+
case "daemon.file_requests": {
|
|
20428
|
+
const ws = workspaceStates.find((w) => w.workspaceId === msg.workspaceId);
|
|
20429
|
+
if (ws) {
|
|
20430
|
+
for (const req of msg.requests) {
|
|
20431
|
+
handleFileRequest(client, config2, ws.workspaceId, req, ws.token).catch((e) => log8.debug("WS file request error", e));
|
|
20432
|
+
}
|
|
20433
|
+
}
|
|
20434
|
+
break;
|
|
20435
|
+
}
|
|
20436
|
+
case "daemon.meetings":
|
|
20437
|
+
for (const m of msg.meetings) {
|
|
20438
|
+
const ws = workspaceStates.find((w) => w.workspaceId === m.workspace_id);
|
|
20439
|
+
if (!ws)
|
|
20440
|
+
continue;
|
|
20441
|
+
const agentBaseDir = join10(config2.workspacesRoot, m.workspace_id, m.agent_id, "workdir");
|
|
20442
|
+
const timelineDir = join10(agentBaseDir, ".context_timeline");
|
|
20443
|
+
spawnMeetingRunner({
|
|
20444
|
+
meetingId: m.id,
|
|
20445
|
+
meetingUrl: m.meeting_url,
|
|
20446
|
+
participants: m.participants,
|
|
20447
|
+
workspaceId: m.workspace_id,
|
|
20448
|
+
callbackUrl: config2.serverURL,
|
|
20449
|
+
authToken: ws.token,
|
|
20450
|
+
agentName: m.agent_name,
|
|
20451
|
+
agentId: m.agent_id,
|
|
20452
|
+
timelineDir,
|
|
20453
|
+
title: m.title
|
|
20454
|
+
});
|
|
20455
|
+
}
|
|
20456
|
+
break;
|
|
20457
|
+
case "daemon.evict":
|
|
20458
|
+
evictWorkspace(msg.workspaceId);
|
|
20459
|
+
break;
|
|
20460
|
+
case "daemon.update":
|
|
20461
|
+
if (!isUpdating() && msg.version !== config2.cliVersion) {
|
|
20462
|
+
handleCliUpdate(msg.version, () => requestRestart(), profile);
|
|
20463
|
+
}
|
|
20464
|
+
break;
|
|
20465
|
+
case "daemon.rescan":
|
|
20466
|
+
log8.info("WS rescan requested — restarting daemon");
|
|
20467
|
+
requestRestart();
|
|
20468
|
+
break;
|
|
20469
|
+
case "daemon.kill": {
|
|
20470
|
+
const ws = workspaceStates.find((w) => w.workspaceId === msg.workspaceId);
|
|
20471
|
+
if (ws) {
|
|
20472
|
+
const killTask = fromApiTask({
|
|
20473
|
+
id: msg.taskId,
|
|
20474
|
+
agent_id: "",
|
|
20475
|
+
runtime_id: "",
|
|
20476
|
+
conversation_id: "",
|
|
20477
|
+
workspace_id: ws.workspaceId,
|
|
20478
|
+
prompt: "",
|
|
20479
|
+
status: "queued",
|
|
20480
|
+
priority: 0,
|
|
20481
|
+
dispatched_at: null,
|
|
20482
|
+
started_at: null,
|
|
20483
|
+
completed_at: null,
|
|
20484
|
+
result: null,
|
|
20485
|
+
error: null,
|
|
20486
|
+
created_at: new Date().toISOString(),
|
|
20487
|
+
type: "kill_task",
|
|
20488
|
+
context: { target_task_id: msg.targetTaskId },
|
|
20489
|
+
agent: null,
|
|
20490
|
+
sender: null
|
|
20491
|
+
});
|
|
20492
|
+
activeTasks.add(killTask.id);
|
|
20493
|
+
handleTask(client, config2, runtimeIndex, killTask, ws.token, activeTasks).catch((e) => {
|
|
20494
|
+
log8.error("WS kill task error", e);
|
|
20495
|
+
activeTasks.delete(killTask.id);
|
|
20496
|
+
});
|
|
20497
|
+
}
|
|
20498
|
+
break;
|
|
20499
|
+
}
|
|
20500
|
+
}
|
|
20501
|
+
}
|
|
20502
|
+
const wsClient = firstToken ? new DaemonWsClient({
|
|
20503
|
+
serverURL: config2.serverURL,
|
|
20504
|
+
daemonId: config2.daemonId,
|
|
20505
|
+
machineToken: firstToken,
|
|
20506
|
+
onMessage: handleWsPush,
|
|
20507
|
+
onConnected: () => {
|
|
20508
|
+
log8.info("WS connected — switching to low-frequency poll");
|
|
20509
|
+
updatePollInterval(config2.wsPollInterval);
|
|
20510
|
+
},
|
|
20511
|
+
onDisconnected: () => {
|
|
20512
|
+
log8.info("WS disconnected — reverting to high-frequency poll");
|
|
20513
|
+
updatePollInterval(config2.pollInterval);
|
|
20514
|
+
}
|
|
20515
|
+
}) : null;
|
|
20516
|
+
wsClient?.connect();
|
|
20517
|
+
const sweepTick = async () => {
|
|
20518
|
+
for (const ws of workspaceStates) {
|
|
20519
|
+
client.sweep(ws.token, config2.daemonId).catch((e) => {
|
|
20520
|
+
log8.debug("sweep ping failed", { workspaceId: ws.workspaceId, err: String(e) });
|
|
20521
|
+
});
|
|
20522
|
+
}
|
|
20214
20523
|
try {
|
|
20215
20524
|
await reconcilePendingCompletions(config2.workspacesRoot);
|
|
20216
20525
|
} catch (e) {
|
|
20217
|
-
|
|
20218
|
-
}
|
|
20219
|
-
if (workspaceStates.length === 0) {
|
|
20220
|
-
log7.info("All workspaces evicted — shutting down");
|
|
20221
|
-
shutdown();
|
|
20526
|
+
log8.debug("reconciliation error", e);
|
|
20222
20527
|
}
|
|
20223
20528
|
};
|
|
20224
|
-
const
|
|
20529
|
+
const sweepTimer = setInterval(sweepTick, config2.sweepInterval);
|
|
20225
20530
|
let shuttingDown = false;
|
|
20226
20531
|
let restartRequested = false;
|
|
20227
20532
|
const requestRestart = () => {
|
|
@@ -20232,8 +20537,11 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20232
20537
|
if (shuttingDown)
|
|
20233
20538
|
return;
|
|
20234
20539
|
shuttingDown = true;
|
|
20235
|
-
|
|
20540
|
+
log8.info(restartRequested ? "Restarting..." : "Shutting down...");
|
|
20236
20541
|
clearInterval(pollTimer);
|
|
20542
|
+
clearInterval(heartbeatTimer);
|
|
20543
|
+
clearInterval(sweepTimer);
|
|
20544
|
+
wsClient?.close();
|
|
20237
20545
|
const shutdownMs = restartRequested ? 30000 : Number(process.env.ALOOK_SHUTDOWN_TIMEOUT_MS) || 5000;
|
|
20238
20546
|
const timeout = setTimeout(() => process.exit(1), shutdownMs);
|
|
20239
20547
|
try {
|
|
@@ -20256,7 +20564,7 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20256
20564
|
mkdirSync7(dirname3(logPath), { recursive: true, mode: 448 });
|
|
20257
20565
|
logFd = openSync(logPath, "a", 384);
|
|
20258
20566
|
} catch (e) {
|
|
20259
|
-
|
|
20567
|
+
log8.error(`Failed to open daemon log file ${logPath}`, e);
|
|
20260
20568
|
}
|
|
20261
20569
|
const child = spawn5(process.execPath, args, {
|
|
20262
20570
|
detached: true,
|
|
@@ -20266,7 +20574,7 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20266
20574
|
child.unref();
|
|
20267
20575
|
if (logFd != null)
|
|
20268
20576
|
closeSync(logFd);
|
|
20269
|
-
|
|
20577
|
+
log8.info(`Spawned new daemon (pid=${child.pid}), logs: ${logPath}`);
|
|
20270
20578
|
}
|
|
20271
20579
|
clearTimeout(timeout);
|
|
20272
20580
|
process.exit(0);
|
|
@@ -20277,7 +20585,7 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20277
20585
|
process.on("SIGHUP", async () => {
|
|
20278
20586
|
if (shuttingDown)
|
|
20279
20587
|
return;
|
|
20280
|
-
|
|
20588
|
+
log8.info("SIGHUP received — reloading config...");
|
|
20281
20589
|
try {
|
|
20282
20590
|
const freshConfig = loadCLIConfigForProfile(profile);
|
|
20283
20591
|
const freshWorkspaces = freshConfig.watched_workspaces || [];
|
|
@@ -20285,7 +20593,7 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20285
20593
|
const newWorkspaces = freshWorkspaces.filter((ws) => ws.token && !existingIds.has(ws.id));
|
|
20286
20594
|
for (const ws of newWorkspaces) {
|
|
20287
20595
|
const runtimes = providers.map((p) => ({ type: p.type, version: p.version }));
|
|
20288
|
-
|
|
20596
|
+
log8.info(`Registering new workspace ${ws.id} (${ws.name ?? "unnamed"})...`);
|
|
20289
20597
|
try {
|
|
20290
20598
|
const resp = await client.register(ws.token, {
|
|
20291
20599
|
workspace_id: ws.id,
|
|
@@ -20304,19 +20612,19 @@ async function startDaemon(profile, serverUrl) {
|
|
|
20304
20612
|
provider: providers[i].type
|
|
20305
20613
|
});
|
|
20306
20614
|
}
|
|
20307
|
-
|
|
20615
|
+
log8.info(`Workspace ${ws.id} added — ${runtimeIds.length} runtime(s)`);
|
|
20308
20616
|
} catch (e) {
|
|
20309
|
-
|
|
20617
|
+
log8.error(`Failed to register new workspace ${ws.id}`, e);
|
|
20310
20618
|
}
|
|
20311
20619
|
}
|
|
20312
20620
|
if (newWorkspaces.length > 0) {
|
|
20313
20621
|
health.setRuntimeCount(workspaceStates.reduce((sum, w) => sum + w.runtimeIds.length, 0));
|
|
20314
|
-
|
|
20622
|
+
log8.info(`Reload complete — now polling ${workspaceStates.length} workspace(s)`);
|
|
20315
20623
|
} else {
|
|
20316
|
-
|
|
20624
|
+
log8.info("Reload complete — no new workspaces found");
|
|
20317
20625
|
}
|
|
20318
20626
|
} catch (e) {
|
|
20319
|
-
|
|
20627
|
+
log8.error("Failed to reload config", e);
|
|
20320
20628
|
}
|
|
20321
20629
|
});
|
|
20322
20630
|
await pollCycle();
|
|
@@ -20331,7 +20639,7 @@ function spawnSessionRunner(input) {
|
|
|
20331
20639
|
try {
|
|
20332
20640
|
fd = openSync(logFilePath, "a");
|
|
20333
20641
|
} catch (e) {
|
|
20334
|
-
|
|
20642
|
+
log8.error(`Failed to open log file ${logFilePath}`, e);
|
|
20335
20643
|
}
|
|
20336
20644
|
const child = spawn5(process.execPath, [sessionRunnerPath, encoded], {
|
|
20337
20645
|
detached: true,
|
|
@@ -20351,7 +20659,7 @@ function spawnMeetingRunner(input) {
|
|
|
20351
20659
|
try {
|
|
20352
20660
|
fd = openSync(logFilePath, "a");
|
|
20353
20661
|
} catch (e) {
|
|
20354
|
-
|
|
20662
|
+
log8.error(`Failed to open meeting log file ${logFilePath}`, e);
|
|
20355
20663
|
}
|
|
20356
20664
|
const child = spawn5(process.execPath, [meetingRunnerPath, encoded], {
|
|
20357
20665
|
detached: true,
|
|
@@ -20360,7 +20668,7 @@ function spawnMeetingRunner(input) {
|
|
|
20360
20668
|
child.unref();
|
|
20361
20669
|
if (fd != null)
|
|
20362
20670
|
closeSync(fd);
|
|
20363
|
-
|
|
20671
|
+
log8.info(`Spawned meeting runner for ${input.meetingId} (pid=${child.pid})`);
|
|
20364
20672
|
return child;
|
|
20365
20673
|
}
|
|
20366
20674
|
async function handleFileRequest(client, config2, workspaceId, req, token) {
|
|
@@ -20387,7 +20695,7 @@ async function handleFileRequest(client, config2, workspaceId, req, token) {
|
|
|
20387
20695
|
}
|
|
20388
20696
|
}
|
|
20389
20697
|
async function handleTask(client, config2, runtimeIndex, task, token, activeTasks) {
|
|
20390
|
-
|
|
20698
|
+
log8.info(`Task ${task.id} claimed agent=${task.agentId}`);
|
|
20391
20699
|
if (task.type === TASK_TYPES.KILL_TASK) {
|
|
20392
20700
|
const targetTaskId = task.context?.target_task_id;
|
|
20393
20701
|
if (!targetTaskId) {
|
|
@@ -20416,18 +20724,18 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
|
|
|
20416
20724
|
try {
|
|
20417
20725
|
process.kill(pid, "SIGTERM");
|
|
20418
20726
|
await client.failTask(token, task.id, "killed");
|
|
20419
|
-
|
|
20727
|
+
log8.info(`Kill task ${task.id}: sent SIGTERM to pid=${pid} for target=${targetTaskId}`);
|
|
20420
20728
|
} catch (e) {
|
|
20421
20729
|
if (e?.code === "ESRCH") {
|
|
20422
20730
|
await client.failTask(token, task.id, "target process already exited");
|
|
20423
|
-
|
|
20731
|
+
log8.info(`Kill task ${task.id}: target pid=${pid} already exited`);
|
|
20424
20732
|
} else {
|
|
20425
20733
|
await client.failTask(token, task.id, `kill failed: ${e}`);
|
|
20426
20734
|
}
|
|
20427
20735
|
}
|
|
20428
20736
|
} else {
|
|
20429
20737
|
await client.failTask(token, task.id, "target not found in timeline");
|
|
20430
|
-
|
|
20738
|
+
log8.info(`Kill task ${task.id}: target ${targetTaskId} not found in timeline`);
|
|
20431
20739
|
}
|
|
20432
20740
|
activeTasks.delete(task.id);
|
|
20433
20741
|
return;
|
|
@@ -20452,12 +20760,12 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
|
|
|
20452
20760
|
const timelineDir = join10(agentBaseDir, ".context_timeline");
|
|
20453
20761
|
const lockAcquired = acquireSteeringLock(agentBaseDir, task.contextKey);
|
|
20454
20762
|
if (!lockAcquired) {
|
|
20455
|
-
|
|
20763
|
+
log8.warn(`Steering lock contention for context_key=${task.contextKey}, proceeding without steering`);
|
|
20456
20764
|
} else {
|
|
20457
20765
|
try {
|
|
20458
20766
|
const predecessor = findRunningEntryByContextKey(timelineDir, task.contextKey, provider);
|
|
20459
20767
|
if (predecessor && predecessor.task_id !== task.id) {
|
|
20460
|
-
|
|
20768
|
+
log8.info(`Steering: task ${task.id} supersedes predecessor ${predecessor.task_id} (context_key=${task.contextKey})`);
|
|
20461
20769
|
if (predecessor.pid != null) {
|
|
20462
20770
|
writeKillIntent(agentBaseDir, {
|
|
20463
20771
|
reason: "superseded",
|
|
@@ -20467,12 +20775,12 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
|
|
|
20467
20775
|
});
|
|
20468
20776
|
try {
|
|
20469
20777
|
process.kill(predecessor.pid, "SIGTERM");
|
|
20470
|
-
|
|
20778
|
+
log8.info(`Steering: sent SIGTERM to predecessor pid=${predecessor.pid}`);
|
|
20471
20779
|
} catch (e) {
|
|
20472
20780
|
if (e?.code === "ESRCH") {
|
|
20473
|
-
|
|
20781
|
+
log8.info(`Steering: predecessor pid=${predecessor.pid} already exited`);
|
|
20474
20782
|
} else {
|
|
20475
|
-
|
|
20783
|
+
log8.warn(`Steering: kill failed for pid=${predecessor.pid}`, e);
|
|
20476
20784
|
}
|
|
20477
20785
|
}
|
|
20478
20786
|
const waitStart = Date.now();
|
|
@@ -20485,14 +20793,14 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
|
|
|
20485
20793
|
await new Promise((r) => setTimeout(r, POLL_MS));
|
|
20486
20794
|
}
|
|
20487
20795
|
if (findRunningPidByTaskId(timelineDir, predecessor.task_id) != null) {
|
|
20488
|
-
|
|
20796
|
+
log8.warn(`Steering: predecessor pid=${predecessor.pid} did not exit within ${MAX_WAIT_MS}ms, proceeding anyway`);
|
|
20489
20797
|
}
|
|
20490
20798
|
}
|
|
20491
20799
|
try {
|
|
20492
20800
|
await client.supersedeTask(token, predecessor.task_id);
|
|
20493
|
-
|
|
20801
|
+
log8.info(`Steering: predecessor ${predecessor.task_id} marked superseded`);
|
|
20494
20802
|
} catch (e) {
|
|
20495
|
-
|
|
20803
|
+
log8.warn(`Steering: failed to mark predecessor superseded server-side`, e);
|
|
20496
20804
|
}
|
|
20497
20805
|
}
|
|
20498
20806
|
} finally {
|
|
@@ -20520,7 +20828,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
|
|
|
20520
20828
|
activeTasks.delete(task.id);
|
|
20521
20829
|
if (code !== 0) {
|
|
20522
20830
|
const msg = code === null ? `session-runner killed by signal (task ${task.id})` : `session-runner crashed (exit code ${code}, task ${task.id})`;
|
|
20523
|
-
|
|
20831
|
+
log8.warn(msg);
|
|
20524
20832
|
const timelineDir = join10(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir", ".context_timeline");
|
|
20525
20833
|
updateEntry(timelineDir, task.id, (entry) => {
|
|
20526
20834
|
entry.pid = null;
|
|
@@ -20531,10 +20839,10 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
|
|
|
20531
20839
|
await client.failTask(token, task.id, msg);
|
|
20532
20840
|
} catch (e) {
|
|
20533
20841
|
if (isClientError2(e)) {
|
|
20534
|
-
|
|
20842
|
+
log8.info(`Backstop: task ${task.id} already in terminal state`);
|
|
20535
20843
|
return;
|
|
20536
20844
|
}
|
|
20537
|
-
|
|
20845
|
+
log8.error(`Backstop: failed to report crash for task ${task.id}`, e);
|
|
20538
20846
|
try {
|
|
20539
20847
|
await writeMarkerFile(config2.workspacesRoot, {
|
|
20540
20848
|
taskId: task.id,
|
|
@@ -20548,7 +20856,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
|
|
|
20548
20856
|
}
|
|
20549
20857
|
}
|
|
20550
20858
|
});
|
|
20551
|
-
|
|
20859
|
+
log8.info(`Task ${task.id} dispatched to session-runner (pid=${child.pid})`);
|
|
20552
20860
|
}
|
|
20553
20861
|
|
|
20554
20862
|
// commands/daemon.ts
|
|
@@ -20722,7 +21030,7 @@ function resolveAgentId(opts) {
|
|
|
20722
21030
|
}
|
|
20723
21031
|
|
|
20724
21032
|
// commands/email.ts
|
|
20725
|
-
var
|
|
21033
|
+
var log9 = createLogger2({ module: "email" });
|
|
20726
21034
|
var VALID_STATUSES = ["unread", "read", "archived", "sent"];
|
|
20727
21035
|
var VALID_FOLDERS = ["inbox", "sent", "untrust"];
|
|
20728
21036
|
var EMAIL_BASE = tempDir("alook-emails");
|
|
@@ -20864,7 +21172,7 @@ function emailCommand() {
|
|
|
20864
21172
|
} catch (err) {
|
|
20865
21173
|
const msg = err instanceof Error ? err.message : String(err);
|
|
20866
21174
|
if (msg.includes("404")) {
|
|
20867
|
-
|
|
21175
|
+
log9.warn(`email body not available for ${email3.id}, skipping`);
|
|
20868
21176
|
continue;
|
|
20869
21177
|
}
|
|
20870
21178
|
throw err;
|
|
@@ -20986,7 +21294,7 @@ function emailCommand() {
|
|
|
20986
21294
|
references = [parentEmail.references, parentEmail.message_id].filter(Boolean).join(" ").trim() || undefined;
|
|
20987
21295
|
}
|
|
20988
21296
|
} catch {
|
|
20989
|
-
|
|
21297
|
+
log9.warn(`could not fetch parent email ${opts.inReplyTo}, sending without threading`);
|
|
20990
21298
|
}
|
|
20991
21299
|
}
|
|
20992
21300
|
const conversationId = process.env.ALOOK_CONVERSATION_ID;
|