@alook/cli 0.0.149 → 0.0.151

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 CHANGED
@@ -14,8 +14,43 @@ var __export = (target, all) => {
14
14
  set: __exportSetter.bind(all, name)
15
15
  });
16
16
  };
17
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
18
19
 
20
+ // ../../node_modules/.pnpm/nanoid@5.1.16/node_modules/nanoid/url-alphabet/index.js
21
+ var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
22
+
23
+ // ../../node_modules/.pnpm/nanoid@5.1.16/node_modules/nanoid/index.js
24
+ import { webcrypto as crypto2 } from "node:crypto";
25
+ function fillPool(bytes) {
26
+ if (bytes < 0)
27
+ throw new RangeError("Wrong ID size");
28
+ try {
29
+ if (!pool || pool.length < bytes) {
30
+ pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
31
+ crypto2.getRandomValues(pool);
32
+ poolOffset = 0;
33
+ } else if (poolOffset + bytes > pool.length) {
34
+ crypto2.getRandomValues(pool);
35
+ poolOffset = 0;
36
+ }
37
+ } catch (e) {
38
+ pool = undefined;
39
+ throw e;
40
+ }
41
+ poolOffset += bytes;
42
+ }
43
+ function nanoid3(size = 21) {
44
+ fillPool(size |= 0);
45
+ let id = "";
46
+ for (let i = poolOffset - size;i < poolOffset; i++) {
47
+ id += urlAlphabet[pool[i] & 63];
48
+ }
49
+ return id;
50
+ }
51
+ var POOL_SIZE_MULTIPLIER = 128, pool, poolOffset;
52
+ var init_nanoid = () => {};
53
+
19
54
  // src/index.ts
20
55
  import { Command as Command14 } from "commander";
21
56
 
@@ -154,6 +189,7 @@ var TERMINAL_ISSUE_STATUSES = [
154
189
  ];
155
190
  var POLL_INTERVAL_MS = Number(process.env.POLL_INTERVAL_MS) || 3000;
156
191
  var OFFLINE_THRESHOLD_MS = Number(process.env.OFFLINE_THRESHOLD_MS) || 30000;
192
+ var COMMUNITY_MACHINE_PAIR_TOKEN_TTL_MS = 15 * 60000;
157
193
  var EVENT_POLL_INTERVAL_MS = Number(process.env.EVENT_POLL_INTERVAL_MS) || 2000;
158
194
  var MeetingStatus = {
159
195
  PENDING: "pending",
@@ -167,9 +203,28 @@ var TERMINAL_MEETING_STATUSES = [
167
203
  MeetingStatus.COMPLETED,
168
204
  MeetingStatus.FAILED
169
205
  ];
170
- var DEV_WEB_URL = process.env.ALOOK_SERVER_URL || "http://localhost:3000";
171
- var DEV_WS_DO_URL = process.env.DEV_WS_DO_URL || "http://localhost:8789";
172
- var DEV_EMAIL_WORKER_URL = process.env.DEV_EMAIL_WORKER_URL || "http://localhost:8787";
206
+ var COMMUNITY_BOT_NAME_MIN = 1;
207
+ var COMMUNITY_BOT_NAME_MAX = 32;
208
+ var COMMUNITY_BOT_DESCRIPTION_MAX = 1024;
209
+ var COMMUNITY_BOT_IMAGE_URL_MAX = 2048;
210
+ var DEV_PORTS = {
211
+ web: 3000,
212
+ emailWorker: 8787,
213
+ wsDo: 8789,
214
+ wakeWorker: 8790
215
+ };
216
+ var DEV_WEB_URL = process.env.ALOOK_SERVER_URL || `http://localhost:${DEV_PORTS.web}`;
217
+ var DEV_WS_DO_URL = process.env.DEV_WS_DO_URL || `http://localhost:${DEV_PORTS.wsDo}`;
218
+ var DEV_EMAIL_WORKER_URL = process.env.DEV_EMAIL_WORKER_URL || `http://localhost:${DEV_PORTS.emailWorker}`;
219
+ var DEV_WAKE_WORKER_URL = process.env.DEV_WAKE_WORKER_URL || `http://localhost:${DEV_PORTS.wakeWorker}`;
220
+ function devWsDoPort() {
221
+ const port = Number(new URL(DEV_WS_DO_URL).port);
222
+ return port || DEV_PORTS.wsDo;
223
+ }
224
+ // ../shared/src/constants/community.ts
225
+ var MAX_MESSAGE_CONTENT_LENGTH = 4000;
226
+ var MAX_ATTACHMENT_SIZE_BYTES = 25 * 1024 * 1024;
227
+ var MAX_SERVER_ICON_SIZE_BYTES = 5 * 1024 * 1024;
173
228
  // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
174
229
  var exports_external = {};
175
230
  __export(exports_external, {
@@ -14934,7 +14989,149 @@ var CreateThreadRequestSchema = exports_external.object({
14934
14989
  content: exports_external.string().optional().default(""),
14935
14990
  attachment_ids: exports_external.array(exports_external.string()).optional()
14936
14991
  });
14937
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/entity.js
14992
+ var COMMUNITY_RUNTIME_ID_MAX = 64;
14993
+ var COMMUNITY_RUNTIME_VERSION_MAX = 64;
14994
+ var COMMUNITY_RUNTIME_LIST_MAX = 64;
14995
+ var RUNTIME_ID_RE = /^[A-Za-z0-9._@/-]+$/;
14996
+ var CommunityMachineRuntimeSchema = exports_external.object({
14997
+ id: exports_external.string().min(1).max(COMMUNITY_RUNTIME_ID_MAX).regex(RUNTIME_ID_RE, "invalid runtime id charset"),
14998
+ version: exports_external.string().max(COMMUNITY_RUNTIME_VERSION_MAX).optional(),
14999
+ status: exports_external.enum(["healthy", "unhealthy"]).catch("healthy").default("healthy"),
15000
+ lastError: exports_external.string().max(128).optional(),
15001
+ lastErrorAt: exports_external.string().optional()
15002
+ });
15003
+ var CommunityMachineRuntimeListSchema = exports_external.array(CommunityMachineRuntimeSchema).max(COMMUNITY_RUNTIME_LIST_MAX).transform((list) => {
15004
+ const seen = new Set;
15005
+ const out = [];
15006
+ for (const r of list) {
15007
+ if (seen.has(r.id))
15008
+ continue;
15009
+ seen.add(r.id);
15010
+ out.push(r);
15011
+ }
15012
+ return out;
15013
+ });
15014
+ var CommunityMachineSummarySchema = exports_external.object({
15015
+ id: exports_external.string(),
15016
+ hostname: exports_external.string(),
15017
+ displayName: exports_external.string(),
15018
+ platform: exports_external.string(),
15019
+ arch: exports_external.string(),
15020
+ osRelease: exports_external.string(),
15021
+ daemonVersion: exports_external.string(),
15022
+ lastSeenAt: exports_external.string().nullable(),
15023
+ status: exports_external.enum(["online", "offline"]),
15024
+ availableRuntimes: exports_external.array(CommunityMachineRuntimeSchema).default([]),
15025
+ lastRuntimeError: exports_external.object({
15026
+ requested: exports_external.string(),
15027
+ available: exports_external.array(exports_external.string()),
15028
+ at: exports_external.string()
15029
+ }).optional(),
15030
+ createdAt: exports_external.string(),
15031
+ updatedAt: exports_external.string()
15032
+ });
15033
+ var HostReadyMessageSchema = exports_external.object({
15034
+ type: exports_external.literal("ready"),
15035
+ runtimeReport: CommunityMachineRuntimeListSchema,
15036
+ runningAgents: exports_external.array(exports_external.string()).default([]),
15037
+ hostname: exports_external.string().optional(),
15038
+ platform: exports_external.string().optional(),
15039
+ arch: exports_external.string().optional(),
15040
+ osRelease: exports_external.string().optional(),
15041
+ daemonVersion: exports_external.string().optional()
15042
+ });
15043
+ var CommunityDaemonReadySchema = exports_external.object({
15044
+ runtimeReport: CommunityMachineRuntimeListSchema.optional(),
15045
+ runningAgents: exports_external.array(exports_external.string()).default([]),
15046
+ hostname: exports_external.string().optional(),
15047
+ os: exports_external.string().optional(),
15048
+ arch: exports_external.string().optional(),
15049
+ osRelease: exports_external.string().optional(),
15050
+ daemonVersion: exports_external.string().optional()
15051
+ });
15052
+ var SessionErrorFrameSchema = exports_external.object({
15053
+ type: exports_external.literal("session.error"),
15054
+ code: exports_external.enum(["runtime_not_available"]),
15055
+ agentId: exports_external.string().optional(),
15056
+ payload: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
15057
+ });
15058
+ var CommunityPairTokenResponseSchema = exports_external.object({
15059
+ tokenId: exports_external.string(),
15060
+ expiresAt: exports_external.string()
15061
+ });
15062
+ var CommunityDaemonActivateRequestSchema = exports_external.object({
15063
+ hostname: exports_external.string(),
15064
+ platform: exports_external.string(),
15065
+ arch: exports_external.string(),
15066
+ osRelease: exports_external.string().optional(),
15067
+ daemonVersion: exports_external.string().optional(),
15068
+ runtimeReport: CommunityMachineRuntimeListSchema.optional()
15069
+ });
15070
+ var CommunityDaemonActivateResponseSchema = exports_external.object({
15071
+ credential: exports_external.string(),
15072
+ machineId: exports_external.string(),
15073
+ expiresAt: exports_external.string().nullable()
15074
+ });
15075
+ var CommunityDaemonEnrollAgentRequestSchema = exports_external.object({
15076
+ agentId: exports_external.string().min(1).max(128)
15077
+ });
15078
+ var CommunityDaemonEnrollAgentResponseSchema = exports_external.object({
15079
+ runnerKey: exports_external.string(),
15080
+ expiresAt: exports_external.string().nullable()
15081
+ });
15082
+ var BotImageUrlSchema = exports_external.string().max(COMMUNITY_BOT_IMAGE_URL_MAX).refine((v) => v.startsWith("https://") || v.startsWith("avatar:"), {
15083
+ message: "image must be an https URL or an avatar: config"
15084
+ });
15085
+ var CommunityBotCreateRequestSchema = exports_external.object({
15086
+ name: exports_external.string().trim().min(COMMUNITY_BOT_NAME_MIN).max(COMMUNITY_BOT_NAME_MAX),
15087
+ description: exports_external.string().max(COMMUNITY_BOT_DESCRIPTION_MAX).optional(),
15088
+ machineId: exports_external.string().min(1),
15089
+ runtime: exports_external.string().min(1),
15090
+ image: BotImageUrlSchema.optional()
15091
+ });
15092
+ var CommunityBotPatchRequestSchema = exports_external.object({
15093
+ name: exports_external.string().trim().min(COMMUNITY_BOT_NAME_MIN).max(COMMUNITY_BOT_NAME_MAX).optional(),
15094
+ description: exports_external.string().max(COMMUNITY_BOT_DESCRIPTION_MAX).optional(),
15095
+ image: BotImageUrlSchema.nullable().optional()
15096
+ }).refine((v) => v.name !== undefined || v.description !== undefined || v.image !== undefined, {
15097
+ message: "at least one field must be provided"
15098
+ });
15099
+ var CommunityBotAddToServerRequestSchema = exports_external.object({
15100
+ botId: exports_external.string().min(1)
15101
+ });
15102
+ var CommunityAgentMessageContentSchema = exports_external.object({ text: exports_external.string().min(1).max(MAX_MESSAGE_CONTENT_LENGTH) }).catchall(exports_external.unknown());
15103
+ var CommunityAgentSeqSchema = exports_external.number().int().min(0);
15104
+ var CommunityAgentPositiveSeqSchema = exports_external.number().int().min(1);
15105
+ var CommunityAgentCursorSchema = exports_external.object({
15106
+ channel: exports_external.string().min(1),
15107
+ seq: CommunityAgentPositiveSeqSchema
15108
+ });
15109
+ var CommunityAgentSendRequestSchema = exports_external.object({
15110
+ channel: exports_external.string().min(1),
15111
+ content: CommunityAgentMessageContentSchema,
15112
+ seenUpToSeq: CommunityAgentSeqSchema.optional()
15113
+ });
15114
+ var CommunityAgentInboxPullRequestSchema = exports_external.object({
15115
+ max: exports_external.number().int().min(1).max(200).optional()
15116
+ });
15117
+ var CommunityAgentAckRequestSchema = exports_external.object({
15118
+ cursors: exports_external.array(CommunityAgentCursorSchema).min(1)
15119
+ });
15120
+ var CommunityAgentReadRequestSchema = exports_external.object({
15121
+ channel: exports_external.string().min(1),
15122
+ before: CommunityAgentSeqSchema.optional(),
15123
+ after: CommunityAgentSeqSchema.optional(),
15124
+ around: CommunityAgentSeqSchema.optional(),
15125
+ limit: exports_external.number().int().min(1).max(200).optional()
15126
+ }).refine((v) => [v.before, v.after, v.around].filter((x) => x !== undefined).length <= 1, { message: "at most one of before/after/around may be supplied" });
15127
+ var CommunityAgentResolveRequestSchema = exports_external.object({
15128
+ channel: exports_external.string().min(1),
15129
+ seq: CommunityAgentSeqSchema
15130
+ });
15131
+ var CommunityAgentListChannelsRequestSchema = exports_external.object({
15132
+ server: exports_external.string().min(1).optional()
15133
+ });
15134
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/entity.js
14938
15135
  var entityKind = Symbol.for("drizzle:entityKind");
14939
15136
  var hasOwnEntityKind = Symbol.for("drizzle:hasOwnEntityKind");
14940
15137
  function is(value, type) {
@@ -14959,48 +15156,7 @@ function is(value, type) {
14959
15156
  return false;
14960
15157
  }
14961
15158
 
14962
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/table.utils.js
14963
- var TableName = Symbol.for("drizzle:Name");
14964
-
14965
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/table.js
14966
- var Schema = Symbol.for("drizzle:Schema");
14967
- var Columns = Symbol.for("drizzle:Columns");
14968
- var ExtraConfigColumns = Symbol.for("drizzle:ExtraConfigColumns");
14969
- var OriginalName = Symbol.for("drizzle:OriginalName");
14970
- var BaseName = Symbol.for("drizzle:BaseName");
14971
- var IsAlias = Symbol.for("drizzle:IsAlias");
14972
- var ExtraConfigBuilder = Symbol.for("drizzle:ExtraConfigBuilder");
14973
- var IsDrizzleTable = Symbol.for("drizzle:IsDrizzleTable");
14974
-
14975
- class Table {
14976
- static [entityKind] = "Table";
14977
- static Symbol = {
14978
- Name: TableName,
14979
- Schema,
14980
- OriginalName,
14981
- Columns,
14982
- ExtraConfigColumns,
14983
- BaseName,
14984
- IsAlias,
14985
- ExtraConfigBuilder
14986
- };
14987
- [TableName];
14988
- [OriginalName];
14989
- [Schema];
14990
- [Columns];
14991
- [ExtraConfigColumns];
14992
- [BaseName];
14993
- [IsAlias] = false;
14994
- [IsDrizzleTable] = true;
14995
- [ExtraConfigBuilder] = undefined;
14996
- constructor(name, schema, baseName) {
14997
- this[TableName] = this[OriginalName] = name;
14998
- this[Schema] = schema;
14999
- this[BaseName] = baseName;
15000
- }
15001
- }
15002
-
15003
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/column.js
15159
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/column.js
15004
15160
  class Column {
15005
15161
  constructor(table, config2) {
15006
15162
  this.table = table;
@@ -15050,7 +15206,7 @@ class Column {
15050
15206
  }
15051
15207
  }
15052
15208
 
15053
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/column-builder.js
15209
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/column-builder.js
15054
15210
  class ColumnBuilder {
15055
15211
  static [entityKind] = "ColumnBuilder";
15056
15212
  config;
@@ -15106,17 +15262,20 @@ class ColumnBuilder {
15106
15262
  }
15107
15263
  }
15108
15264
 
15109
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/tracing-utils.js
15265
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/table.utils.js
15266
+ var TableName = Symbol.for("drizzle:Name");
15267
+
15268
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/tracing-utils.js
15110
15269
  function iife(fn, ...args) {
15111
15270
  return fn(...args);
15112
15271
  }
15113
15272
 
15114
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/pg-core/unique-constraint.js
15273
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/pg-core/unique-constraint.js
15115
15274
  function uniqueKeyName(table, columns) {
15116
15275
  return `${table[TableName]}_${columns.join("_")}_unique`;
15117
15276
  }
15118
15277
 
15119
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/pg-core/columns/common.js
15278
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/pg-core/columns/common.js
15120
15279
  class PgColumn extends Column {
15121
15280
  constructor(table, config2) {
15122
15281
  if (!config2.uniqueName) {
@@ -15165,7 +15324,7 @@ class ExtraConfigColumn extends PgColumn {
15165
15324
  }
15166
15325
  }
15167
15326
 
15168
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/pg-core/columns/enum.js
15327
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/pg-core/columns/enum.js
15169
15328
  class PgEnumObjectColumn extends PgColumn {
15170
15329
  static [entityKind] = "PgEnumObjectColumn";
15171
15330
  enum;
@@ -15195,7 +15354,7 @@ class PgEnumColumn extends PgColumn {
15195
15354
  }
15196
15355
  }
15197
15356
 
15198
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/subquery.js
15357
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/subquery.js
15199
15358
  class Subquery {
15200
15359
  static [entityKind] = "Subquery";
15201
15360
  constructor(sql, fields, alias, isWith = false, usedTables = []) {
@@ -15210,10 +15369,10 @@ class Subquery {
15210
15369
  }
15211
15370
  }
15212
15371
 
15213
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/version.js
15372
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/version.js
15214
15373
  var version2 = "0.45.2";
15215
15374
 
15216
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/tracing.js
15375
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/tracing.js
15217
15376
  var otel;
15218
15377
  var rawTracer;
15219
15378
  var tracer = {
@@ -15240,10 +15399,48 @@ var tracer = {
15240
15399
  }
15241
15400
  };
15242
15401
 
15243
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/view-common.js
15402
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/view-common.js
15244
15403
  var ViewBaseConfig = Symbol.for("drizzle:ViewBaseConfig");
15245
15404
 
15246
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/sql/sql.js
15405
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/table.js
15406
+ var Schema = Symbol.for("drizzle:Schema");
15407
+ var Columns = Symbol.for("drizzle:Columns");
15408
+ var ExtraConfigColumns = Symbol.for("drizzle:ExtraConfigColumns");
15409
+ var OriginalName = Symbol.for("drizzle:OriginalName");
15410
+ var BaseName = Symbol.for("drizzle:BaseName");
15411
+ var IsAlias = Symbol.for("drizzle:IsAlias");
15412
+ var ExtraConfigBuilder = Symbol.for("drizzle:ExtraConfigBuilder");
15413
+ var IsDrizzleTable = Symbol.for("drizzle:IsDrizzleTable");
15414
+
15415
+ class Table {
15416
+ static [entityKind] = "Table";
15417
+ static Symbol = {
15418
+ Name: TableName,
15419
+ Schema,
15420
+ OriginalName,
15421
+ Columns,
15422
+ ExtraConfigColumns,
15423
+ BaseName,
15424
+ IsAlias,
15425
+ ExtraConfigBuilder
15426
+ };
15427
+ [TableName];
15428
+ [OriginalName];
15429
+ [Schema];
15430
+ [Columns];
15431
+ [ExtraConfigColumns];
15432
+ [BaseName];
15433
+ [IsAlias] = false;
15434
+ [IsDrizzleTable] = true;
15435
+ [ExtraConfigBuilder] = undefined;
15436
+ constructor(name, schema, baseName) {
15437
+ this[TableName] = this[OriginalName] = name;
15438
+ this[Schema] = schema;
15439
+ this[BaseName] = baseName;
15440
+ }
15441
+ }
15442
+
15443
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/sql/sql.js
15247
15444
  function isSQLWrapper(value) {
15248
15445
  return value !== null && value !== undefined && typeof value.getSQL === "function";
15249
15446
  }
@@ -15603,7 +15800,7 @@ Subquery.prototype.getSQL = function() {
15603
15800
  return new SQL([this]);
15604
15801
  };
15605
15802
 
15606
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/utils.js
15803
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/utils.js
15607
15804
  function getColumnNameAndConfig(a, b) {
15608
15805
  return {
15609
15806
  name: typeof a === "string" && a.length > 0 ? a : "",
@@ -15612,7 +15809,32 @@ function getColumnNameAndConfig(a, b) {
15612
15809
  }
15613
15810
  var textDecoder = typeof TextDecoder === "undefined" ? null : new TextDecoder;
15614
15811
 
15615
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/sqlite-core/foreign-keys.js
15812
+ // ../shared/src/db/community-schema.ts
15813
+ var exports_community_schema = {};
15814
+ __export(exports_community_schema, {
15815
+ communityUserProfile: () => communityUserProfile,
15816
+ communityServerMember: () => communityServerMember,
15817
+ communityServerInvite: () => communityServerInvite,
15818
+ communityServerFolderItem: () => communityServerFolderItem,
15819
+ communityServerFolder: () => communityServerFolder,
15820
+ communityServer: () => communityServer,
15821
+ communityReadState: () => communityReadState,
15822
+ communityReaction: () => communityReaction,
15823
+ communityPin: () => communityPin,
15824
+ communityNotificationSetting: () => communityNotificationSetting,
15825
+ communityMessageSeq: () => communityMessageSeq,
15826
+ communityMessage: () => communityMessage,
15827
+ communityMention: () => communityMention,
15828
+ communityFriendship: () => communityFriendship,
15829
+ communityDmConversation: () => communityDmConversation,
15830
+ communityChannel: () => communityChannel,
15831
+ communityCategory: () => communityCategory,
15832
+ communityBotApprovalRequest: () => communityBotApprovalRequest,
15833
+ communityAuditLog: () => communityAuditLog,
15834
+ communityAttachment: () => communityAttachment
15835
+ });
15836
+
15837
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/sqlite-core/foreign-keys.js
15616
15838
  class ForeignKeyBuilder {
15617
15839
  static [entityKind] = "SQLiteForeignKeyBuilder";
15618
15840
  reference;
@@ -15680,7 +15902,7 @@ function foreignKey(config2) {
15680
15902
  return new ForeignKeyBuilder(mappedConfig);
15681
15903
  }
15682
15904
 
15683
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/sqlite-core/unique-constraint.js
15905
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/sqlite-core/unique-constraint.js
15684
15906
  function uniqueKeyName2(table, columns) {
15685
15907
  return `${table[TableName]}_${columns.join("_")}_unique`;
15686
15908
  }
@@ -15725,7 +15947,7 @@ class UniqueConstraint {
15725
15947
  }
15726
15948
  }
15727
15949
 
15728
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/sqlite-core/columns/common.js
15950
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/sqlite-core/columns/common.js
15729
15951
  class SQLiteColumnBuilder extends ColumnBuilder {
15730
15952
  static [entityKind] = "SQLiteColumnBuilder";
15731
15953
  foreignKeyConfigs = [];
@@ -15776,7 +15998,7 @@ class SQLiteColumn extends Column {
15776
15998
  static [entityKind] = "SQLiteColumn";
15777
15999
  }
15778
16000
 
15779
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/sqlite-core/columns/blob.js
16001
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/sqlite-core/columns/blob.js
15780
16002
  class SQLiteBigIntBuilder extends SQLiteColumnBuilder {
15781
16003
  static [entityKind] = "SQLiteBigIntBuilder";
15782
16004
  constructor(name) {
@@ -15864,7 +16086,7 @@ function blob(a, b) {
15864
16086
  return new SQLiteBlobBufferBuilder(name);
15865
16087
  }
15866
16088
 
15867
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/sqlite-core/columns/custom.js
16089
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/sqlite-core/columns/custom.js
15868
16090
  class SQLiteCustomColumnBuilder extends SQLiteColumnBuilder {
15869
16091
  static [entityKind] = "SQLiteCustomColumnBuilder";
15870
16092
  constructor(name, fieldConfig, customTypeParams) {
@@ -15905,7 +16127,7 @@ function customType(customTypeParams) {
15905
16127
  };
15906
16128
  }
15907
16129
 
15908
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/sqlite-core/columns/integer.js
16130
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/sqlite-core/columns/integer.js
15909
16131
  class SQLiteBaseIntegerBuilder extends SQLiteColumnBuilder {
15910
16132
  static [entityKind] = "SQLiteBaseIntegerBuilder";
15911
16133
  constructor(name, dataType, columnType) {
@@ -16007,7 +16229,7 @@ function integer2(a, b) {
16007
16229
  return new SQLiteIntegerBuilder(name);
16008
16230
  }
16009
16231
 
16010
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/sqlite-core/columns/numeric.js
16232
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/sqlite-core/columns/numeric.js
16011
16233
  class SQLiteNumericBuilder extends SQLiteColumnBuilder {
16012
16234
  static [entityKind] = "SQLiteNumericBuilder";
16013
16235
  constructor(name) {
@@ -16077,7 +16299,7 @@ function numeric(a, b) {
16077
16299
  return mode === "number" ? new SQLiteNumericNumberBuilder(name) : mode === "bigint" ? new SQLiteNumericBigIntBuilder(name) : new SQLiteNumericBuilder(name);
16078
16300
  }
16079
16301
 
16080
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/sqlite-core/columns/real.js
16302
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/sqlite-core/columns/real.js
16081
16303
  class SQLiteRealBuilder extends SQLiteColumnBuilder {
16082
16304
  static [entityKind] = "SQLiteRealBuilder";
16083
16305
  constructor(name) {
@@ -16098,7 +16320,7 @@ function real(name) {
16098
16320
  return new SQLiteRealBuilder(name ?? "");
16099
16321
  }
16100
16322
 
16101
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/sqlite-core/columns/text.js
16323
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/sqlite-core/columns/text.js
16102
16324
  class SQLiteTextBuilder extends SQLiteColumnBuilder {
16103
16325
  static [entityKind] = "SQLiteTextBuilder";
16104
16326
  constructor(name, config2) {
@@ -16153,7 +16375,7 @@ function text(a, b = {}) {
16153
16375
  return new SQLiteTextBuilder(name, config2);
16154
16376
  }
16155
16377
 
16156
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/sqlite-core/columns/all.js
16378
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/sqlite-core/columns/all.js
16157
16379
  function getSQLiteColumnBuilders() {
16158
16380
  return {
16159
16381
  blob,
@@ -16165,7 +16387,7 @@ function getSQLiteColumnBuilders() {
16165
16387
  };
16166
16388
  }
16167
16389
 
16168
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/sqlite-core/table.js
16390
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/sqlite-core/table.js
16169
16391
  var InlineForeignKeys = Symbol.for("drizzle:SQLiteInlineForeignKeys");
16170
16392
 
16171
16393
  class SQLiteTable extends Table {
@@ -16199,7 +16421,7 @@ var sqliteTable = (name, columns, extraConfig) => {
16199
16421
  return sqliteTableBase(name, columns, extraConfig);
16200
16422
  };
16201
16423
 
16202
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/sqlite-core/indexes.js
16424
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/sqlite-core/indexes.js
16203
16425
  class IndexBuilderOn {
16204
16426
  constructor(name, unique2) {
16205
16427
  this.name = name;
@@ -16241,8 +16463,11 @@ class Index {
16241
16463
  function index(name) {
16242
16464
  return new IndexBuilderOn(name, false);
16243
16465
  }
16466
+ function uniqueIndex(name) {
16467
+ return new IndexBuilderOn(name, true);
16468
+ }
16244
16469
 
16245
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260621.1_@opentelemetry+api@1.9.1_@typ_093d71d59478de43c1b72877af7be041/node_modules/drizzle-orm/sqlite-core/primary-keys.js
16470
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260702.1_@opentelemetry+api@1.9.1_@typ_9f1a3370d3c5742dfd96aef86d667915/node_modules/drizzle-orm/sqlite-core/primary-keys.js
16246
16471
  function primaryKey(...config2) {
16247
16472
  if (config2[0].columns) {
16248
16473
  return new PrimaryKeyBuilder(config2[0].columns, config2[0].name);
@@ -16277,44 +16502,48 @@ class PrimaryKey {
16277
16502
  }
16278
16503
  }
16279
16504
 
16280
- // ../../node_modules/.pnpm/nanoid@5.1.15/node_modules/nanoid/index.js
16281
- import { webcrypto as crypto } from "node:crypto";
16282
-
16283
- // ../../node_modules/.pnpm/nanoid@5.1.15/node_modules/nanoid/url-alphabet/index.js
16284
- var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
16285
-
16286
- // ../../node_modules/.pnpm/nanoid@5.1.15/node_modules/nanoid/index.js
16287
- var POOL_SIZE_MULTIPLIER = 128;
16288
- var pool;
16289
- var poolOffset;
16290
- function fillPool(bytes) {
16291
- if (bytes < 0)
16292
- throw new RangeError("Wrong ID size");
16293
- try {
16294
- if (!pool || pool.length < bytes) {
16295
- pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
16296
- crypto.getRandomValues(pool);
16297
- poolOffset = 0;
16298
- } else if (poolOffset + bytes > pool.length) {
16299
- crypto.getRandomValues(pool);
16300
- poolOffset = 0;
16301
- }
16302
- } catch (e) {
16303
- pool = undefined;
16304
- throw e;
16305
- }
16306
- poolOffset += bytes;
16307
- }
16308
- function nanoid3(size = 21) {
16309
- fillPool(size |= 0);
16310
- let id = "";
16311
- for (let i = poolOffset - size;i < poolOffset; i++) {
16312
- id += urlAlphabet[pool[i] & 63];
16313
- }
16314
- return id;
16315
- }
16505
+ // ../shared/src/db/community-schema.ts
16506
+ init_nanoid();
16316
16507
 
16317
16508
  // ../shared/src/db/schema.ts
16509
+ var exports_schema = {};
16510
+ __export(exports_schema, {
16511
+ workspaceInvite: () => workspaceInvite,
16512
+ workspaceFileRequest: () => workspaceFileRequest,
16513
+ workspace: () => workspace,
16514
+ verification: () => verification,
16515
+ user: () => user,
16516
+ taskMessage: () => taskMessage,
16517
+ session: () => session,
16518
+ messageFlag: () => messageFlag,
16519
+ message: () => message,
16520
+ member: () => member,
16521
+ meetingSession: () => meetingSession,
16522
+ machineToken: () => machineToken,
16523
+ machine: () => machine,
16524
+ issueComment: () => issueComment,
16525
+ issue: () => issue2,
16526
+ inboxUnread: () => inboxUnread,
16527
+ emails: () => emails,
16528
+ conversationReadState: () => conversationReadState,
16529
+ conversationMap: () => conversationMap,
16530
+ conversation: () => conversation,
16531
+ channel: () => channel,
16532
+ calendarEvent: () => calendarEvent,
16533
+ artifact: () => artifact,
16534
+ agentWhitelist: () => agentWhitelist,
16535
+ agentTaskQueue: () => agentTaskQueue,
16536
+ agentSkill: () => agentSkill,
16537
+ agentSidebarOrder: () => agentSidebarOrder,
16538
+ agentRuntime: () => agentRuntime,
16539
+ agentPin: () => agentPin,
16540
+ agentLink: () => agentLink,
16541
+ agentEmailAccount: () => agentEmailAccount,
16542
+ agentAccess: () => agentAccess,
16543
+ agent: () => agent,
16544
+ account: () => account
16545
+ });
16546
+ init_nanoid();
16318
16547
  var user = sqliteTable("user", {
16319
16548
  id: text("id").primaryKey().$defaultFn(() => nanoid3()),
16320
16549
  name: text("name").notNull().default(""),
@@ -16322,8 +16551,12 @@ var user = sqliteTable("user", {
16322
16551
  emailVerified: integer2("emailVerified", { mode: "boolean" }),
16323
16552
  image: text("image"),
16324
16553
  createdAt: text("createdAt").notNull().$defaultFn(() => new Date().toISOString()),
16325
- updatedAt: text("updatedAt").notNull().$defaultFn(() => new Date().toISOString())
16326
- });
16554
+ updatedAt: text("updatedAt").notNull().$defaultFn(() => new Date().toISOString()),
16555
+ isBot: integer2("isBot", { mode: "boolean" }).notNull().default(false),
16556
+ ownerUserId: text("ownerUserId"),
16557
+ deletedAt: text("deletedAt"),
16558
+ discriminator: text("discriminator").notNull().default("0000")
16559
+ }, (t) => [index("idx_user_ownerUserId_isBot").on(t.ownerUserId, t.isBot)]);
16327
16560
  var session = sqliteTable("session", {
16328
16561
  id: text("id").primaryKey().$defaultFn(() => nanoid3()),
16329
16562
  userId: text("userId").notNull().references(() => user.id, { onDelete: "cascade" }),
@@ -16859,84 +17092,518 @@ var inboxUnread = sqliteTable("inbox_unread", {
16859
17092
  unique("inbox_unread_conv_user").on(t.conversationId, t.userId),
16860
17093
  index("idx_inbox_unread_user_ws").on(t.userId, t.workspaceId, t.taskType, t.completedAt)
16861
17094
  ]);
16862
- // ../shared/src/db/queries/task.ts
16863
- var DEFAULT_STALE_SECONDS = Number(process.env.ALOOK_STALE_DISPATCH_TIMEOUT_S) || 20;
16864
- var DEFAULT_STALE_RUNNING_SECONDS = Number(process.env.ALOOK_STALE_RUNNING_TIMEOUT_S) || 3600;
16865
- // ../shared/src/utils/email.ts
16866
- var DOMAIN = `@${process.env.ALOOK_DOMAIN || "alook.ai"}`;
16867
- var RESERVED_HANDLES = new Set([
16868
- "no-reply",
16869
- "noreply",
16870
- "admin",
16871
- "support",
16872
- "help",
16873
- "info",
16874
- "postmaster",
16875
- "abuse",
16876
- "security",
16877
- "mailer-daemon",
16878
- "root",
16879
- "webmaster",
16880
- "hostmaster",
16881
- "system",
16882
- "alook"
17095
+
17096
+ // ../shared/src/db/community-schema.ts
17097
+ var communityServer = sqliteTable("community_server", {
17098
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17099
+ name: text("name").notNull(),
17100
+ description: text("description").default(""),
17101
+ icon: text("icon"),
17102
+ ownerId: text("owner_id").notNull().references(() => user.id, { onDelete: "restrict" }),
17103
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17104
+ });
17105
+ var communityCategory = sqliteTable("community_category", {
17106
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17107
+ serverId: text("server_id").notNull().references(() => communityServer.id, { onDelete: "cascade" }),
17108
+ name: text("name").notNull(),
17109
+ position: integer2("position").default(0),
17110
+ private: integer2("private").default(0),
17111
+ creatorId: text("creator_id").references(() => user.id, { onDelete: "set null" })
17112
+ }, (t) => [unique("uq_category_server_name").on(t.serverId, t.name)]);
17113
+ var communityChannel = sqliteTable("community_channel", {
17114
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17115
+ serverId: text("server_id").notNull().references(() => communityServer.id, { onDelete: "cascade" }),
17116
+ categoryId: text("category_id").references(() => communityCategory.id, {
17117
+ onDelete: "set null"
17118
+ }),
17119
+ name: text("name").notNull(),
17120
+ type: text("type").notNull().default("text"),
17121
+ topic: text("topic").default(""),
17122
+ position: integer2("position").default(0),
17123
+ forumTags: text("forum_tags"),
17124
+ parentChannelId: text("parent_channel_id").references(() => communityChannel.id, {
17125
+ onDelete: "cascade"
17126
+ }),
17127
+ creatorId: text("creator_id").references(() => user.id, { onDelete: "set null" }),
17128
+ messageCount: integer2("message_count").default(0),
17129
+ archived: integer2("archived").default(0),
17130
+ parentMessageId: text("parent_message_id"),
17131
+ lastMessageAt: text("last_message_at"),
17132
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17133
+ }, (t) => [
17134
+ index("idx_channel_server_position").on(t.serverId, t.position),
17135
+ index("idx_channel_server_last_message").on(t.serverId, t.lastMessageAt),
17136
+ index("idx_channel_parent").on(t.parentChannelId)
16883
17137
  ]);
16884
- function toAlookAddress(h) {
16885
- return `${h}${DOMAIN}`;
16886
- }
16887
- // ../shared/src/semver.ts
16888
- function semverGte(a, b) {
16889
- const pa = a.split(".").map(Number);
16890
- const pb = b.split(".").map(Number);
16891
- for (let i = 0;i < Math.max(pa.length, pb.length); i++) {
16892
- const sa = pa[i] ?? 0;
16893
- const sb = pb[i] ?? 0;
16894
- if (sa > sb)
16895
- return true;
16896
- if (sa < sb)
16897
- return false;
16898
- }
16899
- return true;
16900
- }
16901
- // ../shared/src/mode.ts
16902
- function isLocalUrl(url2) {
16903
- try {
16904
- const { hostname: hostname3 } = new URL(url2);
16905
- return ["localhost", "127.0.0.1", "0.0.0.0"].includes(hostname3);
16906
- } catch {
16907
- return false;
16908
- }
16909
- }
16910
- function hasWindow() {
16911
- return typeof globalThis !== "undefined" && "window" in globalThis;
16912
- }
16913
- function isTauri() {
16914
- return hasWindow() && typeof window !== "undefined" && "__TAURI__" in window;
16915
- }
16916
- function isMobile() {
16917
- if (!isTauri())
16918
- return false;
16919
- const ua = typeof navigator !== "undefined" ? navigator.userAgent : "";
16920
- return /(android|iphone|ipad|ipod)/i.test(ua);
16921
- }
16922
- function resolveMode(signals) {
16923
- if (signals.tauri || isTauri()) {
16924
- if (signals.tauriPlatform === "mobile" || isMobile())
16925
- return "mobile";
16926
- return "desktop";
16927
- }
16928
- if (signals.nodeEnv === "development" && !signals.cmdPrefix)
16929
- return "dev";
16930
- if (signals.serverUrl && !signals.cmdPrefix && signals.nodeEnv !== "production" && isLocalUrl(signals.serverUrl))
16931
- return "dev";
16932
- if (signals.cmdPrefix)
16933
- return "app";
16934
- if (signals.hostname && ["localhost", "127.0.0.1"].includes(signals.hostname))
16935
- return "app";
16936
- return "production";
16937
- }
16938
- function cliCommand(mode) {
16939
- switch (mode) {
17138
+ var communityDmConversation = sqliteTable("community_dm_conversation", {
17139
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17140
+ user1Id: text("user1_id").references(() => user.id, { onDelete: "set null" }),
17141
+ user2Id: text("user2_id").references(() => user.id, { onDelete: "set null" }),
17142
+ lastMessageAt: text("last_message_at"),
17143
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17144
+ }, (t) => [
17145
+ unique("uq_dm_conversation_users").on(t.user1Id, t.user2Id),
17146
+ index("idx_dm_conversation_user1_last_message").on(t.user1Id, t.lastMessageAt),
17147
+ index("idx_dm_conversation_user2_last_message").on(t.user2Id, t.lastMessageAt)
17148
+ ]);
17149
+ var communityMessage = sqliteTable("community_message", {
17150
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17151
+ authorId: text("author_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17152
+ content: text("content").notNull().default(""),
17153
+ type: text("type").notNull().default("default"),
17154
+ mentionType: text("mention_type"),
17155
+ replyToId: text("reply_to_id"),
17156
+ embeds: text("embeds"),
17157
+ flags: integer2("flags").default(0),
17158
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17159
+ channelId: text("channel_id").references(() => communityChannel.id, {
17160
+ onDelete: "cascade"
17161
+ }),
17162
+ dmConversationId: text("dm_conversation_id").references(() => communityDmConversation.id, { onDelete: "cascade" }),
17163
+ seq: integer2("seq").notNull().default(0)
17164
+ }, (t) => [
17165
+ index("idx_message_channel_created").on(t.channelId, t.createdAt),
17166
+ index("idx_message_channel_mention_created").on(t.channelId, t.mentionType, t.createdAt),
17167
+ index("idx_message_dm_created").on(t.dmConversationId, t.createdAt)
17168
+ ]);
17169
+ var communityMessageSeq = sqliteTable("community_message_seq", {
17170
+ scopeKey: text("scope_key").primaryKey(),
17171
+ nextSeq: integer2("next_seq").notNull()
17172
+ });
17173
+ var communityServerMember = sqliteTable("community_server_member", {
17174
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17175
+ serverId: text("server_id").notNull().references(() => communityServer.id, { onDelete: "cascade" }),
17176
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17177
+ role: text("role").default("member"),
17178
+ nickname: text("nickname"),
17179
+ railOrder: integer2("rail_order").default(0),
17180
+ joinedAt: text("joined_at").notNull().$defaultFn(() => new Date().toISOString())
17181
+ }, (t) => [
17182
+ unique("uq_server_member_server_user").on(t.serverId, t.userId),
17183
+ index("idx_server_member_user").on(t.userId),
17184
+ index("idx_server_member_user_rail_order").on(t.userId, t.railOrder)
17185
+ ]);
17186
+ var communityServerFolder = sqliteTable("community_server_folder", {
17187
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17188
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17189
+ name: text("name").notNull(),
17190
+ position: integer2("position").default(0)
17191
+ }, (t) => [index("idx_server_folder_user_position").on(t.userId, t.position)]);
17192
+ var communityServerFolderItem = sqliteTable("community_server_folder_item", {
17193
+ folderId: text("folder_id").notNull().references(() => communityServerFolder.id, { onDelete: "cascade" }),
17194
+ serverId: text("server_id").notNull().references(() => communityServer.id, { onDelete: "cascade" }),
17195
+ position: integer2("position").default(0)
17196
+ }, (t) => [
17197
+ primaryKey({ columns: [t.folderId, t.serverId] }),
17198
+ index("idx_server_folder_item_folder_position").on(t.folderId, t.position)
17199
+ ]);
17200
+ var communityServerInvite = sqliteTable("community_server_invite", {
17201
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17202
+ serverId: text("server_id").notNull().references(() => communityServer.id, { onDelete: "cascade" }),
17203
+ createdBy: text("created_by").references(() => user.id, { onDelete: "set null" }),
17204
+ token: text("token").unique().notNull().$defaultFn(() => nanoid3(10)),
17205
+ maxUses: integer2("max_uses"),
17206
+ uses: integer2("uses").default(0),
17207
+ expiresAt: text("expires_at"),
17208
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17209
+ });
17210
+ var communityFriendship = sqliteTable("community_friendship", {
17211
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17212
+ requesterId: text("requester_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17213
+ addresseeId: text("addressee_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17214
+ status: text("status").notNull().default("pending"),
17215
+ blockerId: text("blocker_id"),
17216
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17217
+ updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString())
17218
+ }, (t) => [
17219
+ unique("uq_friendship_requester_addressee").on(t.requesterId, t.addresseeId),
17220
+ index("idx_friendship_addressee_status").on(t.addresseeId, t.status),
17221
+ index("idx_friendship_requester_status").on(t.requesterId, t.status)
17222
+ ]);
17223
+ var communityReadState = sqliteTable("community_read_state", {
17224
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17225
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17226
+ channelId: text("channel_id").references(() => communityChannel.id, {
17227
+ onDelete: "cascade"
17228
+ }),
17229
+ dmConversationId: text("dm_conversation_id").references(() => communityDmConversation.id, { onDelete: "cascade" }),
17230
+ lastReadAt: text("last_read_at").notNull(),
17231
+ lastReadMessageId: text("last_read_message_id"),
17232
+ lastReadSeq: integer2("last_read_seq").notNull().default(0)
17233
+ }, (t) => [index("idx_read_state_user").on(t.userId)]);
17234
+ var communityReaction = sqliteTable("community_reaction", {
17235
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17236
+ messageId: text("message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
17237
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17238
+ emoji: text("emoji").notNull(),
17239
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17240
+ }, (t) => [
17241
+ unique("uq_reaction_message_user_emoji").on(t.messageId, t.userId, t.emoji),
17242
+ index("idx_reaction_message").on(t.messageId)
17243
+ ]);
17244
+ var communityAttachment = sqliteTable("community_attachment", {
17245
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17246
+ messageId: text("message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
17247
+ filename: text("filename").notNull(),
17248
+ url: text("url").notNull(),
17249
+ contentType: text("content_type"),
17250
+ size: integer2("size"),
17251
+ width: integer2("width"),
17252
+ height: integer2("height"),
17253
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17254
+ }, (t) => [index("idx_attachment_message").on(t.messageId)]);
17255
+ var communityPin = sqliteTable("community_pin", {
17256
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17257
+ channelId: text("channel_id").notNull().references(() => communityChannel.id, { onDelete: "cascade" }),
17258
+ messageId: text("message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
17259
+ pinnedBy: text("pinned_by").references(() => user.id, { onDelete: "set null" }),
17260
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17261
+ }, (t) => [
17262
+ unique("uq_pin_channel_message").on(t.channelId, t.messageId),
17263
+ index("idx_pin_channel").on(t.channelId)
17264
+ ]);
17265
+ var communityMention = sqliteTable("community_mention", {
17266
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17267
+ messageId: text("message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
17268
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17269
+ kind: text("kind").notNull().default("mention"),
17270
+ read: integer2("read").default(0)
17271
+ }, (t) => [
17272
+ index("idx_mention_user_read").on(t.userId, t.read),
17273
+ index("idx_mention_message").on(t.messageId)
17274
+ ]);
17275
+ var communityUserProfile = sqliteTable("community_user_profile", {
17276
+ userId: text("user_id").primaryKey().references(() => user.id, { onDelete: "cascade" }),
17277
+ aboutMe: text("about_me").default(""),
17278
+ bannerColor: text("banner_color")
17279
+ });
17280
+ var communityNotificationSetting = sqliteTable("community_notification_setting", {
17281
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17282
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17283
+ serverId: text("server_id").references(() => communityServer.id, {
17284
+ onDelete: "cascade"
17285
+ }),
17286
+ channelId: text("channel_id").references(() => communityChannel.id, {
17287
+ onDelete: "cascade"
17288
+ }),
17289
+ level: text("level").notNull().default("all")
17290
+ }, (t) => [index("idx_notification_setting_user").on(t.userId)]);
17291
+ var communityAuditLog = sqliteTable("community_audit_log", {
17292
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17293
+ serverId: text("server_id").references(() => communityServer.id, {
17294
+ onDelete: "cascade"
17295
+ }),
17296
+ actorId: text("actor_id").references(() => user.id, { onDelete: "set null" }),
17297
+ action: text("action").notNull(),
17298
+ targetType: text("target_type").notNull(),
17299
+ targetId: text("target_id").notNull(),
17300
+ changes: text("changes"),
17301
+ reason: text("reason"),
17302
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17303
+ }, (t) => [
17304
+ index("idx_audit_log_server_created").on(t.serverId, t.createdAt),
17305
+ index("idx_audit_log_server_action").on(t.serverId, t.action),
17306
+ index("idx_audit_log_actor_created").on(t.actorId, t.createdAt)
17307
+ ]);
17308
+ var communityBotApprovalRequest = sqliteTable("community_bot_approval_request", {
17309
+ id: text("id").primaryKey().$defaultFn(() => "bar_" + nanoid3()),
17310
+ botId: text("bot_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17311
+ kind: text("kind").notNull(),
17312
+ serverId: text("server_id").references(() => communityServer.id, {
17313
+ onDelete: "cascade"
17314
+ }),
17315
+ requestedByUserId: text("requested_by_user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17316
+ dmMessageId: text("dm_message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
17317
+ status: text("status").notNull().default("pending"),
17318
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17319
+ resolvedAt: text("resolved_at")
17320
+ }, (t) => [index("idx_community_bot_approval_bot").on(t.botId, t.status)]);
17321
+
17322
+ // ../shared/src/logger.ts
17323
+ var LEVELS = {
17324
+ debug: 0,
17325
+ info: 1,
17326
+ warn: 2,
17327
+ error: 3,
17328
+ silent: 4
17329
+ };
17330
+
17331
+ class Logger {
17332
+ service;
17333
+ level;
17334
+ pretty;
17335
+ fields;
17336
+ constructor(opts, fields) {
17337
+ this.service = opts.service;
17338
+ this.level = LEVELS[opts.level ?? "info"];
17339
+ this.pretty = opts.pretty ?? false;
17340
+ this.fields = fields ?? {};
17341
+ }
17342
+ debug(msg, ctx) {
17343
+ this.write("debug", msg, ctx);
17344
+ }
17345
+ info(msg, ctx) {
17346
+ this.write("info", msg, ctx);
17347
+ }
17348
+ warn(msg, ctx) {
17349
+ this.write("warn", msg, ctx);
17350
+ }
17351
+ error(msg, ctx) {
17352
+ this.write("error", msg, ctx);
17353
+ }
17354
+ child(fields) {
17355
+ const merged = { ...this.fields, ...fields };
17356
+ const child = new Logger({ service: this.service, level: this.levelName(), pretty: this.pretty }, merged);
17357
+ return child;
17358
+ }
17359
+ levelName() {
17360
+ for (const [name, num] of Object.entries(LEVELS)) {
17361
+ if (num === this.level)
17362
+ return name;
17363
+ }
17364
+ return "info";
17365
+ }
17366
+ write(level, msg, ctx) {
17367
+ if (LEVELS[level] < this.level)
17368
+ return;
17369
+ const entry = {
17370
+ level,
17371
+ msg,
17372
+ service: this.service,
17373
+ ...this.fields,
17374
+ ...ctx,
17375
+ ts: new Date().toISOString()
17376
+ };
17377
+ for (const [k, v] of Object.entries(entry)) {
17378
+ if (v instanceof Error) {
17379
+ entry[k] = { message: v.message, stack: v.stack };
17380
+ }
17381
+ }
17382
+ let line;
17383
+ if (this.pretty) {
17384
+ const ts = entry.ts.replace("T", " ").replace("Z", "");
17385
+ const lvl = entry.level.toUpperCase().padEnd(5);
17386
+ const pairs = Object.entries(entry).filter(([k]) => k !== "level" && k !== "msg" && k !== "service" && k !== "ts").map(([k, v]) => `${k}=${typeof v === "object" ? JSON.stringify(v) : v}`).join(" ");
17387
+ line = `${ts} ${lvl} [${entry.service}] ${entry.msg}${pairs ? " " + pairs : ""}`;
17388
+ } else {
17389
+ line = JSON.stringify(entry);
17390
+ }
17391
+ if (level === "error") {
17392
+ console.error(line);
17393
+ } else {
17394
+ console.log(line);
17395
+ }
17396
+ }
17397
+ }
17398
+ function createLogger(opts) {
17399
+ return new Logger(opts);
17400
+ }
17401
+
17402
+ // ../shared/src/db/queries/community/message.ts
17403
+ var log = createLogger({ service: "community-queries" });
17404
+
17405
+ // ../shared/src/db/community-machine-schema.ts
17406
+ var exports_community_machine_schema = {};
17407
+ __export(exports_community_machine_schema, {
17408
+ communityMachineToken: () => communityMachineToken,
17409
+ communityMachineCredential: () => communityMachineCredential,
17410
+ communityMachine: () => communityMachine,
17411
+ communityBotBinding: () => communityBotBinding,
17412
+ communityAgentRunnerKey: () => communityAgentRunnerKey
17413
+ });
17414
+ init_nanoid();
17415
+ var communityMachineToken = sqliteTable("community_machine_token", {
17416
+ id: text("id").primaryKey().$defaultFn(() => "cmt_" + nanoid3(32)),
17417
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17418
+ machineId: text("machine_id"),
17419
+ status: text("status").notNull().default("pending"),
17420
+ expiresAt: text("expires_at").notNull(),
17421
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17422
+ lastUsedAt: text("last_used_at")
17423
+ }, (t) => [
17424
+ index("idx_community_machine_token_user_status").on(t.userId, t.status),
17425
+ uniqueIndex("uq_community_machine_token_user_pending").on(t.userId).where(sql`status = 'pending'`)
17426
+ ]);
17427
+ var communityMachine = sqliteTable("community_machine", {
17428
+ id: text("id").primaryKey().$defaultFn(() => "cm_" + nanoid3()),
17429
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17430
+ displayName: text("display_name").notNull().default(""),
17431
+ hostname: text("hostname").notNull().default(""),
17432
+ platform: text("platform").notNull().default(""),
17433
+ arch: text("arch").notNull().default(""),
17434
+ osRelease: text("os_release").notNull().default(""),
17435
+ daemonVersion: text("daemon_version").notNull().default(""),
17436
+ metadata: text("metadata"),
17437
+ availableRuntimes: text("available_runtimes", { mode: "json" }).$type().notNull().default([]),
17438
+ status: text("status").notNull().default("offline"),
17439
+ lastSeenAt: text("last_seen_at"),
17440
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17441
+ updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString())
17442
+ }, (t) => [
17443
+ index("idx_community_machine_user_last_seen").on(t.userId, t.lastSeenAt),
17444
+ index("idx_community_machine_user_updated").on(t.userId, t.updatedAt),
17445
+ index("idx_community_machine_user_status").on(t.userId, t.status)
17446
+ ]);
17447
+ var communityMachineCredential = sqliteTable("community_machine_credential", {
17448
+ id: text("id").primaryKey().$defaultFn(() => "cmkid_" + nanoid3()),
17449
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17450
+ machineId: text("machine_id").notNull().references(() => communityMachine.id, { onDelete: "cascade" }),
17451
+ credentialHash: text("credential_hash").notNull().unique(),
17452
+ doName: text("do_name").notNull().unique(),
17453
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17454
+ lastUsedAt: text("last_used_at"),
17455
+ revokedAt: text("revoked_at")
17456
+ }, (t) => [
17457
+ index("idx_community_machine_credential_user").on(t.userId),
17458
+ index("idx_community_machine_credential_machine").on(t.machineId)
17459
+ ]);
17460
+ var communityBotBinding = sqliteTable("community_bot_binding", {
17461
+ userId: text("user_id").primaryKey().references(() => user.id, { onDelete: "cascade" }),
17462
+ machineId: text("machine_id").notNull().references(() => communityMachine.id, { onDelete: "restrict" }),
17463
+ runtime: text("runtime").notNull(),
17464
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17465
+ }, (t) => [index("idx_community_bot_binding_machine").on(t.machineId)]);
17466
+ var communityAgentRunnerKey = sqliteTable("community_agent_runner_key", {
17467
+ id: text("id").primaryKey().$defaultFn(() => "crkid_" + nanoid3()),
17468
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17469
+ machineId: text("machine_id").notNull().references(() => communityMachine.id, { onDelete: "cascade" }),
17470
+ agentId: text("agent_id").notNull(),
17471
+ runnerKeyHash: text("runner_key_hash").notNull().unique(),
17472
+ doName: text("do_name").notNull().unique(),
17473
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17474
+ revokedAt: text("revoked_at")
17475
+ }, (t) => [
17476
+ index("idx_community_agent_runner_key_machine_agent").on(t.machineId, t.agentId)
17477
+ ]);
17478
+
17479
+ // ../shared/src/db/queries/community/agent-inbox.ts
17480
+ var AGENT_MESSAGE_COLUMNS = {
17481
+ id: communityMessage.id,
17482
+ authorId: communityMessage.authorId,
17483
+ content: communityMessage.content,
17484
+ createdAt: communityMessage.createdAt,
17485
+ channelId: communityMessage.channelId,
17486
+ dmConversationId: communityMessage.dmConversationId,
17487
+ seq: communityMessage.seq
17488
+ };
17489
+ // ../shared/src/db/index.ts
17490
+ var allSchema = { ...exports_schema, ...exports_community_schema, ...exports_community_machine_schema };
17491
+ // ../shared/src/db/queries/user.ts
17492
+ var publicUserColumns = {
17493
+ id: user.id,
17494
+ name: user.name,
17495
+ email: user.email,
17496
+ emailVerified: user.emailVerified,
17497
+ image: user.image,
17498
+ createdAt: user.createdAt,
17499
+ updatedAt: user.updatedAt,
17500
+ discriminator: user.discriminator
17501
+ };
17502
+ var internalUserColumns = {
17503
+ ...publicUserColumns,
17504
+ isBot: user.isBot,
17505
+ ownerUserId: user.ownerUserId,
17506
+ deletedAt: user.deletedAt
17507
+ };
17508
+ // ../shared/src/db/queries/task.ts
17509
+ var DEFAULT_STALE_SECONDS = Number(process.env.ALOOK_STALE_DISPATCH_TIMEOUT_S) || 20;
17510
+ var DEFAULT_STALE_RUNNING_SECONDS = Number(process.env.ALOOK_STALE_RUNNING_TIMEOUT_S) || 3600;
17511
+ // ../shared/src/utils/email.ts
17512
+ var DOMAIN = `@${process.env.ALOOK_DOMAIN || "alook.ai"}`;
17513
+ var RESERVED_HANDLES = new Set([
17514
+ "no-reply",
17515
+ "noreply",
17516
+ "admin",
17517
+ "support",
17518
+ "help",
17519
+ "info",
17520
+ "postmaster",
17521
+ "abuse",
17522
+ "security",
17523
+ "mailer-daemon",
17524
+ "root",
17525
+ "webmaster",
17526
+ "hostmaster",
17527
+ "system",
17528
+ "alook"
17529
+ ]);
17530
+ function toAlookAddress(h) {
17531
+ return `${h}${DOMAIN}`;
17532
+ }
17533
+ // ../shared/src/db/queries/community/channel.ts
17534
+ var log2 = createLogger({ service: "community-queries" });
17535
+ var CHANNEL_COLUMNS = {
17536
+ id: communityChannel.id,
17537
+ serverId: communityChannel.serverId,
17538
+ categoryId: communityChannel.categoryId,
17539
+ name: communityChannel.name,
17540
+ type: communityChannel.type,
17541
+ topic: communityChannel.topic,
17542
+ position: communityChannel.position,
17543
+ forumTags: communityChannel.forumTags,
17544
+ parentChannelId: communityChannel.parentChannelId,
17545
+ creatorId: communityChannel.creatorId,
17546
+ messageCount: communityChannel.messageCount,
17547
+ archived: communityChannel.archived,
17548
+ parentMessageId: communityChannel.parentMessageId,
17549
+ lastMessageAt: communityChannel.lastMessageAt,
17550
+ createdAt: communityChannel.createdAt
17551
+ };
17552
+ // ../shared/src/db/queries/community/search.ts
17553
+ var FTS_KEYWORDS = new Set(["and", "or", "not", "near"]);
17554
+ // ../shared/src/semver.ts
17555
+ function semverGte(a, b) {
17556
+ const pa = a.split(".").map(Number);
17557
+ const pb = b.split(".").map(Number);
17558
+ for (let i = 0;i < Math.max(pa.length, pb.length); i++) {
17559
+ const sa = pa[i] ?? 0;
17560
+ const sb = pb[i] ?? 0;
17561
+ if (sa > sb)
17562
+ return true;
17563
+ if (sa < sb)
17564
+ return false;
17565
+ }
17566
+ return true;
17567
+ }
17568
+ // ../shared/src/mode.ts
17569
+ function isLocalUrl(url2) {
17570
+ try {
17571
+ const { hostname: hostname3 } = new URL(url2);
17572
+ return ["localhost", "127.0.0.1", "0.0.0.0"].includes(hostname3);
17573
+ } catch {
17574
+ return false;
17575
+ }
17576
+ }
17577
+ function hasWindow() {
17578
+ return typeof globalThis !== "undefined" && "window" in globalThis;
17579
+ }
17580
+ function isTauri() {
17581
+ return hasWindow() && typeof window !== "undefined" && "__TAURI__" in window;
17582
+ }
17583
+ function isMobile() {
17584
+ if (!isTauri())
17585
+ return false;
17586
+ const ua = typeof navigator !== "undefined" ? navigator.userAgent : "";
17587
+ return /(android|iphone|ipad|ipod)/i.test(ua);
17588
+ }
17589
+ function resolveMode(signals) {
17590
+ if (signals.tauri || isTauri()) {
17591
+ if (signals.tauriPlatform === "mobile" || isMobile())
17592
+ return "mobile";
17593
+ return "desktop";
17594
+ }
17595
+ if (signals.nodeEnv === "development" && !signals.cmdPrefix)
17596
+ return "dev";
17597
+ if (signals.serverUrl && !signals.cmdPrefix && signals.nodeEnv !== "production" && isLocalUrl(signals.serverUrl))
17598
+ return "dev";
17599
+ if (signals.cmdPrefix)
17600
+ return "app";
17601
+ if (signals.hostname && ["localhost", "127.0.0.1"].includes(signals.hostname))
17602
+ return "app";
17603
+ return "production";
17604
+ }
17605
+ function cliCommand(mode) {
17606
+ switch (mode) {
16940
17607
  case "dev":
16941
17608
  return "pnpm dev:cli";
16942
17609
  case "app":
@@ -16948,14 +17615,13 @@ function cliCommand(mode) {
16948
17615
  }
16949
17616
  }
16950
17617
  var DEFAULT_BASE_URL = "https://alook.ai";
16951
- var DEV_BASE_URL = "http://localhost:3000";
16952
17618
  function getBaseUrl(signals) {
16953
17619
  if (signals.serverUrl)
16954
17620
  return signals.serverUrl;
16955
17621
  if (signals.appUrl)
16956
17622
  return signals.appUrl;
16957
17623
  if (signals.nodeEnv === "development")
16958
- return DEV_BASE_URL;
17624
+ return DEV_WEB_URL;
16959
17625
  return DEFAULT_BASE_URL;
16960
17626
  }
16961
17627
  // lib/env.ts
@@ -16978,7 +17644,7 @@ function cmdPrefix() {
16978
17644
  // lib/activate.ts
16979
17645
  import { hostname as hostname4 } from "os";
16980
17646
  import { spawn as spawn6 } from "child_process";
16981
- import { openSync as openSync2, closeSync as closeSync2, mkdirSync as mkdirSync9 } from "fs";
17647
+ import { openSync as openSync2, closeSync as closeSync2, mkdirSync as mkdirSync10 } from "fs";
16982
17648
  import { dirname as dirname4 } from "path";
16983
17649
 
16984
17650
  // lib/config.ts
@@ -17138,6 +17804,7 @@ function loadDaemonConfig(profile) {
17138
17804
  agentTimeout: parseDuration(process.env.ALOOK_AGENT_TIMEOUT || "12h"),
17139
17805
  messageInactivityTimeout: parseDuration(process.env.ALOOK_MESSAGE_INACTIVITY_TIMEOUT || "20m"),
17140
17806
  maxConcurrentTasks: parseInt(process.env.ALOOK_DAEMON_MAX_CONCURRENT_TASKS || "20"),
17807
+ enableSteering: process.env.ALOOK_ENABLE_STEERING === "1",
17141
17808
  daemonId,
17142
17809
  deviceName: process.env.ALOOK_DAEMON_DEVICE_NAME || h,
17143
17810
  workspacesRoot,
@@ -17149,7 +17816,7 @@ function normalizeServerBaseURL(url2) {
17149
17816
  }
17150
17817
 
17151
17818
  // lib/logger.ts
17152
- var LEVELS = {
17819
+ var LEVELS2 = {
17153
17820
  debug: 0,
17154
17821
  info: 1,
17155
17822
  warn: 2,
@@ -17195,12 +17862,12 @@ class Logger2 {
17195
17862
  module;
17196
17863
  constructor(opts = {}) {
17197
17864
  const envLevel = process.env.ALOOK_LOG_LEVEL;
17198
- this.level = LEVELS[opts.level ?? envLevel ?? "info"];
17865
+ this.level = LEVELS2[opts.level ?? envLevel ?? "info"];
17199
17866
  this.color = useColor();
17200
17867
  this.module = opts.module;
17201
17868
  }
17202
17869
  setLevel(level) {
17203
- this.level = LEVELS[level];
17870
+ this.level = LEVELS2[level];
17204
17871
  }
17205
17872
  child(module) {
17206
17873
  const child = new Logger2({ level: this.levelName(), module });
@@ -17219,14 +17886,14 @@ class Logger2 {
17219
17886
  this.write("error", msg, args);
17220
17887
  }
17221
17888
  levelName() {
17222
- for (const [name, num] of Object.entries(LEVELS)) {
17889
+ for (const [name, num] of Object.entries(LEVELS2)) {
17223
17890
  if (num === this.level)
17224
17891
  return name;
17225
17892
  }
17226
17893
  return "info";
17227
17894
  }
17228
17895
  write(level, msg, args) {
17229
- if (LEVELS[level] < this.level)
17896
+ if (LEVELS2[level] < this.level)
17230
17897
  return;
17231
17898
  const ts = timestamp();
17232
17899
  const label = LABELS[level];
@@ -17247,7 +17914,7 @@ class Logger2 {
17247
17914
  if (a instanceof Error) {
17248
17915
  dest.write(` ${a.message}
17249
17916
  `);
17250
- if (a.stack && this.level <= LEVELS.debug) {
17917
+ if (a.stack && this.level <= LEVELS2.debug) {
17251
17918
  dest.write(` ${a.stack}
17252
17919
  `);
17253
17920
  }
@@ -17266,10 +17933,10 @@ class Logger2 {
17266
17933
  function createLogger2(opts) {
17267
17934
  return new Logger2(opts);
17268
17935
  }
17269
- var log = createLogger2();
17936
+ var log3 = createLogger2();
17270
17937
 
17271
17938
  // daemon/pidfile.ts
17272
- var log2 = createLogger2({ module: "pidfile" });
17939
+ var log4 = createLogger2({ module: "pidfile" });
17273
17940
  function isProcessAlive(pid) {
17274
17941
  try {
17275
17942
  process.kill(pid, 0);
@@ -17293,7 +17960,7 @@ function acquireDaemonPid(profile) {
17293
17960
  const content = readFileSync3(pidPath, "utf-8").trim();
17294
17961
  const existingPid = parseInt(content, 10);
17295
17962
  if (!isNaN(existingPid) && isProcessAlive(existingPid)) {
17296
- log2.error(`Another daemon is already running (PID ${existingPid}). ` + `Remove ${pidPath} if this is stale.`);
17963
+ log4.error(`Another daemon is already running (PID ${existingPid}). ` + `Remove ${pidPath} if this is stale.`);
17297
17964
  return false;
17298
17965
  }
17299
17966
  } catch {}
@@ -17471,7 +18138,7 @@ import { createInterface } from "readline";
17471
18138
 
17472
18139
  // daemon/kill-tree.ts
17473
18140
  import { execSync } from "child_process";
17474
- var log3 = createLogger2({ module: "kill-tree" });
18141
+ var log5 = createLogger2({ module: "kill-tree" });
17475
18142
  function killGraceMs() {
17476
18143
  return Number(process.env.ALOOK_KILL_GRACE_MS) || 2000;
17477
18144
  }
@@ -17525,7 +18192,7 @@ async function killProcessTree(pid, opts) {
17525
18192
  await new Promise((r) => setTimeout(r, POLL_MS));
17526
18193
  }
17527
18194
  if (isAlive(pid)) {
17528
- log3.warn(`pid=${pid} survived SIGTERM after ${graceMs}ms — escalating to SIGKILL`);
18195
+ log5.warn(`pid=${pid} survived SIGTERM after ${graceMs}ms — escalating to SIGKILL`);
17529
18196
  signalTree(pid, "SIGKILL");
17530
18197
  }
17531
18198
  }
@@ -17534,19 +18201,135 @@ async function killProcessTree(pid, opts) {
17534
18201
  class ClaudeBackend {
17535
18202
  cliPath;
17536
18203
  name = "claude";
18204
+ lifecycle = { kind: "persistent", stdin: "gated", inFlightWake: "queue" };
18205
+ busyDeliveryMode = "gated";
18206
+ supportsStdinNotification = true;
17537
18207
  constructor(cliPath) {
17538
18208
  this.cliPath = cliPath;
17539
18209
  }
18210
+ parseLine(line) {
18211
+ if (!line.trim())
18212
+ return [];
18213
+ let event;
18214
+ try {
18215
+ event = JSON.parse(line);
18216
+ } catch {
18217
+ return [{ kind: "log", content: line, level: "debug" }];
18218
+ }
18219
+ const events = [];
18220
+ const eventType = event.type;
18221
+ switch (eventType) {
18222
+ case "assistant": {
18223
+ const message2 = event.message;
18224
+ if (!message2)
18225
+ break;
18226
+ const content = message2.content;
18227
+ if (!Array.isArray(content))
18228
+ break;
18229
+ for (const block of content) {
18230
+ if (block.type === "text") {
18231
+ events.push({ kind: "text", text: block.text || "" });
18232
+ } else if (block.type === "thinking") {
18233
+ events.push({ kind: "thinking", text: block.text || "" });
18234
+ } else if (block.type === "tool_use") {
18235
+ events.push({ kind: "tool_call", name: block.name || "", input: block.input, callId: block.id });
18236
+ }
18237
+ }
18238
+ break;
18239
+ }
18240
+ case "result": {
18241
+ const result = event.result;
18242
+ const isError = event.is_error;
18243
+ if (isError) {
18244
+ events.push({ kind: "error", message: result || "unknown error" });
18245
+ }
18246
+ const resultSessionId = event.session_id;
18247
+ events.push({ kind: "turn_end", sessionId: resultSessionId || undefined });
18248
+ const usage = event.usage;
18249
+ if (usage || event.total_cost_usd != null) {
18250
+ events.push({
18251
+ kind: "telemetry",
18252
+ name: "token_usage",
18253
+ source: "claude_result_usage",
18254
+ usageKind: "per_turn",
18255
+ attrs: {
18256
+ inputTokens: usage?.input_tokens,
18257
+ outputTokens: usage?.output_tokens,
18258
+ cachedInputTokens: usage?.cache_read_input_tokens,
18259
+ cacheCreationInputTokens: usage?.cache_creation_input_tokens,
18260
+ totalCostUsd: event.total_cost_usd,
18261
+ durationMs: event.duration_ms,
18262
+ durationApiMs: event.duration_api_ms,
18263
+ numTurns: event.num_turns,
18264
+ resultSubtype: event.subtype,
18265
+ resultIsError: event.is_error,
18266
+ serviceTier: usage?.service_tier
18267
+ }
18268
+ });
18269
+ }
18270
+ break;
18271
+ }
18272
+ case "tool_result": {
18273
+ const toolUseId = event.tool_use_id;
18274
+ const content = event.content;
18275
+ events.push({ kind: "tool_output", callId: toolUseId, output: content });
18276
+ break;
18277
+ }
18278
+ case "system": {
18279
+ const subtype = event.subtype;
18280
+ if (subtype === "init") {
18281
+ const sid = event.session_id;
18282
+ events.push({ kind: "session_init", sessionId: sid || "" });
18283
+ } else if (subtype === "context_pruning" || subtype === "compaction") {
18284
+ events.push({ kind: "compaction_started" });
18285
+ } else if (subtype === "compaction_finished" || subtype === "context_pruning_finished") {
18286
+ events.push({ kind: "compaction_finished" });
18287
+ } else if (subtype === "status" || subtype === "stream_event") {
18288
+ events.push({
18289
+ kind: "internal_progress",
18290
+ source: "claude_system",
18291
+ itemType: subtype,
18292
+ payloadBytes: line.length
18293
+ });
18294
+ }
18295
+ break;
18296
+ }
18297
+ case "control_request": {
18298
+ const requestId = event.request_id;
18299
+ if (requestId) {
18300
+ events.push({ kind: "permission_request", requestId, payload: event.payload });
18301
+ }
18302
+ break;
18303
+ }
18304
+ default: {
18305
+ events.push({ kind: "log", content: line, level: "debug" });
18306
+ }
18307
+ }
18308
+ return events;
18309
+ }
18310
+ encodeStdinMessage(text2, mode, opts) {
18311
+ const msg = {
18312
+ type: "user",
18313
+ message: {
18314
+ role: "user",
18315
+ content: [{ type: "text", text: text2 }]
18316
+ }
18317
+ };
18318
+ if (opts?.sessionId) {
18319
+ msg.session_id = opts.sessionId;
18320
+ }
18321
+ return JSON.stringify(msg);
18322
+ }
17540
18323
  execute(prompt, options) {
17541
- const args = [
17542
- "-p",
17543
- prompt,
17544
- "--output-format",
17545
- "stream-json",
17546
- "--verbose",
17547
- "--permission-mode",
17548
- "bypassPermissions"
17549
- ];
18324
+ const useStdinPrompt = options.steeringEnabled === true;
18325
+ const args = [];
18326
+ if (!useStdinPrompt) {
18327
+ args.push("-p", prompt);
18328
+ }
18329
+ args.push("--output-format", "stream-json", "--verbose", "--permission-mode", "bypassPermissions");
18330
+ if (useStdinPrompt) {
18331
+ args.push("--input-format", "stream-json");
18332
+ }
17550
18333
  if (options.model) {
17551
18334
  args.push("--model", options.model);
17552
18335
  }
@@ -17603,15 +18386,58 @@ class ClaudeBackend {
17603
18386
  r();
17604
18387
  }
17605
18388
  };
18389
+ const parsedEventQueue = [];
18390
+ let parsedEventResolve = null;
18391
+ let parsedEventDone = false;
18392
+ const pushParsedEvent = (evt) => {
18393
+ parsedEventQueue.push(evt);
18394
+ if (parsedEventResolve) {
18395
+ const r = parsedEventResolve;
18396
+ parsedEventResolve = null;
18397
+ r();
18398
+ }
18399
+ };
18400
+ const stdinWriteQueue = [];
18401
+ let stdinDraining = false;
18402
+ const enqueueStdinWrite = (data) => {
18403
+ stdinWriteQueue.push(data);
18404
+ drainStdinQueue();
18405
+ };
18406
+ const drainStdinQueue = () => {
18407
+ if (stdinDraining)
18408
+ return;
18409
+ stdinDraining = true;
18410
+ while (stdinWriteQueue.length > 0) {
18411
+ const line = stdinWriteQueue.shift();
18412
+ try {
18413
+ proc.stdin?.write(line + `
18414
+ `);
18415
+ } catch {}
18416
+ }
18417
+ stdinDraining = false;
18418
+ };
17606
18419
  const resultPromise = new Promise((resolve) => {
17607
18420
  const stderrChunks = [];
17608
18421
  proc.stderr?.on("data", (chunk) => {
17609
18422
  stderrChunks.push(chunk.toString());
17610
18423
  });
17611
18424
  const rl = createInterface({ input: proc.stdout });
18425
+ if (useStdinPrompt) {
18426
+ const initialMsg = JSON.stringify({
18427
+ type: "user",
18428
+ message: {
18429
+ role: "user",
18430
+ content: [{ type: "text", text: prompt }]
18431
+ }
18432
+ });
18433
+ enqueueStdinWrite(initialMsg);
18434
+ }
17612
18435
  rl.on("line", (line) => {
17613
18436
  if (!line.trim())
17614
18437
  return;
18438
+ const parsed = this.parseLine(line);
18439
+ for (const pe of parsed)
18440
+ pushParsedEvent(pe);
17615
18441
  let event;
17616
18442
  try {
17617
18443
  event = JSON.parse(line);
@@ -17657,6 +18483,13 @@ class ClaudeBackend {
17657
18483
  resultStatus = "failed";
17658
18484
  lastError = result || "unknown error";
17659
18485
  }
18486
+ if (useStdinPrompt) {
18487
+ setTimeout(() => {
18488
+ try {
18489
+ proc.stdin?.end();
18490
+ } catch {}
18491
+ }, 100);
18492
+ }
17660
18493
  break;
17661
18494
  }
17662
18495
  case "tool_result": {
@@ -17681,7 +18514,7 @@ class ClaudeBackend {
17681
18514
  break;
17682
18515
  }
17683
18516
  case "control_request": {
17684
- handleControlRequest(proc, event);
18517
+ handleControlRequest(proc, event, enqueueStdinWrite);
17685
18518
  break;
17686
18519
  }
17687
18520
  default: {
@@ -17698,11 +18531,17 @@ class ClaudeBackend {
17698
18531
  lastError = `spawn error: ${err.message}`;
17699
18532
  resolveSessionId(lastSessionId);
17700
18533
  messageDone = true;
18534
+ parsedEventDone = true;
17701
18535
  if (messageResolve) {
17702
18536
  const r = messageResolve;
17703
18537
  messageResolve = null;
17704
18538
  r();
17705
18539
  }
18540
+ if (parsedEventResolve) {
18541
+ const r = parsedEventResolve;
18542
+ parsedEventResolve = null;
18543
+ r();
18544
+ }
17706
18545
  resolve({
17707
18546
  status: "failed",
17708
18547
  output: "",
@@ -17725,11 +18564,17 @@ class ClaudeBackend {
17725
18564
  }
17726
18565
  resolveSessionId(lastSessionId);
17727
18566
  messageDone = true;
18567
+ parsedEventDone = true;
17728
18568
  if (messageResolve) {
17729
18569
  const r = messageResolve;
17730
18570
  messageResolve = null;
17731
18571
  r();
17732
18572
  }
18573
+ if (parsedEventResolve) {
18574
+ const r = parsedEventResolve;
18575
+ parsedEventResolve = null;
18576
+ r();
18577
+ }
17733
18578
  resolve({
17734
18579
  status: resultStatus,
17735
18580
  output: lastOutput,
@@ -17756,10 +18601,47 @@ class ClaudeBackend {
17756
18601
  };
17757
18602
  }
17758
18603
  };
17759
- return { pid: proc.pid, messages, sessionId: sessionIdPromise, result: resultPromise };
18604
+ const parsedEvents = {
18605
+ [Symbol.asyncIterator]() {
18606
+ return {
18607
+ async next() {
18608
+ while (parsedEventQueue.length === 0 && !parsedEventDone) {
18609
+ await new Promise((resolve) => {
18610
+ parsedEventResolve = resolve;
18611
+ });
18612
+ }
18613
+ if (parsedEventQueue.length > 0) {
18614
+ return { value: parsedEventQueue.shift(), done: false };
18615
+ }
18616
+ return { value: undefined, done: true };
18617
+ }
18618
+ };
18619
+ }
18620
+ };
18621
+ const send = (text2, mode) => {
18622
+ const encoded = this.encodeStdinMessage(text2, mode, { sessionId: lastSessionId || undefined });
18623
+ if (!encoded)
18624
+ return { ok: false, reason: "encoding failed" };
18625
+ if (!proc.stdin || proc.stdin.destroyed)
18626
+ return { ok: false, reason: "stdin closed" };
18627
+ enqueueStdinWrite(encoded);
18628
+ return { ok: true };
18629
+ };
18630
+ const descriptor = {
18631
+ lifecycle: this.lifecycle,
18632
+ busyDeliveryMode: this.busyDeliveryMode,
18633
+ supportsStdinNotification: this.supportsStdinNotification
18634
+ };
18635
+ const closeStdin = () => {
18636
+ try {
18637
+ if (proc.stdin && !proc.stdin.destroyed)
18638
+ proc.stdin.end();
18639
+ } catch {}
18640
+ };
18641
+ return { pid: proc.pid, messages, parsedEvents, sessionId: sessionIdPromise, result: resultPromise, send, closeStdin, descriptor };
17760
18642
  }
17761
18643
  }
17762
- function handleControlRequest(proc, event) {
18644
+ function handleControlRequest(proc, event, enqueueStdinWrite) {
17763
18645
  const requestId = event.request_id;
17764
18646
  if (!requestId)
17765
18647
  return;
@@ -17788,10 +18670,14 @@ function handleControlRequest(proc, event) {
17788
18670
  }
17789
18671
  }
17790
18672
  });
17791
- try {
17792
- proc.stdin?.write(approval + `
18673
+ if (enqueueStdinWrite) {
18674
+ enqueueStdinWrite(approval);
18675
+ } else {
18676
+ try {
18677
+ proc.stdin?.write(approval + `
17793
18678
  `);
17794
- } catch {}
18679
+ } catch {}
18680
+ }
17795
18681
  }
17796
18682
 
17797
18683
  // daemon/agent/codex.ts
@@ -17823,9 +18709,196 @@ function extractThreadID(response) {
17823
18709
  class CodexBackend {
17824
18710
  cliPath;
17825
18711
  name = "codex";
18712
+ lifecycle = { kind: "persistent", stdin: "direct", inFlightWake: "steer" };
18713
+ busyDeliveryMode = "direct";
18714
+ supportsStdinNotification = true;
18715
+ _rpcId = 0;
17826
18716
  constructor(cliPath) {
17827
18717
  this.cliPath = cliPath;
17828
18718
  }
18719
+ parseLine(line) {
18720
+ if (!line.trim())
18721
+ return [];
18722
+ let msg;
18723
+ try {
18724
+ msg = JSON.parse(line);
18725
+ } catch {
18726
+ return [{ kind: "log", content: line, level: "debug" }];
18727
+ }
18728
+ if (msg.id !== undefined && !msg.method)
18729
+ return [];
18730
+ if (msg.id !== undefined && msg.method)
18731
+ return [];
18732
+ if (!msg.method)
18733
+ return [{ kind: "log", content: line, level: "debug" }];
18734
+ const method = msg.method;
18735
+ const params = msg.params || {};
18736
+ if (method === "codex/event") {
18737
+ return this.parseLegacyEvent(params);
18738
+ }
18739
+ const events = [];
18740
+ switch (method) {
18741
+ case "turn/started":
18742
+ break;
18743
+ case "turn/completed": {
18744
+ const turn = params.turn;
18745
+ const status = turn?.status || params.status || "";
18746
+ if (status === "error" || status === "failed") {
18747
+ const turnErr = turn?.error;
18748
+ events.push({ kind: "error", message: turnErr?.message || "codex turn failed" });
18749
+ }
18750
+ events.push({ kind: "turn_end" });
18751
+ break;
18752
+ }
18753
+ case "error": {
18754
+ const errObj = params.error;
18755
+ const errMsg = errObj?.message || params.message || "";
18756
+ const willRetry = params.willRetry === true;
18757
+ if (errMsg && !willRetry) {
18758
+ events.push({ kind: "error", message: errMsg });
18759
+ }
18760
+ break;
18761
+ }
18762
+ case "thread/status/changed": {
18763
+ const statusObj = params.status;
18764
+ const statusType = typeof statusObj === "object" && statusObj !== null ? statusObj.type || "" : statusObj || "";
18765
+ if (statusType === "idle") {
18766
+ events.push({ kind: "turn_end" });
18767
+ }
18768
+ break;
18769
+ }
18770
+ case "item/started": {
18771
+ const item = params.item;
18772
+ if (!item)
18773
+ break;
18774
+ const itemType = item.type;
18775
+ if (itemType === "commandExecution" || itemType === "fileChange") {
18776
+ events.push({
18777
+ kind: "tool_call",
18778
+ name: itemType === "commandExecution" ? "exec_command" : "patch_apply",
18779
+ callId: item.id,
18780
+ input: item
18781
+ });
18782
+ } else if (itemType === "mcpToolCall") {
18783
+ events.push({
18784
+ kind: "tool_call",
18785
+ name: `mcp_${item.name || "tool"}`,
18786
+ callId: item.id,
18787
+ input: item
18788
+ });
18789
+ } else if (itemType === "webSearch") {
18790
+ events.push({
18791
+ kind: "tool_call",
18792
+ name: "web_search",
18793
+ callId: item.id,
18794
+ input: item
18795
+ });
18796
+ } else if (itemType === "collabAgentToolCall") {
18797
+ events.push({
18798
+ kind: "tool_call",
18799
+ name: "collab_agent",
18800
+ callId: item.id,
18801
+ input: item
18802
+ });
18803
+ } else if (itemType === "contextCompaction") {
18804
+ events.push({ kind: "compaction_started" });
18805
+ }
18806
+ break;
18807
+ }
18808
+ case "item/completed": {
18809
+ const item = params.item;
18810
+ if (!item)
18811
+ break;
18812
+ const itemType = item.type;
18813
+ if (itemType === "commandExecution") {
18814
+ events.push({ kind: "tool_output", callId: item.id, output: item.aggregatedOutput || "" });
18815
+ } else if (itemType === "fileChange") {
18816
+ events.push({ kind: "tool_output", callId: item.id, output: "" });
18817
+ } else if (itemType === "mcpToolCall") {
18818
+ events.push({ kind: "tool_output", callId: item.id, name: `mcp_${item.name || "tool"}`, output: item.output || "" });
18819
+ } else if (itemType === "agentMessage") {
18820
+ const flatText = item.text;
18821
+ if (flatText) {
18822
+ events.push({ kind: "text", text: flatText });
18823
+ } else {
18824
+ const content = item.content;
18825
+ if (Array.isArray(content)) {
18826
+ for (const block of content) {
18827
+ if ((block.type === "output_text" || block.type === "text") && block.text) {
18828
+ events.push({ kind: "text", text: block.text });
18829
+ }
18830
+ }
18831
+ }
18832
+ }
18833
+ } else if (itemType === "reasoning") {
18834
+ events.push({ kind: "thinking", text: item.text || "" });
18835
+ } else if (itemType === "contextCompaction") {
18836
+ events.push({ kind: "compaction_finished" });
18837
+ }
18838
+ break;
18839
+ }
18840
+ case "item/agentMessage/delta": {
18841
+ const delta = params.delta;
18842
+ if (delta)
18843
+ events.push({ kind: "text", text: delta });
18844
+ break;
18845
+ }
18846
+ default:
18847
+ events.push({ kind: "log", content: JSON.stringify(msg), level: "debug" });
18848
+ }
18849
+ return events;
18850
+ }
18851
+ parseLegacyEvent(params) {
18852
+ const eventType = params.type;
18853
+ if (!eventType)
18854
+ return [];
18855
+ const events = [];
18856
+ switch (eventType) {
18857
+ case "agent_message": {
18858
+ const text2 = params.text || params.message || "";
18859
+ if (text2)
18860
+ events.push({ kind: "text", text: text2 });
18861
+ break;
18862
+ }
18863
+ case "exec_command_begin":
18864
+ events.push({ kind: "tool_call", name: "exec_command", callId: params.id, input: params });
18865
+ break;
18866
+ case "exec_command_end":
18867
+ events.push({ kind: "tool_output", callId: params.id, output: params.output || "" });
18868
+ break;
18869
+ case "patch_apply_begin":
18870
+ events.push({ kind: "tool_call", name: "patch_apply", callId: params.id, input: params });
18871
+ break;
18872
+ case "patch_apply_end":
18873
+ events.push({ kind: "tool_output", callId: params.id, output: params.output || "" });
18874
+ break;
18875
+ case "task_complete":
18876
+ events.push({ kind: "turn_end" });
18877
+ break;
18878
+ case "turn_aborted":
18879
+ events.push({ kind: "turn_end" });
18880
+ break;
18881
+ default:
18882
+ break;
18883
+ }
18884
+ return events;
18885
+ }
18886
+ encodeStdinMessage(text2, mode, opts) {
18887
+ const threadId = opts?.threadId;
18888
+ if (!threadId)
18889
+ return null;
18890
+ const id = opts?.requestId ?? ++this._rpcId;
18891
+ const method = mode === "busy" ? "turn/steer" : "turn/start";
18892
+ return JSON.stringify({
18893
+ jsonrpc: "2.0",
18894
+ id,
18895
+ method,
18896
+ params: {
18897
+ threadId,
18898
+ input: [{ type: "text", text: text2 }]
18899
+ }
18900
+ });
18901
+ }
17829
18902
  execute(prompt, options) {
17830
18903
  const proc = spawn2(this.cliPath, ["app-server", "--listen", "stdio://", "--config", "sandbox_mode=danger-full-access"], {
17831
18904
  cwd: options.cwd,
@@ -17874,6 +18947,9 @@ class CodexBackend {
17874
18947
  const messageQueue = [];
17875
18948
  let messageResolve = null;
17876
18949
  let messageDone = false;
18950
+ const parsedEventQueue = [];
18951
+ let parsedEventResolve = null;
18952
+ let parsedEventDone = false;
17877
18953
  const pushMessage = (msg) => {
17878
18954
  messageQueue.push(msg);
17879
18955
  if (messageResolve) {
@@ -17882,6 +18958,14 @@ class CodexBackend {
17882
18958
  r();
17883
18959
  }
17884
18960
  };
18961
+ const pushParsedEvent = (evt) => {
18962
+ parsedEventQueue.push(evt);
18963
+ if (parsedEventResolve) {
18964
+ const r = parsedEventResolve;
18965
+ parsedEventResolve = null;
18966
+ r();
18967
+ }
18968
+ };
17885
18969
  const writeStdin = (data) => {
17886
18970
  try {
17887
18971
  proc.stdin?.write(data + `
@@ -17914,17 +18998,20 @@ class CodexBackend {
17914
18998
  if (msg && !turnError)
17915
18999
  turnError = msg;
17916
19000
  };
19001
+ const steeringKeepAlive = options.steeringEnabled === true;
17917
19002
  const triggerTurnDone = (aborted2) => {
17918
19003
  if (turnDoneTriggered)
17919
19004
  return;
17920
19005
  turnDoneTriggered = true;
17921
19006
  resultStatus = aborted2 ? "aborted" : "completed";
17922
- try {
17923
- proc.stdin?.end();
17924
- } catch {}
17925
- try {
17926
- proc.kill("SIGTERM");
17927
- } catch {}
19007
+ if (!steeringKeepAlive) {
19008
+ try {
19009
+ proc.stdin?.end();
19010
+ } catch {}
19011
+ try {
19012
+ proc.kill("SIGTERM");
19013
+ } catch {}
19014
+ }
17928
19015
  };
17929
19016
  const handleServerRequest = (msg) => {
17930
19017
  const method = msg.method;
@@ -18145,6 +19232,9 @@ class CodexBackend {
18145
19232
  rl.on("line", (line) => {
18146
19233
  if (!line.trim())
18147
19234
  return;
19235
+ const parsed = this.parseLine(line);
19236
+ for (const pe of parsed)
19237
+ pushParsedEvent(pe);
18148
19238
  let msg;
18149
19239
  try {
18150
19240
  msg = JSON.parse(line);
@@ -18231,11 +19321,17 @@ class CodexBackend {
18231
19321
  closeAllPending("spawn error");
18232
19322
  resolveSessionId(sessionId);
18233
19323
  messageDone = true;
19324
+ parsedEventDone = true;
18234
19325
  if (messageResolve) {
18235
19326
  const r = messageResolve;
18236
19327
  messageResolve = null;
18237
19328
  r();
18238
19329
  }
19330
+ if (parsedEventResolve) {
19331
+ const r = parsedEventResolve;
19332
+ parsedEventResolve = null;
19333
+ r();
19334
+ }
18239
19335
  resolve({
18240
19336
  status: "failed",
18241
19337
  output: "",
@@ -18265,11 +19361,17 @@ class CodexBackend {
18265
19361
  }
18266
19362
  resolveSessionId(sessionId);
18267
19363
  messageDone = true;
19364
+ parsedEventDone = true;
18268
19365
  if (messageResolve) {
18269
19366
  const r = messageResolve;
18270
19367
  messageResolve = null;
18271
19368
  r();
18272
19369
  }
19370
+ if (parsedEventResolve) {
19371
+ const r = parsedEventResolve;
19372
+ parsedEventResolve = null;
19373
+ r();
19374
+ }
18273
19375
  resolve({
18274
19376
  status: resultStatus,
18275
19377
  output: lastOutput,
@@ -18296,7 +19398,44 @@ class CodexBackend {
18296
19398
  };
18297
19399
  }
18298
19400
  };
18299
- return { pid: proc.pid, messages, sessionId: sessionIdPromise, result: resultPromise };
19401
+ const parsedEvents = {
19402
+ [Symbol.asyncIterator]() {
19403
+ return {
19404
+ async next() {
19405
+ while (parsedEventQueue.length === 0 && !parsedEventDone) {
19406
+ await new Promise((resolve) => {
19407
+ parsedEventResolve = resolve;
19408
+ });
19409
+ }
19410
+ if (parsedEventQueue.length > 0) {
19411
+ return { value: parsedEventQueue.shift(), done: false };
19412
+ }
19413
+ return { value: undefined, done: true };
19414
+ }
19415
+ };
19416
+ }
19417
+ };
19418
+ const send = (text2, mode) => {
19419
+ if (!proc.stdin || proc.stdin.destroyed)
19420
+ return { ok: false, reason: "stdin closed" };
19421
+ const encoded = this.encodeStdinMessage(text2, mode, { threadId: sessionId, requestId: ++requestId });
19422
+ if (!encoded)
19423
+ return { ok: false, reason: "encoding failed (no threadId)" };
19424
+ writeStdin(encoded);
19425
+ return { ok: true };
19426
+ };
19427
+ const descriptor = {
19428
+ lifecycle: this.lifecycle,
19429
+ busyDeliveryMode: this.busyDeliveryMode,
19430
+ supportsStdinNotification: this.supportsStdinNotification
19431
+ };
19432
+ const closeStdin = () => {
19433
+ try {
19434
+ if (proc.stdin && !proc.stdin.destroyed)
19435
+ proc.stdin.end();
19436
+ } catch {}
19437
+ };
19438
+ return { pid: proc.pid, messages, parsedEvents, sessionId: sessionIdPromise, result: resultPromise, send, closeStdin, descriptor };
18300
19439
  }
18301
19440
  }
18302
19441
 
@@ -18306,9 +19445,102 @@ import { createInterface as createInterface3 } from "readline";
18306
19445
  class OpenCodeBackend {
18307
19446
  cliPath;
18308
19447
  name = "opencode";
19448
+ lifecycle = { kind: "per_turn", inFlightWake: "coalesce_into_pending" };
19449
+ busyDeliveryMode = "none";
19450
+ supportsStdinNotification = false;
18309
19451
  constructor(cliPath) {
18310
19452
  this.cliPath = cliPath;
18311
19453
  }
19454
+ parseLine(line) {
19455
+ if (!line.trim())
19456
+ return [];
19457
+ let event;
19458
+ try {
19459
+ event = JSON.parse(line);
19460
+ } catch {
19461
+ return [{ kind: "log", content: line, level: "debug" }];
19462
+ }
19463
+ const events = [];
19464
+ const eventType = event.type;
19465
+ const part = event.part;
19466
+ const eventSessionId = event.sessionID || event.session_id;
19467
+ switch (eventType) {
19468
+ case "session": {
19469
+ const sessionId = event.session_id;
19470
+ if (sessionId)
19471
+ events.push({ kind: "session_init", sessionId });
19472
+ break;
19473
+ }
19474
+ case "message": {
19475
+ const role = event.role;
19476
+ const content = event.content;
19477
+ if (role === "assistant" && content) {
19478
+ events.push({ kind: "text", text: content });
19479
+ }
19480
+ break;
19481
+ }
19482
+ case "text": {
19483
+ const text2 = part?.text || event.content || "";
19484
+ if (text2)
19485
+ events.push({ kind: "text", text: text2 });
19486
+ break;
19487
+ }
19488
+ case "thinking": {
19489
+ const content = part?.thinking || event.content || "";
19490
+ events.push({ kind: "thinking", text: content });
19491
+ break;
19492
+ }
19493
+ case "tool_call":
19494
+ events.push({
19495
+ kind: "tool_call",
19496
+ name: event.name || part?.name || "",
19497
+ callId: event.call_id || part?.id || "",
19498
+ input: event.input || part?.input
19499
+ });
19500
+ break;
19501
+ case "tool_result":
19502
+ events.push({
19503
+ kind: "tool_output",
19504
+ callId: event.call_id || part?.id || "",
19505
+ output: event.output || part?.output || ""
19506
+ });
19507
+ break;
19508
+ case "error": {
19509
+ const content = event.message || event.content || part?.error || "";
19510
+ events.push({ kind: "error", message: content });
19511
+ events.push({ kind: "turn_end" });
19512
+ break;
19513
+ }
19514
+ case "step_start":
19515
+ break;
19516
+ case "step_finish": {
19517
+ const reason = part?.reason;
19518
+ if (reason === "stop" || reason === "end_turn") {
19519
+ events.push({ kind: "turn_end" });
19520
+ }
19521
+ break;
19522
+ }
19523
+ case "done":
19524
+ case "complete": {
19525
+ const status = event.status;
19526
+ if (status === "error" || status === "failed") {
19527
+ const output = event.output;
19528
+ events.push({ kind: "error", message: output || "task failed" });
19529
+ }
19530
+ events.push({ kind: "turn_end" });
19531
+ break;
19532
+ }
19533
+ default:
19534
+ events.push({ kind: "log", content: line, level: "debug" });
19535
+ }
19536
+ if (eventSessionId && events.length > 0 && events[0].kind !== "session_init") {
19537
+ events.unshift({ kind: "session_init", sessionId: eventSessionId });
19538
+ }
19539
+ return events;
19540
+ }
19541
+ encodeStdinMessage() {
19542
+ return null;
19543
+ }
18312
19544
  execute(prompt, options) {
18313
19545
  const args = ["run", "--format", "json", "--dir", options.cwd];
18314
19546
  if (options.model) {
@@ -18366,6 +19598,9 @@ class OpenCodeBackend {
18366
19598
  const messageQueue = [];
18367
19599
  let messageResolve = null;
18368
19600
  let messageDone = false;
19601
+ const parsedEventQueue = [];
19602
+ let parsedEventResolve = null;
19603
+ let parsedEventDone = false;
18369
19604
  const pushMessage = (msg) => {
18370
19605
  messageQueue.push(msg);
18371
19606
  if (messageResolve) {
@@ -18374,6 +19609,14 @@ class OpenCodeBackend {
18374
19609
  r();
18375
19610
  }
18376
19611
  };
19612
+ const pushParsedEvent = (evt) => {
19613
+ parsedEventQueue.push(evt);
19614
+ if (parsedEventResolve) {
19615
+ const r = parsedEventResolve;
19616
+ parsedEventResolve = null;
19617
+ r();
19618
+ }
19619
+ };
18377
19620
  const resultPromise = new Promise((resolve) => {
18378
19621
  const stderrChunks = [];
18379
19622
  proc.stderr?.on("data", (chunk) => {
@@ -18383,6 +19626,9 @@ class OpenCodeBackend {
18383
19626
  rl.on("line", (line) => {
18384
19627
  if (!line.trim())
18385
19628
  return;
19629
+ const parsed = this.parseLine(line);
19630
+ for (const pe of parsed)
19631
+ pushParsedEvent(pe);
18386
19632
  let event;
18387
19633
  try {
18388
19634
  event = JSON.parse(line);
@@ -18494,11 +19740,17 @@ class OpenCodeBackend {
18494
19740
  lastError = `spawn error: ${err.message}`;
18495
19741
  resolveSessionId(lastSessionId);
18496
19742
  messageDone = true;
19743
+ parsedEventDone = true;
18497
19744
  if (messageResolve) {
18498
19745
  const r = messageResolve;
18499
19746
  messageResolve = null;
18500
19747
  r();
18501
19748
  }
19749
+ if (parsedEventResolve) {
19750
+ const r = parsedEventResolve;
19751
+ parsedEventResolve = null;
19752
+ r();
19753
+ }
18502
19754
  resolve({
18503
19755
  status: "failed",
18504
19756
  output: "",
@@ -18523,11 +19775,17 @@ class OpenCodeBackend {
18523
19775
  }
18524
19776
  resolveSessionId(lastSessionId);
18525
19777
  messageDone = true;
19778
+ parsedEventDone = true;
18526
19779
  if (messageResolve) {
18527
19780
  const r = messageResolve;
18528
19781
  messageResolve = null;
18529
19782
  r();
18530
19783
  }
19784
+ if (parsedEventResolve) {
19785
+ const r = parsedEventResolve;
19786
+ parsedEventResolve = null;
19787
+ r();
19788
+ }
18531
19789
  resolve({
18532
19790
  status: resultStatus,
18533
19791
  output: lastOutput,
@@ -18554,7 +19812,32 @@ class OpenCodeBackend {
18554
19812
  };
18555
19813
  }
18556
19814
  };
18557
- return { pid: proc.pid, messages, sessionId: sessionIdPromise, result: resultPromise };
19815
+ const parsedEvents = {
19816
+ [Symbol.asyncIterator]() {
19817
+ return {
19818
+ async next() {
19819
+ while (parsedEventQueue.length === 0 && !parsedEventDone) {
19820
+ await new Promise((resolve) => {
19821
+ parsedEventResolve = resolve;
19822
+ });
19823
+ }
19824
+ if (parsedEventQueue.length > 0) {
19825
+ return { value: parsedEventQueue.shift(), done: false };
19826
+ }
19827
+ return { value: undefined, done: true };
19828
+ }
19829
+ };
19830
+ }
19831
+ };
19832
+ const send = () => {
19833
+ return { ok: false, reason: "unsupported" };
19834
+ };
19835
+ const descriptor = {
19836
+ lifecycle: this.lifecycle,
19837
+ busyDeliveryMode: this.busyDeliveryMode,
19838
+ supportsStdinNotification: this.supportsStdinNotification
19839
+ };
19840
+ return { pid: proc.pid, messages, parsedEvents, sessionId: sessionIdPromise, result: resultPromise, send, descriptor };
18558
19841
  }
18559
19842
  }
18560
19843
 
@@ -18620,7 +19903,7 @@ function fromApiTask(api2) {
18620
19903
 
18621
19904
  // daemon/session-runner.ts
18622
19905
  import { mkdir, writeFile, rm, rename } from "fs/promises";
18623
- import { mkdirSync as mkdirSync6 } from "fs";
19906
+ import { mkdirSync as mkdirSync7 } from "fs";
18624
19907
  import path from "path";
18625
19908
 
18626
19909
  // daemon/execenv/index.ts
@@ -19080,7 +20363,7 @@ function releaseLock(lockPath) {
19080
20363
  }
19081
20364
 
19082
20365
  // daemon/execenv/timeline.ts
19083
- var log4 = createLogger2({ module: "timeline" });
20366
+ var log6 = createLogger2({ module: "timeline" });
19084
20367
  function readJsonl(filePath) {
19085
20368
  let content;
19086
20369
  try {
@@ -19149,7 +20432,7 @@ async function initEntryAsync(timelineDir, entry) {
19149
20432
  acquired = acquireLock(lockPath);
19150
20433
  }
19151
20434
  if (!acquired) {
19152
- log4.debug(`Timeline initEntry: could not acquire lock for ${filename}`);
20435
+ log6.debug(`Timeline initEntry: could not acquire lock for ${filename}`);
19153
20436
  return;
19154
20437
  }
19155
20438
  try {
@@ -19159,7 +20442,7 @@ async function initEntryAsync(timelineDir, entry) {
19159
20442
  releaseLock(lockPath);
19160
20443
  }
19161
20444
  } catch (err) {
19162
- log4.debug("Timeline initEntry failed", err);
20445
+ log6.debug("Timeline initEntry failed", err);
19163
20446
  }
19164
20447
  }
19165
20448
  function updateEntry(timelineDir, taskId, updater) {
@@ -19169,7 +20452,7 @@ function updateEntry(timelineDir, taskId, updater) {
19169
20452
  try {
19170
20453
  const acquired = acquireLock(lockPath);
19171
20454
  if (!acquired) {
19172
- log4.debug(`Timeline updateEntry: lock held for ${filename}, skipping`);
20455
+ log6.debug(`Timeline updateEntry: lock held for ${filename}, skipping`);
19173
20456
  continue;
19174
20457
  }
19175
20458
  try {
@@ -19202,10 +20485,10 @@ function updateEntry(timelineDir, taskId, updater) {
19202
20485
  releaseLock(lockPath);
19203
20486
  }
19204
20487
  } catch (err) {
19205
- log4.debug(`Timeline updateEntry failed for ${filename}`, err);
20488
+ log6.debug(`Timeline updateEntry failed for ${filename}`, err);
19206
20489
  }
19207
20490
  }
19208
- log4.debug(`Timeline updateEntry: task_id ${taskId} not found in last 7 days`);
20491
+ log6.debug(`Timeline updateEntry: task_id ${taskId} not found in last 7 days`);
19209
20492
  }
19210
20493
  function createTimelineEntry(taskId, prompt, type, sessionId, pid, provider, contextKey, detailedLog) {
19211
20494
  return {
@@ -19274,7 +20557,7 @@ function findSupersedablePredecessor(timelineDir, contextKey, provider, warmupGr
19274
20557
  // daemon/execenv/steering.ts
19275
20558
  import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5, readFileSync as readFileSync6, unlinkSync as unlinkSync3, readdirSync, statSync as statSync2 } from "fs";
19276
20559
  import { join as join8 } from "path";
19277
- var log5 = createLogger2({ module: "steering" });
20560
+ var log7 = createLogger2({ module: "steering" });
19278
20561
  var INTENT_DIR_NAME = ".kill_intents";
19279
20562
  var STEERING_LOCK_DIR = ".steering_locks";
19280
20563
  var INTENT_STALE_MS = 10 * 60 * 1000;
@@ -19328,7 +20611,7 @@ function cleanupStaleIntents(baseDir) {
19328
20611
  const stat = statSync2(filePath);
19329
20612
  if (now - stat.mtimeMs > INTENT_STALE_MS) {
19330
20613
  unlinkSync3(filePath);
19331
- log5.debug(`Cleaned up stale kill intent for task ${intent.targetTaskId}`);
20614
+ log7.debug(`Cleaned up stale kill intent for task ${intent.targetTaskId}`);
19332
20615
  }
19333
20616
  } catch {}
19334
20617
  }
@@ -19345,6 +20628,684 @@ function releaseSteeringLock(baseDir, contextKey) {
19345
20628
  releaseLock(lockPath);
19346
20629
  }
19347
20630
 
20631
+ // daemon/steering/mailbox.ts
20632
+ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, readFileSync as readFileSync7, renameSync as renameSync2, readdirSync as readdirSync2, unlinkSync as unlinkSync4, rmSync, existsSync as existsSync2, watch } from "fs";
20633
+ import { join as join9 } from "path";
20634
+ var log8 = createLogger2({ module: "mailbox" });
20635
+ function inboxDir(baseDir, contextKey) {
20636
+ const safeKey = contextKey.replace(/[^a-zA-Z0-9_:-]/g, "_");
20637
+ return join9(baseDir, ".steering", safeKey, "inbox");
20638
+ }
20639
+ function ackDir(baseDir, contextKey) {
20640
+ const safeKey = contextKey.replace(/[^a-zA-Z0-9_:-]/g, "_");
20641
+ return join9(baseDir, ".steering", safeKey, "ack");
20642
+ }
20643
+ function steeringDir(baseDir, contextKey) {
20644
+ const safeKey = contextKey.replace(/[^a-zA-Z0-9_:-]/g, "_");
20645
+ return join9(baseDir, ".steering", safeKey);
20646
+ }
20647
+ function ensureMailboxDirs(baseDir, contextKey) {
20648
+ const inbox = inboxDir(baseDir, contextKey);
20649
+ const ack = ackDir(baseDir, contextKey);
20650
+ mkdirSync6(inbox, { recursive: true });
20651
+ mkdirSync6(ack, { recursive: true });
20652
+ }
20653
+ var seqCounter = 0;
20654
+ function writeSteerMessage(baseDir, contextKey, message2) {
20655
+ const inbox = inboxDir(baseDir, contextKey);
20656
+ const seq = String(++seqCounter).padStart(6, "0");
20657
+ const tmpPath = join9(inbox, `${seq}.json.tmp`);
20658
+ const finalPath = join9(inbox, `${seq}.json`);
20659
+ writeFileSync6(tmpPath, JSON.stringify(message2));
20660
+ renameSync2(tmpPath, finalPath);
20661
+ return seq;
20662
+ }
20663
+ function waitForAck(baseDir, contextKey, seq, timeoutMs = 3000) {
20664
+ const ackPath = join9(ackDir(baseDir, contextKey), `${seq}.ack`);
20665
+ const nackPath = join9(ackDir(baseDir, contextKey), `${seq}.nack`);
20666
+ return new Promise((resolve) => {
20667
+ const deadline = Date.now() + timeoutMs;
20668
+ const pollInterval = 100;
20669
+ const check2 = () => {
20670
+ try {
20671
+ if (existsSync2(ackPath)) {
20672
+ resolve({ acked: true });
20673
+ return;
20674
+ }
20675
+ if (existsSync2(nackPath)) {
20676
+ let reason = "unknown";
20677
+ try {
20678
+ const content = readFileSync7(nackPath, "utf-8");
20679
+ const parsed = JSON.parse(content);
20680
+ reason = parsed.reason || "unknown";
20681
+ } catch {}
20682
+ resolve({ acked: false, nackReason: reason });
20683
+ return;
20684
+ }
20685
+ } catch {}
20686
+ if (Date.now() >= deadline) {
20687
+ resolve({ acked: false, nackReason: "timeout" });
20688
+ return;
20689
+ }
20690
+ setTimeout(check2, pollInterval);
20691
+ };
20692
+ check2();
20693
+ });
20694
+ }
20695
+ function readSteerMessage(filePath) {
20696
+ try {
20697
+ const content = readFileSync7(filePath, "utf-8");
20698
+ return JSON.parse(content);
20699
+ } catch {
20700
+ return null;
20701
+ }
20702
+ }
20703
+ function writeAck(baseDir, contextKey, seq) {
20704
+ const ack = ackDir(baseDir, contextKey);
20705
+ mkdirSync6(ack, { recursive: true });
20706
+ writeFileSync6(join9(ack, `${seq}.ack`), "");
20707
+ }
20708
+ function writeNack(baseDir, contextKey, seq, reason) {
20709
+ const ack = ackDir(baseDir, contextKey);
20710
+ mkdirSync6(ack, { recursive: true });
20711
+ writeFileSync6(join9(ack, `${seq}.nack`), JSON.stringify({ reason }));
20712
+ }
20713
+ function cleanupInboxFile(baseDir, contextKey, seq) {
20714
+ try {
20715
+ unlinkSync4(join9(inboxDir(baseDir, contextKey), `${seq}.json`));
20716
+ } catch {}
20717
+ }
20718
+ function cleanupSteeringDir(baseDir, contextKey) {
20719
+ const dir = steeringDir(baseDir, contextKey);
20720
+ try {
20721
+ rmSync(dir, { recursive: true, force: true });
20722
+ } catch {}
20723
+ }
20724
+ function watchInbox(baseDir, contextKey, onMessage) {
20725
+ const inbox = inboxDir(baseDir, contextKey);
20726
+ mkdirSync6(inbox, { recursive: true });
20727
+ const seen = new Set;
20728
+ let stopped = false;
20729
+ const scan = () => {
20730
+ if (stopped)
20731
+ return;
20732
+ try {
20733
+ const files = readdirSync2(inbox).filter((f) => f.endsWith(".json") && !f.endsWith(".tmp")).sort();
20734
+ for (const file2 of files) {
20735
+ if (seen.has(file2))
20736
+ continue;
20737
+ const seq = file2.replace(/\.json$/, "");
20738
+ const srcPath = join9(inbox, file2);
20739
+ const claimPath = join9(inbox, `${seq}.processing`);
20740
+ try {
20741
+ renameSync2(srcPath, claimPath);
20742
+ } catch {
20743
+ continue;
20744
+ }
20745
+ seen.add(file2);
20746
+ const msg = readSteerMessage(claimPath);
20747
+ try {
20748
+ unlinkSync4(claimPath);
20749
+ } catch {}
20750
+ if (msg) {
20751
+ onMessage(seq, msg);
20752
+ }
20753
+ }
20754
+ } catch {}
20755
+ };
20756
+ scan();
20757
+ let watcher = null;
20758
+ try {
20759
+ watcher = watch(inbox, () => {
20760
+ if (!stopped)
20761
+ scan();
20762
+ });
20763
+ } catch {
20764
+ log8.debug("fs.watch failed, relying on polling only");
20765
+ }
20766
+ const pollTimer = setInterval(scan, 200);
20767
+ return {
20768
+ stop() {
20769
+ stopped = true;
20770
+ clearInterval(pollTimer);
20771
+ watcher?.close();
20772
+ }
20773
+ };
20774
+ }
20775
+
20776
+ // daemon/steering/turnState.ts
20777
+ class RuntimeTurnState {
20778
+ currentTurnId = null;
20779
+ steeringGateActive = false;
20780
+ get isInTurn() {
20781
+ return this.currentTurnId !== null;
20782
+ }
20783
+ get turnId() {
20784
+ return this.currentTurnId;
20785
+ }
20786
+ get canSteerBusy() {
20787
+ return Boolean(this.currentTurnId && !this.steeringGateActive);
20788
+ }
20789
+ markTurnStarted(turnId) {
20790
+ if (turnId !== undefined && turnId !== null) {
20791
+ this.currentTurnId = turnId;
20792
+ }
20793
+ this.steeringGateActive = false;
20794
+ }
20795
+ adoptTurnId(turnId) {
20796
+ this.currentTurnId = turnId;
20797
+ }
20798
+ markToolBoundary() {
20799
+ this.steeringGateActive = true;
20800
+ }
20801
+ markProgress() {
20802
+ this.steeringGateActive = false;
20803
+ }
20804
+ markTurnCompleted() {
20805
+ this.currentTurnId = null;
20806
+ this.steeringGateActive = false;
20807
+ }
20808
+ reset() {
20809
+ this.currentTurnId = null;
20810
+ this.steeringGateActive = false;
20811
+ }
20812
+ }
20813
+
20814
+ // daemon/steering/apmStateMachine.ts
20815
+ var MAX_APM_GATED_STEERING_EVENTS = 12;
20816
+ function createInitialApmState() {
20817
+ return {
20818
+ isIdle: false,
20819
+ expectedTerminationReason: null,
20820
+ phase: "idle",
20821
+ outstandingToolUses: 0,
20822
+ compacting: false,
20823
+ toolBoundaryFlushDisabled: false,
20824
+ lastFlushReason: null,
20825
+ recentEvents: [],
20826
+ pendingMessages: []
20827
+ };
20828
+ }
20829
+ function reduceApmGatedToolUse(state, input) {
20830
+ if (input.kind === "tool_call") {
20831
+ return {
20832
+ nextState: {
20833
+ ...state,
20834
+ isIdle: false,
20835
+ phase: "tool_wait",
20836
+ outstandingToolUses: state.outstandingToolUses + 1
20837
+ },
20838
+ hadOutstandingToolUse: state.outstandingToolUses > 0,
20839
+ shouldFlushToolBatch: false
20840
+ };
20841
+ }
20842
+ const hadOutstandingToolUse = state.outstandingToolUses > 0;
20843
+ const outstandingToolUses = Math.max(0, state.outstandingToolUses - 1);
20844
+ return {
20845
+ nextState: {
20846
+ ...state,
20847
+ isIdle: false,
20848
+ phase: "tool_boundary",
20849
+ outstandingToolUses
20850
+ },
20851
+ hadOutstandingToolUse,
20852
+ shouldFlushToolBatch: hadOutstandingToolUse && outstandingToolUses === 0
20853
+ };
20854
+ }
20855
+ function reduceApmGatedCompaction(state, input) {
20856
+ if (input.kind === "compaction_started") {
20857
+ return { nextState: { ...state, isIdle: false, phase: "compacting", compacting: true } };
20858
+ }
20859
+ if (input.kind === "compaction_interrupted") {
20860
+ return { nextState: { ...state, isIdle: false, compacting: false } };
20861
+ }
20862
+ return {
20863
+ nextState: { ...state, isIdle: false, phase: "assistant_continuation", compacting: false }
20864
+ };
20865
+ }
20866
+ function reduceApmGatedFlushReadiness(state, input) {
20867
+ if (!input.isGated)
20868
+ return { shouldNotify: false, blockedReason: "non_gated", effects: [] };
20869
+ if (!input.hasSession)
20870
+ return { shouldNotify: false, blockedReason: "missing_session", effects: [] };
20871
+ if (input.inboxLength === 0)
20872
+ return { shouldNotify: false, blockedReason: "empty_inbox", effects: [] };
20873
+ if (state.toolBoundaryFlushDisabled) {
20874
+ return { shouldNotify: false, blockedReason: "tool_boundary_flush_disabled", effects: [] };
20875
+ }
20876
+ if (state.compacting)
20877
+ return { shouldNotify: false, blockedReason: "compacting", effects: [] };
20878
+ if (state.outstandingToolUses > 0) {
20879
+ return { shouldNotify: false, blockedReason: "outstanding_tool_uses", effects: [] };
20880
+ }
20881
+ return {
20882
+ shouldNotify: true,
20883
+ blockedReason: null,
20884
+ effects: [{ kind: "notify_stdin", reason: input.reason, stdinMode: "busy", clauseId: "SMR-002" }]
20885
+ };
20886
+ }
20887
+ function reduceApmGatedTurnEnd(state, input = {}) {
20888
+ const shouldDeliverQueuedMessages = Boolean(input.inboxLength && input.inboxLength > 0 && input.supportsStdinNotification && input.hasSession);
20889
+ return {
20890
+ nextState: {
20891
+ ...state,
20892
+ isIdle: !shouldDeliverQueuedMessages,
20893
+ phase: "idle",
20894
+ outstandingToolUses: 0,
20895
+ compacting: false,
20896
+ pendingMessages: shouldDeliverQueuedMessages ? state.pendingMessages : []
20897
+ },
20898
+ effects: shouldDeliverQueuedMessages ? [{ kind: "deliver_stdin", reason: "turn_end", stdinMode: "idle", clauseId: "SMR-002" }] : []
20899
+ };
20900
+ }
20901
+ function reduceApmGatedError(state, input = {}) {
20902
+ const shouldDisableToolBoundaryFlush = input.disableToolBoundaryFlush === true;
20903
+ return {
20904
+ nextState: {
20905
+ ...state,
20906
+ phase: "error",
20907
+ compacting: false,
20908
+ toolBoundaryFlushDisabled: state.toolBoundaryFlushDisabled || shouldDisableToolBoundaryFlush
20909
+ },
20910
+ shouldDisableToolBoundaryFlush
20911
+ };
20912
+ }
20913
+ function reduceApmGatedRecentEvent(state, input) {
20914
+ const summary = `${input.event}:${state.phase}:tools=${state.outstandingToolUses}:compact=${state.compacting}`;
20915
+ return {
20916
+ nextState: {
20917
+ ...state,
20918
+ recentEvents: [...state.recentEvents, summary].slice(-MAX_APM_GATED_STEERING_EVENTS)
20919
+ }
20920
+ };
20921
+ }
20922
+ function reduceApmGatedEnqueue(state, message2) {
20923
+ return {
20924
+ nextState: {
20925
+ ...state,
20926
+ pendingMessages: [...state.pendingMessages, message2]
20927
+ }
20928
+ };
20929
+ }
20930
+ function reduceApmStalledRecoveryTermination(state, input) {
20931
+ if (input.inboxLength === 0) {
20932
+ return { nextState: state, shouldTerminate: false, alreadyRecovering: false, blockedReason: "empty_inbox" };
20933
+ }
20934
+ if (state.expectedTerminationReason === "stalled_recovery") {
20935
+ return { nextState: state, shouldTerminate: false, alreadyRecovering: true, blockedReason: null };
20936
+ }
20937
+ const supportsStdinNotification = input.busyDeliveryMode !== "none";
20938
+ const directStdinRuntime = supportsStdinNotification && input.busyDeliveryMode === "direct";
20939
+ const canRestartDirectStdinProcess = directStdinRuntime && input.hasSession && (state.outstandingToolUses === 0 || input.hasDirectStdinRecoveryEvidence);
20940
+ const canRestartStalledProcess = !supportsStdinNotification || canRestartDirectStdinProcess;
20941
+ if (!canRestartStalledProcess) {
20942
+ return {
20943
+ nextState: state,
20944
+ shouldTerminate: false,
20945
+ alreadyRecovering: false,
20946
+ blockedReason: "runtime_not_restartable"
20947
+ };
20948
+ }
20949
+ if (input.staleForMs < input.staleThresholdMs && !input.runtimeProgressIsStale) {
20950
+ return {
20951
+ nextState: state,
20952
+ shouldTerminate: false,
20953
+ alreadyRecovering: false,
20954
+ blockedReason: "runtime_progress_recent"
20955
+ };
20956
+ }
20957
+ return {
20958
+ nextState: { ...state, expectedTerminationReason: "stalled_recovery" },
20959
+ shouldTerminate: true,
20960
+ alreadyRecovering: false,
20961
+ blockedReason: null
20962
+ };
20963
+ }
20964
+ function reduceApmStartupTimeoutTermination(state, input) {
20965
+ if (input.hasRuntimeProgressEvent) {
20966
+ return { nextState: state, shouldTerminate: false, blockedReason: "runtime_progress_started" };
20967
+ }
20968
+ return {
20969
+ nextState: { ...state, isIdle: false, expectedTerminationReason: "startup_timeout" },
20970
+ shouldTerminate: true,
20971
+ blockedReason: null
20972
+ };
20973
+ }
20974
+
20975
+ // daemon/steering/notificationState.ts
20976
+ function inboxNoticeMessageIdentity(message2) {
20977
+ const seq = typeof message2.seq === "number" && Number.isFinite(message2.seq) && message2.seq > 0 ? Math.floor(message2.seq) : null;
20978
+ if (seq !== null)
20979
+ return `s:${seq}`;
20980
+ const id = typeof message2.message_id === "string" && message2.message_id.length > 0 ? message2.message_id : typeof message2.id === "string" && message2.id.length > 0 ? message2.id : "";
20981
+ return id.length > 0 ? `m:${id}` : "";
20982
+ }
20983
+ class RuntimeNotificationState {
20984
+ pendingCountValue = 0;
20985
+ timerValue = null;
20986
+ lastNoticeFingerprint = null;
20987
+ lastNoticeSessionId = null;
20988
+ lastEncodeFailedFingerprint = null;
20989
+ lastEncodeFailedSessionId = null;
20990
+ contributedIdentities = new Set;
20991
+ contributionSessionId = null;
20992
+ get pendingCount() {
20993
+ return this.pendingCountValue;
20994
+ }
20995
+ isDuplicateNotice(fingerprint, sessionId) {
20996
+ if (fingerprint.length === 0)
20997
+ return false;
20998
+ return this.lastNoticeFingerprint === fingerprint && this.lastNoticeSessionId === sessionId;
20999
+ }
21000
+ recordNoticeWritten(fingerprint, sessionId, messages = []) {
21001
+ this.lastNoticeFingerprint = fingerprint;
21002
+ this.lastNoticeSessionId = sessionId;
21003
+ this.lastEncodeFailedFingerprint = null;
21004
+ this.lastEncodeFailedSessionId = null;
21005
+ this.ensureContributionSession(sessionId);
21006
+ for (const message2 of messages) {
21007
+ const identity = inboxNoticeMessageIdentity(message2);
21008
+ if (identity.length > 0)
21009
+ this.contributedIdentities.add(identity);
21010
+ }
21011
+ }
21012
+ recordNoticeEncodeFailed(fingerprint, sessionId) {
21013
+ if (fingerprint.length === 0)
21014
+ return;
21015
+ this.lastEncodeFailedFingerprint = fingerprint;
21016
+ this.lastEncodeFailedSessionId = sessionId;
21017
+ }
21018
+ isDuplicateEncodeFailedNotice(fingerprint, sessionId) {
21019
+ if (fingerprint.length === 0)
21020
+ return false;
21021
+ return this.lastEncodeFailedFingerprint === fingerprint && this.lastEncodeFailedSessionId === sessionId;
21022
+ }
21023
+ filterUncontributedMessages(messages, sessionId) {
21024
+ if (this.contributionSessionId !== sessionId)
21025
+ return messages;
21026
+ return messages.filter((m) => {
21027
+ const identity = inboxNoticeMessageIdentity(m);
21028
+ return identity.length === 0 || !this.contributedIdentities.has(identity);
21029
+ });
21030
+ }
21031
+ add(count = 1) {
21032
+ this.pendingCountValue += count;
21033
+ }
21034
+ schedule(callback, delayMs) {
21035
+ if (this.timerValue)
21036
+ return false;
21037
+ this.timerValue = setTimeout(() => {
21038
+ this.timerValue = null;
21039
+ callback();
21040
+ }, delayMs);
21041
+ this.timerValue.unref?.();
21042
+ return true;
21043
+ }
21044
+ takePendingAndClearTimer() {
21045
+ const count = this.pendingCountValue;
21046
+ this.pendingCountValue = 0;
21047
+ if (this.timerValue) {
21048
+ clearTimeout(this.timerValue);
21049
+ this.timerValue = null;
21050
+ }
21051
+ return count;
21052
+ }
21053
+ ensureContributionSession(sessionId) {
21054
+ if (this.contributionSessionId !== sessionId) {
21055
+ this.contributionSessionId = sessionId;
21056
+ this.contributedIdentities = new Set;
21057
+ }
21058
+ }
21059
+ }
21060
+
21061
+ // daemon/steering/progressState.ts
21062
+ class RuntimeProgressState {
21063
+ lastEventAt;
21064
+ lastEventKind = null;
21065
+ _staleSince = null;
21066
+ _isStale = false;
21067
+ constructor(now = Date.now()) {
21068
+ this.lastEventAt = now;
21069
+ }
21070
+ get isStale() {
21071
+ return this._isStale;
21072
+ }
21073
+ get staleSince() {
21074
+ return this._staleSince;
21075
+ }
21076
+ get lastActivity() {
21077
+ return this.lastEventAt;
21078
+ }
21079
+ ageMs(nowMs = Date.now()) {
21080
+ return nowMs - this.lastEventAt;
21081
+ }
21082
+ recordRealEvent(kind, now = Date.now()) {
21083
+ this.lastEventAt = now;
21084
+ this.lastEventKind = kind;
21085
+ this._isStale = false;
21086
+ this._staleSince = null;
21087
+ }
21088
+ recordInternalProgress(kind, now = Date.now()) {
21089
+ this.lastEventAt = now;
21090
+ this.lastEventKind = kind;
21091
+ }
21092
+ markStale(now = Date.now()) {
21093
+ if (this._isStale)
21094
+ return;
21095
+ this._isStale = true;
21096
+ this._staleSince = now;
21097
+ }
21098
+ shouldMarkStale(thresholdMs, now = Date.now()) {
21099
+ if (this._isStale)
21100
+ return false;
21101
+ return this.ageMs(now) > thresholdMs;
21102
+ }
21103
+ processEvent(event, now = Date.now()) {
21104
+ switch (event.kind) {
21105
+ case "text":
21106
+ case "tool_call":
21107
+ case "tool_output":
21108
+ case "turn_end":
21109
+ case "session_init":
21110
+ case "error":
21111
+ this.recordRealEvent(event.kind, now);
21112
+ break;
21113
+ case "internal_progress":
21114
+ case "compaction_started":
21115
+ case "compaction_finished":
21116
+ case "telemetry":
21117
+ case "thinking":
21118
+ this.recordInternalProgress(event.kind, now);
21119
+ break;
21120
+ default:
21121
+ this.recordInternalProgress(event.kind, now);
21122
+ }
21123
+ }
21124
+ }
21125
+
21126
+ // daemon/steering/errorDiagnostics.ts
21127
+ var ACTION_BY_CLASS = {
21128
+ RateLimitError: "retry_backoff",
21129
+ AuthError: "abort",
21130
+ NotFoundError: "report",
21131
+ ModelConfigError: "abort",
21132
+ TimeoutError: "retry",
21133
+ ProviderConnectionError: "retry_jitter",
21134
+ ProviderStreamError: "retry",
21135
+ ProviderServerError: "retry",
21136
+ ProviderApiError: "report",
21137
+ RuntimeError: "report"
21138
+ };
21139
+ var EXPLICIT_TOKEN_RE = /\b([A-Z][A-Za-z0-9_]*(?:Error|Exception))\b/;
21140
+ var EXPLICIT_TOKEN_MAP = {
21141
+ RateLimitError: "RateLimitError",
21142
+ TooManyRequestsError: "RateLimitError",
21143
+ AuthenticationError: "AuthError",
21144
+ AuthorizationError: "AuthError",
21145
+ PermissionError: "AuthError",
21146
+ NotFoundError: "NotFoundError",
21147
+ ModelNotFoundError: "ModelConfigError",
21148
+ TimeoutError: "TimeoutError",
21149
+ ConnectionError: "ProviderConnectionError",
21150
+ APIConnectionError: "ProviderConnectionError",
21151
+ StreamError: "ProviderStreamError",
21152
+ InternalServerError: "ProviderServerError",
21153
+ APIError: "ProviderApiError",
21154
+ BadRequestError: "ProviderApiError"
21155
+ };
21156
+ function extractHttpStatus(message2) {
21157
+ const labeled = /\b(?:HTTP|status(?:\s+code)?|API\s+Error)[:\s]+([45]\d{2})\b/i.exec(message2);
21158
+ if (labeled)
21159
+ return Number(labeled[1]);
21160
+ const semantic = /\b([45]\d{2})\s+(?:Unauthorized|Forbidden|Not Found|Too Many Requests|Internal Server Error|Bad Gateway|Service Unavailable|Gateway Timeout)\b/i.exec(message2);
21161
+ return semantic ? Number(semantic[1]) : null;
21162
+ }
21163
+ var AUTH_ACTION_REQUIRED_PATTERNS = [
21164
+ /access token could not be refreshed/i,
21165
+ /\btoken_(?:revoked|invalidated)\b/i,
21166
+ /refresh token was already used/i,
21167
+ /access token.*invalidated/i,
21168
+ /authentication token has been invalidated/i,
21169
+ /logged out or signed in to another account/i,
21170
+ /not logged in/i,
21171
+ /not signed in/i,
21172
+ /login required/i,
21173
+ /log in first/i,
21174
+ /please log in/i,
21175
+ /authentication failed/i,
21176
+ /auth(?:entication)? failed/i,
21177
+ /authentication timed out/i,
21178
+ /missing (?:api )?token/i,
21179
+ /no (?:api )?token/i,
21180
+ /missing credentials/i,
21181
+ /credentials? not found/i,
21182
+ /invalid api key/i,
21183
+ /api key (?:is )?not set/i,
21184
+ /token revoked/i,
21185
+ /refresh token expired/i,
21186
+ /session expired/i,
21187
+ /unauthorized/i,
21188
+ /forbidden/i,
21189
+ /invalid.?token/i
21190
+ ];
21191
+ var RATE_LIMIT_PATTERNS = [
21192
+ /too many requests/i,
21193
+ /rate.?limit/i,
21194
+ /quota.?exceeded/i,
21195
+ /overloaded/i
21196
+ ];
21197
+ var MODEL_CONFIG_PATTERNS = [
21198
+ /model.?not.?(?:found|supported|available)/i,
21199
+ /invalid.?model/i,
21200
+ /does not exist/i
21201
+ ];
21202
+ var TIMEOUT_PATTERNS = [
21203
+ /timeout/i,
21204
+ /ETIMEDOUT/,
21205
+ /timed.?out/i,
21206
+ /deadline.?exceeded/i
21207
+ ];
21208
+ var CONNECTION_PATTERNS = [
21209
+ /ECONNREFUSED/,
21210
+ /ECONNRESET/,
21211
+ /ENETUNREACH/,
21212
+ /EHOSTUNREACH/,
21213
+ /EAI_AGAIN/,
21214
+ /ENOTFOUND/,
21215
+ /connection.?refused/i,
21216
+ /connection.?reset/i,
21217
+ /network.?error/i,
21218
+ /Unable to connect to API/i
21219
+ ];
21220
+ var STREAM_PATTERNS = [
21221
+ /stream.?error/i,
21222
+ /stream closed before response/i,
21223
+ /error decoding response body/i,
21224
+ /premature.?close/i,
21225
+ /aborted/i
21226
+ ];
21227
+ var SERVER_PATTERNS = [
21228
+ /internal.?server/i,
21229
+ /bad.?gateway/i,
21230
+ /service.?unavailable/i
21231
+ ];
21232
+ function classifyByExplicitToken(message2) {
21233
+ const match = EXPLICIT_TOKEN_RE.exec(message2);
21234
+ if (!match)
21235
+ return null;
21236
+ const token = match[1];
21237
+ return EXPLICIT_TOKEN_MAP[token] ?? null;
21238
+ }
21239
+ function classifyByHttpStatus(httpStatus) {
21240
+ if (httpStatus === 429)
21241
+ return "RateLimitError";
21242
+ if (httpStatus === 401 || httpStatus === 403)
21243
+ return "AuthError";
21244
+ if (httpStatus === 404)
21245
+ return "NotFoundError";
21246
+ if (httpStatus >= 500)
21247
+ return "ProviderServerError";
21248
+ return "ProviderApiError";
21249
+ }
21250
+ function classifyByTextPatterns(message2) {
21251
+ for (const pat of RATE_LIMIT_PATTERNS) {
21252
+ if (pat.test(message2))
21253
+ return "RateLimitError";
21254
+ }
21255
+ for (const pat of AUTH_ACTION_REQUIRED_PATTERNS) {
21256
+ if (pat.test(message2))
21257
+ return "AuthError";
21258
+ }
21259
+ for (const pat of MODEL_CONFIG_PATTERNS) {
21260
+ if (pat.test(message2))
21261
+ return "ModelConfigError";
21262
+ }
21263
+ for (const pat of TIMEOUT_PATTERNS) {
21264
+ if (pat.test(message2))
21265
+ return "TimeoutError";
21266
+ }
21267
+ for (const pat of CONNECTION_PATTERNS) {
21268
+ if (pat.test(message2))
21269
+ return "ProviderConnectionError";
21270
+ }
21271
+ for (const pat of STREAM_PATTERNS) {
21272
+ if (pat.test(message2))
21273
+ return "ProviderStreamError";
21274
+ }
21275
+ for (const pat of SERVER_PATTERNS) {
21276
+ if (pat.test(message2))
21277
+ return "ProviderServerError";
21278
+ }
21279
+ return null;
21280
+ }
21281
+ function classifyRuntimeError(message2, httpStatus) {
21282
+ const byToken = classifyByExplicitToken(message2);
21283
+ if (byToken) {
21284
+ return { errorClass: byToken, action: ACTION_BY_CLASS[byToken], reason: message2 };
21285
+ }
21286
+ const status = httpStatus ?? extractHttpStatus(message2);
21287
+ if (status !== null && status !== undefined) {
21288
+ const cls = classifyByHttpStatus(status);
21289
+ return { errorClass: cls, action: ACTION_BY_CLASS[cls], reason: message2 };
21290
+ }
21291
+ const byPattern = classifyByTextPatterns(message2);
21292
+ if (byPattern) {
21293
+ return { errorClass: byPattern, action: ACTION_BY_CLASS[byPattern], reason: message2 };
21294
+ }
21295
+ return { errorClass: "RuntimeError", action: "report", reason: message2 };
21296
+ }
21297
+ function scrubDiagnosticText(text2) {
21298
+ let scrubbed = text2;
21299
+ scrubbed = scrubbed.replace(/sk-ant-[a-zA-Z0-9_-]+/g, "sk-ant-***");
21300
+ scrubbed = scrubbed.replace(/sk-proj-[a-zA-Z0-9_-]+/g, "sk-proj-***");
21301
+ scrubbed = scrubbed.replace(/sk-[a-zA-Z0-9_-]{20,}/g, "sk-***");
21302
+ scrubbed = scrubbed.replace(/Bearer\s+[a-zA-Z0-9._-]+/gi, "Bearer ***");
21303
+ scrubbed = scrubbed.replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, "***@***.***");
21304
+ scrubbed = scrubbed.replace(/:\/\/[^:@\s]+:[^@\s]+@/g, "://***:***@");
21305
+ scrubbed = scrubbed.replace(/\/(?:Users|home)\/[a-zA-Z0-9._-]+/g, "/***");
21306
+ return scrubbed;
21307
+ }
21308
+
19348
21309
  // daemon/prompt.ts
19349
21310
  var DM_RESPONSE_NOTICE = "Reply with `alook sync send-dm` — that's the only thing the user sees; your task output and reasoning are not shown." + " Talk to them at milestones like a colleague would, and don't end your turn without sending what they need." + " If this task will take more than 30 seconds, send a quick ack first so the user knows you're on it." + " IMPORTANT: If you were working on a previous task before this message arrived, do NOT silently drop it. After handling this message, return to any prior unfinished work and report the result to the user.";
19350
21311
  var EMAIL_NOTICE = "This task was triggered by an incoming email. Reply to the sender via email — use the email sending tool to respond." + " If you need more information or confirmation, email them and then exit." + " Do not wait — when they reply, a new task will be triggered automatically and you will be woken up with their response." + " IMPORTANT: Do not let this email interrupt any task you were previously working on. After handling this email, return to your original task and make sure it reaches completion.";
@@ -19448,7 +21409,7 @@ function buildMergedPrompt(tasks, attachmentsMap) {
19448
21409
  }
19449
21410
 
19450
21411
  // daemon/session-runner.ts
19451
- var log6 = createLogger2({ module: "session-runner" });
21412
+ var log9 = createLogger2({ module: "session-runner" });
19452
21413
  var ATTACHMENTS_BASE = tempDir("alook-attachments");
19453
21414
  async function writeMarkerFile(workspacesRoot, marker) {
19454
21415
  const dir = path.join(workspacesRoot, ".pending_completions");
@@ -19496,20 +21457,20 @@ async function reportToServer(fn, markerData, workspacesRoot) {
19496
21457
  } catch (e) {
19497
21458
  lastErr = e;
19498
21459
  if (isClientError(e)) {
19499
- log6.info(`server report for task ${markerData.taskId}: task already in terminal state (${e})`);
21460
+ log9.info(`server report for task ${markerData.taskId}: task already in terminal state (${e})`);
19500
21461
  return;
19501
21462
  }
19502
21463
  if (attempt < RETRY_DELAYS.length && isRetryableError(e)) {
19503
- log6.debug(`server report attempt ${attempt + 1} failed for task ${markerData.taskId}, retrying in ${RETRY_DELAYS[attempt]}ms`);
21464
+ log9.debug(`server report attempt ${attempt + 1} failed for task ${markerData.taskId}, retrying in ${RETRY_DELAYS[attempt]}ms`);
19504
21465
  await new Promise((r) => setTimeout(r, RETRY_DELAYS[attempt]));
19505
21466
  }
19506
21467
  }
19507
21468
  }
19508
- log6.warn(`server report failed for task ${markerData.taskId} after retries, writing marker: ${lastErr}`);
21469
+ log9.warn(`server report failed for task ${markerData.taskId} after retries, writing marker: ${lastErr}`);
19509
21470
  try {
19510
21471
  await writeMarkerFile(workspacesRoot, markerData);
19511
21472
  } catch (writeErr) {
19512
- log6.error(`marker write also failed for task ${markerData.taskId}: ${writeErr}`);
21473
+ log9.error(`marker write also failed for task ${markerData.taskId}: ${writeErr}`);
19513
21474
  }
19514
21475
  }
19515
21476
  function sanitizeFilename(name) {
@@ -19540,12 +21501,12 @@ async function downloadAttachments(client, token, workspaceId, taskId, attachmen
19540
21501
  }
19541
21502
  async function runSession(input) {
19542
21503
  const { task, provider, cliPath, model, serverURL, token, workspacesRoot, agentTimeout, messageInactivityTimeout } = input;
19543
- log6.info(`starting (task=${task.id}, type=${task.type}, agent=${task.agentId}, provider=${provider}, model=${model || "default"})`);
21504
+ log9.info(`starting (task=${task.id}, type=${task.type}, agent=${task.agentId}, provider=${provider}, model=${model || "default"})`);
19544
21505
  const client = new DaemonClient(serverURL);
19545
21506
  const backend = createBackend(provider, cliPath);
19546
21507
  const agentBaseDir = path.join(workspacesRoot, task.workspaceId, task.agentId, "workdir");
19547
21508
  const timelineDir = path.join(agentBaseDir, ".context_timeline").replace(/\\/g, "/");
19548
- mkdirSync6(timelineDir, { recursive: true });
21509
+ mkdirSync7(timelineDir, { recursive: true });
19549
21510
  await initEntryAsync(timelineDir, createTimelineEntry(task.id, task.prompt, task.type, undefined, process.pid, provider, task.contextKey, input.logFilePath));
19550
21511
  const { workDir, env } = prepare({ workspacesRoot, token }, task);
19551
21512
  let killed = false;
@@ -19563,16 +21524,22 @@ async function runSession(input) {
19563
21524
  try {
19564
21525
  await client.reportMessages(token, task.id, batch);
19565
21526
  } catch (e) {
19566
- log6.debug("message report failed", e);
21527
+ log9.debug("message report failed", e);
19567
21528
  }
19568
21529
  };
21530
+ let mailboxWatcher = null;
21531
+ let stalledRecoveryTimer;
19569
21532
  const onKill = async () => {
19570
21533
  if (killed)
19571
21534
  return;
19572
21535
  killed = true;
19573
- log6.info(`killed by signal (messages=${seq}, tools=${toolCount})`);
21536
+ log9.info(`killed by signal (messages=${seq}, tools=${toolCount})`);
21537
+ if (mailboxWatcher)
21538
+ mailboxWatcher.stop();
21539
+ if (stalledRecoveryTimer)
21540
+ clearInterval(stalledRecoveryTimer);
19574
21541
  if (agentPid !== undefined) {
19575
- log6.info(`killing inner agent group (pid=${agentPid})`);
21542
+ log9.info(`killing inner agent group (pid=${agentPid})`);
19576
21543
  await killProcessTree(agentPid);
19577
21544
  }
19578
21545
  if (flushTimer)
@@ -19615,14 +21582,14 @@ async function runSession(input) {
19615
21582
  const attachmentIds = task.context?.attachment_ids ?? [];
19616
21583
  let attachments;
19617
21584
  if (attachmentIds.length > 0) {
19618
- log6.info(`downloading ${attachmentIds.length} attachment(s)`);
21585
+ log9.info(`downloading ${attachmentIds.length} attachment(s)`);
19619
21586
  try {
19620
21587
  attachments = await downloadAttachments(client, token, task.workspaceId, task.id, attachmentIds);
19621
- log6.info(`attachments ready (${attachments.length} file(s))`);
21588
+ log9.info(`attachments ready (${attachments.length} file(s))`);
19622
21589
  } catch (e) {
19623
21590
  await cleanupAttachments(task.id);
19624
21591
  const errMsg = `failed to download attachments: ${e}`;
19625
- log6.error(errMsg);
21592
+ log9.error(errMsg);
19626
21593
  updateEntry(timelineDir, task.id, (entry) => {
19627
21594
  entry.pid = null;
19628
21595
  entry.status = "failed";
@@ -19639,32 +21606,301 @@ async function runSession(input) {
19639
21606
  const prompt = input.promptOverride ?? buildPrompt(task, attachments);
19640
21607
  const resumeSessionId = task.contextKey ? findResumableSessionByContextKey(timelineDir, task.contextKey, provider) ?? undefined : undefined;
19641
21608
  if (resumeSessionId) {
19642
- log6.info(`resuming session ${resumeSessionId} (context_key: ${task.contextKey})`);
21609
+ log9.info(`resuming session ${resumeSessionId} (context_key: ${task.contextKey})`);
19643
21610
  }
19644
21611
  const session2 = backend.execute(prompt, {
19645
21612
  cwd: workDir,
19646
21613
  model: model || undefined,
19647
21614
  env,
19648
21615
  timeout: agentTimeout,
19649
- resumeSessionId
21616
+ resumeSessionId,
21617
+ steeringEnabled: input.steeringEnabled
19650
21618
  });
19651
21619
  agentPid = session2.pid;
19652
21620
  if (killed) {
19653
21621
  if (agentPid !== undefined) {
19654
- log6.info(`kill landed during spawn — reaping inner agent group (pid=${agentPid})`);
21622
+ log9.info(`kill landed during spawn — reaping inner agent group (pid=${agentPid})`);
19655
21623
  await killProcessTree(agentPid);
19656
21624
  }
19657
21625
  process.exit(1);
19658
21626
  }
19659
21627
  const earlySessionId = await session2.sessionId;
19660
- log6.info(`agent started (pid=${agentPid ?? "unknown"}, session=${earlySessionId})`);
19661
- log6.info(JSON.stringify({ role: "user", type: "text", content: prompt }));
21628
+ log9.info(`agent started (pid=${agentPid ?? "unknown"}, session=${earlySessionId})`);
21629
+ log9.info(JSON.stringify({ role: "user", type: "text", content: prompt }));
19662
21630
  updateEntry(timelineDir, task.id, (entry) => {
19663
21631
  entry.session_id = earlySessionId || null;
19664
21632
  if (earlySessionId)
19665
21633
  entry.agent_started = true;
19666
21634
  });
19667
21635
  flushTimer = setInterval(flushMessages, FLUSH_INTERVAL_MS);
21636
+ const turnState = new RuntimeTurnState;
21637
+ let apmState = createInitialApmState();
21638
+ const notificationState = new RuntimeNotificationState;
21639
+ const progressState = new RuntimeProgressState;
21640
+ const pendingSteeredTasks = new Set;
21641
+ const pendingAcks = [];
21642
+ let hasReceivedProgressEvent = false;
21643
+ if (input.steeringEnabled && input.steeringMailboxDir && task.contextKey) {
21644
+ const descriptor = session2.descriptor;
21645
+ const STALLED_THRESHOLD_MS = 120000;
21646
+ const STALLED_CHECK_INTERVAL_MS = 30000;
21647
+ if (session2.parsedEvents) {
21648
+ const parsedIter = session2.parsedEvents[Symbol.asyncIterator]();
21649
+ const consumeParsedEvents = async () => {
21650
+ try {
21651
+ while (!killed) {
21652
+ const { value: event, done } = await parsedIter.next();
21653
+ if (done)
21654
+ break;
21655
+ hasReceivedProgressEvent = true;
21656
+ progressState.processEvent(event);
21657
+ const recentResult = reduceApmGatedRecentEvent(apmState, { event: event.kind });
21658
+ apmState = recentResult.nextState;
21659
+ if (event.kind === "error") {
21660
+ const classified = classifyRuntimeError(event.message);
21661
+ log9.info(`steering: error classified as ${classified.errorClass}: ${scrubDiagnosticText(event.message)}`);
21662
+ const errResult = reduceApmGatedError(apmState, { disableToolBoundaryFlush: true });
21663
+ apmState = errResult.nextState;
21664
+ }
21665
+ switch (event.kind) {
21666
+ case "tool_call":
21667
+ case "thinking":
21668
+ case "compaction_started":
21669
+ turnState.markToolBoundary();
21670
+ break;
21671
+ case "text":
21672
+ case "tool_output":
21673
+ case "compaction_finished":
21674
+ turnState.markProgress();
21675
+ break;
21676
+ }
21677
+ switch (event.kind) {
21678
+ case "session_init":
21679
+ turnState.markTurnStarted(event.sessionId);
21680
+ break;
21681
+ case "text":
21682
+ if (!turnState.isInTurn)
21683
+ turnState.markTurnStarted();
21684
+ break;
21685
+ case "tool_call": {
21686
+ if (!turnState.isInTurn)
21687
+ turnState.markTurnStarted();
21688
+ const result2 = reduceApmGatedToolUse(apmState, { kind: "tool_call" });
21689
+ apmState = result2.nextState;
21690
+ break;
21691
+ }
21692
+ case "tool_output": {
21693
+ const result2 = reduceApmGatedToolUse(apmState, { kind: "tool_output" });
21694
+ apmState = result2.nextState;
21695
+ if (result2.shouldFlushToolBatch && session2.send && apmState.pendingMessages.length > 0) {
21696
+ const readiness = reduceApmGatedFlushReadiness(apmState, {
21697
+ isGated: descriptor?.busyDeliveryMode === "gated",
21698
+ hasSession: !!earlySessionId,
21699
+ inboxLength: apmState.pendingMessages.length,
21700
+ reason: "tool_batch_complete"
21701
+ });
21702
+ if (readiness.shouldNotify) {
21703
+ let allSent = true;
21704
+ for (const msg of apmState.pendingMessages) {
21705
+ const sendResult = session2.send(msg, "busy");
21706
+ if (!sendResult.ok) {
21707
+ allSent = false;
21708
+ break;
21709
+ }
21710
+ }
21711
+ if (allSent) {
21712
+ apmState = { ...apmState, pendingMessages: [] };
21713
+ for (const ack of pendingAcks) {
21714
+ notificationState.recordNoticeWritten(String(ack.seq), ack.sessionId, [{ id: String(ack.seq) }]);
21715
+ writeAck(agentBaseDir, task.contextKey, ack.seq);
21716
+ }
21717
+ pendingAcks.length = 0;
21718
+ }
21719
+ }
21720
+ }
21721
+ break;
21722
+ }
21723
+ case "compaction_started":
21724
+ case "compaction_finished": {
21725
+ const result2 = reduceApmGatedCompaction(apmState, { kind: event.kind });
21726
+ apmState = result2.nextState;
21727
+ if (event.kind === "compaction_finished" && session2.send && apmState.pendingMessages.length > 0) {
21728
+ const readiness = reduceApmGatedFlushReadiness(apmState, {
21729
+ isGated: descriptor?.busyDeliveryMode === "gated",
21730
+ hasSession: !!earlySessionId,
21731
+ inboxLength: apmState.pendingMessages.length,
21732
+ reason: "compaction_finished"
21733
+ });
21734
+ if (readiness.shouldNotify) {
21735
+ let allSent = true;
21736
+ for (const msg of apmState.pendingMessages) {
21737
+ const sendResult = session2.send(msg, "busy");
21738
+ if (!sendResult.ok) {
21739
+ allSent = false;
21740
+ break;
21741
+ }
21742
+ }
21743
+ if (allSent) {
21744
+ apmState = { ...apmState, pendingMessages: [] };
21745
+ for (const ack of pendingAcks) {
21746
+ notificationState.recordNoticeWritten(String(ack.seq), ack.sessionId, [{ id: String(ack.seq) }]);
21747
+ writeAck(agentBaseDir, task.contextKey, ack.seq);
21748
+ }
21749
+ pendingAcks.length = 0;
21750
+ }
21751
+ }
21752
+ }
21753
+ break;
21754
+ }
21755
+ case "turn_end": {
21756
+ const result2 = reduceApmGatedTurnEnd(apmState, {
21757
+ inboxLength: apmState.pendingMessages.length,
21758
+ supportsStdinNotification: descriptor?.supportsStdinNotification,
21759
+ hasSession: !!earlySessionId
21760
+ });
21761
+ apmState = result2.nextState;
21762
+ let flushedOk = false;
21763
+ for (const eff of result2.effects) {
21764
+ if (eff.kind === "deliver_stdin" && session2.send) {
21765
+ let allSent = true;
21766
+ for (const msg of apmState.pendingMessages) {
21767
+ const sendResult = session2.send(msg, eff.stdinMode);
21768
+ if (!sendResult.ok) {
21769
+ log9.warn("steering: send failed during turn_end flush", { reason: sendResult.reason });
21770
+ allSent = false;
21771
+ break;
21772
+ }
21773
+ }
21774
+ if (allSent) {
21775
+ apmState = { ...apmState, pendingMessages: [] };
21776
+ flushedOk = true;
21777
+ }
21778
+ }
21779
+ }
21780
+ if (flushedOk && pendingAcks.length > 0) {
21781
+ for (const ack of pendingAcks) {
21782
+ notificationState.recordNoticeWritten(String(ack.seq), ack.sessionId, [{ id: String(ack.seq) }]);
21783
+ writeAck(agentBaseDir, task.contextKey, ack.seq);
21784
+ }
21785
+ pendingAcks.length = 0;
21786
+ }
21787
+ if (flushedOk || apmState.pendingMessages.length === 0) {
21788
+ for (const steeredId of pendingSteeredTasks) {
21789
+ client.completeTask(token, steeredId, { output: "" }).catch((e) => {
21790
+ log9.debug(`steering: failed to complete steered task ${steeredId}`, e);
21791
+ });
21792
+ }
21793
+ pendingSteeredTasks.clear();
21794
+ }
21795
+ turnState.markTurnCompleted();
21796
+ break;
21797
+ }
21798
+ }
21799
+ }
21800
+ } catch (err) {
21801
+ log9.warn("steering: consumeParsedEvents error", { err: err instanceof Error ? err.message : String(err) });
21802
+ }
21803
+ };
21804
+ consumeParsedEvents().catch((err) => {
21805
+ log9.error("steering: consumeParsedEvents unhandled error", { err: err instanceof Error ? err.message : String(err) });
21806
+ });
21807
+ }
21808
+ stalledRecoveryTimer = setInterval(() => {
21809
+ if (killed)
21810
+ return;
21811
+ if (!hasReceivedProgressEvent) {
21812
+ const startupResult = reduceApmStartupTimeoutTermination(apmState, {
21813
+ hasRuntimeProgressEvent: hasReceivedProgressEvent
21814
+ });
21815
+ apmState = startupResult.nextState;
21816
+ if (startupResult.shouldTerminate) {
21817
+ log9.warn("steering: startup timeout — no progress events received, killing agent");
21818
+ if (agentPid !== undefined)
21819
+ killProcessTree(agentPid);
21820
+ return;
21821
+ }
21822
+ }
21823
+ const staleForMs = progressState.ageMs();
21824
+ if (staleForMs > STALLED_THRESHOLD_MS && !progressState.isStale) {
21825
+ progressState.markStale();
21826
+ }
21827
+ const stalledResult = reduceApmStalledRecoveryTermination(apmState, {
21828
+ inboxLength: apmState.pendingMessages.length,
21829
+ staleForMs,
21830
+ staleThresholdMs: STALLED_THRESHOLD_MS,
21831
+ runtimeProgressIsStale: progressState.isStale,
21832
+ hasSession: !!earlySessionId,
21833
+ busyDeliveryMode: descriptor?.busyDeliveryMode ?? "none",
21834
+ hasDirectStdinRecoveryEvidence: false
21835
+ });
21836
+ apmState = stalledResult.nextState;
21837
+ if (stalledResult.shouldTerminate) {
21838
+ log9.warn(`steering: stalled recovery — agent stale for ${(staleForMs / 1000).toFixed(1)}s with ${apmState.pendingMessages.length} pending messages, killing`);
21839
+ if (agentPid !== undefined)
21840
+ killProcessTree(agentPid);
21841
+ }
21842
+ }, STALLED_CHECK_INTERVAL_MS);
21843
+ mailboxWatcher = watchInbox(agentBaseDir, task.contextKey, (seq2, message2) => {
21844
+ const sessionId = earlySessionId || "";
21845
+ if (notificationState.isDuplicateNotice(String(seq2), sessionId)) {
21846
+ writeAck(agentBaseDir, task.contextKey, seq2);
21847
+ cleanupInboxFile(agentBaseDir, task.contextKey, seq2);
21848
+ return;
21849
+ }
21850
+ const busyMode = session2.descriptor?.busyDeliveryMode;
21851
+ let delivered = false;
21852
+ if (busyMode === "direct" && session2.send) {
21853
+ const result2 = session2.send(message2.text, turnState.isInTurn ? "busy" : "idle");
21854
+ if (result2.ok) {
21855
+ notificationState.recordNoticeWritten(String(seq2), sessionId, [{ id: String(seq2) }]);
21856
+ writeAck(agentBaseDir, task.contextKey, seq2);
21857
+ delivered = true;
21858
+ } else {
21859
+ writeNack(agentBaseDir, task.contextKey, seq2, result2.reason || "send failed");
21860
+ }
21861
+ } else if (busyMode === "gated") {
21862
+ const enqueueResult = reduceApmGatedEnqueue(apmState, message2.text);
21863
+ apmState = enqueueResult.nextState;
21864
+ if (turnState.canSteerBusy && session2.send && apmState.pendingMessages.length > 0) {
21865
+ const readiness = reduceApmGatedFlushReadiness(apmState, {
21866
+ isGated: true,
21867
+ hasSession: !!earlySessionId,
21868
+ inboxLength: apmState.pendingMessages.length,
21869
+ reason: "enqueue"
21870
+ });
21871
+ if (readiness.shouldNotify) {
21872
+ let allSent = true;
21873
+ for (const msg of apmState.pendingMessages) {
21874
+ const sendResult = session2.send(msg, "busy");
21875
+ if (!sendResult.ok) {
21876
+ allSent = false;
21877
+ break;
21878
+ }
21879
+ }
21880
+ if (allSent) {
21881
+ apmState = { ...apmState, pendingMessages: [] };
21882
+ }
21883
+ }
21884
+ }
21885
+ if (apmState.pendingMessages.length === 0) {
21886
+ notificationState.recordNoticeWritten(String(seq2), sessionId, [{ id: String(seq2) }]);
21887
+ writeAck(agentBaseDir, task.contextKey, seq2);
21888
+ } else {
21889
+ pendingAcks.push({ seq: seq2, sessionId });
21890
+ }
21891
+ delivered = true;
21892
+ } else {
21893
+ writeNack(agentBaseDir, task.contextKey, seq2, "unsupported backend");
21894
+ }
21895
+ if (delivered && message2.taskId) {
21896
+ pendingSteeredTasks.add(message2.taskId);
21897
+ client.startTask(token, message2.taskId).catch((e) => {
21898
+ log9.debug(`steering: failed to start steered task ${message2.taskId}`, e);
21899
+ });
21900
+ }
21901
+ cleanupInboxFile(agentBaseDir, task.contextKey, seq2);
21902
+ });
21903
+ }
19668
21904
  const INACTIVITY_TIMEOUT_MS = messageInactivityTimeout ?? 5 * 60 * 1000;
19669
21905
  let inactivityTimedOut = false;
19670
21906
  try {
@@ -19680,7 +21916,7 @@ async function runSession(input) {
19680
21916
  ]) : next);
19681
21917
  if (raceResult === "timeout") {
19682
21918
  inactivityTimedOut = true;
19683
- log6.warn(`message inactivity timeout (${INACTIVITY_TIMEOUT_MS / 1000}s) — killing agent`);
21919
+ log9.warn(`message inactivity timeout (${INACTIVITY_TIMEOUT_MS / 1000}s) — killing agent`);
19684
21920
  if (session2.pid !== undefined) {
19685
21921
  await killProcessTree(session2.pid);
19686
21922
  }
@@ -19695,9 +21931,9 @@ async function runSession(input) {
19695
21931
  if (msg.type === "tool-use")
19696
21932
  toolCount++;
19697
21933
  if (msg.type === "tool-result" && msg.output && msg.output.length > 500) {
19698
- log6.info(JSON.stringify({ role: "assistant", ...msg, output: msg.output.slice(0, 500) + `... (${msg.output.length} chars)` }));
21934
+ log9.info(JSON.stringify({ role: "assistant", ...msg, output: msg.output.slice(0, 500) + `... (${msg.output.length} chars)` }));
19699
21935
  } else {
19700
- log6.info(JSON.stringify({ role: "assistant", ...msg }));
21936
+ log9.info(JSON.stringify({ role: "assistant", ...msg }));
19701
21937
  }
19702
21938
  if (msg.type === "status" || msg.type === "log")
19703
21939
  continue;
@@ -19736,6 +21972,13 @@ async function runSession(input) {
19736
21972
  result.status = "failed";
19737
21973
  result.error = `message inactivity timeout (no messages for ${INACTIVITY_TIMEOUT_MS / 1000}s)`;
19738
21974
  }
21975
+ if (stalledRecoveryTimer)
21976
+ clearInterval(stalledRecoveryTimer);
21977
+ if (mailboxWatcher) {
21978
+ mailboxWatcher.stop();
21979
+ if (task.contextKey)
21980
+ cleanupSteeringDir(agentBaseDir, task.contextKey);
21981
+ }
19739
21982
  await cleanupAttachments(task.id);
19740
21983
  if (result.status === "completed") {
19741
21984
  updateEntry(timelineDir, task.id, (entry) => {
@@ -19758,18 +22001,18 @@ async function runSession(input) {
19758
22001
  body.session_id = result.sessionId;
19759
22002
  await reportToServer(() => client.completeTask(token, task.id, body), { taskId: task.id, type: "complete", payload: body, token, serverURL, createdAt: new Date().toISOString() }, workspacesRoot);
19760
22003
  const dur = (result.durationMs / 1000).toFixed(1);
19761
- log6.info(`completed (duration=${dur}s, messages=${seq}, tools=${toolCount})`);
22004
+ log9.info(`completed (duration=${dur}s, messages=${seq}, tools=${toolCount})`);
19762
22005
  } else {
19763
22006
  const errorMsg = result.error || "agent exited unexpectedly";
19764
22007
  await reportToServer(() => client.failTask(token, task.id, errorMsg), { taskId: task.id, type: "fail", payload: { error: errorMsg }, token, serverURL, createdAt: new Date().toISOString() }, workspacesRoot);
19765
22008
  const dur = (result.durationMs / 1000).toFixed(1);
19766
- log6.info(`failed (duration=${dur}s, messages=${seq}, tools=${toolCount}) — ${result.error}`);
22009
+ log9.info(`failed (duration=${dur}s, messages=${seq}, tools=${toolCount}) — ${result.error}`);
19767
22010
  }
19768
22011
  }
19769
22012
  async function main() {
19770
22013
  const encoded = process.argv[2];
19771
22014
  if (!encoded) {
19772
- log6.error("session-runner: missing base64-encoded input argument");
22015
+ log9.error("session-runner: missing base64-encoded input argument");
19773
22016
  process.exit(1);
19774
22017
  }
19775
22018
  let input;
@@ -19777,14 +22020,14 @@ async function main() {
19777
22020
  const json2 = Buffer.from(encoded, "base64").toString("utf-8");
19778
22021
  input = JSON.parse(json2);
19779
22022
  } catch (e) {
19780
- log6.error("session-runner: failed to parse input", e);
22023
+ log9.error("session-runner: failed to parse input", e);
19781
22024
  process.exit(1);
19782
22025
  }
19783
22026
  const client = new DaemonClient(input.serverURL);
19784
22027
  try {
19785
22028
  await runSession(input);
19786
22029
  } catch (e) {
19787
- log6.error(`session-runner: unhandled error for task ${input.task.id}`, e);
22030
+ log9.error(`session-runner: unhandled error for task ${input.task.id}`, e);
19788
22031
  await cleanupAttachments(input.task.id);
19789
22032
  const timelineDir = path.join(input.workspacesRoot, input.task.workspaceId, input.task.agentId, "workdir", ".context_timeline").replace(/\\/g, "/");
19790
22033
  updateEntry(timelineDir, input.task.id, (entry) => {
@@ -19803,12 +22046,12 @@ if (isDirectExecution) {
19803
22046
  }
19804
22047
 
19805
22048
  // daemon/ws-client.ts
19806
- var log7 = createLogger2({ module: "ws-client" });
22049
+ var log10 = createLogger2({ module: "ws-client" });
19807
22050
  var WS_RECONNECT_INIT = 1000;
19808
22051
  var WS_RECONNECT_MAX = 30000;
19809
22052
  var WS_PING_INTERVAL = 25000;
19810
22053
  var WS_LIVENESS_TIMEOUT = 50000;
19811
- var WS_DO_DEV_PORT = Number(process.env.ALOOK_WS_DO_PORT) || 8789;
22054
+ var WS_DO_DEV_PORT = Number(process.env.ALOOK_WS_DO_PORT) || devWsDoPort();
19812
22055
 
19813
22056
  class DaemonWsClient {
19814
22057
  opts;
@@ -19840,11 +22083,11 @@ class DaemonWsClient {
19840
22083
  return;
19841
22084
  this.cleanup();
19842
22085
  const wsUrl = this.getUrl();
19843
- log7.info("connecting", { url: wsUrl });
22086
+ log10.info("connecting", { url: wsUrl });
19844
22087
  try {
19845
22088
  this.ws = new WebSocket(wsUrl);
19846
22089
  } catch (err) {
19847
- log7.warn("ws creation failed", { err: String(err) });
22090
+ log10.warn("ws creation failed", { err: String(err) });
19848
22091
  this.scheduleReconnect();
19849
22092
  return;
19850
22093
  }
@@ -19866,23 +22109,23 @@ class DaemonWsClient {
19866
22109
  try {
19867
22110
  const msg = JSON.parse(str);
19868
22111
  if (msg.type === "auth.ok") {
19869
- log7.info("authenticated");
22112
+ log10.info("authenticated");
19870
22113
  this.connected = true;
19871
22114
  this.opts.onConnected();
19872
22115
  return;
19873
22116
  }
19874
22117
  const parsed = DaemonPushMessageSchema.safeParse(msg);
19875
22118
  if (!parsed.success) {
19876
- log7.warn("invalid push message", { err: parsed.error.message });
22119
+ log10.warn("invalid push message", { err: parsed.error.message });
19877
22120
  return;
19878
22121
  }
19879
22122
  this.opts.onMessage(parsed.data);
19880
22123
  } catch (err) {
19881
- log7.debug("message parse error", { err: String(err) });
22124
+ log10.debug("message parse error", { err: String(err) });
19882
22125
  }
19883
22126
  });
19884
22127
  this.ws.addEventListener("error", () => {
19885
- log7.debug("ws error");
22128
+ log10.debug("ws error");
19886
22129
  });
19887
22130
  this.ws.addEventListener("close", () => {
19888
22131
  const wasConnected = this.connected;
@@ -19920,7 +22163,7 @@ class DaemonWsClient {
19920
22163
  const delay = Math.min(this.reconnectDelay, WS_RECONNECT_MAX);
19921
22164
  this.reconnectDelay = Math.min(delay * 2, WS_RECONNECT_MAX);
19922
22165
  const jitter = Math.random() * 500;
19923
- log7.debug("reconnecting", { delayMs: Math.round(delay + jitter) });
22166
+ log10.debug("reconnecting", { delayMs: Math.round(delay + jitter) });
19924
22167
  this.reconnectTimer = setTimeout(() => {
19925
22168
  this.reconnectTimer = null;
19926
22169
  this.connect();
@@ -19934,7 +22177,7 @@ class DaemonWsClient {
19934
22177
  }, WS_PING_INTERVAL);
19935
22178
  this.livenessInterval = setInterval(() => {
19936
22179
  if (Date.now() - this.lastMessageAt > WS_LIVENESS_TIMEOUT) {
19937
- log7.warn("liveness timeout, closing");
22180
+ log10.warn("liveness timeout, closing");
19938
22181
  this.ws?.close();
19939
22182
  }
19940
22183
  }, 5000);
@@ -19952,7 +22195,7 @@ class DaemonWsClient {
19952
22195
  }
19953
22196
 
19954
22197
  // daemon/update-handler.ts
19955
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync6, unlinkSync as unlinkSync4 } from "fs";
22198
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, unlinkSync as unlinkSync5 } from "fs";
19956
22199
 
19957
22200
  // lib/update.ts
19958
22201
  import { spawn as spawn4 } from "child_process";
@@ -19982,7 +22225,7 @@ function runNpmUpdate(targetVersion) {
19982
22225
  }
19983
22226
 
19984
22227
  // daemon/update-handler.ts
19985
- var log8 = createLogger2({ module: "updater" });
22228
+ var log11 = createLogger2({ module: "updater" });
19986
22229
  var updating = false;
19987
22230
  var retryCount = 0;
19988
22231
  var MAX_RETRIES = 3;
@@ -19991,19 +22234,19 @@ function isUpdating() {
19991
22234
  }
19992
22235
  function readUpdateMarker(profile) {
19993
22236
  try {
19994
- return readFileSync7(lastUpdateMarkerPath(profile), "utf-8").trim() || null;
22237
+ return readFileSync8(lastUpdateMarkerPath(profile), "utf-8").trim() || null;
19995
22238
  } catch {
19996
22239
  return null;
19997
22240
  }
19998
22241
  }
19999
22242
  function writeUpdateMarker(version3, profile) {
20000
22243
  try {
20001
- writeFileSync6(lastUpdateMarkerPath(profile), version3, { mode: 384 });
22244
+ writeFileSync7(lastUpdateMarkerPath(profile), version3, { mode: 384 });
20002
22245
  } catch {}
20003
22246
  }
20004
22247
  function clearUpdateMarker(profile) {
20005
22248
  try {
20006
- unlinkSync4(lastUpdateMarkerPath(profile));
22249
+ unlinkSync5(lastUpdateMarkerPath(profile));
20007
22250
  } catch {}
20008
22251
  }
20009
22252
  async function handleCliUpdate(version3, onSuccess, profile) {
@@ -20012,29 +22255,29 @@ async function handleCliUpdate(version3, onSuccess, profile) {
20012
22255
  if (retryCount >= MAX_RETRIES)
20013
22256
  return;
20014
22257
  if (process.env.ALOOK_CMD_PREFIX) {
20015
- log8.info(`Skipping auto-update in app mode — user should run: npx @alook/app@latest update`);
22258
+ log11.info(`Skipping auto-update in app mode — user should run: npx @alook/app@latest update`);
20016
22259
  return;
20017
22260
  }
20018
22261
  const marker = readUpdateMarker(profile);
20019
22262
  if (marker === version3) {
20020
- log8.info(`Skipping update to v${version3} — already attempted (marker exists)`);
22263
+ log11.info(`Skipping update to v${version3} — already attempted (marker exists)`);
20021
22264
  return;
20022
22265
  }
20023
22266
  updating = true;
20024
22267
  try {
20025
- log8.info(`Updating CLI to v${version3}...`);
22268
+ log11.info(`Updating CLI to v${version3}...`);
20026
22269
  const result = await runNpmUpdate(version3);
20027
22270
  if (result.success) {
20028
22271
  writeUpdateMarker(version3, profile);
20029
- log8.info(`CLI updated to v${version3} — restarting`);
22272
+ log11.info(`CLI updated to v${version3} — restarting`);
20030
22273
  onSuccess();
20031
22274
  } else {
20032
22275
  retryCount++;
20033
- log8.error(`CLI update failed (attempt ${retryCount}/${MAX_RETRIES}): ${result.output}`);
22276
+ log11.error(`CLI update failed (attempt ${retryCount}/${MAX_RETRIES}): ${result.output}`);
20034
22277
  }
20035
22278
  } catch (e) {
20036
22279
  retryCount++;
20037
- log8.error(`CLI update error (attempt ${retryCount}/${MAX_RETRIES})`, e);
22280
+ log11.error(`CLI update error (attempt ${retryCount}/${MAX_RETRIES})`, e);
20038
22281
  } finally {
20039
22282
  updating = false;
20040
22283
  }
@@ -20042,7 +22285,7 @@ async function handleCliUpdate(version3, onSuccess, profile) {
20042
22285
 
20043
22286
  // daemon/workspace-files.ts
20044
22287
  import { readdir, stat, readFile } from "fs/promises";
20045
- import { join as join9, resolve, extname, relative, sep as sep2 } from "path";
22288
+ import { join as join10, resolve, extname, relative, sep as sep2 } from "path";
20046
22289
  var SKIP_DIRS = new Set([".git", "node_modules", ".next", ".wrangler", "__pycache__", ".venv"]);
20047
22290
  var TEXT_EXTENSIONS = new Set([
20048
22291
  ".md",
@@ -20101,7 +22344,7 @@ async function readDirectoryTree(dirPath, basePath) {
20101
22344
  if (ext !== "" && !TEXT_EXTENSIONS.has(ext))
20102
22345
  continue;
20103
22346
  }
20104
- const fullPath = join9(dirPath, entry.name);
22347
+ const fullPath = join10(dirPath, entry.name);
20105
22348
  let info;
20106
22349
  try {
20107
22350
  info = await stat(fullPath);
@@ -20139,13 +22382,13 @@ function validatePath(agentWorkdir, requestedPath) {
20139
22382
  }
20140
22383
 
20141
22384
  // daemon/skill-scanner.ts
20142
- import { existsSync as existsSync2, mkdirSync as mkdirSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync7, readdirSync as readdirSync2, statSync as statSync3, realpathSync } from "fs";
20143
- import { join as join10, basename } from "path";
22385
+ import { existsSync as existsSync3, mkdirSync as mkdirSync8, readFileSync as readFileSync9, writeFileSync as writeFileSync8, readdirSync as readdirSync3, statSync as statSync3, realpathSync } from "fs";
22386
+ import { join as join11, basename } from "path";
20144
22387
  import { homedir as homedir2 } from "os";
20145
22388
  import { createHash as createHash2 } from "crypto";
20146
- var log9 = createLogger2({ module: "skill-scanner" });
22389
+ var log12 = createLogger2({ module: "skill-scanner" });
20147
22390
  function getCacheDir() {
20148
- return join10(configDir(), "skills");
22391
+ return join11(configDir(), "skills");
20149
22392
  }
20150
22393
  function parseFrontmatter(content) {
20151
22394
  const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
@@ -20163,22 +22406,22 @@ function parseFrontmatter(content) {
20163
22406
  }
20164
22407
  function safeReadDir(dir) {
20165
22408
  try {
20166
- if (!existsSync2(dir))
22409
+ if (!existsSync3(dir))
20167
22410
  return [];
20168
- return readdirSync2(dir);
22411
+ return readdirSync3(dir);
20169
22412
  } catch {
20170
22413
  return [];
20171
22414
  }
20172
22415
  }
20173
22416
  function findSkillFiles(baseDir, pattern) {
20174
22417
  const results = [];
20175
- if (!existsSync2(baseDir))
22418
+ if (!existsSync3(baseDir))
20176
22419
  return results;
20177
22420
  if (pattern === "*/SKILL.md") {
20178
22421
  for (const entry of safeReadDir(baseDir)) {
20179
- const skillPath = join10(baseDir, entry, "SKILL.md");
22422
+ const skillPath = join11(baseDir, entry, "SKILL.md");
20180
22423
  try {
20181
- if (existsSync2(skillPath) && statSync3(skillPath).isFile()) {
22424
+ if (existsSync3(skillPath) && statSync3(skillPath).isFile()) {
20182
22425
  results.push(skillPath);
20183
22426
  }
20184
22427
  } catch {}
@@ -20188,7 +22431,7 @@ function findSkillFiles(baseDir, pattern) {
20188
22431
  } else if (pattern === "*.md") {
20189
22432
  for (const entry of safeReadDir(baseDir)) {
20190
22433
  if (entry.endsWith(".md")) {
20191
- const filePath = join10(baseDir, entry);
22434
+ const filePath = join11(baseDir, entry);
20192
22435
  try {
20193
22436
  if (statSync3(filePath).isFile()) {
20194
22437
  results.push(filePath);
@@ -20203,16 +22446,16 @@ function walkForSkills(dir, results, depth = 0) {
20203
22446
  if (depth > 5)
20204
22447
  return;
20205
22448
  try {
20206
- for (const entry of readdirSync2(dir)) {
20207
- const full = join10(dir, entry);
22449
+ for (const entry of readdirSync3(dir)) {
22450
+ const full = join11(dir, entry);
20208
22451
  try {
20209
22452
  const st = statSync3(full);
20210
22453
  if (st.isDirectory()) {
20211
22454
  if (entry === "skills") {
20212
22455
  for (const skillDir of safeReadDir(full)) {
20213
- const skillPath = join10(full, skillDir, "SKILL.md");
22456
+ const skillPath = join11(full, skillDir, "SKILL.md");
20214
22457
  try {
20215
- if (existsSync2(skillPath) && statSync3(skillPath).isFile()) {
22458
+ if (existsSync3(skillPath) && statSync3(skillPath).isFile()) {
20216
22459
  results.push(skillPath);
20217
22460
  }
20218
22461
  } catch {}
@@ -20229,7 +22472,7 @@ function scanFrontmatterSkills(paths) {
20229
22472
  const skills = new Map;
20230
22473
  for (const filePath of paths) {
20231
22474
  try {
20232
- const content = readFileSync8(filePath, "utf-8");
22475
+ const content = readFileSync9(filePath, "utf-8");
20233
22476
  const meta3 = parseFrontmatter(content);
20234
22477
  if (meta3 && !skills.has(meta3.name)) {
20235
22478
  skills.set(meta3.name, meta3);
@@ -20241,14 +22484,14 @@ function scanFrontmatterSkills(paths) {
20241
22484
  function scanClaudeGlobalSkills() {
20242
22485
  const home = homedir2();
20243
22486
  const allSkills = [];
20244
- const directPaths = findSkillFiles(join10(home, ".claude", "skills"), "*/SKILL.md");
22487
+ const directPaths = findSkillFiles(join11(home, ".claude", "skills"), "*/SKILL.md");
20245
22488
  allSkills.push(...scanFrontmatterSkills(directPaths));
20246
- const pluginCacheDir = join10(home, ".claude", "plugins", "cache");
22489
+ const pluginCacheDir = join11(home, ".claude", "plugins", "cache");
20247
22490
  const pluginPaths = findSkillFiles(pluginCacheDir, "**/skills/*/SKILL.md");
20248
22491
  const names = new Set(allSkills.map((s) => s.name));
20249
22492
  for (const filePath of pluginPaths) {
20250
22493
  try {
20251
- const content = readFileSync8(filePath, "utf-8");
22494
+ const content = readFileSync9(filePath, "utf-8");
20252
22495
  const meta3 = parseFrontmatter(content);
20253
22496
  if (meta3 && !names.has(meta3.name)) {
20254
22497
  names.add(meta3.name);
@@ -20259,23 +22502,23 @@ function scanClaudeGlobalSkills() {
20259
22502
  return allSkills;
20260
22503
  }
20261
22504
  function scanClaudeAgentSkills(workdir) {
20262
- const paths = findSkillFiles(join10(workdir, ".claude", "skills"), "*/SKILL.md");
22505
+ const paths = findSkillFiles(join11(workdir, ".claude", "skills"), "*/SKILL.md");
20263
22506
  return scanFrontmatterSkills(paths);
20264
22507
  }
20265
22508
  function scanCodexGlobalSkills() {
20266
22509
  const home = homedir2();
20267
22510
  const allSkills = [];
20268
22511
  const paths = [
20269
- ...findSkillFiles(join10(home, ".agents", "skills"), "*/SKILL.md"),
20270
- ...findSkillFiles(join10(home, ".codex", "skills", ".system"), "*/SKILL.md")
22512
+ ...findSkillFiles(join11(home, ".agents", "skills"), "*/SKILL.md"),
22513
+ ...findSkillFiles(join11(home, ".codex", "skills", ".system"), "*/SKILL.md")
20271
22514
  ];
20272
22515
  allSkills.push(...scanFrontmatterSkills(paths));
20273
- const codexPluginDir = join10(home, ".codex", "plugins", "cache");
22516
+ const codexPluginDir = join11(home, ".codex", "plugins", "cache");
20274
22517
  const pluginPaths = findSkillFiles(codexPluginDir, "**/skills/*/SKILL.md");
20275
22518
  const names = new Set(allSkills.map((s) => s.name));
20276
22519
  for (const filePath of pluginPaths) {
20277
22520
  try {
20278
- const content = readFileSync8(filePath, "utf-8");
22521
+ const content = readFileSync9(filePath, "utf-8");
20279
22522
  const meta3 = parseFrontmatter(content);
20280
22523
  if (meta3 && !names.has(meta3.name)) {
20281
22524
  names.add(meta3.name);
@@ -20286,7 +22529,7 @@ function scanCodexGlobalSkills() {
20286
22529
  return allSkills;
20287
22530
  }
20288
22531
  function scanCodexAgentSkills(workdir) {
20289
- const paths = findSkillFiles(join10(workdir, ".agents", "skills"), "*/SKILL.md");
22532
+ const paths = findSkillFiles(join11(workdir, ".agents", "skills"), "*/SKILL.md");
20290
22533
  return scanFrontmatterSkills(paths);
20291
22534
  }
20292
22535
  function scanOpenCodeMdFiles(dir) {
@@ -20294,7 +22537,7 @@ function scanOpenCodeMdFiles(dir) {
20294
22537
  const files = findSkillFiles(dir, "*.md");
20295
22538
  for (const filePath of files) {
20296
22539
  try {
20297
- const content = readFileSync8(filePath, "utf-8");
22540
+ const content = readFileSync9(filePath, "utf-8");
20298
22541
  const name = basename(filePath, ".md");
20299
22542
  const firstLine = content.split(`
20300
22543
  `).find((l) => l.trim().length > 0) ?? "";
@@ -20307,13 +22550,13 @@ function scanOpenCodeGlobalSkills() {
20307
22550
  const home = homedir2();
20308
22551
  const skills = [];
20309
22552
  const names = new Set;
20310
- for (const s of scanOpenCodeMdFiles(join10(home, ".config", "opencode", "commands"))) {
22553
+ for (const s of scanOpenCodeMdFiles(join11(home, ".config", "opencode", "commands"))) {
20311
22554
  if (!names.has(s.name)) {
20312
22555
  names.add(s.name);
20313
22556
  skills.push(s);
20314
22557
  }
20315
22558
  }
20316
- for (const s of scanOpenCodeMdFiles(join10(home, ".config", "opencode", "skills"))) {
22559
+ for (const s of scanOpenCodeMdFiles(join11(home, ".config", "opencode", "skills"))) {
20317
22560
  if (!names.has(s.name)) {
20318
22561
  names.add(s.name);
20319
22562
  skills.push(s);
@@ -20324,13 +22567,13 @@ function scanOpenCodeGlobalSkills() {
20324
22567
  function scanOpenCodeAgentSkills(workdir) {
20325
22568
  const skills = [];
20326
22569
  const names = new Set;
20327
- for (const s of scanOpenCodeMdFiles(join10(workdir, ".opencode", "commands"))) {
22570
+ for (const s of scanOpenCodeMdFiles(join11(workdir, ".opencode", "commands"))) {
20328
22571
  if (!names.has(s.name)) {
20329
22572
  names.add(s.name);
20330
22573
  skills.push(s);
20331
22574
  }
20332
22575
  }
20333
- for (const s of scanOpenCodeMdFiles(join10(workdir, ".opencode", "skills"))) {
22576
+ for (const s of scanOpenCodeMdFiles(join11(workdir, ".opencode", "skills"))) {
20334
22577
  if (!names.has(s.name)) {
20335
22578
  names.add(s.name);
20336
22579
  skills.push(s);
@@ -20342,26 +22585,26 @@ function computeHash(skills) {
20342
22585
  return createHash2("md5").update(JSON.stringify(skills)).digest("hex");
20343
22586
  }
20344
22587
  function globalCachePath(daemonId, runtime) {
20345
- return join10(getCacheDir(), "global", daemonId, `${runtime}.json`);
22588
+ return join11(getCacheDir(), "global", daemonId, `${runtime}.json`);
20346
22589
  }
20347
22590
  function agentCachePath(agentId, runtime) {
20348
- return join10(getCacheDir(), "agents", agentId, `${runtime}.json`);
22591
+ return join11(getCacheDir(), "agents", agentId, `${runtime}.json`);
20349
22592
  }
20350
22593
  function readCacheHash(filePath) {
20351
22594
  try {
20352
- if (!existsSync2(filePath))
22595
+ if (!existsSync3(filePath))
20353
22596
  return null;
20354
- const data = JSON.parse(readFileSync8(filePath, "utf-8"));
22597
+ const data = JSON.parse(readFileSync9(filePath, "utf-8"));
20355
22598
  return data.hash ?? null;
20356
22599
  } catch {
20357
22600
  return null;
20358
22601
  }
20359
22602
  }
20360
22603
  function writeCacheFile(filePath, hash2, skills) {
20361
- const dir = join10(filePath, "..");
20362
- mkdirSync7(dir, { recursive: true });
22604
+ const dir = join11(filePath, "..");
22605
+ mkdirSync8(dir, { recursive: true });
20363
22606
  const data = { hash: hash2, skills };
20364
- writeFileSync7(filePath, JSON.stringify(data, null, 2), "utf-8");
22607
+ writeFileSync8(filePath, JSON.stringify(data, null, 2), "utf-8");
20365
22608
  }
20366
22609
  function isClientError2(err) {
20367
22610
  if (err instanceof Error) {
@@ -20379,17 +22622,17 @@ var clientRef = null;
20379
22622
  function discoverTargets() {
20380
22623
  if (!scannerConfig)
20381
22624
  return [];
20382
- const rootExists = existsSync2(scannerConfig.workspacesRoot);
22625
+ const rootExists = existsSync3(scannerConfig.workspacesRoot);
20383
22626
  const rootReal = rootExists ? realpathSync(scannerConfig.workspacesRoot) : null;
20384
22627
  const targets = [];
20385
22628
  for (const ws of scannerConfig.workspaces) {
20386
22629
  const agentIds = new Set(ws.agentIds);
20387
22630
  if (rootReal) {
20388
- const wsDir = join10(scannerConfig.workspacesRoot, ws.workspaceId);
22631
+ const wsDir = join11(scannerConfig.workspacesRoot, ws.workspaceId);
20389
22632
  try {
20390
- if (existsSync2(wsDir)) {
20391
- for (const dir of readdirSync2(wsDir)) {
20392
- if (existsSync2(join10(wsDir, dir, "workdir")))
22633
+ if (existsSync3(wsDir)) {
22634
+ for (const dir of readdirSync3(wsDir)) {
22635
+ if (existsSync3(join11(wsDir, dir, "workdir")))
20393
22636
  agentIds.add(dir);
20394
22637
  }
20395
22638
  }
@@ -20398,8 +22641,8 @@ function discoverTargets() {
20398
22641
  for (const agentId of agentIds) {
20399
22642
  let validWorkdir = null;
20400
22643
  if (rootReal) {
20401
- const workdir = join10(scannerConfig.workspacesRoot, ws.workspaceId, agentId, "workdir");
20402
- if (existsSync2(workdir)) {
22644
+ const workdir = join11(scannerConfig.workspacesRoot, ws.workspaceId, agentId, "workdir");
22645
+ if (existsSync3(workdir)) {
20403
22646
  try {
20404
22647
  if (realpathSync(workdir).startsWith(rootReal))
20405
22648
  validWorkdir = workdir;
@@ -20439,7 +22682,7 @@ function runScan() {
20439
22682
  const prevHash = readCacheHash(globalCachePath(scannerConfig.daemonId, runtime));
20440
22683
  if (prevHash !== hash2) {
20441
22684
  const skillItems = skills.map((s) => ({ name: s.name, description: s.description }));
20442
- log9.debug(`Syncing global ${runtime} — ${skills.length} skills`);
22685
+ log12.debug(`Syncing global ${runtime} — ${skills.length} skills`);
20443
22686
  const daemonId = scannerConfig.daemonId;
20444
22687
  const syncPromises = scannerConfig.workspaces.map((ws) => clientRef.syncSkills(ws.token, {
20445
22688
  scope: "global",
@@ -20453,11 +22696,11 @@ function runScan() {
20453
22696
  if (isClientError2(e)) {
20454
22697
  writeCacheFile(globalCachePath(daemonId, runtime), hash2, skills);
20455
22698
  }
20456
- log9.debug("Global skill sync failed", e);
22699
+ log12.debug("Global skill sync failed", e);
20457
22700
  });
20458
22701
  }
20459
22702
  } catch (e) {
20460
- log9.debug(`Global scan error for ${runtime}`, e);
22703
+ log12.debug(`Global scan error for ${runtime}`, e);
20461
22704
  }
20462
22705
  }
20463
22706
  const targets = discoverTargets();
@@ -20470,7 +22713,7 @@ function runScan() {
20470
22713
  const prevHash = readCacheHash(agentCachePath(target.agentId, target.runtime));
20471
22714
  if (prevHash !== hash2) {
20472
22715
  const skillItems = skills.map((s) => ({ name: s.name, description: s.description }));
20473
- log9.debug(`Syncing ${target.agentId}:${target.runtime} — ${skills.length} agent skills`);
22716
+ log12.debug(`Syncing ${target.agentId}:${target.runtime} — ${skills.length} agent skills`);
20474
22717
  clientRef.syncSkills(target.token, {
20475
22718
  scope: "agent",
20476
22719
  agent_id: target.agentId,
@@ -20482,11 +22725,11 @@ function runScan() {
20482
22725
  if (isClientError2(e)) {
20483
22726
  writeCacheFile(agentCachePath(target.agentId, target.runtime), hash2, skills);
20484
22727
  }
20485
- log9.debug("Agent skill sync failed", e);
22728
+ log12.debug("Agent skill sync failed", e);
20486
22729
  });
20487
22730
  }
20488
22731
  } catch (e) {
20489
- log9.debug(`Agent scan error for ${target.agentId}:${target.runtime}`, e);
22732
+ log12.debug(`Agent scan error for ${target.agentId}:${target.runtime}`, e);
20490
22733
  }
20491
22734
  }
20492
22735
  }
@@ -20537,15 +22780,15 @@ function resolveLoginShellEnv() {
20537
22780
  }
20538
22781
 
20539
22782
  // daemon/daemon.ts
20540
- import { existsSync as existsSync3, mkdirSync as mkdirSync8, openSync, closeSync, readdirSync as readdirSync3, statSync as statSync4, unlinkSync as unlinkSync5 } from "fs";
22783
+ import { existsSync as existsSync4, mkdirSync as mkdirSync9, openSync, closeSync, readdirSync as readdirSync4, statSync as statSync4, unlinkSync as unlinkSync6 } from "fs";
20541
22784
  import { readdir as readdir2, readFile as readFile2, unlink, stat as fsStat } from "fs/promises";
20542
22785
  import { execSync as execSync4, spawn as spawn5 } from "child_process";
20543
22786
  import { fileURLToPath as fileURLToPath2 } from "url";
20544
- import { dirname as dirname3, join as join11 } from "path";
20545
- var log10 = createLogger2({ module: "daemon" });
22787
+ import { dirname as dirname3, join as join12 } from "path";
22788
+ var log13 = createLogger2({ module: "daemon" });
20546
22789
  var _dir = dirname3(fileURLToPath2(import.meta.url));
20547
- var sessionRunnerPath = existsSync3(join11(_dir, "session-runner.js")) ? join11(_dir, "session-runner.js") : join11(_dir, "session-runner.ts");
20548
- var meetingRunnerPath = existsSync3(join11(_dir, "meeting-runner.js")) ? join11(_dir, "meeting-runner.js") : join11(_dir, "meeting-runner.ts");
22790
+ var sessionRunnerPath = existsSync4(join12(_dir, "session-runner.js")) ? join12(_dir, "session-runner.js") : join12(_dir, "session-runner.ts");
22791
+ var meetingRunnerPath = existsSync4(join12(_dir, "meeting-runner.js")) ? join12(_dir, "meeting-runner.js") : join12(_dir, "meeting-runner.ts");
20549
22792
  function isCommandAvailable(cmd) {
20550
22793
  try {
20551
22794
  const check2 = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
@@ -20560,14 +22803,14 @@ function pruneSessionRunnerLogs() {
20560
22803
  const logDir = sessionRunnerLogDir();
20561
22804
  let entries;
20562
22805
  try {
20563
- entries = readdirSync3(logDir).filter((f) => f.endsWith(".log"));
22806
+ entries = readdirSync4(logDir).filter((f) => f.endsWith(".log"));
20564
22807
  } catch {
20565
22808
  return;
20566
22809
  }
20567
22810
  if (entries.length <= MAX_SESSION_RUNNER_LOGS)
20568
22811
  return;
20569
22812
  const withMtime = entries.map((name) => {
20570
- const full = join11(logDir, name);
22813
+ const full = join12(logDir, name);
20571
22814
  try {
20572
22815
  return { name, mtime: statSync4(full).mtimeMs };
20573
22816
  } catch {
@@ -20577,7 +22820,7 @@ function pruneSessionRunnerLogs() {
20577
22820
  withMtime.sort((a, b) => b.mtime - a.mtime);
20578
22821
  for (const entry of withMtime.slice(MAX_SESSION_RUNNER_LOGS)) {
20579
22822
  try {
20580
- unlinkSync5(join11(logDir, entry.name));
22823
+ unlinkSync6(join12(logDir, entry.name));
20581
22824
  } catch {}
20582
22825
  }
20583
22826
  }
@@ -20618,7 +22861,7 @@ function isValidMarker(data) {
20618
22861
  var MARKER_STALE_MS = 24 * 60 * 60 * 1000;
20619
22862
  var TMP_STALE_MS = 60 * 60 * 1000;
20620
22863
  async function reconcilePendingCompletions(workspacesRoot) {
20621
- const dir = join11(workspacesRoot, ".pending_completions");
22864
+ const dir = join12(workspacesRoot, ".pending_completions");
20622
22865
  let entries;
20623
22866
  try {
20624
22867
  entries = await readdir2(dir);
@@ -20629,15 +22872,15 @@ async function reconcilePendingCompletions(workspacesRoot) {
20629
22872
  if (!name.endsWith(".tmp"))
20630
22873
  continue;
20631
22874
  try {
20632
- const s = await fsStat(join11(dir, name));
22875
+ const s = await fsStat(join12(dir, name));
20633
22876
  if (Date.now() - s.mtimeMs > TMP_STALE_MS) {
20634
- await unlink(join11(dir, name));
22877
+ await unlink(join12(dir, name));
20635
22878
  }
20636
22879
  } catch {}
20637
22880
  }
20638
22881
  const jsonFiles = entries.filter((f) => f.endsWith(".json"));
20639
22882
  for (const name of jsonFiles) {
20640
- const filePath = join11(dir, name);
22883
+ const filePath = join12(dir, name);
20641
22884
  try {
20642
22885
  let raw;
20643
22886
  try {
@@ -20649,14 +22892,14 @@ async function reconcilePendingCompletions(workspacesRoot) {
20649
22892
  try {
20650
22893
  parsed = JSON.parse(raw);
20651
22894
  } catch {
20652
- log10.warn(`reconcile: malformed marker ${name}, deleting`);
22895
+ log13.warn(`reconcile: malformed marker ${name}, deleting`);
20653
22896
  try {
20654
22897
  await unlink(filePath);
20655
22898
  } catch {}
20656
22899
  continue;
20657
22900
  }
20658
22901
  if (!isValidMarker(parsed)) {
20659
- log10.warn(`reconcile: invalid marker structure ${name}, deleting`);
22902
+ log13.warn(`reconcile: invalid marker structure ${name}, deleting`);
20660
22903
  try {
20661
22904
  await unlink(filePath);
20662
22905
  } catch {}
@@ -20665,7 +22908,7 @@ async function reconcilePendingCompletions(workspacesRoot) {
20665
22908
  const marker = parsed;
20666
22909
  const age = Date.now() - new Date(marker.createdAt).getTime();
20667
22910
  if (age > MARKER_STALE_MS) {
20668
- log10.warn(`reconcile: stale marker ${name} (${Math.round(age / 3600000)}h old), deleting`);
22911
+ log13.warn(`reconcile: stale marker ${name} (${Math.round(age / 3600000)}h old), deleting`);
20669
22912
  try {
20670
22913
  await unlink(filePath);
20671
22914
  } catch {}
@@ -20681,7 +22924,7 @@ async function reconcilePendingCompletions(workspacesRoot) {
20681
22924
  try {
20682
22925
  await unlink(filePath);
20683
22926
  } catch (delErr) {
20684
- log10.warn(`reconcile: delivered marker ${name} but failed to delete: ${delErr}`);
22927
+ log13.warn(`reconcile: delivered marker ${name} but failed to delete: ${delErr}`);
20685
22928
  }
20686
22929
  } catch (deliverErr) {
20687
22930
  if (isClientError3(deliverErr)) {
@@ -20689,11 +22932,11 @@ async function reconcilePendingCompletions(workspacesRoot) {
20689
22932
  await unlink(filePath);
20690
22933
  } catch {}
20691
22934
  } else {
20692
- log10.debug(`reconcile: delivery failed for ${name}, will retry next cycle`);
22935
+ log13.debug(`reconcile: delivery failed for ${name}, will retry next cycle`);
20693
22936
  }
20694
22937
  }
20695
22938
  } catch (e) {
20696
- log10.debug(`reconcile: error processing ${name}`, e);
22939
+ log13.debug(`reconcile: error processing ${name}`, e);
20697
22940
  }
20698
22941
  }
20699
22942
  }
@@ -20704,7 +22947,7 @@ async function startDaemon(profile, serverUrl) {
20704
22947
  }
20705
22948
  process.once("exit", () => releaseDaemonPid(profile));
20706
22949
  const bailOnUnexpected = (label, err) => {
20707
- log10.error(`${label} — shutting down`, err);
22950
+ log13.error(`${label} — shutting down`, err);
20708
22951
  releaseDaemonPid(profile);
20709
22952
  process.exit(1);
20710
22953
  };
@@ -20717,21 +22960,21 @@ async function startDaemon(profile, serverUrl) {
20717
22960
  if (marker) {
20718
22961
  clearUpdateMarker(profile);
20719
22962
  if (marker === config2.cliVersion) {
20720
- log10.info(`Cleared update marker — now running v${config2.cliVersion}`);
22963
+ log13.info(`Cleared update marker — now running v${config2.cliVersion}`);
20721
22964
  } else {
20722
- log10.info(`Cleared stale update marker (was v${marker}, running v${config2.cliVersion}) — update will be retried`);
22965
+ log13.info(`Cleared stale update marker (was v${marker}, running v${config2.cliVersion}) — update will be retried`);
20723
22966
  }
20724
22967
  }
20725
22968
  const cliConfig = loadCLIConfigForProfile(profile);
20726
22969
  const allEntries = cliConfig.watched_workspaces || [];
20727
22970
  const workspaces = allEntries.filter((ws) => ws.status !== "deleted" && !!ws.id);
20728
22971
  if (workspaces.length === 0) {
20729
- log10.info("No workspaces configured — daemon starting in standby mode. Register a workspace to begin.");
22972
+ log13.info("No workspaces configured — daemon starting in standby mode. Register a workspace to begin.");
20730
22973
  }
20731
22974
  if (workspaces.length > 0) {
20732
22975
  const hasPerWorkspaceTokens = workspaces.every((ws) => !!ws.token);
20733
22976
  if (!hasPerWorkspaceTokens) {
20734
- log10.error(`Config uses old format. Run '${cmdPrefix()} register --token <token>' for each workspace to upgrade.`);
22977
+ log13.error(`Config uses old format. Run '${cmdPrefix()} register --token <token>' for each workspace to upgrade.`);
20735
22978
  process.exit(1);
20736
22979
  return;
20737
22980
  }
@@ -20752,11 +22995,11 @@ async function startDaemon(profile, serverUrl) {
20752
22995
  }
20753
22996
  }
20754
22997
  if (providers.length === 0) {
20755
- log10.error("No agent CLI tools found on PATH.");
22998
+ log13.error("No agent CLI tools found on PATH.");
20756
22999
  process.exit(1);
20757
23000
  return;
20758
23001
  }
20759
- log10.info(`Detected providers: ${providers.map((p) => `${p.type}@${p.version}`).join(", ")}`);
23002
+ log13.info(`Detected providers: ${providers.map((p) => `${p.type}@${p.version}`).join(", ")}`);
20760
23003
  const workspaceStates = [];
20761
23004
  const runtimeIndex = new Map;
20762
23005
  let hadWorkspaces = workspaces.length > 0;
@@ -20765,7 +23008,7 @@ async function startDaemon(profile, serverUrl) {
20765
23008
  type: p.type,
20766
23009
  version: p.version
20767
23010
  }));
20768
- log10.info(`Registering workspace ${ws.id} (${ws.name ?? "unnamed"}) with ${runtimes.length} runtime(s)...`);
23011
+ log13.info(`Registering workspace ${ws.id} (${ws.name ?? "unnamed"}) with ${runtimes.length} runtime(s)...`);
20769
23012
  let resp;
20770
23013
  try {
20771
23014
  resp = await client.register(ws.token, {
@@ -20778,13 +23021,13 @@ async function startDaemon(profile, serverUrl) {
20778
23021
  });
20779
23022
  } catch (e) {
20780
23023
  if (e instanceof Error && e.message.startsWith("HTTP 401")) {
20781
- log10.warn(`Workspace ${ws.id} token invalid — skipping (run '${cmdPrefix()} register --token <token>' to fix)`);
23024
+ log13.warn(`Workspace ${ws.id} token invalid — skipping (run '${cmdPrefix()} register --token <token>' to fix)`);
20782
23025
  } else {
20783
- log10.error(`Failed to register workspace ${ws.id}, skipping`, e);
23026
+ log13.error(`Failed to register workspace ${ws.id}, skipping`, e);
20784
23027
  }
20785
23028
  continue;
20786
23029
  }
20787
- log10.info(`Workspace ${ws.id} registered — ${resp.runtimes.length} runtime(s)`);
23030
+ log13.info(`Workspace ${ws.id} registered — ${resp.runtimes.length} runtime(s)`);
20788
23031
  const runtimeIds = resp.runtimes.map((r) => r.id);
20789
23032
  workspaceStates.push({ workspaceId: ws.id, token: ws.token, runtimeIds });
20790
23033
  for (let i = 0;i < runtimeIds.length; i++) {
@@ -20796,13 +23039,13 @@ async function startDaemon(profile, serverUrl) {
20796
23039
  }
20797
23040
  }
20798
23041
  if (workspaceStates.length === 0 && hadWorkspaces) {
20799
- log10.error("No workspaces registered successfully.");
23042
+ log13.error("No workspaces registered successfully.");
20800
23043
  process.exit(1);
20801
23044
  return;
20802
23045
  }
20803
23046
  const allRuntimeIds = workspaceStates.flatMap((ws) => ws.runtimeIds);
20804
23047
  health.setRuntimeCount(allRuntimeIds.length);
20805
- log10.info(`Daemon started — ${allRuntimeIds.length} runtime(s) across ${workspaceStates.length} workspace(s)`);
23048
+ log13.info(`Daemon started — ${allRuntimeIds.length} runtime(s) across ${workspaceStates.length} workspace(s)`);
20806
23049
  const activeTasks = new Set;
20807
23050
  const pendingSteer = new Map;
20808
23051
  const knownAgentIds = new Set(workspaces.flatMap((ws) => ws.agent_ids ?? []));
@@ -20838,7 +23081,7 @@ async function startDaemon(profile, serverUrl) {
20838
23081
  cfg.watched_workspaces = (cfg.watched_workspaces || []).filter((w) => w.id !== workspaceId);
20839
23082
  saveCLIConfigForProfile(profile, cfg);
20840
23083
  } catch {}
20841
- log10.info(`Workspace ${workspaceId} deleted server-side — removed from config`);
23084
+ log13.info(`Workspace ${workspaceId} deleted server-side — removed from config`);
20842
23085
  }
20843
23086
  const pollCycle = async () => {
20844
23087
  let remaining = config2.maxConcurrentTasks - activeTasks.size;
@@ -20864,7 +23107,7 @@ async function startDaemon(profile, serverUrl) {
20864
23107
  handleCliUpdate(pending_update.version, () => requestRestart(), profile);
20865
23108
  }
20866
23109
  if (pending_rescan) {
20867
- log10.info("Rescan requested — restarting daemon to re-detect runtimes");
23110
+ log13.info("Rescan requested — restarting daemon to re-detect runtimes");
20868
23111
  for (const id of evictedIds) {
20869
23112
  evictWorkspace(id);
20870
23113
  }
@@ -20877,19 +23120,19 @@ async function startDaemon(profile, serverUrl) {
20877
23120
  activeTasks.add(task.id);
20878
23121
  remaining--;
20879
23122
  handleTask(client, config2, runtimeIndex, task, ws.token, activeTasks, pendingSteer).catch((e) => {
20880
- log10.error("Task error", e);
23123
+ log13.error("Task error", e);
20881
23124
  activeTasks.delete(task.id);
20882
23125
  });
20883
23126
  }
20884
23127
  if (file_requests) {
20885
23128
  for (const req of file_requests) {
20886
- handleFileRequest(client, config2, ws.workspaceId, req, ws.token).catch((e) => log10.debug("File request error", e));
23129
+ handleFileRequest(client, config2, ws.workspaceId, req, ws.token).catch((e) => log13.debug("File request error", e));
20887
23130
  }
20888
23131
  }
20889
23132
  if (meetings) {
20890
23133
  for (const m of meetings) {
20891
- const agentBaseDir = join11(config2.workspacesRoot, m.workspace_id, m.agent_id, "workdir");
20892
- const timelineDir = join11(agentBaseDir, ".context_timeline");
23134
+ const agentBaseDir = join12(config2.workspacesRoot, m.workspace_id, m.agent_id, "workdir");
23135
+ const timelineDir = join12(agentBaseDir, ".context_timeline");
20893
23136
  spawnMeetingRunner({
20894
23137
  meetingId: m.id,
20895
23138
  meetingUrl: m.meeting_url,
@@ -20906,9 +23149,9 @@ async function startDaemon(profile, serverUrl) {
20906
23149
  }
20907
23150
  } catch (e) {
20908
23151
  if (e instanceof Error && e.message.startsWith("HTTP 401")) {
20909
- log10.warn(`Workspace ${ws.workspaceId} poll returned 401 — will retry next cycle`);
23152
+ log13.warn(`Workspace ${ws.workspaceId} poll returned 401 — will retry next cycle`);
20910
23153
  } else {
20911
- log10.debug("Poll error", e);
23154
+ log13.debug("Poll error", e);
20912
23155
  }
20913
23156
  }
20914
23157
  }
@@ -20916,7 +23159,7 @@ async function startDaemon(profile, serverUrl) {
20916
23159
  evictWorkspace(id);
20917
23160
  }
20918
23161
  if (workspaceStates.length === 0 && hadWorkspaces) {
20919
- log10.info("All workspaces evicted — shutting down");
23162
+ log13.info("All workspaces evicted — shutting down");
20920
23163
  shutdown();
20921
23164
  }
20922
23165
  };
@@ -20924,7 +23167,7 @@ async function startDaemon(profile, serverUrl) {
20924
23167
  const heartbeatPing = () => {
20925
23168
  for (const ws of workspaceStates) {
20926
23169
  client.heartbeat(ws.token, config2.daemonId).catch((e) => {
20927
- log10.debug("heartbeat failed", { workspaceId: ws.workspaceId, err: String(e) });
23170
+ log13.debug("heartbeat failed", { workspaceId: ws.workspaceId, err: String(e) });
20928
23171
  });
20929
23172
  }
20930
23173
  };
@@ -20950,7 +23193,7 @@ async function startDaemon(profile, serverUrl) {
20950
23193
  syncAgentId(task.agentId, ws.workspaceId);
20951
23194
  activeTasks.add(task.id);
20952
23195
  handleTask(client, config2, runtimeIndex, task, ws.token, activeTasks, pendingSteer).catch((e) => {
20953
- log10.error("WS task error", e);
23196
+ log13.error("WS task error", e);
20954
23197
  activeTasks.delete(task.id);
20955
23198
  });
20956
23199
  }
@@ -20959,7 +23202,7 @@ async function startDaemon(profile, serverUrl) {
20959
23202
  const ws = wsMap.get(msg.workspaceId);
20960
23203
  if (ws) {
20961
23204
  for (const req of msg.requests) {
20962
- handleFileRequest(client, config2, ws.workspaceId, req, ws.token).catch((e) => log10.debug("WS file request error", e));
23205
+ handleFileRequest(client, config2, ws.workspaceId, req, ws.token).catch((e) => log13.debug("WS file request error", e));
20963
23206
  }
20964
23207
  }
20965
23208
  break;
@@ -20969,8 +23212,8 @@ async function startDaemon(profile, serverUrl) {
20969
23212
  const ws = wsMap.get(m.workspace_id);
20970
23213
  if (!ws)
20971
23214
  continue;
20972
- const agentBaseDir = join11(config2.workspacesRoot, m.workspace_id, m.agent_id, "workdir");
20973
- const timelineDir = join11(agentBaseDir, ".context_timeline");
23215
+ const agentBaseDir = join12(config2.workspacesRoot, m.workspace_id, m.agent_id, "workdir");
23216
+ const timelineDir = join12(agentBaseDir, ".context_timeline");
20974
23217
  spawnMeetingRunner({
20975
23218
  meetingId: m.id,
20976
23219
  meetingUrl: m.meeting_url,
@@ -20994,7 +23237,7 @@ async function startDaemon(profile, serverUrl) {
20994
23237
  }
20995
23238
  break;
20996
23239
  case "daemon.rescan":
20997
- log10.info("WS rescan requested — restarting daemon");
23240
+ log13.info("WS rescan requested — restarting daemon");
20998
23241
  requestRestart();
20999
23242
  break;
21000
23243
  case "daemon.kill": {
@@ -21022,7 +23265,7 @@ async function startDaemon(profile, serverUrl) {
21022
23265
  });
21023
23266
  activeTasks.add(killTask.id);
21024
23267
  handleTask(client, config2, runtimeIndex, killTask, ws.token, activeTasks, pendingSteer).catch((e) => {
21025
- log10.error("WS kill task error", e);
23268
+ log13.error("WS kill task error", e);
21026
23269
  activeTasks.delete(killTask.id);
21027
23270
  });
21028
23271
  }
@@ -21037,11 +23280,11 @@ async function startDaemon(profile, serverUrl) {
21037
23280
  machineToken: wsToken,
21038
23281
  onMessage: handleWsPush,
21039
23282
  onConnected: () => {
21040
- log10.info("WS connected — switching to low-frequency poll");
23283
+ log13.info("WS connected — switching to low-frequency poll");
21041
23284
  updatePollInterval(config2.wsPollInterval);
21042
23285
  },
21043
23286
  onDisconnected: () => {
21044
- log10.info("WS disconnected — reverting to high-frequency poll");
23287
+ log13.info("WS disconnected — reverting to high-frequency poll");
21045
23288
  updatePollInterval(config2.pollInterval);
21046
23289
  }
21047
23290
  }) : null;
@@ -21049,13 +23292,13 @@ async function startDaemon(profile, serverUrl) {
21049
23292
  const sweepTick = async () => {
21050
23293
  for (const ws of workspaceStates) {
21051
23294
  client.sweep(ws.token, config2.daemonId).catch((e) => {
21052
- log10.debug("sweep ping failed", { workspaceId: ws.workspaceId, err: String(e) });
23295
+ log13.debug("sweep ping failed", { workspaceId: ws.workspaceId, err: String(e) });
21053
23296
  });
21054
23297
  }
21055
23298
  try {
21056
23299
  await reconcilePendingCompletions(config2.workspacesRoot);
21057
23300
  } catch (e) {
21058
- log10.debug("reconciliation error", e);
23301
+ log13.debug("reconciliation error", e);
21059
23302
  }
21060
23303
  };
21061
23304
  const sweepTimer = setInterval(sweepTick, config2.sweepInterval);
@@ -21079,7 +23322,7 @@ async function startDaemon(profile, serverUrl) {
21079
23322
  if (shuttingDown)
21080
23323
  return;
21081
23324
  shuttingDown = true;
21082
- log10.info(restartRequested ? "Restarting..." : "Shutting down...");
23325
+ log13.info(restartRequested ? "Restarting..." : "Shutting down...");
21083
23326
  clearInterval(pollTimer);
21084
23327
  clearInterval(heartbeatTimer);
21085
23328
  clearInterval(sweepTimer);
@@ -21104,10 +23347,10 @@ async function startDaemon(profile, serverUrl) {
21104
23347
  const logPath = daemonLogFilePath();
21105
23348
  let logFd;
21106
23349
  try {
21107
- mkdirSync8(dirname3(logPath), { recursive: true, mode: 448 });
23350
+ mkdirSync9(dirname3(logPath), { recursive: true, mode: 448 });
21108
23351
  logFd = openSync(logPath, "a", 384);
21109
23352
  } catch (e) {
21110
- log10.error(`Failed to open daemon log file ${logPath}`, e);
23353
+ log13.error(`Failed to open daemon log file ${logPath}`, e);
21111
23354
  }
21112
23355
  const child = spawn5(process.execPath, args, {
21113
23356
  detached: true,
@@ -21117,7 +23360,7 @@ async function startDaemon(profile, serverUrl) {
21117
23360
  child.unref();
21118
23361
  if (logFd != null)
21119
23362
  closeSync(logFd);
21120
- log10.info(`Spawned new daemon (pid=${child.pid}), logs: ${logPath}`);
23363
+ log13.info(`Spawned new daemon (pid=${child.pid}), logs: ${logPath}`);
21121
23364
  }
21122
23365
  clearTimeout(timeout);
21123
23366
  process.exit(0);
@@ -21128,7 +23371,7 @@ async function startDaemon(profile, serverUrl) {
21128
23371
  process.on("SIGHUP", async () => {
21129
23372
  if (shuttingDown)
21130
23373
  return;
21131
- log10.info("SIGHUP received — reloading config...");
23374
+ log13.info("SIGHUP received — reloading config...");
21132
23375
  try {
21133
23376
  const freshConfig = loadCLIConfigForProfile(profile);
21134
23377
  const freshWorkspaces = (freshConfig.watched_workspaces || []).filter((ws) => ws.status !== "deleted" && !!ws.id);
@@ -21136,7 +23379,7 @@ async function startDaemon(profile, serverUrl) {
21136
23379
  const newWorkspaces = freshWorkspaces.filter((ws) => ws.token && !existingIds.has(ws.id));
21137
23380
  for (const ws of newWorkspaces) {
21138
23381
  const runtimes = providers.map((p) => ({ type: p.type, version: p.version }));
21139
- log10.info(`Registering new workspace ${ws.id} (${ws.name ?? "unnamed"})...`);
23382
+ log13.info(`Registering new workspace ${ws.id} (${ws.name ?? "unnamed"})...`);
21140
23383
  try {
21141
23384
  const resp = await client.register(ws.token, {
21142
23385
  workspace_id: ws.id,
@@ -21155,9 +23398,9 @@ async function startDaemon(profile, serverUrl) {
21155
23398
  provider: providers[i].type
21156
23399
  });
21157
23400
  }
21158
- log10.info(`Workspace ${ws.id} added — ${runtimeIds.length} runtime(s)`);
23401
+ log13.info(`Workspace ${ws.id} added — ${runtimeIds.length} runtime(s)`);
21159
23402
  } catch (e) {
21160
- log10.error(`Failed to register new workspace ${ws.id}`, e);
23403
+ log13.error(`Failed to register new workspace ${ws.id}`, e);
21161
23404
  }
21162
23405
  }
21163
23406
  if (newWorkspaces.length > 0) {
@@ -21171,38 +23414,38 @@ async function startDaemon(profile, serverUrl) {
21171
23414
  machineToken: token,
21172
23415
  onMessage: handleWsPush,
21173
23416
  onConnected: () => {
21174
- log10.info("WS connected — switching to low-frequency poll");
23417
+ log13.info("WS connected — switching to low-frequency poll");
21175
23418
  updatePollInterval(config2.wsPollInterval);
21176
23419
  },
21177
23420
  onDisconnected: () => {
21178
- log10.info("WS disconnected — reverting to high-frequency poll");
23421
+ log13.info("WS disconnected — reverting to high-frequency poll");
21179
23422
  updatePollInterval(config2.pollInterval);
21180
23423
  }
21181
23424
  });
21182
23425
  wsClient.connect();
21183
- log10.info("WS push client initialized after SIGHUP reload");
23426
+ log13.info("WS push client initialized after SIGHUP reload");
21184
23427
  }
21185
- log10.info(`Reload complete — now polling ${workspaceStates.length} workspace(s)`);
23428
+ log13.info(`Reload complete — now polling ${workspaceStates.length} workspace(s)`);
21186
23429
  } else {
21187
- log10.info("Reload complete — no new workspaces found");
23430
+ log13.info("Reload complete — no new workspaces found");
21188
23431
  }
21189
23432
  } catch (e) {
21190
- log10.error("Failed to reload config", e);
23433
+ log13.error("Failed to reload config", e);
21191
23434
  }
21192
23435
  });
21193
23436
  await pollCycle();
21194
23437
  }
21195
23438
  function spawnSessionRunner(input) {
21196
23439
  const logDir = sessionRunnerLogDir();
21197
- mkdirSync8(logDir, { recursive: true });
21198
- const logFilePath = join11(logDir, `${input.task.id}.log`);
23440
+ mkdirSync9(logDir, { recursive: true });
23441
+ const logFilePath = join12(logDir, `${input.task.id}.log`);
21199
23442
  input.logFilePath = logFilePath;
21200
23443
  const encoded = Buffer.from(JSON.stringify(input)).toString("base64");
21201
23444
  let fd;
21202
23445
  try {
21203
23446
  fd = openSync(logFilePath, "a");
21204
23447
  } catch (e) {
21205
- log10.error(`Failed to open log file ${logFilePath}`, e);
23448
+ log13.error(`Failed to open log file ${logFilePath}`, e);
21206
23449
  }
21207
23450
  const child = spawn5(process.execPath, [sessionRunnerPath, encoded], {
21208
23451
  detached: true,
@@ -21215,14 +23458,14 @@ function spawnSessionRunner(input) {
21215
23458
  }
21216
23459
  function spawnMeetingRunner(input) {
21217
23460
  const logDir = sessionRunnerLogDir();
21218
- mkdirSync8(logDir, { recursive: true });
21219
- const logFilePath = join11(logDir, `meeting-${input.meetingId}.log`);
23461
+ mkdirSync9(logDir, { recursive: true });
23462
+ const logFilePath = join12(logDir, `meeting-${input.meetingId}.log`);
21220
23463
  const encoded = Buffer.from(JSON.stringify(input)).toString("base64");
21221
23464
  let fd;
21222
23465
  try {
21223
23466
  fd = openSync(logFilePath, "a");
21224
23467
  } catch (e) {
21225
- log10.error(`Failed to open meeting log file ${logFilePath}`, e);
23468
+ log13.error(`Failed to open meeting log file ${logFilePath}`, e);
21226
23469
  }
21227
23470
  const child = spawn5(process.execPath, [meetingRunnerPath, encoded], {
21228
23471
  detached: true,
@@ -21231,11 +23474,11 @@ function spawnMeetingRunner(input) {
21231
23474
  child.unref();
21232
23475
  if (fd != null)
21233
23476
  closeSync(fd);
21234
- log10.info(`Spawned meeting runner for ${input.meetingId} (pid=${child.pid})`);
23477
+ log13.info(`Spawned meeting runner for ${input.meetingId} (pid=${child.pid})`);
21235
23478
  return child;
21236
23479
  }
21237
23480
  async function handleFileRequest(client, config2, workspaceId, req, token) {
21238
- const agentWorkdir = join11(config2.workspacesRoot, workspaceId, req.agent_id, "workdir");
23481
+ const agentWorkdir = join12(config2.workspacesRoot, workspaceId, req.agent_id, "workdir");
21239
23482
  const resolved = validatePath(agentWorkdir, req.path);
21240
23483
  if (!resolved) {
21241
23484
  await client.reportFileData(token, { request_id: req.id, error: "invalid path", path: req.path });
@@ -21273,7 +23516,7 @@ async function killAndVerify(pid) {
21273
23516
  await new Promise((r) => setTimeout(r, 100));
21274
23517
  }
21275
23518
  if (isAlive(pid)) {
21276
- log10.warn(`session-runner pid=${pid} survived SIGTERM after ${verifyMs}ms — escalating to SIGKILL`);
23519
+ log13.warn(`session-runner pid=${pid} survived SIGTERM after ${verifyMs}ms — escalating to SIGKILL`);
21277
23520
  try {
21278
23521
  process.kill(pid, "SIGKILL");
21279
23522
  } catch {}
@@ -21281,7 +23524,7 @@ async function killAndVerify(pid) {
21281
23524
  return true;
21282
23525
  }
21283
23526
  async function handleTask(client, config2, runtimeIndex, task, token, activeTasks, pendingSteer) {
21284
- log10.info(`Task ${task.id} claimed agent=${task.agentId}`);
23527
+ log13.info(`Task ${task.id} claimed agent=${task.agentId}`);
21285
23528
  if (task.type === TASK_TYPES.KILL_TASK) {
21286
23529
  const targetTaskId = task.context?.target_task_id;
21287
23530
  if (!targetTaskId) {
@@ -21289,8 +23532,8 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21289
23532
  activeTasks.delete(task.id);
21290
23533
  return;
21291
23534
  }
21292
- const agentBaseDir = join11(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
21293
- const timelineDir = join11(agentBaseDir, ".context_timeline");
23535
+ const agentBaseDir = join12(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
23536
+ const timelineDir = join12(agentBaseDir, ".context_timeline");
21294
23537
  const MAX_WAIT_MS = Number(process.env.ALOOK_KILL_TASK_MAX_WAIT_MS) || 15000;
21295
23538
  const POLL_MS2 = Number(process.env.ALOOK_KILL_TASK_POLL_MS) || 200;
21296
23539
  const waitStart = Date.now();
@@ -21311,17 +23554,17 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21311
23554
  const delivered = await killAndVerify(pid);
21312
23555
  if (delivered) {
21313
23556
  await client.failTask(token, task.id, "killed");
21314
- log10.info(`Kill task ${task.id}: terminated pid=${pid} for target=${targetTaskId}`);
23557
+ log13.info(`Kill task ${task.id}: terminated pid=${pid} for target=${targetTaskId}`);
21315
23558
  } else {
21316
23559
  await client.failTask(token, task.id, "target process already exited");
21317
- log10.info(`Kill task ${task.id}: target pid=${pid} already exited`);
23560
+ log13.info(`Kill task ${task.id}: target pid=${pid} already exited`);
21318
23561
  }
21319
23562
  } catch (e) {
21320
23563
  await client.failTask(token, task.id, `kill failed: ${e}`);
21321
23564
  }
21322
23565
  } else {
21323
23566
  await client.failTask(token, task.id, "target not found in timeline");
21324
- log10.info(`Kill task ${task.id}: target ${targetTaskId} not found in timeline`);
23567
+ log13.info(`Kill task ${task.id}: target ${targetTaskId} not found in timeline`);
21325
23568
  }
21326
23569
  activeTasks.delete(task.id);
21327
23570
  return;
@@ -21342,9 +23585,9 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21342
23585
  const provider = runtimeData.provider;
21343
23586
  let promptOverride;
21344
23587
  if (task.contextKey) {
21345
- const agentBaseDir = join11(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
23588
+ const agentBaseDir = join12(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
21346
23589
  cleanupStaleIntents(agentBaseDir);
21347
- const timelineDir = join11(agentBaseDir, ".context_timeline");
23590
+ const timelineDir = join12(agentBaseDir, ".context_timeline");
21348
23591
  const ctxKey = task.contextKey;
21349
23592
  let lockAcquired = acquireSteeringLock(agentBaseDir, ctxKey);
21350
23593
  if (!lockAcquired) {
@@ -21363,7 +23606,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21363
23606
  }
21364
23607
  existing.tasks.push(task);
21365
23608
  existing.attachments.set(task.id, myAttachments);
21366
- log10.info(`Steering: ${task.id} merged into pending entry (lock contention) for context_key=${ctxKey} (${existing.tasks.length} tasks)`);
23609
+ log13.info(`Steering: ${task.id} merged into pending entry (lock contention) for context_key=${ctxKey} (${existing.tasks.length} tasks)`);
21367
23610
  existing.wake();
21368
23611
  try {
21369
23612
  await client.supersedeTask(token, task.id);
@@ -21377,7 +23620,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21377
23620
  await new Promise((r) => setTimeout(r, MERGE_POLL_MS));
21378
23621
  }
21379
23622
  if (!lockAcquired) {
21380
- log10.warn(`Steering lock contention for context_key=${ctxKey}, proceeding without steering`);
23623
+ log13.warn(`Steering lock contention for context_key=${ctxKey}, proceeding without steering`);
21381
23624
  }
21382
23625
  }
21383
23626
  if (lockAcquired) {
@@ -21392,7 +23635,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21392
23635
  try {
21393
23636
  myAttachments = await downloadAttachments(client, token, task.workspaceId, task.id, attachmentIds);
21394
23637
  } catch (e) {
21395
- log10.warn(`Steering: failed to download attachments for ${task.id}`, e);
23638
+ log13.warn(`Steering: failed to download attachments for ${task.id}`, e);
21396
23639
  }
21397
23640
  }
21398
23641
  let ownerWake;
@@ -21408,7 +23651,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21408
23651
  pendingSteer.set(ctxKey, entry);
21409
23652
  let predecessor = "entry" in result ? result.entry : null;
21410
23653
  if (!predecessor) {
21411
- log10.info(`Steering: predecessor ${result.pending.task_id} warming up; ${task.id} waiting`);
23654
+ log13.info(`Steering: predecessor ${result.pending.task_id} warming up; ${task.id} waiting`);
21412
23655
  const POLL_MS2 = 200;
21413
23656
  const MAX_WAIT_MS = steerWarmupGraceMs();
21414
23657
  const waitStart = Date.now();
@@ -21419,7 +23662,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21419
23662
  continue;
21420
23663
  const r = findSupersedablePredecessor(timelineDir, ctxKey, provider, steerWarmupGraceMs(), Date.now());
21421
23664
  if (!r) {
21422
- log10.info(`Steering: predecessor vanished; ${task.id} proceeding`);
23665
+ log13.info(`Steering: predecessor vanished; ${task.id} proceeding`);
21423
23666
  break;
21424
23667
  }
21425
23668
  if ("entry" in r) {
@@ -21437,14 +23680,51 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21437
23680
  }
21438
23681
  }
21439
23682
  if (predecessor && predecessor.task_id !== task.id) {
21440
- log10.info(`Steering: task ${task.id} supersedes predecessor ${predecessor.task_id} (context_key=${ctxKey})`);
23683
+ const backendInst = createBackend(provider, "");
23684
+ const isPersistent = backendInst.lifecycle?.kind === "persistent";
23685
+ if (config2.enableSteering && isPersistent && predecessor.pid != null) {
23686
+ log13.info(`Steering: task ${task.id} steering into predecessor ${predecessor.task_id} via mailbox (context_key=${ctxKey})`);
23687
+ try {
23688
+ ensureMailboxDirs(agentBaseDir, ctxKey);
23689
+ const attachmentIds2 = task.context?.attachment_ids ?? [];
23690
+ let steerAttachments = [];
23691
+ if (attachmentIds2.length > 0) {
23692
+ try {
23693
+ const downloaded = await downloadAttachments(client, token, task.workspaceId, task.id, attachmentIds2);
23694
+ steerAttachments = downloaded.map((a) => ({ localPath: a.path, filename: a.filename, contentType: a.content_type }));
23695
+ } catch (e) {
23696
+ log13.warn(`Steering mailbox: failed to download attachments for ${task.id}`, e);
23697
+ }
23698
+ }
23699
+ const seq = writeSteerMessage(agentBaseDir, ctxKey, {
23700
+ taskId: task.id,
23701
+ text: buildPrompt(task),
23702
+ attachments: steerAttachments,
23703
+ createdAt: new Date().toISOString()
23704
+ });
23705
+ const ackResult = await waitForAck(agentBaseDir, ctxKey, seq);
23706
+ if (ackResult.acked) {
23707
+ log13.info(`Steering: task ${task.id} steered into predecessor ${predecessor.task_id} (acked)`);
23708
+ try {
23709
+ await client.startTask(token, task.id);
23710
+ } catch {}
23711
+ pendingSteer.delete(ctxKey);
23712
+ activeTasks.delete(task.id);
23713
+ return;
23714
+ }
23715
+ log13.info(`Steering: mailbox delivery failed for ${task.id} (${ackResult.nackReason}), falling back to kill-and-respawn`);
23716
+ } catch (e) {
23717
+ log13.warn(`Steering: mailbox error for ${task.id}, falling back to kill-and-respawn`, e);
23718
+ }
23719
+ }
23720
+ log13.info(`Steering: task ${task.id} supersedes predecessor ${predecessor.task_id} (context_key=${ctxKey})`);
21441
23721
  if (predecessor.pid != null) {
21442
23722
  writeKillIntent(agentBaseDir, { reason: "superseded", targetTaskId: predecessor.task_id, expectedPid: predecessor.pid, successorTaskId: task.id });
21443
23723
  try {
21444
23724
  const delivered = await killAndVerify(predecessor.pid);
21445
- log10.info(delivered ? `Steering: terminated predecessor pid=${predecessor.pid}` : `Steering: predecessor pid=${predecessor.pid} already exited`);
23725
+ log13.info(delivered ? `Steering: terminated predecessor pid=${predecessor.pid}` : `Steering: predecessor pid=${predecessor.pid} already exited`);
21446
23726
  } catch (e) {
21447
- log10.warn(`Steering: kill failed for pid=${predecessor.pid}`, e);
23727
+ log13.warn(`Steering: kill failed for pid=${predecessor.pid}`, e);
21448
23728
  }
21449
23729
  const killWaitStart = Date.now();
21450
23730
  while (Date.now() - killWaitStart < 15000) {
@@ -21460,7 +23740,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21460
23740
  const finalEntry = pendingSteer.get(ctxKey);
21461
23741
  if (finalEntry && finalEntry.tasks.length > 1) {
21462
23742
  promptOverride = buildMergedPrompt(finalEntry.tasks, finalEntry.attachments);
21463
- log10.info(`Steering: merged ${finalEntry.tasks.length} tasks for context_key=${ctxKey}`);
23743
+ log13.info(`Steering: merged ${finalEntry.tasks.length} tasks for context_key=${ctxKey}`);
21464
23744
  } else if (finalEntry && finalEntry.tasks.length === 1) {
21465
23745
  const att = finalEntry.attachments.get(task.id);
21466
23746
  if (att && att.length > 0) {
@@ -21475,7 +23755,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21475
23755
  try {
21476
23756
  myAttachments = await downloadAttachments(client, token, task.workspaceId, task.id, attachmentIds);
21477
23757
  } catch (e) {
21478
- log10.warn(`Steering: failed to download attachments for ${task.id}`, e);
23758
+ log13.warn(`Steering: failed to download attachments for ${task.id}`, e);
21479
23759
  }
21480
23760
  }
21481
23761
  for (const prev of existing.tasks) {
@@ -21487,7 +23767,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21487
23767
  }
21488
23768
  existing.tasks.push(task);
21489
23769
  existing.attachments.set(task.id, myAttachments);
21490
- log10.info(`Steering: ${task.id} merged into pending entry for context_key=${ctxKey} (${existing.tasks.length} tasks)`);
23770
+ log13.info(`Steering: ${task.id} merged into pending entry for context_key=${ctxKey} (${existing.tasks.length} tasks)`);
21491
23771
  existing.wake();
21492
23772
  try {
21493
23773
  await client.supersedeTask(token, task.id);
@@ -21505,6 +23785,14 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21505
23785
  const configModel = provider === "claude" ? config2.claudeModel : provider === "codex" ? config2.codexModel : config2.opencodeModel;
21506
23786
  const agentModel = task.agent?.runtimeConfig?.model;
21507
23787
  const model = typeof agentModel === "string" && agentModel ? agentModel : configModel;
23788
+ const backendForInput = createBackend(provider, "");
23789
+ const steeringEligible = config2.enableSteering && backendForInput.lifecycle?.kind === "persistent" && !!task.contextKey;
23790
+ let steeringMailboxDir;
23791
+ if (steeringEligible) {
23792
+ const agentBaseDirForSteering = join12(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
23793
+ ensureMailboxDirs(agentBaseDirForSteering, task.contextKey);
23794
+ steeringMailboxDir = inboxDir(agentBaseDirForSteering, task.contextKey);
23795
+ }
21508
23796
  const input = {
21509
23797
  task,
21510
23798
  provider,
@@ -21515,24 +23803,26 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21515
23803
  workspacesRoot: config2.workspacesRoot,
21516
23804
  agentTimeout: config2.agentTimeout,
21517
23805
  messageInactivityTimeout: config2.messageInactivityTimeout,
21518
- ...promptOverride && { promptOverride }
23806
+ ...promptOverride && { promptOverride },
23807
+ ...steeringEligible && { steeringEnabled: true },
23808
+ ...steeringMailboxDir && { steeringMailboxDir }
21519
23809
  };
21520
23810
  const child = spawnSessionRunner(input);
21521
23811
  child.on("close", async (code) => {
21522
23812
  activeTasks.delete(task.id);
21523
23813
  if (code !== 0) {
21524
- const agentBaseDir = join11(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
23814
+ const agentBaseDir = join12(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
21525
23815
  const killIntent = readKillIntent(agentBaseDir, task.id);
21526
23816
  if (killIntent) {
21527
- log10.info(`Task ${task.id} exited (${killIntent.reason}) — expected, skipping failTask`);
23817
+ log13.info(`Task ${task.id} exited (${killIntent.reason}) — expected, skipping failTask`);
21528
23818
  clearKillIntent(agentBaseDir, task.id);
21529
23819
  return;
21530
23820
  }
21531
23821
  const errorMsg = code === null ? "killed by signal" : `session-runner exited with code ${code}`;
21532
23822
  try {
21533
23823
  await client.failTask(token, task.id, errorMsg);
21534
- log10.warn(`session-runner crashed (${errorMsg}, task ${task.id})`);
21535
- const timelineDir = join11(agentBaseDir, ".context_timeline");
23824
+ log13.warn(`session-runner crashed (${errorMsg}, task ${task.id})`);
23825
+ const timelineDir = join12(agentBaseDir, ".context_timeline");
21536
23826
  updateEntry(timelineDir, task.id, (entry) => {
21537
23827
  entry.pid = null;
21538
23828
  entry.status = "failed";
@@ -21540,10 +23830,10 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21540
23830
  });
21541
23831
  } catch (e) {
21542
23832
  if (isClientError3(e)) {
21543
- log10.info(`Task ${task.id} exited (already terminal) — session-runner handled cleanup`);
23833
+ log13.info(`Task ${task.id} exited (already terminal) — session-runner handled cleanup`);
21544
23834
  return;
21545
23835
  }
21546
- log10.error(`Failed to report crash for task ${task.id}`, e);
23836
+ log13.error(`Failed to report crash for task ${task.id}`, e);
21547
23837
  try {
21548
23838
  await writeMarkerFile(config2.workspacesRoot, {
21549
23839
  taskId: task.id,
@@ -21557,7 +23847,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21557
23847
  }
21558
23848
  }
21559
23849
  });
21560
- log10.info(`Task ${task.id} dispatched to session-runner (pid=${child.pid})`);
23850
+ log13.info(`Task ${task.id} dispatched to session-runner (pid=${child.pid})`);
21561
23851
  }
21562
23852
 
21563
23853
  // lib/runtimes.ts
@@ -21669,7 +23959,7 @@ Starting daemon...`);
21669
23959
  args.push("--profile", profile);
21670
23960
  args.push("daemon", "start", "--foreground");
21671
23961
  const logPath = daemonLogFilePath();
21672
- mkdirSync9(dirname4(logPath), { recursive: true, mode: 448 });
23962
+ mkdirSync10(dirname4(logPath), { recursive: true, mode: 448 });
21673
23963
  const logFd = openSync2(logPath, "a", 384);
21674
23964
  const child = spawn6(process.execPath, args, {
21675
23965
  detached: true,
@@ -21992,7 +24282,7 @@ function statusCommand() {
21992
24282
  // commands/daemon.ts
21993
24283
  import { Command as Command4 } from "commander";
21994
24284
  import { spawn as spawn8 } from "child_process";
21995
- import { openSync as openSync3, closeSync as closeSync3, mkdirSync as mkdirSync10 } from "fs";
24285
+ import { openSync as openSync3, closeSync as closeSync3, mkdirSync as mkdirSync11 } from "fs";
21996
24286
  import { dirname as dirname5 } from "path";
21997
24287
  var PID_POLL_INTERVAL_MS = 200;
21998
24288
  var PID_POLL_TIMEOUT_MS = 2000;
@@ -22028,7 +24318,7 @@ async function startInBackground(profile, serverUrl) {
22028
24318
  return;
22029
24319
  }
22030
24320
  const logPath = daemonLogFilePath();
22031
- mkdirSync10(dirname5(logPath), { recursive: true, mode: 448 });
24321
+ mkdirSync11(dirname5(logPath), { recursive: true, mode: 448 });
22032
24322
  const logFd = openSync3(logPath, "a", 384);
22033
24323
  const child = spawn8(process.execPath, buildChildArgs(profile, serverUrl), {
22034
24324
  detached: true,
@@ -22149,12 +24439,12 @@ function configCommand() {
22149
24439
 
22150
24440
  // commands/email.ts
22151
24441
  import { Command as Command6 } from "commander";
22152
- import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync11, readFileSync as readFileSync11 } from "fs";
22153
- import { join as join12 } from "path";
24442
+ import { writeFileSync as writeFileSync9, mkdirSync as mkdirSync12, readFileSync as readFileSync12 } from "fs";
24443
+ import { join as join13 } from "path";
22154
24444
  import PostalMime from "postal-mime";
22155
24445
 
22156
24446
  // lib/flags.ts
22157
- import { readFileSync as readFileSync9 } from "fs";
24447
+ import { readFileSync as readFileSync10 } from "fs";
22158
24448
  function resolveAgentId(opts) {
22159
24449
  const id = opts.agent_id || process.env.ALOOK_AGENT_ID;
22160
24450
  if (!id) {
@@ -22172,7 +24462,7 @@ function readBody(opts) {
22172
24462
  process.exit(1);
22173
24463
  }
22174
24464
  if (opts.bodyFile)
22175
- return readFileSync9(opts.bodyFile, "utf-8");
24465
+ return readFileSync10(opts.bodyFile, "utf-8");
22176
24466
  return opts.body ?? "";
22177
24467
  }
22178
24468
 
@@ -22235,7 +24525,7 @@ function resolveClientOptsPartial(command, opts = {}) {
22235
24525
  }
22236
24526
 
22237
24527
  // lib/file-utils.ts
22238
- import { readFileSync as readFileSync10, statSync as statSync5 } from "fs";
24528
+ import { readFileSync as readFileSync11, statSync as statSync5 } from "fs";
22239
24529
  import { basename as basename2 } from "path";
22240
24530
  var MIME_BY_EXT = {
22241
24531
  ".pdf": "application/pdf",
@@ -22277,7 +24567,7 @@ async function uploadFile(client, filePath, endpoint) {
22277
24567
  let bytes;
22278
24568
  let size;
22279
24569
  try {
22280
- bytes = readFileSync10(filePath);
24570
+ bytes = readFileSync11(filePath);
22281
24571
  size = statSync5(filePath).size;
22282
24572
  } catch (err) {
22283
24573
  throw new Error(`cannot read file "${filePath}": ${err instanceof Error ? err.message : err}`);
@@ -22304,7 +24594,7 @@ function gatherContextEnvVars() {
22304
24594
  }
22305
24595
 
22306
24596
  // commands/email.ts
22307
- var log11 = createLogger2({ module: "email" });
24597
+ var log14 = createLogger2({ module: "email" });
22308
24598
  var VALID_STATUSES = ["unread", "read", "archived", "sent"];
22309
24599
  var VALID_FOLDERS = ["inbox", "sent", "untrust"];
22310
24600
  var EMAIL_BASE = tempDir("alook-emails");
@@ -22340,7 +24630,7 @@ function emailCommand() {
22340
24630
  process.exit(1);
22341
24631
  }
22342
24632
  }
22343
- const emailDir_base = join12(EMAIL_BASE, workspaceId, agentId);
24633
+ const emailDir_base = join13(EMAIL_BASE, workspaceId, agentId);
22344
24634
  try {
22345
24635
  let emails2;
22346
24636
  if (opts.email_id) {
@@ -22366,11 +24656,11 @@ function emailCommand() {
22366
24656
  printJSON(emails2);
22367
24657
  return;
22368
24658
  }
22369
- mkdirSync11(emailDir_base, { recursive: true });
24659
+ mkdirSync12(emailDir_base, { recursive: true });
22370
24660
  const downloadedPaths = [];
22371
24661
  for (const email3 of emails2) {
22372
- const emailDir = join12(emailDir_base, email3.id);
22373
- mkdirSync11(emailDir, { recursive: true });
24662
+ const emailDir = join13(emailDir_base, email3.id);
24663
+ mkdirSync12(emailDir, { recursive: true });
22374
24664
  const metadata = {
22375
24665
  id: email3.id,
22376
24666
  from: email3.from_email,
@@ -22382,8 +24672,8 @@ function emailCommand() {
22382
24672
  in_reply_to: email3.in_reply_to || "",
22383
24673
  references: email3.references || ""
22384
24674
  };
22385
- const metadataPath = join12(emailDir, "metadata.json");
22386
- writeFileSync8(metadataPath, JSON.stringify(metadata, null, 2));
24675
+ const metadataPath = join13(emailDir, "metadata.json");
24676
+ writeFileSync9(metadataPath, JSON.stringify(metadata, null, 2));
22387
24677
  downloadedPaths.push(metadataPath);
22388
24678
  let rawMime;
22389
24679
  try {
@@ -22391,25 +24681,25 @@ function emailCommand() {
22391
24681
  } catch (err) {
22392
24682
  const msg = err instanceof Error ? err.message : String(err);
22393
24683
  if (msg.includes("404")) {
22394
- log11.warn(`email body not available for ${email3.id}, skipping`);
24684
+ log14.warn(`email body not available for ${email3.id}, skipping`);
22395
24685
  continue;
22396
24686
  }
22397
24687
  throw err;
22398
24688
  }
22399
24689
  const parsed = await new PostalMime().parse(rawMime);
22400
24690
  if (parsed.text) {
22401
- const bodyPath = join12(emailDir, "body.txt");
22402
- writeFileSync8(bodyPath, parsed.text);
24691
+ const bodyPath = join13(emailDir, "body.txt");
24692
+ writeFileSync9(bodyPath, parsed.text);
22403
24693
  downloadedPaths.push(bodyPath);
22404
24694
  }
22405
24695
  if (parsed.html) {
22406
- const htmlPath = join12(emailDir, "body.html");
22407
- writeFileSync8(htmlPath, parsed.html);
24696
+ const htmlPath = join13(emailDir, "body.html");
24697
+ writeFileSync9(htmlPath, parsed.html);
22408
24698
  downloadedPaths.push(htmlPath);
22409
24699
  }
22410
24700
  if (parsed.attachments && parsed.attachments.length > 0) {
22411
- const attDir = join12(emailDir, "attachments");
22412
- mkdirSync11(attDir, { recursive: true });
24701
+ const attDir = join13(emailDir, "attachments");
24702
+ mkdirSync12(attDir, { recursive: true });
22413
24703
  const usedFilenames = new Set;
22414
24704
  for (let i = 0;i < parsed.attachments.length; i++) {
22415
24705
  const att = parsed.attachments[i];
@@ -22418,8 +24708,8 @@ function emailCommand() {
22418
24708
  filename = `${i}-${filename}`;
22419
24709
  }
22420
24710
  usedFilenames.add(filename);
22421
- const attPath = join12(attDir, filename);
22422
- writeFileSync8(attPath, contentToBuffer(att.content));
24711
+ const attPath = join13(attDir, filename);
24712
+ writeFileSync9(attPath, contentToBuffer(att.content));
22423
24713
  downloadedPaths.push(attPath);
22424
24714
  }
22425
24715
  }
@@ -22460,7 +24750,7 @@ function emailCommand() {
22460
24750
  const client = new APIClient(serverUrl, token, workspaceId);
22461
24751
  let htmlBody;
22462
24752
  try {
22463
- htmlBody = readFileSync11(opts.bodyFile, "utf-8");
24753
+ htmlBody = readFileSync12(opts.bodyFile, "utf-8");
22464
24754
  } catch (err) {
22465
24755
  console.error(`Error: cannot read body file "${opts.bodyFile}": ${err instanceof Error ? err.message : err}`);
22466
24756
  process.exit(1);
@@ -22485,7 +24775,7 @@ function emailCommand() {
22485
24775
  references = [parentEmail.references, parentEmail.message_id].filter(Boolean).join(" ").trim() || undefined;
22486
24776
  }
22487
24777
  } catch {
22488
- log11.warn(`could not fetch parent email ${opts.inReplyTo}, sending without threading`);
24778
+ log14.warn(`could not fetch parent email ${opts.inReplyTo}, sending without threading`);
22489
24779
  }
22490
24780
  }
22491
24781
  const ctx = gatherContextEnvVars();
@@ -23024,14 +25314,14 @@ function issueCommand() {
23024
25314
 
23025
25315
  // commands/agent.ts
23026
25316
  import { Command as Command9 } from "commander";
23027
- import { readFileSync as readFileSync12 } from "fs";
25317
+ import { readFileSync as readFileSync13 } from "fs";
23028
25318
  function readField(opts, inlineName, fileName) {
23029
25319
  if (opts.inline && opts.file) {
23030
25320
  console.error(`Error: --${inlineName} and --${fileName} are mutually exclusive`);
23031
25321
  process.exit(1);
23032
25322
  }
23033
25323
  if (opts.file)
23034
- return readFileSync12(opts.file, "utf-8");
25324
+ return readFileSync13(opts.file, "utf-8");
23035
25325
  return opts.inline ?? null;
23036
25326
  }
23037
25327
  function agentCommand() {
@@ -23171,7 +25461,7 @@ ${result.output}`);
23171
25461
 
23172
25462
  // commands/sync.ts
23173
25463
  import { Command as Command12 } from "commander";
23174
- import { readFileSync as readFileSync13 } from "fs";
25464
+ import { readFileSync as readFileSync14 } from "fs";
23175
25465
  import { basename as basename3 } from "path";
23176
25466
  function syncCommand() {
23177
25467
  const cmd = new Command12("sync").description("Sync info with the user (files, messages)");
@@ -23181,7 +25471,7 @@ function syncCommand() {
23181
25471
  const client = new APIClient(serverUrl, token, workspaceId);
23182
25472
  let bytes;
23183
25473
  try {
23184
- bytes = readFileSync13(opts.file);
25474
+ bytes = readFileSync14(opts.file);
23185
25475
  } catch (err) {
23186
25476
  console.error(`Error: cannot read file "${opts.file}": ${err.message}`);
23187
25477
  process.exit(1);
@@ -23222,7 +25512,7 @@ function syncCommand() {
23222
25512
  let content;
23223
25513
  if (opts.messageFile) {
23224
25514
  try {
23225
- content = readFileSync13(opts.messageFile, "utf-8");
25515
+ content = readFileSync14(opts.messageFile, "utf-8");
23226
25516
  } catch (err) {
23227
25517
  console.error(`Error: cannot read file "${opts.messageFile}": ${err.message}`);
23228
25518
  process.exit(1);
@@ -23256,7 +25546,7 @@ function syncCommand() {
23256
25546
 
23257
25547
  // commands/workspace.ts
23258
25548
  import { Command as Command13 } from "commander";
23259
- import { readFileSync as readFileSync14 } from "fs";
25549
+ import { readFileSync as readFileSync15 } from "fs";
23260
25550
  function slugify2(name) {
23261
25551
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
23262
25552
  }
@@ -23296,7 +25586,7 @@ function workspaceCommand() {
23296
25586
  const client = new APIClient(serverUrl, token, resolvedWorkspaceId);
23297
25587
  let configJson;
23298
25588
  try {
23299
- configJson = readFileSync14(opts.jsonFile, "utf-8");
25589
+ configJson = readFileSync15(opts.jsonFile, "utf-8");
23300
25590
  } catch (err) {
23301
25591
  console.error(`Error: cannot read file '${opts.jsonFile}': ${err instanceof Error ? err.message : err}`);
23302
25592
  process.exit(1);