@alook/cli 0.0.149 → 0.0.150

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,16 @@ var TERMINAL_MEETING_STATUSES = [
167
203
  MeetingStatus.COMPLETED,
168
204
  MeetingStatus.FAILED
169
205
  ];
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;
170
210
  var DEV_WEB_URL = process.env.ALOOK_SERVER_URL || "http://localhost:3000";
171
211
  var DEV_WS_DO_URL = process.env.DEV_WS_DO_URL || "http://localhost:8789";
172
212
  var DEV_EMAIL_WORKER_URL = process.env.DEV_EMAIL_WORKER_URL || "http://localhost:8787";
213
+ // ../shared/src/constants/community.ts
214
+ var MAX_ATTACHMENT_SIZE_BYTES = 25 * 1024 * 1024;
215
+ var MAX_SERVER_ICON_SIZE_BYTES = 5 * 1024 * 1024;
173
216
  // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
174
217
  var exports_external = {};
175
218
  __export(exports_external, {
@@ -14934,7 +14977,126 @@ var CreateThreadRequestSchema = exports_external.object({
14934
14977
  content: exports_external.string().optional().default(""),
14935
14978
  attachment_ids: exports_external.array(exports_external.string()).optional()
14936
14979
  });
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
14980
+ var COMMUNITY_RUNTIME_ID_MAX = 64;
14981
+ var COMMUNITY_RUNTIME_VERSION_MAX = 64;
14982
+ var COMMUNITY_RUNTIME_LIST_MAX = 64;
14983
+ var RUNTIME_ID_RE = /^[A-Za-z0-9._@/-]+$/;
14984
+ var CommunityMachineRuntimeSchema = exports_external.object({
14985
+ id: exports_external.string().min(1).max(COMMUNITY_RUNTIME_ID_MAX).regex(RUNTIME_ID_RE, "invalid runtime id charset"),
14986
+ version: exports_external.string().max(COMMUNITY_RUNTIME_VERSION_MAX).optional(),
14987
+ status: exports_external.enum(["healthy", "unhealthy"]).catch("healthy").default("healthy"),
14988
+ lastError: exports_external.string().max(128).optional(),
14989
+ lastErrorAt: exports_external.string().optional()
14990
+ });
14991
+ var CommunityMachineRuntimeListSchema = exports_external.array(CommunityMachineRuntimeSchema).max(COMMUNITY_RUNTIME_LIST_MAX).transform((list) => {
14992
+ const seen = new Set;
14993
+ const out = [];
14994
+ for (const r of list) {
14995
+ if (seen.has(r.id))
14996
+ continue;
14997
+ seen.add(r.id);
14998
+ out.push(r);
14999
+ }
15000
+ return out;
15001
+ });
15002
+ var CommunityMachineSummarySchema = exports_external.object({
15003
+ id: exports_external.string(),
15004
+ hostname: exports_external.string(),
15005
+ displayName: exports_external.string(),
15006
+ platform: exports_external.string(),
15007
+ arch: exports_external.string(),
15008
+ osRelease: exports_external.string(),
15009
+ daemonVersion: exports_external.string(),
15010
+ lastSeenAt: exports_external.string().nullable(),
15011
+ status: exports_external.enum(["online", "offline"]),
15012
+ availableRuntimes: exports_external.array(CommunityMachineRuntimeSchema).default([]),
15013
+ lastRuntimeError: exports_external.object({
15014
+ requested: exports_external.string(),
15015
+ available: exports_external.array(exports_external.string()),
15016
+ at: exports_external.string()
15017
+ }).optional(),
15018
+ createdAt: exports_external.string(),
15019
+ updatedAt: exports_external.string()
15020
+ });
15021
+ var HostReadyMessageSchema = exports_external.object({
15022
+ type: exports_external.literal("ready"),
15023
+ runtimeReport: CommunityMachineRuntimeListSchema,
15024
+ runningAgents: exports_external.array(exports_external.string()).default([]),
15025
+ hostname: exports_external.string().optional(),
15026
+ platform: exports_external.string().optional(),
15027
+ arch: exports_external.string().optional(),
15028
+ osRelease: exports_external.string().optional(),
15029
+ daemonVersion: exports_external.string().optional()
15030
+ });
15031
+ var CommunityDaemonReadySchema = exports_external.object({
15032
+ runtimeReport: CommunityMachineRuntimeListSchema.optional(),
15033
+ runningAgents: exports_external.array(exports_external.string()).default([]),
15034
+ hostname: exports_external.string().optional(),
15035
+ os: exports_external.string().optional(),
15036
+ arch: exports_external.string().optional(),
15037
+ osRelease: exports_external.string().optional(),
15038
+ daemonVersion: exports_external.string().optional()
15039
+ });
15040
+ var SessionErrorFrameSchema = exports_external.object({
15041
+ type: exports_external.literal("session.error"),
15042
+ code: exports_external.enum(["runtime_not_available"]),
15043
+ agentId: exports_external.string().optional(),
15044
+ payload: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
15045
+ });
15046
+ var CommunityPairTokenResponseSchema = exports_external.object({
15047
+ tokenId: exports_external.string(),
15048
+ expiresAt: exports_external.string()
15049
+ });
15050
+ var CommunityDaemonActivateRequestSchema = exports_external.object({
15051
+ hostname: exports_external.string(),
15052
+ platform: exports_external.string(),
15053
+ arch: exports_external.string(),
15054
+ osRelease: exports_external.string().optional(),
15055
+ daemonVersion: exports_external.string().optional(),
15056
+ runtimeReport: CommunityMachineRuntimeListSchema.optional()
15057
+ });
15058
+ var CommunityDaemonActivateResponseSchema = exports_external.object({
15059
+ credential: exports_external.string(),
15060
+ machineId: exports_external.string(),
15061
+ expiresAt: exports_external.string().nullable()
15062
+ });
15063
+ var CommunityDaemonEnrollAgentRequestSchema = exports_external.object({
15064
+ agentId: exports_external.string().min(1).max(128)
15065
+ });
15066
+ var CommunityDaemonEnrollAgentResponseSchema = exports_external.object({
15067
+ runnerKey: exports_external.string(),
15068
+ expiresAt: exports_external.string().nullable()
15069
+ });
15070
+ var BotImageUrlSchema = exports_external.string().max(COMMUNITY_BOT_IMAGE_URL_MAX).refine((v) => v.startsWith("https://") || v.startsWith("avatar:"), {
15071
+ message: "image must be an https URL or an avatar: config"
15072
+ });
15073
+ var CommunityBotCreateRequestSchema = exports_external.object({
15074
+ name: exports_external.string().trim().min(COMMUNITY_BOT_NAME_MIN).max(COMMUNITY_BOT_NAME_MAX),
15075
+ description: exports_external.string().max(COMMUNITY_BOT_DESCRIPTION_MAX).optional(),
15076
+ machineId: exports_external.string().min(1),
15077
+ runtime: exports_external.string().min(1),
15078
+ image: BotImageUrlSchema.optional()
15079
+ });
15080
+ var CommunityBotPatchRequestSchema = exports_external.object({
15081
+ name: exports_external.string().trim().min(COMMUNITY_BOT_NAME_MIN).max(COMMUNITY_BOT_NAME_MAX).optional(),
15082
+ description: exports_external.string().max(COMMUNITY_BOT_DESCRIPTION_MAX).optional(),
15083
+ image: BotImageUrlSchema.nullable().optional()
15084
+ }).refine((v) => v.name !== undefined || v.description !== undefined || v.image !== undefined, {
15085
+ message: "at least one field must be provided"
15086
+ });
15087
+ var CommunityBotAddToServerRequestSchema = exports_external.object({
15088
+ botId: exports_external.string().min(1)
15089
+ });
15090
+ var CommunityDaemonSendAsBotRequestSchema = exports_external.object({
15091
+ target: exports_external.enum(["channel", "dm"]),
15092
+ targetId: exports_external.string().min(1),
15093
+ content: exports_external.string().max(4000),
15094
+ replyToId: exports_external.string().optional(),
15095
+ mentionType: exports_external.enum(["everyone", "here", "user"]).optional(),
15096
+ embeds: exports_external.array(exports_external.unknown()).optional(),
15097
+ attachments: exports_external.array(exports_external.unknown()).optional()
15098
+ });
15099
+ // ../../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
15100
  var entityKind = Symbol.for("drizzle:entityKind");
14939
15101
  var hasOwnEntityKind = Symbol.for("drizzle:hasOwnEntityKind");
14940
15102
  function is(value, type) {
@@ -14959,10 +15121,10 @@ function is(value, type) {
14959
15121
  return false;
14960
15122
  }
14961
15123
 
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
15124
+ // ../../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
14963
15125
  var TableName = Symbol.for("drizzle:Name");
14964
15126
 
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
15127
+ // ../../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
14966
15128
  var Schema = Symbol.for("drizzle:Schema");
14967
15129
  var Columns = Symbol.for("drizzle:Columns");
14968
15130
  var ExtraConfigColumns = Symbol.for("drizzle:ExtraConfigColumns");
@@ -15000,7 +15162,7 @@ class Table {
15000
15162
  }
15001
15163
  }
15002
15164
 
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
15165
+ // ../../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
15166
  class Column {
15005
15167
  constructor(table, config2) {
15006
15168
  this.table = table;
@@ -15050,7 +15212,7 @@ class Column {
15050
15212
  }
15051
15213
  }
15052
15214
 
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
15215
+ // ../../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
15216
  class ColumnBuilder {
15055
15217
  static [entityKind] = "ColumnBuilder";
15056
15218
  config;
@@ -15106,17 +15268,17 @@ class ColumnBuilder {
15106
15268
  }
15107
15269
  }
15108
15270
 
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
15271
+ // ../../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
15272
  function iife(fn, ...args) {
15111
15273
  return fn(...args);
15112
15274
  }
15113
15275
 
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
15276
+ // ../../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
15277
  function uniqueKeyName(table, columns) {
15116
15278
  return `${table[TableName]}_${columns.join("_")}_unique`;
15117
15279
  }
15118
15280
 
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
15281
+ // ../../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
15282
  class PgColumn extends Column {
15121
15283
  constructor(table, config2) {
15122
15284
  if (!config2.uniqueName) {
@@ -15165,7 +15327,7 @@ class ExtraConfigColumn extends PgColumn {
15165
15327
  }
15166
15328
  }
15167
15329
 
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
15330
+ // ../../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
15331
  class PgEnumObjectColumn extends PgColumn {
15170
15332
  static [entityKind] = "PgEnumObjectColumn";
15171
15333
  enum;
@@ -15195,7 +15357,7 @@ class PgEnumColumn extends PgColumn {
15195
15357
  }
15196
15358
  }
15197
15359
 
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
15360
+ // ../../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
15361
  class Subquery {
15200
15362
  static [entityKind] = "Subquery";
15201
15363
  constructor(sql, fields, alias, isWith = false, usedTables = []) {
@@ -15210,10 +15372,10 @@ class Subquery {
15210
15372
  }
15211
15373
  }
15212
15374
 
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
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/version.js
15214
15376
  var version2 = "0.45.2";
15215
15377
 
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
15378
+ // ../../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
15379
  var otel;
15218
15380
  var rawTracer;
15219
15381
  var tracer = {
@@ -15240,10 +15402,10 @@ var tracer = {
15240
15402
  }
15241
15403
  };
15242
15404
 
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
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/view-common.js
15244
15406
  var ViewBaseConfig = Symbol.for("drizzle:ViewBaseConfig");
15245
15407
 
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
15408
+ // ../../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
15409
  function isSQLWrapper(value) {
15248
15410
  return value !== null && value !== undefined && typeof value.getSQL === "function";
15249
15411
  }
@@ -15603,7 +15765,7 @@ Subquery.prototype.getSQL = function() {
15603
15765
  return new SQL([this]);
15604
15766
  };
15605
15767
 
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
15768
+ // ../../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
15769
  function getColumnNameAndConfig(a, b) {
15608
15770
  return {
15609
15771
  name: typeof a === "string" && a.length > 0 ? a : "",
@@ -15612,7 +15774,7 @@ function getColumnNameAndConfig(a, b) {
15612
15774
  }
15613
15775
  var textDecoder = typeof TextDecoder === "undefined" ? null : new TextDecoder;
15614
15776
 
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
15777
+ // ../../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
15778
  class ForeignKeyBuilder {
15617
15779
  static [entityKind] = "SQLiteForeignKeyBuilder";
15618
15780
  reference;
@@ -15680,7 +15842,7 @@ function foreignKey(config2) {
15680
15842
  return new ForeignKeyBuilder(mappedConfig);
15681
15843
  }
15682
15844
 
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
15845
+ // ../../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
15846
  function uniqueKeyName2(table, columns) {
15685
15847
  return `${table[TableName]}_${columns.join("_")}_unique`;
15686
15848
  }
@@ -15725,7 +15887,7 @@ class UniqueConstraint {
15725
15887
  }
15726
15888
  }
15727
15889
 
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
15890
+ // ../../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
15891
  class SQLiteColumnBuilder extends ColumnBuilder {
15730
15892
  static [entityKind] = "SQLiteColumnBuilder";
15731
15893
  foreignKeyConfigs = [];
@@ -15776,7 +15938,7 @@ class SQLiteColumn extends Column {
15776
15938
  static [entityKind] = "SQLiteColumn";
15777
15939
  }
15778
15940
 
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
15941
+ // ../../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
15942
  class SQLiteBigIntBuilder extends SQLiteColumnBuilder {
15781
15943
  static [entityKind] = "SQLiteBigIntBuilder";
15782
15944
  constructor(name) {
@@ -15864,7 +16026,7 @@ function blob(a, b) {
15864
16026
  return new SQLiteBlobBufferBuilder(name);
15865
16027
  }
15866
16028
 
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
16029
+ // ../../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
16030
  class SQLiteCustomColumnBuilder extends SQLiteColumnBuilder {
15869
16031
  static [entityKind] = "SQLiteCustomColumnBuilder";
15870
16032
  constructor(name, fieldConfig, customTypeParams) {
@@ -15905,7 +16067,7 @@ function customType(customTypeParams) {
15905
16067
  };
15906
16068
  }
15907
16069
 
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
16070
+ // ../../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
16071
  class SQLiteBaseIntegerBuilder extends SQLiteColumnBuilder {
15910
16072
  static [entityKind] = "SQLiteBaseIntegerBuilder";
15911
16073
  constructor(name, dataType, columnType) {
@@ -16007,7 +16169,7 @@ function integer2(a, b) {
16007
16169
  return new SQLiteIntegerBuilder(name);
16008
16170
  }
16009
16171
 
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
16172
+ // ../../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
16173
  class SQLiteNumericBuilder extends SQLiteColumnBuilder {
16012
16174
  static [entityKind] = "SQLiteNumericBuilder";
16013
16175
  constructor(name) {
@@ -16077,7 +16239,7 @@ function numeric(a, b) {
16077
16239
  return mode === "number" ? new SQLiteNumericNumberBuilder(name) : mode === "bigint" ? new SQLiteNumericBigIntBuilder(name) : new SQLiteNumericBuilder(name);
16078
16240
  }
16079
16241
 
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
16242
+ // ../../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
16243
  class SQLiteRealBuilder extends SQLiteColumnBuilder {
16082
16244
  static [entityKind] = "SQLiteRealBuilder";
16083
16245
  constructor(name) {
@@ -16098,7 +16260,7 @@ function real(name) {
16098
16260
  return new SQLiteRealBuilder(name ?? "");
16099
16261
  }
16100
16262
 
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
16263
+ // ../../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
16264
  class SQLiteTextBuilder extends SQLiteColumnBuilder {
16103
16265
  static [entityKind] = "SQLiteTextBuilder";
16104
16266
  constructor(name, config2) {
@@ -16153,7 +16315,7 @@ function text(a, b = {}) {
16153
16315
  return new SQLiteTextBuilder(name, config2);
16154
16316
  }
16155
16317
 
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
16318
+ // ../../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
16319
  function getSQLiteColumnBuilders() {
16158
16320
  return {
16159
16321
  blob,
@@ -16165,7 +16327,7 @@ function getSQLiteColumnBuilders() {
16165
16327
  };
16166
16328
  }
16167
16329
 
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
16330
+ // ../../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
16331
  var InlineForeignKeys = Symbol.for("drizzle:SQLiteInlineForeignKeys");
16170
16332
 
16171
16333
  class SQLiteTable extends Table {
@@ -16199,7 +16361,7 @@ var sqliteTable = (name, columns, extraConfig) => {
16199
16361
  return sqliteTableBase(name, columns, extraConfig);
16200
16362
  };
16201
16363
 
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
16364
+ // ../../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
16365
  class IndexBuilderOn {
16204
16366
  constructor(name, unique2) {
16205
16367
  this.name = name;
@@ -16241,8 +16403,11 @@ class Index {
16241
16403
  function index(name) {
16242
16404
  return new IndexBuilderOn(name, false);
16243
16405
  }
16406
+ function uniqueIndex(name) {
16407
+ return new IndexBuilderOn(name, true);
16408
+ }
16244
16409
 
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
16410
+ // ../../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
16411
  function primaryKey(...config2) {
16247
16412
  if (config2[0].columns) {
16248
16413
  return new PrimaryKeyBuilder(config2[0].columns, config2[0].name);
@@ -16277,44 +16442,45 @@ class PrimaryKey {
16277
16442
  }
16278
16443
  }
16279
16444
 
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
- }
16316
-
16317
16445
  // ../shared/src/db/schema.ts
16446
+ var exports_schema = {};
16447
+ __export(exports_schema, {
16448
+ workspaceInvite: () => workspaceInvite,
16449
+ workspaceFileRequest: () => workspaceFileRequest,
16450
+ workspace: () => workspace,
16451
+ verification: () => verification,
16452
+ user: () => user,
16453
+ taskMessage: () => taskMessage,
16454
+ session: () => session,
16455
+ messageFlag: () => messageFlag,
16456
+ message: () => message,
16457
+ member: () => member,
16458
+ meetingSession: () => meetingSession,
16459
+ machineToken: () => machineToken,
16460
+ machine: () => machine,
16461
+ issueComment: () => issueComment,
16462
+ issue: () => issue2,
16463
+ inboxUnread: () => inboxUnread,
16464
+ emails: () => emails,
16465
+ conversationReadState: () => conversationReadState,
16466
+ conversationMap: () => conversationMap,
16467
+ conversation: () => conversation,
16468
+ channel: () => channel,
16469
+ calendarEvent: () => calendarEvent,
16470
+ artifact: () => artifact,
16471
+ agentWhitelist: () => agentWhitelist,
16472
+ agentTaskQueue: () => agentTaskQueue,
16473
+ agentSkill: () => agentSkill,
16474
+ agentSidebarOrder: () => agentSidebarOrder,
16475
+ agentRuntime: () => agentRuntime,
16476
+ agentPin: () => agentPin,
16477
+ agentLink: () => agentLink,
16478
+ agentEmailAccount: () => agentEmailAccount,
16479
+ agentAccess: () => agentAccess,
16480
+ agent: () => agent,
16481
+ account: () => account
16482
+ });
16483
+ init_nanoid();
16318
16484
  var user = sqliteTable("user", {
16319
16485
  id: text("id").primaryKey().$defaultFn(() => nanoid3()),
16320
16486
  name: text("name").notNull().default(""),
@@ -16322,8 +16488,12 @@ var user = sqliteTable("user", {
16322
16488
  emailVerified: integer2("emailVerified", { mode: "boolean" }),
16323
16489
  image: text("image"),
16324
16490
  createdAt: text("createdAt").notNull().$defaultFn(() => new Date().toISOString()),
16325
- updatedAt: text("updatedAt").notNull().$defaultFn(() => new Date().toISOString())
16326
- });
16491
+ updatedAt: text("updatedAt").notNull().$defaultFn(() => new Date().toISOString()),
16492
+ isBot: integer2("isBot", { mode: "boolean" }).notNull().default(false),
16493
+ ownerUserId: text("ownerUserId"),
16494
+ deletedAt: text("deletedAt"),
16495
+ discriminator: text("discriminator").notNull().default("0000")
16496
+ }, (t) => [index("idx_user_ownerUserId_isBot").on(t.ownerUserId, t.isBot)]);
16327
16497
  var session = sqliteTable("session", {
16328
16498
  id: text("id").primaryKey().$defaultFn(() => nanoid3()),
16329
16499
  userId: text("userId").notNull().references(() => user.id, { onDelete: "cascade" }),
@@ -16859,6 +17029,353 @@ var inboxUnread = sqliteTable("inbox_unread", {
16859
17029
  unique("inbox_unread_conv_user").on(t.conversationId, t.userId),
16860
17030
  index("idx_inbox_unread_user_ws").on(t.userId, t.workspaceId, t.taskType, t.completedAt)
16861
17031
  ]);
17032
+
17033
+ // ../shared/src/db/community-schema.ts
17034
+ var exports_community_schema = {};
17035
+ __export(exports_community_schema, {
17036
+ communityUserProfile: () => communityUserProfile,
17037
+ communityServerMember: () => communityServerMember,
17038
+ communityServerInvite: () => communityServerInvite,
17039
+ communityServerFolderItem: () => communityServerFolderItem,
17040
+ communityServerFolder: () => communityServerFolder,
17041
+ communityServer: () => communityServer,
17042
+ communityReadState: () => communityReadState,
17043
+ communityReaction: () => communityReaction,
17044
+ communityPin: () => communityPin,
17045
+ communityNotificationSetting: () => communityNotificationSetting,
17046
+ communityMessage: () => communityMessage,
17047
+ communityMention: () => communityMention,
17048
+ communityInboxDismissal: () => communityInboxDismissal,
17049
+ communityFriendship: () => communityFriendship,
17050
+ communityDmConversation: () => communityDmConversation,
17051
+ communityChannel: () => communityChannel,
17052
+ communityCategory: () => communityCategory,
17053
+ communityBotApprovalRequest: () => communityBotApprovalRequest,
17054
+ communityAuditLog: () => communityAuditLog,
17055
+ communityAttachment: () => communityAttachment
17056
+ });
17057
+ init_nanoid();
17058
+ var communityServer = sqliteTable("community_server", {
17059
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17060
+ name: text("name").notNull(),
17061
+ description: text("description").default(""),
17062
+ icon: text("icon"),
17063
+ ownerId: text("owner_id").notNull().references(() => user.id, { onDelete: "restrict" }),
17064
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17065
+ });
17066
+ var communityCategory = sqliteTable("community_category", {
17067
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17068
+ serverId: text("server_id").notNull().references(() => communityServer.id, { onDelete: "cascade" }),
17069
+ name: text("name").notNull(),
17070
+ position: integer2("position").default(0),
17071
+ private: integer2("private").default(0),
17072
+ creatorId: text("creator_id").references(() => user.id, { onDelete: "set null" })
17073
+ }, (t) => [unique("uq_category_server_name").on(t.serverId, t.name)]);
17074
+ var communityChannel = sqliteTable("community_channel", {
17075
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17076
+ serverId: text("server_id").notNull().references(() => communityServer.id, { onDelete: "cascade" }),
17077
+ categoryId: text("category_id").references(() => communityCategory.id, {
17078
+ onDelete: "set null"
17079
+ }),
17080
+ name: text("name").notNull(),
17081
+ type: text("type").notNull().default("text"),
17082
+ topic: text("topic").default(""),
17083
+ position: integer2("position").default(0),
17084
+ forumTags: text("forum_tags"),
17085
+ parentChannelId: text("parent_channel_id").references(() => communityChannel.id, {
17086
+ onDelete: "cascade"
17087
+ }),
17088
+ creatorId: text("creator_id").references(() => user.id, { onDelete: "set null" }),
17089
+ messageCount: integer2("message_count").default(0),
17090
+ archived: integer2("archived").default(0),
17091
+ parentMessageId: text("parent_message_id"),
17092
+ lastMessageAt: text("last_message_at"),
17093
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17094
+ }, (t) => [
17095
+ index("idx_channel_server_position").on(t.serverId, t.position),
17096
+ index("idx_channel_server_last_message").on(t.serverId, t.lastMessageAt),
17097
+ index("idx_channel_parent").on(t.parentChannelId)
17098
+ ]);
17099
+ var communityDmConversation = sqliteTable("community_dm_conversation", {
17100
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17101
+ user1Id: text("user1_id").references(() => user.id, { onDelete: "set null" }),
17102
+ user2Id: text("user2_id").references(() => user.id, { onDelete: "set null" }),
17103
+ lastMessageAt: text("last_message_at"),
17104
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17105
+ }, (t) => [
17106
+ unique("uq_dm_conversation_users").on(t.user1Id, t.user2Id),
17107
+ index("idx_dm_conversation_user1_last_message").on(t.user1Id, t.lastMessageAt),
17108
+ index("idx_dm_conversation_user2_last_message").on(t.user2Id, t.lastMessageAt)
17109
+ ]);
17110
+ var communityMessage = sqliteTable("community_message", {
17111
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17112
+ authorId: text("author_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17113
+ content: text("content").notNull().default(""),
17114
+ type: text("type").notNull().default("default"),
17115
+ mentionType: text("mention_type"),
17116
+ replyToId: text("reply_to_id"),
17117
+ embeds: text("embeds"),
17118
+ flags: integer2("flags").default(0),
17119
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17120
+ channelId: text("channel_id").references(() => communityChannel.id, {
17121
+ onDelete: "cascade"
17122
+ }),
17123
+ dmConversationId: text("dm_conversation_id").references(() => communityDmConversation.id, { onDelete: "cascade" })
17124
+ }, (t) => [
17125
+ index("idx_message_channel_created").on(t.channelId, t.createdAt),
17126
+ index("idx_message_channel_mention_created").on(t.channelId, t.mentionType, t.createdAt),
17127
+ index("idx_message_dm_created").on(t.dmConversationId, t.createdAt)
17128
+ ]);
17129
+ var communityServerMember = sqliteTable("community_server_member", {
17130
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17131
+ serverId: text("server_id").notNull().references(() => communityServer.id, { onDelete: "cascade" }),
17132
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17133
+ role: text("role").default("member"),
17134
+ nickname: text("nickname"),
17135
+ railOrder: integer2("rail_order").default(0),
17136
+ joinedAt: text("joined_at").notNull().$defaultFn(() => new Date().toISOString())
17137
+ }, (t) => [
17138
+ unique("uq_server_member_server_user").on(t.serverId, t.userId),
17139
+ index("idx_server_member_user").on(t.userId),
17140
+ index("idx_server_member_user_rail_order").on(t.userId, t.railOrder)
17141
+ ]);
17142
+ var communityServerFolder = sqliteTable("community_server_folder", {
17143
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17144
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17145
+ name: text("name").notNull(),
17146
+ position: integer2("position").default(0)
17147
+ }, (t) => [index("idx_server_folder_user_position").on(t.userId, t.position)]);
17148
+ var communityServerFolderItem = sqliteTable("community_server_folder_item", {
17149
+ folderId: text("folder_id").notNull().references(() => communityServerFolder.id, { onDelete: "cascade" }),
17150
+ serverId: text("server_id").notNull().references(() => communityServer.id, { onDelete: "cascade" }),
17151
+ position: integer2("position").default(0)
17152
+ }, (t) => [
17153
+ primaryKey({ columns: [t.folderId, t.serverId] }),
17154
+ index("idx_server_folder_item_folder_position").on(t.folderId, t.position)
17155
+ ]);
17156
+ var communityServerInvite = sqliteTable("community_server_invite", {
17157
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17158
+ serverId: text("server_id").notNull().references(() => communityServer.id, { onDelete: "cascade" }),
17159
+ createdBy: text("created_by").references(() => user.id, { onDelete: "set null" }),
17160
+ token: text("token").unique().notNull().$defaultFn(() => nanoid3(10)),
17161
+ maxUses: integer2("max_uses"),
17162
+ uses: integer2("uses").default(0),
17163
+ expiresAt: text("expires_at"),
17164
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17165
+ });
17166
+ var communityFriendship = sqliteTable("community_friendship", {
17167
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17168
+ requesterId: text("requester_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17169
+ addresseeId: text("addressee_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17170
+ status: text("status").notNull().default("pending"),
17171
+ blockerId: text("blocker_id"),
17172
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17173
+ updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString())
17174
+ }, (t) => [
17175
+ unique("uq_friendship_requester_addressee").on(t.requesterId, t.addresseeId),
17176
+ index("idx_friendship_addressee_status").on(t.addresseeId, t.status),
17177
+ index("idx_friendship_requester_status").on(t.requesterId, t.status)
17178
+ ]);
17179
+ var communityReadState = sqliteTable("community_read_state", {
17180
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17181
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17182
+ channelId: text("channel_id").references(() => communityChannel.id, {
17183
+ onDelete: "cascade"
17184
+ }),
17185
+ dmConversationId: text("dm_conversation_id").references(() => communityDmConversation.id, { onDelete: "cascade" }),
17186
+ lastReadAt: text("last_read_at").notNull(),
17187
+ lastReadMessageId: text("last_read_message_id")
17188
+ }, (t) => [index("idx_read_state_user").on(t.userId)]);
17189
+ var communityReaction = sqliteTable("community_reaction", {
17190
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17191
+ messageId: text("message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
17192
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17193
+ emoji: text("emoji").notNull(),
17194
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17195
+ }, (t) => [
17196
+ unique("uq_reaction_message_user_emoji").on(t.messageId, t.userId, t.emoji),
17197
+ index("idx_reaction_message").on(t.messageId)
17198
+ ]);
17199
+ var communityAttachment = sqliteTable("community_attachment", {
17200
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17201
+ messageId: text("message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
17202
+ filename: text("filename").notNull(),
17203
+ url: text("url").notNull(),
17204
+ contentType: text("content_type"),
17205
+ size: integer2("size"),
17206
+ width: integer2("width"),
17207
+ height: integer2("height"),
17208
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17209
+ }, (t) => [index("idx_attachment_message").on(t.messageId)]);
17210
+ var communityPin = sqliteTable("community_pin", {
17211
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17212
+ channelId: text("channel_id").notNull().references(() => communityChannel.id, { onDelete: "cascade" }),
17213
+ messageId: text("message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
17214
+ pinnedBy: text("pinned_by").references(() => user.id, { onDelete: "set null" }),
17215
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17216
+ }, (t) => [
17217
+ unique("uq_pin_channel_message").on(t.channelId, t.messageId),
17218
+ index("idx_pin_channel").on(t.channelId)
17219
+ ]);
17220
+ var communityMention = sqliteTable("community_mention", {
17221
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17222
+ messageId: text("message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
17223
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17224
+ kind: text("kind").notNull().default("mention"),
17225
+ read: integer2("read").default(0)
17226
+ }, (t) => [
17227
+ index("idx_mention_user_read").on(t.userId, t.read),
17228
+ index("idx_mention_message").on(t.messageId)
17229
+ ]);
17230
+ var communityUserProfile = sqliteTable("community_user_profile", {
17231
+ userId: text("user_id").primaryKey().references(() => user.id, { onDelete: "cascade" }),
17232
+ aboutMe: text("about_me").default(""),
17233
+ bannerColor: text("banner_color")
17234
+ });
17235
+ var communityNotificationSetting = sqliteTable("community_notification_setting", {
17236
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17237
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17238
+ serverId: text("server_id").references(() => communityServer.id, {
17239
+ onDelete: "cascade"
17240
+ }),
17241
+ channelId: text("channel_id").references(() => communityChannel.id, {
17242
+ onDelete: "cascade"
17243
+ }),
17244
+ level: text("level").notNull().default("all")
17245
+ }, (t) => [index("idx_notification_setting_user").on(t.userId)]);
17246
+ var communityAuditLog = sqliteTable("community_audit_log", {
17247
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17248
+ serverId: text("server_id").references(() => communityServer.id, {
17249
+ onDelete: "cascade"
17250
+ }),
17251
+ actorId: text("actor_id").references(() => user.id, { onDelete: "set null" }),
17252
+ action: text("action").notNull(),
17253
+ targetType: text("target_type").notNull(),
17254
+ targetId: text("target_id").notNull(),
17255
+ changes: text("changes"),
17256
+ reason: text("reason"),
17257
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17258
+ }, (t) => [
17259
+ index("idx_audit_log_server_created").on(t.serverId, t.createdAt),
17260
+ index("idx_audit_log_server_action").on(t.serverId, t.action),
17261
+ index("idx_audit_log_actor_created").on(t.actorId, t.createdAt)
17262
+ ]);
17263
+ var communityBotApprovalRequest = sqliteTable("community_bot_approval_request", {
17264
+ id: text("id").primaryKey().$defaultFn(() => "bar_" + nanoid3()),
17265
+ botId: text("bot_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17266
+ kind: text("kind").notNull(),
17267
+ serverId: text("server_id").references(() => communityServer.id, {
17268
+ onDelete: "cascade"
17269
+ }),
17270
+ requestedByUserId: text("requested_by_user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17271
+ dmMessageId: text("dm_message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
17272
+ status: text("status").notNull().default("pending"),
17273
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17274
+ resolvedAt: text("resolved_at")
17275
+ }, (t) => [index("idx_community_bot_approval_bot").on(t.botId, t.status)]);
17276
+ var communityInboxDismissal = sqliteTable("community_inbox_dismissal", {
17277
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17278
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17279
+ eventKey: text("event_key").notNull(),
17280
+ dismissedAt: text("dismissed_at").notNull().$defaultFn(() => new Date().toISOString())
17281
+ }, (t) => [
17282
+ unique("uq_inbox_dismissal_user_event").on(t.userId, t.eventKey),
17283
+ index("idx_inbox_dismissal_user").on(t.userId)
17284
+ ]);
17285
+
17286
+ // ../shared/src/db/community-machine-schema.ts
17287
+ var exports_community_machine_schema = {};
17288
+ __export(exports_community_machine_schema, {
17289
+ communityMachineToken: () => communityMachineToken,
17290
+ communityMachineCredential: () => communityMachineCredential,
17291
+ communityMachine: () => communityMachine,
17292
+ communityBotBinding: () => communityBotBinding,
17293
+ communityAgentRunnerKey: () => communityAgentRunnerKey
17294
+ });
17295
+ init_nanoid();
17296
+ var communityMachineToken = sqliteTable("community_machine_token", {
17297
+ id: text("id").primaryKey().$defaultFn(() => "cmt_" + nanoid3(32)),
17298
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17299
+ machineId: text("machine_id"),
17300
+ status: text("status").notNull().default("pending"),
17301
+ expiresAt: text("expires_at").notNull(),
17302
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17303
+ lastUsedAt: text("last_used_at")
17304
+ }, (t) => [
17305
+ index("idx_community_machine_token_user_status").on(t.userId, t.status),
17306
+ uniqueIndex("uq_community_machine_token_user_pending").on(t.userId).where(sql`status = 'pending'`)
17307
+ ]);
17308
+ var communityMachine = sqliteTable("community_machine", {
17309
+ id: text("id").primaryKey().$defaultFn(() => "cm_" + nanoid3()),
17310
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17311
+ displayName: text("display_name").notNull().default(""),
17312
+ hostname: text("hostname").notNull().default(""),
17313
+ platform: text("platform").notNull().default(""),
17314
+ arch: text("arch").notNull().default(""),
17315
+ osRelease: text("os_release").notNull().default(""),
17316
+ daemonVersion: text("daemon_version").notNull().default(""),
17317
+ metadata: text("metadata"),
17318
+ availableRuntimes: text("available_runtimes", { mode: "json" }).$type().notNull().default([]),
17319
+ status: text("status").notNull().default("offline"),
17320
+ lastSeenAt: text("last_seen_at"),
17321
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17322
+ updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString())
17323
+ }, (t) => [
17324
+ index("idx_community_machine_user_last_seen").on(t.userId, t.lastSeenAt),
17325
+ index("idx_community_machine_user_updated").on(t.userId, t.updatedAt),
17326
+ index("idx_community_machine_user_status").on(t.userId, t.status)
17327
+ ]);
17328
+ var communityMachineCredential = sqliteTable("community_machine_credential", {
17329
+ id: text("id").primaryKey().$defaultFn(() => "cmkid_" + nanoid3()),
17330
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17331
+ machineId: text("machine_id").notNull().references(() => communityMachine.id, { onDelete: "cascade" }),
17332
+ credentialHash: text("credential_hash").notNull().unique(),
17333
+ doName: text("do_name").notNull().unique(),
17334
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17335
+ lastUsedAt: text("last_used_at"),
17336
+ revokedAt: text("revoked_at")
17337
+ }, (t) => [
17338
+ index("idx_community_machine_credential_user").on(t.userId),
17339
+ index("idx_community_machine_credential_machine").on(t.machineId)
17340
+ ]);
17341
+ var communityBotBinding = sqliteTable("community_bot_binding", {
17342
+ userId: text("user_id").primaryKey().references(() => user.id, { onDelete: "cascade" }),
17343
+ machineId: text("machine_id").notNull().references(() => communityMachine.id, { onDelete: "restrict" }),
17344
+ runtime: text("runtime").notNull(),
17345
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17346
+ }, (t) => [index("idx_community_bot_binding_machine").on(t.machineId)]);
17347
+ var communityAgentRunnerKey = sqliteTable("community_agent_runner_key", {
17348
+ id: text("id").primaryKey().$defaultFn(() => "crkid_" + nanoid3()),
17349
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17350
+ machineId: text("machine_id").notNull().references(() => communityMachine.id, { onDelete: "cascade" }),
17351
+ agentId: text("agent_id").notNull(),
17352
+ runnerKeyHash: text("runner_key_hash").notNull().unique(),
17353
+ doName: text("do_name").notNull().unique(),
17354
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17355
+ revokedAt: text("revoked_at")
17356
+ }, (t) => [
17357
+ index("idx_community_agent_runner_key_machine_agent").on(t.machineId, t.agentId)
17358
+ ]);
17359
+
17360
+ // ../shared/src/db/index.ts
17361
+ var allSchema = { ...exports_schema, ...exports_community_schema, ...exports_community_machine_schema };
17362
+ // ../shared/src/db/queries/user.ts
17363
+ var publicUserColumns = {
17364
+ id: user.id,
17365
+ name: user.name,
17366
+ email: user.email,
17367
+ emailVerified: user.emailVerified,
17368
+ image: user.image,
17369
+ createdAt: user.createdAt,
17370
+ updatedAt: user.updatedAt,
17371
+ discriminator: user.discriminator
17372
+ };
17373
+ var internalUserColumns = {
17374
+ ...publicUserColumns,
17375
+ isBot: user.isBot,
17376
+ ownerUserId: user.ownerUserId,
17377
+ deletedAt: user.deletedAt
17378
+ };
16862
17379
  // ../shared/src/db/queries/task.ts
16863
17380
  var DEFAULT_STALE_SECONDS = Number(process.env.ALOOK_STALE_DISPATCH_TIMEOUT_S) || 20;
16864
17381
  var DEFAULT_STALE_RUNNING_SECONDS = Number(process.env.ALOOK_STALE_RUNNING_TIMEOUT_S) || 3600;
@@ -16884,6 +17401,109 @@ var RESERVED_HANDLES = new Set([
16884
17401
  function toAlookAddress(h) {
16885
17402
  return `${h}${DOMAIN}`;
16886
17403
  }
17404
+ // ../shared/src/logger.ts
17405
+ var LEVELS = {
17406
+ debug: 0,
17407
+ info: 1,
17408
+ warn: 2,
17409
+ error: 3,
17410
+ silent: 4
17411
+ };
17412
+
17413
+ class Logger {
17414
+ service;
17415
+ level;
17416
+ pretty;
17417
+ fields;
17418
+ constructor(opts, fields) {
17419
+ this.service = opts.service;
17420
+ this.level = LEVELS[opts.level ?? "info"];
17421
+ this.pretty = opts.pretty ?? false;
17422
+ this.fields = fields ?? {};
17423
+ }
17424
+ debug(msg, ctx) {
17425
+ this.write("debug", msg, ctx);
17426
+ }
17427
+ info(msg, ctx) {
17428
+ this.write("info", msg, ctx);
17429
+ }
17430
+ warn(msg, ctx) {
17431
+ this.write("warn", msg, ctx);
17432
+ }
17433
+ error(msg, ctx) {
17434
+ this.write("error", msg, ctx);
17435
+ }
17436
+ child(fields) {
17437
+ const merged = { ...this.fields, ...fields };
17438
+ const child = new Logger({ service: this.service, level: this.levelName(), pretty: this.pretty }, merged);
17439
+ return child;
17440
+ }
17441
+ levelName() {
17442
+ for (const [name, num] of Object.entries(LEVELS)) {
17443
+ if (num === this.level)
17444
+ return name;
17445
+ }
17446
+ return "info";
17447
+ }
17448
+ write(level, msg, ctx) {
17449
+ if (LEVELS[level] < this.level)
17450
+ return;
17451
+ const entry = {
17452
+ level,
17453
+ msg,
17454
+ service: this.service,
17455
+ ...this.fields,
17456
+ ...ctx,
17457
+ ts: new Date().toISOString()
17458
+ };
17459
+ for (const [k, v] of Object.entries(entry)) {
17460
+ if (v instanceof Error) {
17461
+ entry[k] = { message: v.message, stack: v.stack };
17462
+ }
17463
+ }
17464
+ let line;
17465
+ if (this.pretty) {
17466
+ const ts = entry.ts.replace("T", " ").replace("Z", "");
17467
+ const lvl = entry.level.toUpperCase().padEnd(5);
17468
+ 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(" ");
17469
+ line = `${ts} ${lvl} [${entry.service}] ${entry.msg}${pairs ? " " + pairs : ""}`;
17470
+ } else {
17471
+ line = JSON.stringify(entry);
17472
+ }
17473
+ if (level === "error") {
17474
+ console.error(line);
17475
+ } else {
17476
+ console.log(line);
17477
+ }
17478
+ }
17479
+ }
17480
+ function createLogger(opts) {
17481
+ return new Logger(opts);
17482
+ }
17483
+
17484
+ // ../shared/src/db/queries/community/channel.ts
17485
+ var log = createLogger({ service: "community-queries" });
17486
+ var CHANNEL_COLUMNS = {
17487
+ id: communityChannel.id,
17488
+ serverId: communityChannel.serverId,
17489
+ categoryId: communityChannel.categoryId,
17490
+ name: communityChannel.name,
17491
+ type: communityChannel.type,
17492
+ topic: communityChannel.topic,
17493
+ position: communityChannel.position,
17494
+ forumTags: communityChannel.forumTags,
17495
+ parentChannelId: communityChannel.parentChannelId,
17496
+ creatorId: communityChannel.creatorId,
17497
+ messageCount: communityChannel.messageCount,
17498
+ archived: communityChannel.archived,
17499
+ parentMessageId: communityChannel.parentMessageId,
17500
+ lastMessageAt: communityChannel.lastMessageAt,
17501
+ createdAt: communityChannel.createdAt
17502
+ };
17503
+ // ../shared/src/db/queries/community/message.ts
17504
+ var log2 = createLogger({ service: "community-queries" });
17505
+ // ../shared/src/db/queries/community/search.ts
17506
+ var FTS_KEYWORDS = new Set(["and", "or", "not", "near"]);
16887
17507
  // ../shared/src/semver.ts
16888
17508
  function semverGte(a, b) {
16889
17509
  const pa = a.split(".").map(Number);
@@ -16978,7 +17598,7 @@ function cmdPrefix() {
16978
17598
  // lib/activate.ts
16979
17599
  import { hostname as hostname4 } from "os";
16980
17600
  import { spawn as spawn6 } from "child_process";
16981
- import { openSync as openSync2, closeSync as closeSync2, mkdirSync as mkdirSync9 } from "fs";
17601
+ import { openSync as openSync2, closeSync as closeSync2, mkdirSync as mkdirSync10 } from "fs";
16982
17602
  import { dirname as dirname4 } from "path";
16983
17603
 
16984
17604
  // lib/config.ts
@@ -17138,6 +17758,7 @@ function loadDaemonConfig(profile) {
17138
17758
  agentTimeout: parseDuration(process.env.ALOOK_AGENT_TIMEOUT || "12h"),
17139
17759
  messageInactivityTimeout: parseDuration(process.env.ALOOK_MESSAGE_INACTIVITY_TIMEOUT || "20m"),
17140
17760
  maxConcurrentTasks: parseInt(process.env.ALOOK_DAEMON_MAX_CONCURRENT_TASKS || "20"),
17761
+ enableSteering: process.env.ALOOK_ENABLE_STEERING === "1",
17141
17762
  daemonId,
17142
17763
  deviceName: process.env.ALOOK_DAEMON_DEVICE_NAME || h,
17143
17764
  workspacesRoot,
@@ -17149,7 +17770,7 @@ function normalizeServerBaseURL(url2) {
17149
17770
  }
17150
17771
 
17151
17772
  // lib/logger.ts
17152
- var LEVELS = {
17773
+ var LEVELS2 = {
17153
17774
  debug: 0,
17154
17775
  info: 1,
17155
17776
  warn: 2,
@@ -17195,12 +17816,12 @@ class Logger2 {
17195
17816
  module;
17196
17817
  constructor(opts = {}) {
17197
17818
  const envLevel = process.env.ALOOK_LOG_LEVEL;
17198
- this.level = LEVELS[opts.level ?? envLevel ?? "info"];
17819
+ this.level = LEVELS2[opts.level ?? envLevel ?? "info"];
17199
17820
  this.color = useColor();
17200
17821
  this.module = opts.module;
17201
17822
  }
17202
17823
  setLevel(level) {
17203
- this.level = LEVELS[level];
17824
+ this.level = LEVELS2[level];
17204
17825
  }
17205
17826
  child(module) {
17206
17827
  const child = new Logger2({ level: this.levelName(), module });
@@ -17219,14 +17840,14 @@ class Logger2 {
17219
17840
  this.write("error", msg, args);
17220
17841
  }
17221
17842
  levelName() {
17222
- for (const [name, num] of Object.entries(LEVELS)) {
17843
+ for (const [name, num] of Object.entries(LEVELS2)) {
17223
17844
  if (num === this.level)
17224
17845
  return name;
17225
17846
  }
17226
17847
  return "info";
17227
17848
  }
17228
17849
  write(level, msg, args) {
17229
- if (LEVELS[level] < this.level)
17850
+ if (LEVELS2[level] < this.level)
17230
17851
  return;
17231
17852
  const ts = timestamp();
17232
17853
  const label = LABELS[level];
@@ -17247,7 +17868,7 @@ class Logger2 {
17247
17868
  if (a instanceof Error) {
17248
17869
  dest.write(` ${a.message}
17249
17870
  `);
17250
- if (a.stack && this.level <= LEVELS.debug) {
17871
+ if (a.stack && this.level <= LEVELS2.debug) {
17251
17872
  dest.write(` ${a.stack}
17252
17873
  `);
17253
17874
  }
@@ -17266,10 +17887,10 @@ class Logger2 {
17266
17887
  function createLogger2(opts) {
17267
17888
  return new Logger2(opts);
17268
17889
  }
17269
- var log = createLogger2();
17890
+ var log3 = createLogger2();
17270
17891
 
17271
17892
  // daemon/pidfile.ts
17272
- var log2 = createLogger2({ module: "pidfile" });
17893
+ var log4 = createLogger2({ module: "pidfile" });
17273
17894
  function isProcessAlive(pid) {
17274
17895
  try {
17275
17896
  process.kill(pid, 0);
@@ -17293,7 +17914,7 @@ function acquireDaemonPid(profile) {
17293
17914
  const content = readFileSync3(pidPath, "utf-8").trim();
17294
17915
  const existingPid = parseInt(content, 10);
17295
17916
  if (!isNaN(existingPid) && isProcessAlive(existingPid)) {
17296
- log2.error(`Another daemon is already running (PID ${existingPid}). ` + `Remove ${pidPath} if this is stale.`);
17917
+ log4.error(`Another daemon is already running (PID ${existingPid}). ` + `Remove ${pidPath} if this is stale.`);
17297
17918
  return false;
17298
17919
  }
17299
17920
  } catch {}
@@ -17471,7 +18092,7 @@ import { createInterface } from "readline";
17471
18092
 
17472
18093
  // daemon/kill-tree.ts
17473
18094
  import { execSync } from "child_process";
17474
- var log3 = createLogger2({ module: "kill-tree" });
18095
+ var log5 = createLogger2({ module: "kill-tree" });
17475
18096
  function killGraceMs() {
17476
18097
  return Number(process.env.ALOOK_KILL_GRACE_MS) || 2000;
17477
18098
  }
@@ -17525,7 +18146,7 @@ async function killProcessTree(pid, opts) {
17525
18146
  await new Promise((r) => setTimeout(r, POLL_MS));
17526
18147
  }
17527
18148
  if (isAlive(pid)) {
17528
- log3.warn(`pid=${pid} survived SIGTERM after ${graceMs}ms — escalating to SIGKILL`);
18149
+ log5.warn(`pid=${pid} survived SIGTERM after ${graceMs}ms — escalating to SIGKILL`);
17529
18150
  signalTree(pid, "SIGKILL");
17530
18151
  }
17531
18152
  }
@@ -17534,41 +18155,157 @@ async function killProcessTree(pid, opts) {
17534
18155
  class ClaudeBackend {
17535
18156
  cliPath;
17536
18157
  name = "claude";
18158
+ lifecycle = { kind: "persistent", stdin: "gated", inFlightWake: "queue" };
18159
+ busyDeliveryMode = "gated";
18160
+ supportsStdinNotification = true;
17537
18161
  constructor(cliPath) {
17538
18162
  this.cliPath = cliPath;
17539
18163
  }
17540
- execute(prompt, options) {
17541
- const args = [
17542
- "-p",
17543
- prompt,
17544
- "--output-format",
17545
- "stream-json",
17546
- "--verbose",
17547
- "--permission-mode",
17548
- "bypassPermissions"
17549
- ];
17550
- if (options.model) {
17551
- args.push("--model", options.model);
17552
- }
17553
- if (options.maxTurns) {
17554
- args.push("--max-turns", String(options.maxTurns));
17555
- }
17556
- if (options.resumeSessionId) {
17557
- args.push("--resume", options.resumeSessionId);
17558
- }
17559
- const proc = spawn(this.cliPath, args, {
17560
- cwd: options.cwd,
17561
- stdio: ["pipe", "pipe", "pipe"],
17562
- env: { ...process.env, ...options.env },
17563
- shell: process.platform === "win32",
17564
- windowsHide: true,
17565
- detached: process.platform !== "win32"
17566
- });
17567
- if (!proc.pid) {
17568
- const error51 = `Failed to start ${this.cliPath}: binary not found or not executable. Is 'claude' installed and on PATH?`;
17569
- const failedResult = { status: "failed", output: "", error: error51, durationMs: 0, sessionId: "" };
17570
- const emptyMessages = { [Symbol.asyncIterator]() {
17571
- return { async next() {
18164
+ parseLine(line) {
18165
+ if (!line.trim())
18166
+ return [];
18167
+ let event;
18168
+ try {
18169
+ event = JSON.parse(line);
18170
+ } catch {
18171
+ return [{ kind: "log", content: line, level: "debug" }];
18172
+ }
18173
+ const events = [];
18174
+ const eventType = event.type;
18175
+ switch (eventType) {
18176
+ case "assistant": {
18177
+ const message2 = event.message;
18178
+ if (!message2)
18179
+ break;
18180
+ const content = message2.content;
18181
+ if (!Array.isArray(content))
18182
+ break;
18183
+ for (const block of content) {
18184
+ if (block.type === "text") {
18185
+ events.push({ kind: "text", text: block.text || "" });
18186
+ } else if (block.type === "thinking") {
18187
+ events.push({ kind: "thinking", text: block.text || "" });
18188
+ } else if (block.type === "tool_use") {
18189
+ events.push({ kind: "tool_call", name: block.name || "", input: block.input, callId: block.id });
18190
+ }
18191
+ }
18192
+ break;
18193
+ }
18194
+ case "result": {
18195
+ const result = event.result;
18196
+ const isError = event.is_error;
18197
+ if (isError) {
18198
+ events.push({ kind: "error", message: result || "unknown error" });
18199
+ }
18200
+ const resultSessionId = event.session_id;
18201
+ events.push({ kind: "turn_end", sessionId: resultSessionId || undefined });
18202
+ const usage = event.usage;
18203
+ if (usage || event.total_cost_usd != null) {
18204
+ events.push({
18205
+ kind: "telemetry",
18206
+ name: "token_usage",
18207
+ source: "claude_result_usage",
18208
+ usageKind: "per_turn",
18209
+ attrs: {
18210
+ inputTokens: usage?.input_tokens,
18211
+ outputTokens: usage?.output_tokens,
18212
+ cachedInputTokens: usage?.cache_read_input_tokens,
18213
+ cacheCreationInputTokens: usage?.cache_creation_input_tokens,
18214
+ totalCostUsd: event.total_cost_usd,
18215
+ durationMs: event.duration_ms,
18216
+ durationApiMs: event.duration_api_ms,
18217
+ numTurns: event.num_turns,
18218
+ resultSubtype: event.subtype,
18219
+ resultIsError: event.is_error,
18220
+ serviceTier: usage?.service_tier
18221
+ }
18222
+ });
18223
+ }
18224
+ break;
18225
+ }
18226
+ case "tool_result": {
18227
+ const toolUseId = event.tool_use_id;
18228
+ const content = event.content;
18229
+ events.push({ kind: "tool_output", callId: toolUseId, output: content });
18230
+ break;
18231
+ }
18232
+ case "system": {
18233
+ const subtype = event.subtype;
18234
+ if (subtype === "init") {
18235
+ const sid = event.session_id;
18236
+ events.push({ kind: "session_init", sessionId: sid || "" });
18237
+ } else if (subtype === "context_pruning" || subtype === "compaction") {
18238
+ events.push({ kind: "compaction_started" });
18239
+ } else if (subtype === "compaction_finished" || subtype === "context_pruning_finished") {
18240
+ events.push({ kind: "compaction_finished" });
18241
+ } else if (subtype === "status" || subtype === "stream_event") {
18242
+ events.push({
18243
+ kind: "internal_progress",
18244
+ source: "claude_system",
18245
+ itemType: subtype,
18246
+ payloadBytes: line.length
18247
+ });
18248
+ }
18249
+ break;
18250
+ }
18251
+ case "control_request": {
18252
+ const requestId = event.request_id;
18253
+ if (requestId) {
18254
+ events.push({ kind: "permission_request", requestId, payload: event.payload });
18255
+ }
18256
+ break;
18257
+ }
18258
+ default: {
18259
+ events.push({ kind: "log", content: line, level: "debug" });
18260
+ }
18261
+ }
18262
+ return events;
18263
+ }
18264
+ encodeStdinMessage(text2, mode, opts) {
18265
+ const msg = {
18266
+ type: "user",
18267
+ message: {
18268
+ role: "user",
18269
+ content: [{ type: "text", text: text2 }]
18270
+ }
18271
+ };
18272
+ if (opts?.sessionId) {
18273
+ msg.session_id = opts.sessionId;
18274
+ }
18275
+ return JSON.stringify(msg);
18276
+ }
18277
+ execute(prompt, options) {
18278
+ const useStdinPrompt = options.steeringEnabled === true;
18279
+ const args = [];
18280
+ if (!useStdinPrompt) {
18281
+ args.push("-p", prompt);
18282
+ }
18283
+ args.push("--output-format", "stream-json", "--verbose", "--permission-mode", "bypassPermissions");
18284
+ if (useStdinPrompt) {
18285
+ args.push("--input-format", "stream-json");
18286
+ }
18287
+ if (options.model) {
18288
+ args.push("--model", options.model);
18289
+ }
18290
+ if (options.maxTurns) {
18291
+ args.push("--max-turns", String(options.maxTurns));
18292
+ }
18293
+ if (options.resumeSessionId) {
18294
+ args.push("--resume", options.resumeSessionId);
18295
+ }
18296
+ const proc = spawn(this.cliPath, args, {
18297
+ cwd: options.cwd,
18298
+ stdio: ["pipe", "pipe", "pipe"],
18299
+ env: { ...process.env, ...options.env },
18300
+ shell: process.platform === "win32",
18301
+ windowsHide: true,
18302
+ detached: process.platform !== "win32"
18303
+ });
18304
+ if (!proc.pid) {
18305
+ const error51 = `Failed to start ${this.cliPath}: binary not found or not executable. Is 'claude' installed and on PATH?`;
18306
+ const failedResult = { status: "failed", output: "", error: error51, durationMs: 0, sessionId: "" };
18307
+ const emptyMessages = { [Symbol.asyncIterator]() {
18308
+ return { async next() {
17572
18309
  return { value: undefined, done: true };
17573
18310
  } };
17574
18311
  } };
@@ -17603,15 +18340,58 @@ class ClaudeBackend {
17603
18340
  r();
17604
18341
  }
17605
18342
  };
18343
+ const parsedEventQueue = [];
18344
+ let parsedEventResolve = null;
18345
+ let parsedEventDone = false;
18346
+ const pushParsedEvent = (evt) => {
18347
+ parsedEventQueue.push(evt);
18348
+ if (parsedEventResolve) {
18349
+ const r = parsedEventResolve;
18350
+ parsedEventResolve = null;
18351
+ r();
18352
+ }
18353
+ };
18354
+ const stdinWriteQueue = [];
18355
+ let stdinDraining = false;
18356
+ const enqueueStdinWrite = (data) => {
18357
+ stdinWriteQueue.push(data);
18358
+ drainStdinQueue();
18359
+ };
18360
+ const drainStdinQueue = () => {
18361
+ if (stdinDraining)
18362
+ return;
18363
+ stdinDraining = true;
18364
+ while (stdinWriteQueue.length > 0) {
18365
+ const line = stdinWriteQueue.shift();
18366
+ try {
18367
+ proc.stdin?.write(line + `
18368
+ `);
18369
+ } catch {}
18370
+ }
18371
+ stdinDraining = false;
18372
+ };
17606
18373
  const resultPromise = new Promise((resolve) => {
17607
18374
  const stderrChunks = [];
17608
18375
  proc.stderr?.on("data", (chunk) => {
17609
18376
  stderrChunks.push(chunk.toString());
17610
18377
  });
17611
18378
  const rl = createInterface({ input: proc.stdout });
18379
+ if (useStdinPrompt) {
18380
+ const initialMsg = JSON.stringify({
18381
+ type: "user",
18382
+ message: {
18383
+ role: "user",
18384
+ content: [{ type: "text", text: prompt }]
18385
+ }
18386
+ });
18387
+ enqueueStdinWrite(initialMsg);
18388
+ }
17612
18389
  rl.on("line", (line) => {
17613
18390
  if (!line.trim())
17614
18391
  return;
18392
+ const parsed = this.parseLine(line);
18393
+ for (const pe of parsed)
18394
+ pushParsedEvent(pe);
17615
18395
  let event;
17616
18396
  try {
17617
18397
  event = JSON.parse(line);
@@ -17657,6 +18437,13 @@ class ClaudeBackend {
17657
18437
  resultStatus = "failed";
17658
18438
  lastError = result || "unknown error";
17659
18439
  }
18440
+ if (useStdinPrompt) {
18441
+ setTimeout(() => {
18442
+ try {
18443
+ proc.stdin?.end();
18444
+ } catch {}
18445
+ }, 100);
18446
+ }
17660
18447
  break;
17661
18448
  }
17662
18449
  case "tool_result": {
@@ -17681,7 +18468,7 @@ class ClaudeBackend {
17681
18468
  break;
17682
18469
  }
17683
18470
  case "control_request": {
17684
- handleControlRequest(proc, event);
18471
+ handleControlRequest(proc, event, enqueueStdinWrite);
17685
18472
  break;
17686
18473
  }
17687
18474
  default: {
@@ -17698,11 +18485,17 @@ class ClaudeBackend {
17698
18485
  lastError = `spawn error: ${err.message}`;
17699
18486
  resolveSessionId(lastSessionId);
17700
18487
  messageDone = true;
18488
+ parsedEventDone = true;
17701
18489
  if (messageResolve) {
17702
18490
  const r = messageResolve;
17703
18491
  messageResolve = null;
17704
18492
  r();
17705
18493
  }
18494
+ if (parsedEventResolve) {
18495
+ const r = parsedEventResolve;
18496
+ parsedEventResolve = null;
18497
+ r();
18498
+ }
17706
18499
  resolve({
17707
18500
  status: "failed",
17708
18501
  output: "",
@@ -17725,11 +18518,17 @@ class ClaudeBackend {
17725
18518
  }
17726
18519
  resolveSessionId(lastSessionId);
17727
18520
  messageDone = true;
18521
+ parsedEventDone = true;
17728
18522
  if (messageResolve) {
17729
18523
  const r = messageResolve;
17730
18524
  messageResolve = null;
17731
18525
  r();
17732
18526
  }
18527
+ if (parsedEventResolve) {
18528
+ const r = parsedEventResolve;
18529
+ parsedEventResolve = null;
18530
+ r();
18531
+ }
17733
18532
  resolve({
17734
18533
  status: resultStatus,
17735
18534
  output: lastOutput,
@@ -17756,10 +18555,47 @@ class ClaudeBackend {
17756
18555
  };
17757
18556
  }
17758
18557
  };
17759
- return { pid: proc.pid, messages, sessionId: sessionIdPromise, result: resultPromise };
18558
+ const parsedEvents = {
18559
+ [Symbol.asyncIterator]() {
18560
+ return {
18561
+ async next() {
18562
+ while (parsedEventQueue.length === 0 && !parsedEventDone) {
18563
+ await new Promise((resolve) => {
18564
+ parsedEventResolve = resolve;
18565
+ });
18566
+ }
18567
+ if (parsedEventQueue.length > 0) {
18568
+ return { value: parsedEventQueue.shift(), done: false };
18569
+ }
18570
+ return { value: undefined, done: true };
18571
+ }
18572
+ };
18573
+ }
18574
+ };
18575
+ const send = (text2, mode) => {
18576
+ const encoded = this.encodeStdinMessage(text2, mode, { sessionId: lastSessionId || undefined });
18577
+ if (!encoded)
18578
+ return { ok: false, reason: "encoding failed" };
18579
+ if (!proc.stdin || proc.stdin.destroyed)
18580
+ return { ok: false, reason: "stdin closed" };
18581
+ enqueueStdinWrite(encoded);
18582
+ return { ok: true };
18583
+ };
18584
+ const descriptor = {
18585
+ lifecycle: this.lifecycle,
18586
+ busyDeliveryMode: this.busyDeliveryMode,
18587
+ supportsStdinNotification: this.supportsStdinNotification
18588
+ };
18589
+ const closeStdin = () => {
18590
+ try {
18591
+ if (proc.stdin && !proc.stdin.destroyed)
18592
+ proc.stdin.end();
18593
+ } catch {}
18594
+ };
18595
+ return { pid: proc.pid, messages, parsedEvents, sessionId: sessionIdPromise, result: resultPromise, send, closeStdin, descriptor };
17760
18596
  }
17761
18597
  }
17762
- function handleControlRequest(proc, event) {
18598
+ function handleControlRequest(proc, event, enqueueStdinWrite) {
17763
18599
  const requestId = event.request_id;
17764
18600
  if (!requestId)
17765
18601
  return;
@@ -17788,10 +18624,14 @@ function handleControlRequest(proc, event) {
17788
18624
  }
17789
18625
  }
17790
18626
  });
17791
- try {
17792
- proc.stdin?.write(approval + `
18627
+ if (enqueueStdinWrite) {
18628
+ enqueueStdinWrite(approval);
18629
+ } else {
18630
+ try {
18631
+ proc.stdin?.write(approval + `
17793
18632
  `);
17794
- } catch {}
18633
+ } catch {}
18634
+ }
17795
18635
  }
17796
18636
 
17797
18637
  // daemon/agent/codex.ts
@@ -17823,9 +18663,196 @@ function extractThreadID(response) {
17823
18663
  class CodexBackend {
17824
18664
  cliPath;
17825
18665
  name = "codex";
18666
+ lifecycle = { kind: "persistent", stdin: "direct", inFlightWake: "steer" };
18667
+ busyDeliveryMode = "direct";
18668
+ supportsStdinNotification = true;
18669
+ _rpcId = 0;
17826
18670
  constructor(cliPath) {
17827
18671
  this.cliPath = cliPath;
17828
18672
  }
18673
+ parseLine(line) {
18674
+ if (!line.trim())
18675
+ return [];
18676
+ let msg;
18677
+ try {
18678
+ msg = JSON.parse(line);
18679
+ } catch {
18680
+ return [{ kind: "log", content: line, level: "debug" }];
18681
+ }
18682
+ if (msg.id !== undefined && !msg.method)
18683
+ return [];
18684
+ if (msg.id !== undefined && msg.method)
18685
+ return [];
18686
+ if (!msg.method)
18687
+ return [{ kind: "log", content: line, level: "debug" }];
18688
+ const method = msg.method;
18689
+ const params = msg.params || {};
18690
+ if (method === "codex/event") {
18691
+ return this.parseLegacyEvent(params);
18692
+ }
18693
+ const events = [];
18694
+ switch (method) {
18695
+ case "turn/started":
18696
+ break;
18697
+ case "turn/completed": {
18698
+ const turn = params.turn;
18699
+ const status = turn?.status || params.status || "";
18700
+ if (status === "error" || status === "failed") {
18701
+ const turnErr = turn?.error;
18702
+ events.push({ kind: "error", message: turnErr?.message || "codex turn failed" });
18703
+ }
18704
+ events.push({ kind: "turn_end" });
18705
+ break;
18706
+ }
18707
+ case "error": {
18708
+ const errObj = params.error;
18709
+ const errMsg = errObj?.message || params.message || "";
18710
+ const willRetry = params.willRetry === true;
18711
+ if (errMsg && !willRetry) {
18712
+ events.push({ kind: "error", message: errMsg });
18713
+ }
18714
+ break;
18715
+ }
18716
+ case "thread/status/changed": {
18717
+ const statusObj = params.status;
18718
+ const statusType = typeof statusObj === "object" && statusObj !== null ? statusObj.type || "" : statusObj || "";
18719
+ if (statusType === "idle") {
18720
+ events.push({ kind: "turn_end" });
18721
+ }
18722
+ break;
18723
+ }
18724
+ case "item/started": {
18725
+ const item = params.item;
18726
+ if (!item)
18727
+ break;
18728
+ const itemType = item.type;
18729
+ if (itemType === "commandExecution" || itemType === "fileChange") {
18730
+ events.push({
18731
+ kind: "tool_call",
18732
+ name: itemType === "commandExecution" ? "exec_command" : "patch_apply",
18733
+ callId: item.id,
18734
+ input: item
18735
+ });
18736
+ } else if (itemType === "mcpToolCall") {
18737
+ events.push({
18738
+ kind: "tool_call",
18739
+ name: `mcp_${item.name || "tool"}`,
18740
+ callId: item.id,
18741
+ input: item
18742
+ });
18743
+ } else if (itemType === "webSearch") {
18744
+ events.push({
18745
+ kind: "tool_call",
18746
+ name: "web_search",
18747
+ callId: item.id,
18748
+ input: item
18749
+ });
18750
+ } else if (itemType === "collabAgentToolCall") {
18751
+ events.push({
18752
+ kind: "tool_call",
18753
+ name: "collab_agent",
18754
+ callId: item.id,
18755
+ input: item
18756
+ });
18757
+ } else if (itemType === "contextCompaction") {
18758
+ events.push({ kind: "compaction_started" });
18759
+ }
18760
+ break;
18761
+ }
18762
+ case "item/completed": {
18763
+ const item = params.item;
18764
+ if (!item)
18765
+ break;
18766
+ const itemType = item.type;
18767
+ if (itemType === "commandExecution") {
18768
+ events.push({ kind: "tool_output", callId: item.id, output: item.aggregatedOutput || "" });
18769
+ } else if (itemType === "fileChange") {
18770
+ events.push({ kind: "tool_output", callId: item.id, output: "" });
18771
+ } else if (itemType === "mcpToolCall") {
18772
+ events.push({ kind: "tool_output", callId: item.id, name: `mcp_${item.name || "tool"}`, output: item.output || "" });
18773
+ } else if (itemType === "agentMessage") {
18774
+ const flatText = item.text;
18775
+ if (flatText) {
18776
+ events.push({ kind: "text", text: flatText });
18777
+ } else {
18778
+ const content = item.content;
18779
+ if (Array.isArray(content)) {
18780
+ for (const block of content) {
18781
+ if ((block.type === "output_text" || block.type === "text") && block.text) {
18782
+ events.push({ kind: "text", text: block.text });
18783
+ }
18784
+ }
18785
+ }
18786
+ }
18787
+ } else if (itemType === "reasoning") {
18788
+ events.push({ kind: "thinking", text: item.text || "" });
18789
+ } else if (itemType === "contextCompaction") {
18790
+ events.push({ kind: "compaction_finished" });
18791
+ }
18792
+ break;
18793
+ }
18794
+ case "item/agentMessage/delta": {
18795
+ const delta = params.delta;
18796
+ if (delta)
18797
+ events.push({ kind: "text", text: delta });
18798
+ break;
18799
+ }
18800
+ default:
18801
+ events.push({ kind: "log", content: JSON.stringify(msg), level: "debug" });
18802
+ }
18803
+ return events;
18804
+ }
18805
+ parseLegacyEvent(params) {
18806
+ const eventType = params.type;
18807
+ if (!eventType)
18808
+ return [];
18809
+ const events = [];
18810
+ switch (eventType) {
18811
+ case "agent_message": {
18812
+ const text2 = params.text || params.message || "";
18813
+ if (text2)
18814
+ events.push({ kind: "text", text: text2 });
18815
+ break;
18816
+ }
18817
+ case "exec_command_begin":
18818
+ events.push({ kind: "tool_call", name: "exec_command", callId: params.id, input: params });
18819
+ break;
18820
+ case "exec_command_end":
18821
+ events.push({ kind: "tool_output", callId: params.id, output: params.output || "" });
18822
+ break;
18823
+ case "patch_apply_begin":
18824
+ events.push({ kind: "tool_call", name: "patch_apply", callId: params.id, input: params });
18825
+ break;
18826
+ case "patch_apply_end":
18827
+ events.push({ kind: "tool_output", callId: params.id, output: params.output || "" });
18828
+ break;
18829
+ case "task_complete":
18830
+ events.push({ kind: "turn_end" });
18831
+ break;
18832
+ case "turn_aborted":
18833
+ events.push({ kind: "turn_end" });
18834
+ break;
18835
+ default:
18836
+ break;
18837
+ }
18838
+ return events;
18839
+ }
18840
+ encodeStdinMessage(text2, mode, opts) {
18841
+ const threadId = opts?.threadId;
18842
+ if (!threadId)
18843
+ return null;
18844
+ const id = opts?.requestId ?? ++this._rpcId;
18845
+ const method = mode === "busy" ? "turn/steer" : "turn/start";
18846
+ return JSON.stringify({
18847
+ jsonrpc: "2.0",
18848
+ id,
18849
+ method,
18850
+ params: {
18851
+ threadId,
18852
+ input: [{ type: "text", text: text2 }]
18853
+ }
18854
+ });
18855
+ }
17829
18856
  execute(prompt, options) {
17830
18857
  const proc = spawn2(this.cliPath, ["app-server", "--listen", "stdio://", "--config", "sandbox_mode=danger-full-access"], {
17831
18858
  cwd: options.cwd,
@@ -17874,6 +18901,9 @@ class CodexBackend {
17874
18901
  const messageQueue = [];
17875
18902
  let messageResolve = null;
17876
18903
  let messageDone = false;
18904
+ const parsedEventQueue = [];
18905
+ let parsedEventResolve = null;
18906
+ let parsedEventDone = false;
17877
18907
  const pushMessage = (msg) => {
17878
18908
  messageQueue.push(msg);
17879
18909
  if (messageResolve) {
@@ -17882,6 +18912,14 @@ class CodexBackend {
17882
18912
  r();
17883
18913
  }
17884
18914
  };
18915
+ const pushParsedEvent = (evt) => {
18916
+ parsedEventQueue.push(evt);
18917
+ if (parsedEventResolve) {
18918
+ const r = parsedEventResolve;
18919
+ parsedEventResolve = null;
18920
+ r();
18921
+ }
18922
+ };
17885
18923
  const writeStdin = (data) => {
17886
18924
  try {
17887
18925
  proc.stdin?.write(data + `
@@ -17914,17 +18952,20 @@ class CodexBackend {
17914
18952
  if (msg && !turnError)
17915
18953
  turnError = msg;
17916
18954
  };
18955
+ const steeringKeepAlive = options.steeringEnabled === true;
17917
18956
  const triggerTurnDone = (aborted2) => {
17918
18957
  if (turnDoneTriggered)
17919
18958
  return;
17920
18959
  turnDoneTriggered = true;
17921
18960
  resultStatus = aborted2 ? "aborted" : "completed";
17922
- try {
17923
- proc.stdin?.end();
17924
- } catch {}
17925
- try {
17926
- proc.kill("SIGTERM");
17927
- } catch {}
18961
+ if (!steeringKeepAlive) {
18962
+ try {
18963
+ proc.stdin?.end();
18964
+ } catch {}
18965
+ try {
18966
+ proc.kill("SIGTERM");
18967
+ } catch {}
18968
+ }
17928
18969
  };
17929
18970
  const handleServerRequest = (msg) => {
17930
18971
  const method = msg.method;
@@ -18145,6 +19186,9 @@ class CodexBackend {
18145
19186
  rl.on("line", (line) => {
18146
19187
  if (!line.trim())
18147
19188
  return;
19189
+ const parsed = this.parseLine(line);
19190
+ for (const pe of parsed)
19191
+ pushParsedEvent(pe);
18148
19192
  let msg;
18149
19193
  try {
18150
19194
  msg = JSON.parse(line);
@@ -18231,11 +19275,17 @@ class CodexBackend {
18231
19275
  closeAllPending("spawn error");
18232
19276
  resolveSessionId(sessionId);
18233
19277
  messageDone = true;
19278
+ parsedEventDone = true;
18234
19279
  if (messageResolve) {
18235
19280
  const r = messageResolve;
18236
19281
  messageResolve = null;
18237
19282
  r();
18238
19283
  }
19284
+ if (parsedEventResolve) {
19285
+ const r = parsedEventResolve;
19286
+ parsedEventResolve = null;
19287
+ r();
19288
+ }
18239
19289
  resolve({
18240
19290
  status: "failed",
18241
19291
  output: "",
@@ -18265,11 +19315,17 @@ class CodexBackend {
18265
19315
  }
18266
19316
  resolveSessionId(sessionId);
18267
19317
  messageDone = true;
19318
+ parsedEventDone = true;
18268
19319
  if (messageResolve) {
18269
19320
  const r = messageResolve;
18270
19321
  messageResolve = null;
18271
19322
  r();
18272
19323
  }
19324
+ if (parsedEventResolve) {
19325
+ const r = parsedEventResolve;
19326
+ parsedEventResolve = null;
19327
+ r();
19328
+ }
18273
19329
  resolve({
18274
19330
  status: resultStatus,
18275
19331
  output: lastOutput,
@@ -18296,7 +19352,44 @@ class CodexBackend {
18296
19352
  };
18297
19353
  }
18298
19354
  };
18299
- return { pid: proc.pid, messages, sessionId: sessionIdPromise, result: resultPromise };
19355
+ const parsedEvents = {
19356
+ [Symbol.asyncIterator]() {
19357
+ return {
19358
+ async next() {
19359
+ while (parsedEventQueue.length === 0 && !parsedEventDone) {
19360
+ await new Promise((resolve) => {
19361
+ parsedEventResolve = resolve;
19362
+ });
19363
+ }
19364
+ if (parsedEventQueue.length > 0) {
19365
+ return { value: parsedEventQueue.shift(), done: false };
19366
+ }
19367
+ return { value: undefined, done: true };
19368
+ }
19369
+ };
19370
+ }
19371
+ };
19372
+ const send = (text2, mode) => {
19373
+ if (!proc.stdin || proc.stdin.destroyed)
19374
+ return { ok: false, reason: "stdin closed" };
19375
+ const encoded = this.encodeStdinMessage(text2, mode, { threadId: sessionId, requestId: ++requestId });
19376
+ if (!encoded)
19377
+ return { ok: false, reason: "encoding failed (no threadId)" };
19378
+ writeStdin(encoded);
19379
+ return { ok: true };
19380
+ };
19381
+ const descriptor = {
19382
+ lifecycle: this.lifecycle,
19383
+ busyDeliveryMode: this.busyDeliveryMode,
19384
+ supportsStdinNotification: this.supportsStdinNotification
19385
+ };
19386
+ const closeStdin = () => {
19387
+ try {
19388
+ if (proc.stdin && !proc.stdin.destroyed)
19389
+ proc.stdin.end();
19390
+ } catch {}
19391
+ };
19392
+ return { pid: proc.pid, messages, parsedEvents, sessionId: sessionIdPromise, result: resultPromise, send, closeStdin, descriptor };
18300
19393
  }
18301
19394
  }
18302
19395
 
@@ -18306,9 +19399,102 @@ import { createInterface as createInterface3 } from "readline";
18306
19399
  class OpenCodeBackend {
18307
19400
  cliPath;
18308
19401
  name = "opencode";
19402
+ lifecycle = { kind: "per_turn", inFlightWake: "coalesce_into_pending" };
19403
+ busyDeliveryMode = "none";
19404
+ supportsStdinNotification = false;
18309
19405
  constructor(cliPath) {
18310
19406
  this.cliPath = cliPath;
18311
19407
  }
19408
+ parseLine(line) {
19409
+ if (!line.trim())
19410
+ return [];
19411
+ let event;
19412
+ try {
19413
+ event = JSON.parse(line);
19414
+ } catch {
19415
+ return [{ kind: "log", content: line, level: "debug" }];
19416
+ }
19417
+ const events = [];
19418
+ const eventType = event.type;
19419
+ const part = event.part;
19420
+ const eventSessionId = event.sessionID || event.session_id;
19421
+ switch (eventType) {
19422
+ case "session": {
19423
+ const sessionId = event.session_id;
19424
+ if (sessionId)
19425
+ events.push({ kind: "session_init", sessionId });
19426
+ break;
19427
+ }
19428
+ case "message": {
19429
+ const role = event.role;
19430
+ const content = event.content;
19431
+ if (role === "assistant" && content) {
19432
+ events.push({ kind: "text", text: content });
19433
+ }
19434
+ break;
19435
+ }
19436
+ case "text": {
19437
+ const text2 = part?.text || event.content || "";
19438
+ if (text2)
19439
+ events.push({ kind: "text", text: text2 });
19440
+ break;
19441
+ }
19442
+ case "thinking": {
19443
+ const content = part?.thinking || event.content || "";
19444
+ events.push({ kind: "thinking", text: content });
19445
+ break;
19446
+ }
19447
+ case "tool_call":
19448
+ events.push({
19449
+ kind: "tool_call",
19450
+ name: event.name || part?.name || "",
19451
+ callId: event.call_id || part?.id || "",
19452
+ input: event.input || part?.input
19453
+ });
19454
+ break;
19455
+ case "tool_result":
19456
+ events.push({
19457
+ kind: "tool_output",
19458
+ callId: event.call_id || part?.id || "",
19459
+ output: event.output || part?.output || ""
19460
+ });
19461
+ break;
19462
+ case "error": {
19463
+ const content = event.message || event.content || part?.error || "";
19464
+ events.push({ kind: "error", message: content });
19465
+ events.push({ kind: "turn_end" });
19466
+ break;
19467
+ }
19468
+ case "step_start":
19469
+ break;
19470
+ case "step_finish": {
19471
+ const reason = part?.reason;
19472
+ if (reason === "stop" || reason === "end_turn") {
19473
+ events.push({ kind: "turn_end" });
19474
+ }
19475
+ break;
19476
+ }
19477
+ case "done":
19478
+ case "complete": {
19479
+ const status = event.status;
19480
+ if (status === "error" || status === "failed") {
19481
+ const output = event.output;
19482
+ events.push({ kind: "error", message: output || "task failed" });
19483
+ }
19484
+ events.push({ kind: "turn_end" });
19485
+ break;
19486
+ }
19487
+ default:
19488
+ events.push({ kind: "log", content: line, level: "debug" });
19489
+ }
19490
+ if (eventSessionId && events.length > 0 && events[0].kind !== "session_init") {
19491
+ events.unshift({ kind: "session_init", sessionId: eventSessionId });
19492
+ }
19493
+ return events;
19494
+ }
19495
+ encodeStdinMessage() {
19496
+ return null;
19497
+ }
18312
19498
  execute(prompt, options) {
18313
19499
  const args = ["run", "--format", "json", "--dir", options.cwd];
18314
19500
  if (options.model) {
@@ -18366,6 +19552,9 @@ class OpenCodeBackend {
18366
19552
  const messageQueue = [];
18367
19553
  let messageResolve = null;
18368
19554
  let messageDone = false;
19555
+ const parsedEventQueue = [];
19556
+ let parsedEventResolve = null;
19557
+ let parsedEventDone = false;
18369
19558
  const pushMessage = (msg) => {
18370
19559
  messageQueue.push(msg);
18371
19560
  if (messageResolve) {
@@ -18374,6 +19563,14 @@ class OpenCodeBackend {
18374
19563
  r();
18375
19564
  }
18376
19565
  };
19566
+ const pushParsedEvent = (evt) => {
19567
+ parsedEventQueue.push(evt);
19568
+ if (parsedEventResolve) {
19569
+ const r = parsedEventResolve;
19570
+ parsedEventResolve = null;
19571
+ r();
19572
+ }
19573
+ };
18377
19574
  const resultPromise = new Promise((resolve) => {
18378
19575
  const stderrChunks = [];
18379
19576
  proc.stderr?.on("data", (chunk) => {
@@ -18383,6 +19580,9 @@ class OpenCodeBackend {
18383
19580
  rl.on("line", (line) => {
18384
19581
  if (!line.trim())
18385
19582
  return;
19583
+ const parsed = this.parseLine(line);
19584
+ for (const pe of parsed)
19585
+ pushParsedEvent(pe);
18386
19586
  let event;
18387
19587
  try {
18388
19588
  event = JSON.parse(line);
@@ -18494,11 +19694,17 @@ class OpenCodeBackend {
18494
19694
  lastError = `spawn error: ${err.message}`;
18495
19695
  resolveSessionId(lastSessionId);
18496
19696
  messageDone = true;
19697
+ parsedEventDone = true;
18497
19698
  if (messageResolve) {
18498
19699
  const r = messageResolve;
18499
19700
  messageResolve = null;
18500
19701
  r();
18501
19702
  }
19703
+ if (parsedEventResolve) {
19704
+ const r = parsedEventResolve;
19705
+ parsedEventResolve = null;
19706
+ r();
19707
+ }
18502
19708
  resolve({
18503
19709
  status: "failed",
18504
19710
  output: "",
@@ -18523,11 +19729,17 @@ class OpenCodeBackend {
18523
19729
  }
18524
19730
  resolveSessionId(lastSessionId);
18525
19731
  messageDone = true;
19732
+ parsedEventDone = true;
18526
19733
  if (messageResolve) {
18527
19734
  const r = messageResolve;
18528
19735
  messageResolve = null;
18529
19736
  r();
18530
19737
  }
19738
+ if (parsedEventResolve) {
19739
+ const r = parsedEventResolve;
19740
+ parsedEventResolve = null;
19741
+ r();
19742
+ }
18531
19743
  resolve({
18532
19744
  status: resultStatus,
18533
19745
  output: lastOutput,
@@ -18554,7 +19766,32 @@ class OpenCodeBackend {
18554
19766
  };
18555
19767
  }
18556
19768
  };
18557
- return { pid: proc.pid, messages, sessionId: sessionIdPromise, result: resultPromise };
19769
+ const parsedEvents = {
19770
+ [Symbol.asyncIterator]() {
19771
+ return {
19772
+ async next() {
19773
+ while (parsedEventQueue.length === 0 && !parsedEventDone) {
19774
+ await new Promise((resolve) => {
19775
+ parsedEventResolve = resolve;
19776
+ });
19777
+ }
19778
+ if (parsedEventQueue.length > 0) {
19779
+ return { value: parsedEventQueue.shift(), done: false };
19780
+ }
19781
+ return { value: undefined, done: true };
19782
+ }
19783
+ };
19784
+ }
19785
+ };
19786
+ const send = () => {
19787
+ return { ok: false, reason: "unsupported" };
19788
+ };
19789
+ const descriptor = {
19790
+ lifecycle: this.lifecycle,
19791
+ busyDeliveryMode: this.busyDeliveryMode,
19792
+ supportsStdinNotification: this.supportsStdinNotification
19793
+ };
19794
+ return { pid: proc.pid, messages, parsedEvents, sessionId: sessionIdPromise, result: resultPromise, send, descriptor };
18558
19795
  }
18559
19796
  }
18560
19797
 
@@ -18620,7 +19857,7 @@ function fromApiTask(api2) {
18620
19857
 
18621
19858
  // daemon/session-runner.ts
18622
19859
  import { mkdir, writeFile, rm, rename } from "fs/promises";
18623
- import { mkdirSync as mkdirSync6 } from "fs";
19860
+ import { mkdirSync as mkdirSync7 } from "fs";
18624
19861
  import path from "path";
18625
19862
 
18626
19863
  // daemon/execenv/index.ts
@@ -19080,7 +20317,7 @@ function releaseLock(lockPath) {
19080
20317
  }
19081
20318
 
19082
20319
  // daemon/execenv/timeline.ts
19083
- var log4 = createLogger2({ module: "timeline" });
20320
+ var log6 = createLogger2({ module: "timeline" });
19084
20321
  function readJsonl(filePath) {
19085
20322
  let content;
19086
20323
  try {
@@ -19149,7 +20386,7 @@ async function initEntryAsync(timelineDir, entry) {
19149
20386
  acquired = acquireLock(lockPath);
19150
20387
  }
19151
20388
  if (!acquired) {
19152
- log4.debug(`Timeline initEntry: could not acquire lock for ${filename}`);
20389
+ log6.debug(`Timeline initEntry: could not acquire lock for ${filename}`);
19153
20390
  return;
19154
20391
  }
19155
20392
  try {
@@ -19159,7 +20396,7 @@ async function initEntryAsync(timelineDir, entry) {
19159
20396
  releaseLock(lockPath);
19160
20397
  }
19161
20398
  } catch (err) {
19162
- log4.debug("Timeline initEntry failed", err);
20399
+ log6.debug("Timeline initEntry failed", err);
19163
20400
  }
19164
20401
  }
19165
20402
  function updateEntry(timelineDir, taskId, updater) {
@@ -19169,7 +20406,7 @@ function updateEntry(timelineDir, taskId, updater) {
19169
20406
  try {
19170
20407
  const acquired = acquireLock(lockPath);
19171
20408
  if (!acquired) {
19172
- log4.debug(`Timeline updateEntry: lock held for ${filename}, skipping`);
20409
+ log6.debug(`Timeline updateEntry: lock held for ${filename}, skipping`);
19173
20410
  continue;
19174
20411
  }
19175
20412
  try {
@@ -19202,10 +20439,10 @@ function updateEntry(timelineDir, taskId, updater) {
19202
20439
  releaseLock(lockPath);
19203
20440
  }
19204
20441
  } catch (err) {
19205
- log4.debug(`Timeline updateEntry failed for ${filename}`, err);
20442
+ log6.debug(`Timeline updateEntry failed for ${filename}`, err);
19206
20443
  }
19207
20444
  }
19208
- log4.debug(`Timeline updateEntry: task_id ${taskId} not found in last 7 days`);
20445
+ log6.debug(`Timeline updateEntry: task_id ${taskId} not found in last 7 days`);
19209
20446
  }
19210
20447
  function createTimelineEntry(taskId, prompt, type, sessionId, pid, provider, contextKey, detailedLog) {
19211
20448
  return {
@@ -19274,7 +20511,7 @@ function findSupersedablePredecessor(timelineDir, contextKey, provider, warmupGr
19274
20511
  // daemon/execenv/steering.ts
19275
20512
  import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5, readFileSync as readFileSync6, unlinkSync as unlinkSync3, readdirSync, statSync as statSync2 } from "fs";
19276
20513
  import { join as join8 } from "path";
19277
- var log5 = createLogger2({ module: "steering" });
20514
+ var log7 = createLogger2({ module: "steering" });
19278
20515
  var INTENT_DIR_NAME = ".kill_intents";
19279
20516
  var STEERING_LOCK_DIR = ".steering_locks";
19280
20517
  var INTENT_STALE_MS = 10 * 60 * 1000;
@@ -19328,7 +20565,7 @@ function cleanupStaleIntents(baseDir) {
19328
20565
  const stat = statSync2(filePath);
19329
20566
  if (now - stat.mtimeMs > INTENT_STALE_MS) {
19330
20567
  unlinkSync3(filePath);
19331
- log5.debug(`Cleaned up stale kill intent for task ${intent.targetTaskId}`);
20568
+ log7.debug(`Cleaned up stale kill intent for task ${intent.targetTaskId}`);
19332
20569
  }
19333
20570
  } catch {}
19334
20571
  }
@@ -19345,6 +20582,684 @@ function releaseSteeringLock(baseDir, contextKey) {
19345
20582
  releaseLock(lockPath);
19346
20583
  }
19347
20584
 
20585
+ // daemon/steering/mailbox.ts
20586
+ 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";
20587
+ import { join as join9 } from "path";
20588
+ var log8 = createLogger2({ module: "mailbox" });
20589
+ function inboxDir(baseDir, contextKey) {
20590
+ const safeKey = contextKey.replace(/[^a-zA-Z0-9_:-]/g, "_");
20591
+ return join9(baseDir, ".steering", safeKey, "inbox");
20592
+ }
20593
+ function ackDir(baseDir, contextKey) {
20594
+ const safeKey = contextKey.replace(/[^a-zA-Z0-9_:-]/g, "_");
20595
+ return join9(baseDir, ".steering", safeKey, "ack");
20596
+ }
20597
+ function steeringDir(baseDir, contextKey) {
20598
+ const safeKey = contextKey.replace(/[^a-zA-Z0-9_:-]/g, "_");
20599
+ return join9(baseDir, ".steering", safeKey);
20600
+ }
20601
+ function ensureMailboxDirs(baseDir, contextKey) {
20602
+ const inbox = inboxDir(baseDir, contextKey);
20603
+ const ack = ackDir(baseDir, contextKey);
20604
+ mkdirSync6(inbox, { recursive: true });
20605
+ mkdirSync6(ack, { recursive: true });
20606
+ }
20607
+ var seqCounter = 0;
20608
+ function writeSteerMessage(baseDir, contextKey, message2) {
20609
+ const inbox = inboxDir(baseDir, contextKey);
20610
+ const seq = String(++seqCounter).padStart(6, "0");
20611
+ const tmpPath = join9(inbox, `${seq}.json.tmp`);
20612
+ const finalPath = join9(inbox, `${seq}.json`);
20613
+ writeFileSync6(tmpPath, JSON.stringify(message2));
20614
+ renameSync2(tmpPath, finalPath);
20615
+ return seq;
20616
+ }
20617
+ function waitForAck(baseDir, contextKey, seq, timeoutMs = 3000) {
20618
+ const ackPath = join9(ackDir(baseDir, contextKey), `${seq}.ack`);
20619
+ const nackPath = join9(ackDir(baseDir, contextKey), `${seq}.nack`);
20620
+ return new Promise((resolve) => {
20621
+ const deadline = Date.now() + timeoutMs;
20622
+ const pollInterval = 100;
20623
+ const check2 = () => {
20624
+ try {
20625
+ if (existsSync2(ackPath)) {
20626
+ resolve({ acked: true });
20627
+ return;
20628
+ }
20629
+ if (existsSync2(nackPath)) {
20630
+ let reason = "unknown";
20631
+ try {
20632
+ const content = readFileSync7(nackPath, "utf-8");
20633
+ const parsed = JSON.parse(content);
20634
+ reason = parsed.reason || "unknown";
20635
+ } catch {}
20636
+ resolve({ acked: false, nackReason: reason });
20637
+ return;
20638
+ }
20639
+ } catch {}
20640
+ if (Date.now() >= deadline) {
20641
+ resolve({ acked: false, nackReason: "timeout" });
20642
+ return;
20643
+ }
20644
+ setTimeout(check2, pollInterval);
20645
+ };
20646
+ check2();
20647
+ });
20648
+ }
20649
+ function readSteerMessage(filePath) {
20650
+ try {
20651
+ const content = readFileSync7(filePath, "utf-8");
20652
+ return JSON.parse(content);
20653
+ } catch {
20654
+ return null;
20655
+ }
20656
+ }
20657
+ function writeAck(baseDir, contextKey, seq) {
20658
+ const ack = ackDir(baseDir, contextKey);
20659
+ mkdirSync6(ack, { recursive: true });
20660
+ writeFileSync6(join9(ack, `${seq}.ack`), "");
20661
+ }
20662
+ function writeNack(baseDir, contextKey, seq, reason) {
20663
+ const ack = ackDir(baseDir, contextKey);
20664
+ mkdirSync6(ack, { recursive: true });
20665
+ writeFileSync6(join9(ack, `${seq}.nack`), JSON.stringify({ reason }));
20666
+ }
20667
+ function cleanupInboxFile(baseDir, contextKey, seq) {
20668
+ try {
20669
+ unlinkSync4(join9(inboxDir(baseDir, contextKey), `${seq}.json`));
20670
+ } catch {}
20671
+ }
20672
+ function cleanupSteeringDir(baseDir, contextKey) {
20673
+ const dir = steeringDir(baseDir, contextKey);
20674
+ try {
20675
+ rmSync(dir, { recursive: true, force: true });
20676
+ } catch {}
20677
+ }
20678
+ function watchInbox(baseDir, contextKey, onMessage) {
20679
+ const inbox = inboxDir(baseDir, contextKey);
20680
+ mkdirSync6(inbox, { recursive: true });
20681
+ const seen = new Set;
20682
+ let stopped = false;
20683
+ const scan = () => {
20684
+ if (stopped)
20685
+ return;
20686
+ try {
20687
+ const files = readdirSync2(inbox).filter((f) => f.endsWith(".json") && !f.endsWith(".tmp")).sort();
20688
+ for (const file2 of files) {
20689
+ if (seen.has(file2))
20690
+ continue;
20691
+ const seq = file2.replace(/\.json$/, "");
20692
+ const srcPath = join9(inbox, file2);
20693
+ const claimPath = join9(inbox, `${seq}.processing`);
20694
+ try {
20695
+ renameSync2(srcPath, claimPath);
20696
+ } catch {
20697
+ continue;
20698
+ }
20699
+ seen.add(file2);
20700
+ const msg = readSteerMessage(claimPath);
20701
+ try {
20702
+ unlinkSync4(claimPath);
20703
+ } catch {}
20704
+ if (msg) {
20705
+ onMessage(seq, msg);
20706
+ }
20707
+ }
20708
+ } catch {}
20709
+ };
20710
+ scan();
20711
+ let watcher = null;
20712
+ try {
20713
+ watcher = watch(inbox, () => {
20714
+ if (!stopped)
20715
+ scan();
20716
+ });
20717
+ } catch {
20718
+ log8.debug("fs.watch failed, relying on polling only");
20719
+ }
20720
+ const pollTimer = setInterval(scan, 200);
20721
+ return {
20722
+ stop() {
20723
+ stopped = true;
20724
+ clearInterval(pollTimer);
20725
+ watcher?.close();
20726
+ }
20727
+ };
20728
+ }
20729
+
20730
+ // daemon/steering/turnState.ts
20731
+ class RuntimeTurnState {
20732
+ currentTurnId = null;
20733
+ steeringGateActive = false;
20734
+ get isInTurn() {
20735
+ return this.currentTurnId !== null;
20736
+ }
20737
+ get turnId() {
20738
+ return this.currentTurnId;
20739
+ }
20740
+ get canSteerBusy() {
20741
+ return Boolean(this.currentTurnId && !this.steeringGateActive);
20742
+ }
20743
+ markTurnStarted(turnId) {
20744
+ if (turnId !== undefined && turnId !== null) {
20745
+ this.currentTurnId = turnId;
20746
+ }
20747
+ this.steeringGateActive = false;
20748
+ }
20749
+ adoptTurnId(turnId) {
20750
+ this.currentTurnId = turnId;
20751
+ }
20752
+ markToolBoundary() {
20753
+ this.steeringGateActive = true;
20754
+ }
20755
+ markProgress() {
20756
+ this.steeringGateActive = false;
20757
+ }
20758
+ markTurnCompleted() {
20759
+ this.currentTurnId = null;
20760
+ this.steeringGateActive = false;
20761
+ }
20762
+ reset() {
20763
+ this.currentTurnId = null;
20764
+ this.steeringGateActive = false;
20765
+ }
20766
+ }
20767
+
20768
+ // daemon/steering/apmStateMachine.ts
20769
+ var MAX_APM_GATED_STEERING_EVENTS = 12;
20770
+ function createInitialApmState() {
20771
+ return {
20772
+ isIdle: false,
20773
+ expectedTerminationReason: null,
20774
+ phase: "idle",
20775
+ outstandingToolUses: 0,
20776
+ compacting: false,
20777
+ toolBoundaryFlushDisabled: false,
20778
+ lastFlushReason: null,
20779
+ recentEvents: [],
20780
+ pendingMessages: []
20781
+ };
20782
+ }
20783
+ function reduceApmGatedToolUse(state, input) {
20784
+ if (input.kind === "tool_call") {
20785
+ return {
20786
+ nextState: {
20787
+ ...state,
20788
+ isIdle: false,
20789
+ phase: "tool_wait",
20790
+ outstandingToolUses: state.outstandingToolUses + 1
20791
+ },
20792
+ hadOutstandingToolUse: state.outstandingToolUses > 0,
20793
+ shouldFlushToolBatch: false
20794
+ };
20795
+ }
20796
+ const hadOutstandingToolUse = state.outstandingToolUses > 0;
20797
+ const outstandingToolUses = Math.max(0, state.outstandingToolUses - 1);
20798
+ return {
20799
+ nextState: {
20800
+ ...state,
20801
+ isIdle: false,
20802
+ phase: "tool_boundary",
20803
+ outstandingToolUses
20804
+ },
20805
+ hadOutstandingToolUse,
20806
+ shouldFlushToolBatch: hadOutstandingToolUse && outstandingToolUses === 0
20807
+ };
20808
+ }
20809
+ function reduceApmGatedCompaction(state, input) {
20810
+ if (input.kind === "compaction_started") {
20811
+ return { nextState: { ...state, isIdle: false, phase: "compacting", compacting: true } };
20812
+ }
20813
+ if (input.kind === "compaction_interrupted") {
20814
+ return { nextState: { ...state, isIdle: false, compacting: false } };
20815
+ }
20816
+ return {
20817
+ nextState: { ...state, isIdle: false, phase: "assistant_continuation", compacting: false }
20818
+ };
20819
+ }
20820
+ function reduceApmGatedFlushReadiness(state, input) {
20821
+ if (!input.isGated)
20822
+ return { shouldNotify: false, blockedReason: "non_gated", effects: [] };
20823
+ if (!input.hasSession)
20824
+ return { shouldNotify: false, blockedReason: "missing_session", effects: [] };
20825
+ if (input.inboxLength === 0)
20826
+ return { shouldNotify: false, blockedReason: "empty_inbox", effects: [] };
20827
+ if (state.toolBoundaryFlushDisabled) {
20828
+ return { shouldNotify: false, blockedReason: "tool_boundary_flush_disabled", effects: [] };
20829
+ }
20830
+ if (state.compacting)
20831
+ return { shouldNotify: false, blockedReason: "compacting", effects: [] };
20832
+ if (state.outstandingToolUses > 0) {
20833
+ return { shouldNotify: false, blockedReason: "outstanding_tool_uses", effects: [] };
20834
+ }
20835
+ return {
20836
+ shouldNotify: true,
20837
+ blockedReason: null,
20838
+ effects: [{ kind: "notify_stdin", reason: input.reason, stdinMode: "busy", clauseId: "SMR-002" }]
20839
+ };
20840
+ }
20841
+ function reduceApmGatedTurnEnd(state, input = {}) {
20842
+ const shouldDeliverQueuedMessages = Boolean(input.inboxLength && input.inboxLength > 0 && input.supportsStdinNotification && input.hasSession);
20843
+ return {
20844
+ nextState: {
20845
+ ...state,
20846
+ isIdle: !shouldDeliverQueuedMessages,
20847
+ phase: "idle",
20848
+ outstandingToolUses: 0,
20849
+ compacting: false,
20850
+ pendingMessages: shouldDeliverQueuedMessages ? state.pendingMessages : []
20851
+ },
20852
+ effects: shouldDeliverQueuedMessages ? [{ kind: "deliver_stdin", reason: "turn_end", stdinMode: "idle", clauseId: "SMR-002" }] : []
20853
+ };
20854
+ }
20855
+ function reduceApmGatedError(state, input = {}) {
20856
+ const shouldDisableToolBoundaryFlush = input.disableToolBoundaryFlush === true;
20857
+ return {
20858
+ nextState: {
20859
+ ...state,
20860
+ phase: "error",
20861
+ compacting: false,
20862
+ toolBoundaryFlushDisabled: state.toolBoundaryFlushDisabled || shouldDisableToolBoundaryFlush
20863
+ },
20864
+ shouldDisableToolBoundaryFlush
20865
+ };
20866
+ }
20867
+ function reduceApmGatedRecentEvent(state, input) {
20868
+ const summary = `${input.event}:${state.phase}:tools=${state.outstandingToolUses}:compact=${state.compacting}`;
20869
+ return {
20870
+ nextState: {
20871
+ ...state,
20872
+ recentEvents: [...state.recentEvents, summary].slice(-MAX_APM_GATED_STEERING_EVENTS)
20873
+ }
20874
+ };
20875
+ }
20876
+ function reduceApmGatedEnqueue(state, message2) {
20877
+ return {
20878
+ nextState: {
20879
+ ...state,
20880
+ pendingMessages: [...state.pendingMessages, message2]
20881
+ }
20882
+ };
20883
+ }
20884
+ function reduceApmStalledRecoveryTermination(state, input) {
20885
+ if (input.inboxLength === 0) {
20886
+ return { nextState: state, shouldTerminate: false, alreadyRecovering: false, blockedReason: "empty_inbox" };
20887
+ }
20888
+ if (state.expectedTerminationReason === "stalled_recovery") {
20889
+ return { nextState: state, shouldTerminate: false, alreadyRecovering: true, blockedReason: null };
20890
+ }
20891
+ const supportsStdinNotification = input.busyDeliveryMode !== "none";
20892
+ const directStdinRuntime = supportsStdinNotification && input.busyDeliveryMode === "direct";
20893
+ const canRestartDirectStdinProcess = directStdinRuntime && input.hasSession && (state.outstandingToolUses === 0 || input.hasDirectStdinRecoveryEvidence);
20894
+ const canRestartStalledProcess = !supportsStdinNotification || canRestartDirectStdinProcess;
20895
+ if (!canRestartStalledProcess) {
20896
+ return {
20897
+ nextState: state,
20898
+ shouldTerminate: false,
20899
+ alreadyRecovering: false,
20900
+ blockedReason: "runtime_not_restartable"
20901
+ };
20902
+ }
20903
+ if (input.staleForMs < input.staleThresholdMs && !input.runtimeProgressIsStale) {
20904
+ return {
20905
+ nextState: state,
20906
+ shouldTerminate: false,
20907
+ alreadyRecovering: false,
20908
+ blockedReason: "runtime_progress_recent"
20909
+ };
20910
+ }
20911
+ return {
20912
+ nextState: { ...state, expectedTerminationReason: "stalled_recovery" },
20913
+ shouldTerminate: true,
20914
+ alreadyRecovering: false,
20915
+ blockedReason: null
20916
+ };
20917
+ }
20918
+ function reduceApmStartupTimeoutTermination(state, input) {
20919
+ if (input.hasRuntimeProgressEvent) {
20920
+ return { nextState: state, shouldTerminate: false, blockedReason: "runtime_progress_started" };
20921
+ }
20922
+ return {
20923
+ nextState: { ...state, isIdle: false, expectedTerminationReason: "startup_timeout" },
20924
+ shouldTerminate: true,
20925
+ blockedReason: null
20926
+ };
20927
+ }
20928
+
20929
+ // daemon/steering/notificationState.ts
20930
+ function inboxNoticeMessageIdentity(message2) {
20931
+ const seq = typeof message2.seq === "number" && Number.isFinite(message2.seq) && message2.seq > 0 ? Math.floor(message2.seq) : null;
20932
+ if (seq !== null)
20933
+ return `s:${seq}`;
20934
+ 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 : "";
20935
+ return id.length > 0 ? `m:${id}` : "";
20936
+ }
20937
+ class RuntimeNotificationState {
20938
+ pendingCountValue = 0;
20939
+ timerValue = null;
20940
+ lastNoticeFingerprint = null;
20941
+ lastNoticeSessionId = null;
20942
+ lastEncodeFailedFingerprint = null;
20943
+ lastEncodeFailedSessionId = null;
20944
+ contributedIdentities = new Set;
20945
+ contributionSessionId = null;
20946
+ get pendingCount() {
20947
+ return this.pendingCountValue;
20948
+ }
20949
+ isDuplicateNotice(fingerprint, sessionId) {
20950
+ if (fingerprint.length === 0)
20951
+ return false;
20952
+ return this.lastNoticeFingerprint === fingerprint && this.lastNoticeSessionId === sessionId;
20953
+ }
20954
+ recordNoticeWritten(fingerprint, sessionId, messages = []) {
20955
+ this.lastNoticeFingerprint = fingerprint;
20956
+ this.lastNoticeSessionId = sessionId;
20957
+ this.lastEncodeFailedFingerprint = null;
20958
+ this.lastEncodeFailedSessionId = null;
20959
+ this.ensureContributionSession(sessionId);
20960
+ for (const message2 of messages) {
20961
+ const identity = inboxNoticeMessageIdentity(message2);
20962
+ if (identity.length > 0)
20963
+ this.contributedIdentities.add(identity);
20964
+ }
20965
+ }
20966
+ recordNoticeEncodeFailed(fingerprint, sessionId) {
20967
+ if (fingerprint.length === 0)
20968
+ return;
20969
+ this.lastEncodeFailedFingerprint = fingerprint;
20970
+ this.lastEncodeFailedSessionId = sessionId;
20971
+ }
20972
+ isDuplicateEncodeFailedNotice(fingerprint, sessionId) {
20973
+ if (fingerprint.length === 0)
20974
+ return false;
20975
+ return this.lastEncodeFailedFingerprint === fingerprint && this.lastEncodeFailedSessionId === sessionId;
20976
+ }
20977
+ filterUncontributedMessages(messages, sessionId) {
20978
+ if (this.contributionSessionId !== sessionId)
20979
+ return messages;
20980
+ return messages.filter((m) => {
20981
+ const identity = inboxNoticeMessageIdentity(m);
20982
+ return identity.length === 0 || !this.contributedIdentities.has(identity);
20983
+ });
20984
+ }
20985
+ add(count = 1) {
20986
+ this.pendingCountValue += count;
20987
+ }
20988
+ schedule(callback, delayMs) {
20989
+ if (this.timerValue)
20990
+ return false;
20991
+ this.timerValue = setTimeout(() => {
20992
+ this.timerValue = null;
20993
+ callback();
20994
+ }, delayMs);
20995
+ this.timerValue.unref?.();
20996
+ return true;
20997
+ }
20998
+ takePendingAndClearTimer() {
20999
+ const count = this.pendingCountValue;
21000
+ this.pendingCountValue = 0;
21001
+ if (this.timerValue) {
21002
+ clearTimeout(this.timerValue);
21003
+ this.timerValue = null;
21004
+ }
21005
+ return count;
21006
+ }
21007
+ ensureContributionSession(sessionId) {
21008
+ if (this.contributionSessionId !== sessionId) {
21009
+ this.contributionSessionId = sessionId;
21010
+ this.contributedIdentities = new Set;
21011
+ }
21012
+ }
21013
+ }
21014
+
21015
+ // daemon/steering/progressState.ts
21016
+ class RuntimeProgressState {
21017
+ lastEventAt;
21018
+ lastEventKind = null;
21019
+ _staleSince = null;
21020
+ _isStale = false;
21021
+ constructor(now = Date.now()) {
21022
+ this.lastEventAt = now;
21023
+ }
21024
+ get isStale() {
21025
+ return this._isStale;
21026
+ }
21027
+ get staleSince() {
21028
+ return this._staleSince;
21029
+ }
21030
+ get lastActivity() {
21031
+ return this.lastEventAt;
21032
+ }
21033
+ ageMs(nowMs = Date.now()) {
21034
+ return nowMs - this.lastEventAt;
21035
+ }
21036
+ recordRealEvent(kind, now = Date.now()) {
21037
+ this.lastEventAt = now;
21038
+ this.lastEventKind = kind;
21039
+ this._isStale = false;
21040
+ this._staleSince = null;
21041
+ }
21042
+ recordInternalProgress(kind, now = Date.now()) {
21043
+ this.lastEventAt = now;
21044
+ this.lastEventKind = kind;
21045
+ }
21046
+ markStale(now = Date.now()) {
21047
+ if (this._isStale)
21048
+ return;
21049
+ this._isStale = true;
21050
+ this._staleSince = now;
21051
+ }
21052
+ shouldMarkStale(thresholdMs, now = Date.now()) {
21053
+ if (this._isStale)
21054
+ return false;
21055
+ return this.ageMs(now) > thresholdMs;
21056
+ }
21057
+ processEvent(event, now = Date.now()) {
21058
+ switch (event.kind) {
21059
+ case "text":
21060
+ case "tool_call":
21061
+ case "tool_output":
21062
+ case "turn_end":
21063
+ case "session_init":
21064
+ case "error":
21065
+ this.recordRealEvent(event.kind, now);
21066
+ break;
21067
+ case "internal_progress":
21068
+ case "compaction_started":
21069
+ case "compaction_finished":
21070
+ case "telemetry":
21071
+ case "thinking":
21072
+ this.recordInternalProgress(event.kind, now);
21073
+ break;
21074
+ default:
21075
+ this.recordInternalProgress(event.kind, now);
21076
+ }
21077
+ }
21078
+ }
21079
+
21080
+ // daemon/steering/errorDiagnostics.ts
21081
+ var ACTION_BY_CLASS = {
21082
+ RateLimitError: "retry_backoff",
21083
+ AuthError: "abort",
21084
+ NotFoundError: "report",
21085
+ ModelConfigError: "abort",
21086
+ TimeoutError: "retry",
21087
+ ProviderConnectionError: "retry_jitter",
21088
+ ProviderStreamError: "retry",
21089
+ ProviderServerError: "retry",
21090
+ ProviderApiError: "report",
21091
+ RuntimeError: "report"
21092
+ };
21093
+ var EXPLICIT_TOKEN_RE = /\b([A-Z][A-Za-z0-9_]*(?:Error|Exception))\b/;
21094
+ var EXPLICIT_TOKEN_MAP = {
21095
+ RateLimitError: "RateLimitError",
21096
+ TooManyRequestsError: "RateLimitError",
21097
+ AuthenticationError: "AuthError",
21098
+ AuthorizationError: "AuthError",
21099
+ PermissionError: "AuthError",
21100
+ NotFoundError: "NotFoundError",
21101
+ ModelNotFoundError: "ModelConfigError",
21102
+ TimeoutError: "TimeoutError",
21103
+ ConnectionError: "ProviderConnectionError",
21104
+ APIConnectionError: "ProviderConnectionError",
21105
+ StreamError: "ProviderStreamError",
21106
+ InternalServerError: "ProviderServerError",
21107
+ APIError: "ProviderApiError",
21108
+ BadRequestError: "ProviderApiError"
21109
+ };
21110
+ function extractHttpStatus(message2) {
21111
+ const labeled = /\b(?:HTTP|status(?:\s+code)?|API\s+Error)[:\s]+([45]\d{2})\b/i.exec(message2);
21112
+ if (labeled)
21113
+ return Number(labeled[1]);
21114
+ 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);
21115
+ return semantic ? Number(semantic[1]) : null;
21116
+ }
21117
+ var AUTH_ACTION_REQUIRED_PATTERNS = [
21118
+ /access token could not be refreshed/i,
21119
+ /\btoken_(?:revoked|invalidated)\b/i,
21120
+ /refresh token was already used/i,
21121
+ /access token.*invalidated/i,
21122
+ /authentication token has been invalidated/i,
21123
+ /logged out or signed in to another account/i,
21124
+ /not logged in/i,
21125
+ /not signed in/i,
21126
+ /login required/i,
21127
+ /log in first/i,
21128
+ /please log in/i,
21129
+ /authentication failed/i,
21130
+ /auth(?:entication)? failed/i,
21131
+ /authentication timed out/i,
21132
+ /missing (?:api )?token/i,
21133
+ /no (?:api )?token/i,
21134
+ /missing credentials/i,
21135
+ /credentials? not found/i,
21136
+ /invalid api key/i,
21137
+ /api key (?:is )?not set/i,
21138
+ /token revoked/i,
21139
+ /refresh token expired/i,
21140
+ /session expired/i,
21141
+ /unauthorized/i,
21142
+ /forbidden/i,
21143
+ /invalid.?token/i
21144
+ ];
21145
+ var RATE_LIMIT_PATTERNS = [
21146
+ /too many requests/i,
21147
+ /rate.?limit/i,
21148
+ /quota.?exceeded/i,
21149
+ /overloaded/i
21150
+ ];
21151
+ var MODEL_CONFIG_PATTERNS = [
21152
+ /model.?not.?(?:found|supported|available)/i,
21153
+ /invalid.?model/i,
21154
+ /does not exist/i
21155
+ ];
21156
+ var TIMEOUT_PATTERNS = [
21157
+ /timeout/i,
21158
+ /ETIMEDOUT/,
21159
+ /timed.?out/i,
21160
+ /deadline.?exceeded/i
21161
+ ];
21162
+ var CONNECTION_PATTERNS = [
21163
+ /ECONNREFUSED/,
21164
+ /ECONNRESET/,
21165
+ /ENETUNREACH/,
21166
+ /EHOSTUNREACH/,
21167
+ /EAI_AGAIN/,
21168
+ /ENOTFOUND/,
21169
+ /connection.?refused/i,
21170
+ /connection.?reset/i,
21171
+ /network.?error/i,
21172
+ /Unable to connect to API/i
21173
+ ];
21174
+ var STREAM_PATTERNS = [
21175
+ /stream.?error/i,
21176
+ /stream closed before response/i,
21177
+ /error decoding response body/i,
21178
+ /premature.?close/i,
21179
+ /aborted/i
21180
+ ];
21181
+ var SERVER_PATTERNS = [
21182
+ /internal.?server/i,
21183
+ /bad.?gateway/i,
21184
+ /service.?unavailable/i
21185
+ ];
21186
+ function classifyByExplicitToken(message2) {
21187
+ const match = EXPLICIT_TOKEN_RE.exec(message2);
21188
+ if (!match)
21189
+ return null;
21190
+ const token = match[1];
21191
+ return EXPLICIT_TOKEN_MAP[token] ?? null;
21192
+ }
21193
+ function classifyByHttpStatus(httpStatus) {
21194
+ if (httpStatus === 429)
21195
+ return "RateLimitError";
21196
+ if (httpStatus === 401 || httpStatus === 403)
21197
+ return "AuthError";
21198
+ if (httpStatus === 404)
21199
+ return "NotFoundError";
21200
+ if (httpStatus >= 500)
21201
+ return "ProviderServerError";
21202
+ return "ProviderApiError";
21203
+ }
21204
+ function classifyByTextPatterns(message2) {
21205
+ for (const pat of RATE_LIMIT_PATTERNS) {
21206
+ if (pat.test(message2))
21207
+ return "RateLimitError";
21208
+ }
21209
+ for (const pat of AUTH_ACTION_REQUIRED_PATTERNS) {
21210
+ if (pat.test(message2))
21211
+ return "AuthError";
21212
+ }
21213
+ for (const pat of MODEL_CONFIG_PATTERNS) {
21214
+ if (pat.test(message2))
21215
+ return "ModelConfigError";
21216
+ }
21217
+ for (const pat of TIMEOUT_PATTERNS) {
21218
+ if (pat.test(message2))
21219
+ return "TimeoutError";
21220
+ }
21221
+ for (const pat of CONNECTION_PATTERNS) {
21222
+ if (pat.test(message2))
21223
+ return "ProviderConnectionError";
21224
+ }
21225
+ for (const pat of STREAM_PATTERNS) {
21226
+ if (pat.test(message2))
21227
+ return "ProviderStreamError";
21228
+ }
21229
+ for (const pat of SERVER_PATTERNS) {
21230
+ if (pat.test(message2))
21231
+ return "ProviderServerError";
21232
+ }
21233
+ return null;
21234
+ }
21235
+ function classifyRuntimeError(message2, httpStatus) {
21236
+ const byToken = classifyByExplicitToken(message2);
21237
+ if (byToken) {
21238
+ return { errorClass: byToken, action: ACTION_BY_CLASS[byToken], reason: message2 };
21239
+ }
21240
+ const status = httpStatus ?? extractHttpStatus(message2);
21241
+ if (status !== null && status !== undefined) {
21242
+ const cls = classifyByHttpStatus(status);
21243
+ return { errorClass: cls, action: ACTION_BY_CLASS[cls], reason: message2 };
21244
+ }
21245
+ const byPattern = classifyByTextPatterns(message2);
21246
+ if (byPattern) {
21247
+ return { errorClass: byPattern, action: ACTION_BY_CLASS[byPattern], reason: message2 };
21248
+ }
21249
+ return { errorClass: "RuntimeError", action: "report", reason: message2 };
21250
+ }
21251
+ function scrubDiagnosticText(text2) {
21252
+ let scrubbed = text2;
21253
+ scrubbed = scrubbed.replace(/sk-ant-[a-zA-Z0-9_-]+/g, "sk-ant-***");
21254
+ scrubbed = scrubbed.replace(/sk-proj-[a-zA-Z0-9_-]+/g, "sk-proj-***");
21255
+ scrubbed = scrubbed.replace(/sk-[a-zA-Z0-9_-]{20,}/g, "sk-***");
21256
+ scrubbed = scrubbed.replace(/Bearer\s+[a-zA-Z0-9._-]+/gi, "Bearer ***");
21257
+ scrubbed = scrubbed.replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, "***@***.***");
21258
+ scrubbed = scrubbed.replace(/:\/\/[^:@\s]+:[^@\s]+@/g, "://***:***@");
21259
+ scrubbed = scrubbed.replace(/\/(?:Users|home)\/[a-zA-Z0-9._-]+/g, "/***");
21260
+ return scrubbed;
21261
+ }
21262
+
19348
21263
  // daemon/prompt.ts
19349
21264
  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
21265
  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 +21363,7 @@ function buildMergedPrompt(tasks, attachmentsMap) {
19448
21363
  }
19449
21364
 
19450
21365
  // daemon/session-runner.ts
19451
- var log6 = createLogger2({ module: "session-runner" });
21366
+ var log9 = createLogger2({ module: "session-runner" });
19452
21367
  var ATTACHMENTS_BASE = tempDir("alook-attachments");
19453
21368
  async function writeMarkerFile(workspacesRoot, marker) {
19454
21369
  const dir = path.join(workspacesRoot, ".pending_completions");
@@ -19496,20 +21411,20 @@ async function reportToServer(fn, markerData, workspacesRoot) {
19496
21411
  } catch (e) {
19497
21412
  lastErr = e;
19498
21413
  if (isClientError(e)) {
19499
- log6.info(`server report for task ${markerData.taskId}: task already in terminal state (${e})`);
21414
+ log9.info(`server report for task ${markerData.taskId}: task already in terminal state (${e})`);
19500
21415
  return;
19501
21416
  }
19502
21417
  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`);
21418
+ log9.debug(`server report attempt ${attempt + 1} failed for task ${markerData.taskId}, retrying in ${RETRY_DELAYS[attempt]}ms`);
19504
21419
  await new Promise((r) => setTimeout(r, RETRY_DELAYS[attempt]));
19505
21420
  }
19506
21421
  }
19507
21422
  }
19508
- log6.warn(`server report failed for task ${markerData.taskId} after retries, writing marker: ${lastErr}`);
21423
+ log9.warn(`server report failed for task ${markerData.taskId} after retries, writing marker: ${lastErr}`);
19509
21424
  try {
19510
21425
  await writeMarkerFile(workspacesRoot, markerData);
19511
21426
  } catch (writeErr) {
19512
- log6.error(`marker write also failed for task ${markerData.taskId}: ${writeErr}`);
21427
+ log9.error(`marker write also failed for task ${markerData.taskId}: ${writeErr}`);
19513
21428
  }
19514
21429
  }
19515
21430
  function sanitizeFilename(name) {
@@ -19540,12 +21455,12 @@ async function downloadAttachments(client, token, workspaceId, taskId, attachmen
19540
21455
  }
19541
21456
  async function runSession(input) {
19542
21457
  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"})`);
21458
+ log9.info(`starting (task=${task.id}, type=${task.type}, agent=${task.agentId}, provider=${provider}, model=${model || "default"})`);
19544
21459
  const client = new DaemonClient(serverURL);
19545
21460
  const backend = createBackend(provider, cliPath);
19546
21461
  const agentBaseDir = path.join(workspacesRoot, task.workspaceId, task.agentId, "workdir");
19547
21462
  const timelineDir = path.join(agentBaseDir, ".context_timeline").replace(/\\/g, "/");
19548
- mkdirSync6(timelineDir, { recursive: true });
21463
+ mkdirSync7(timelineDir, { recursive: true });
19549
21464
  await initEntryAsync(timelineDir, createTimelineEntry(task.id, task.prompt, task.type, undefined, process.pid, provider, task.contextKey, input.logFilePath));
19550
21465
  const { workDir, env } = prepare({ workspacesRoot, token }, task);
19551
21466
  let killed = false;
@@ -19563,16 +21478,22 @@ async function runSession(input) {
19563
21478
  try {
19564
21479
  await client.reportMessages(token, task.id, batch);
19565
21480
  } catch (e) {
19566
- log6.debug("message report failed", e);
21481
+ log9.debug("message report failed", e);
19567
21482
  }
19568
21483
  };
21484
+ let mailboxWatcher = null;
21485
+ let stalledRecoveryTimer;
19569
21486
  const onKill = async () => {
19570
21487
  if (killed)
19571
21488
  return;
19572
21489
  killed = true;
19573
- log6.info(`killed by signal (messages=${seq}, tools=${toolCount})`);
21490
+ log9.info(`killed by signal (messages=${seq}, tools=${toolCount})`);
21491
+ if (mailboxWatcher)
21492
+ mailboxWatcher.stop();
21493
+ if (stalledRecoveryTimer)
21494
+ clearInterval(stalledRecoveryTimer);
19574
21495
  if (agentPid !== undefined) {
19575
- log6.info(`killing inner agent group (pid=${agentPid})`);
21496
+ log9.info(`killing inner agent group (pid=${agentPid})`);
19576
21497
  await killProcessTree(agentPid);
19577
21498
  }
19578
21499
  if (flushTimer)
@@ -19615,14 +21536,14 @@ async function runSession(input) {
19615
21536
  const attachmentIds = task.context?.attachment_ids ?? [];
19616
21537
  let attachments;
19617
21538
  if (attachmentIds.length > 0) {
19618
- log6.info(`downloading ${attachmentIds.length} attachment(s)`);
21539
+ log9.info(`downloading ${attachmentIds.length} attachment(s)`);
19619
21540
  try {
19620
21541
  attachments = await downloadAttachments(client, token, task.workspaceId, task.id, attachmentIds);
19621
- log6.info(`attachments ready (${attachments.length} file(s))`);
21542
+ log9.info(`attachments ready (${attachments.length} file(s))`);
19622
21543
  } catch (e) {
19623
21544
  await cleanupAttachments(task.id);
19624
21545
  const errMsg = `failed to download attachments: ${e}`;
19625
- log6.error(errMsg);
21546
+ log9.error(errMsg);
19626
21547
  updateEntry(timelineDir, task.id, (entry) => {
19627
21548
  entry.pid = null;
19628
21549
  entry.status = "failed";
@@ -19639,32 +21560,301 @@ async function runSession(input) {
19639
21560
  const prompt = input.promptOverride ?? buildPrompt(task, attachments);
19640
21561
  const resumeSessionId = task.contextKey ? findResumableSessionByContextKey(timelineDir, task.contextKey, provider) ?? undefined : undefined;
19641
21562
  if (resumeSessionId) {
19642
- log6.info(`resuming session ${resumeSessionId} (context_key: ${task.contextKey})`);
21563
+ log9.info(`resuming session ${resumeSessionId} (context_key: ${task.contextKey})`);
19643
21564
  }
19644
21565
  const session2 = backend.execute(prompt, {
19645
21566
  cwd: workDir,
19646
21567
  model: model || undefined,
19647
21568
  env,
19648
21569
  timeout: agentTimeout,
19649
- resumeSessionId
21570
+ resumeSessionId,
21571
+ steeringEnabled: input.steeringEnabled
19650
21572
  });
19651
21573
  agentPid = session2.pid;
19652
21574
  if (killed) {
19653
21575
  if (agentPid !== undefined) {
19654
- log6.info(`kill landed during spawn — reaping inner agent group (pid=${agentPid})`);
21576
+ log9.info(`kill landed during spawn — reaping inner agent group (pid=${agentPid})`);
19655
21577
  await killProcessTree(agentPid);
19656
21578
  }
19657
21579
  process.exit(1);
19658
21580
  }
19659
21581
  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 }));
21582
+ log9.info(`agent started (pid=${agentPid ?? "unknown"}, session=${earlySessionId})`);
21583
+ log9.info(JSON.stringify({ role: "user", type: "text", content: prompt }));
19662
21584
  updateEntry(timelineDir, task.id, (entry) => {
19663
21585
  entry.session_id = earlySessionId || null;
19664
21586
  if (earlySessionId)
19665
21587
  entry.agent_started = true;
19666
21588
  });
19667
21589
  flushTimer = setInterval(flushMessages, FLUSH_INTERVAL_MS);
21590
+ const turnState = new RuntimeTurnState;
21591
+ let apmState = createInitialApmState();
21592
+ const notificationState = new RuntimeNotificationState;
21593
+ const progressState = new RuntimeProgressState;
21594
+ const pendingSteeredTasks = new Set;
21595
+ const pendingAcks = [];
21596
+ let hasReceivedProgressEvent = false;
21597
+ if (input.steeringEnabled && input.steeringMailboxDir && task.contextKey) {
21598
+ const descriptor = session2.descriptor;
21599
+ const STALLED_THRESHOLD_MS = 120000;
21600
+ const STALLED_CHECK_INTERVAL_MS = 30000;
21601
+ if (session2.parsedEvents) {
21602
+ const parsedIter = session2.parsedEvents[Symbol.asyncIterator]();
21603
+ const consumeParsedEvents = async () => {
21604
+ try {
21605
+ while (!killed) {
21606
+ const { value: event, done } = await parsedIter.next();
21607
+ if (done)
21608
+ break;
21609
+ hasReceivedProgressEvent = true;
21610
+ progressState.processEvent(event);
21611
+ const recentResult = reduceApmGatedRecentEvent(apmState, { event: event.kind });
21612
+ apmState = recentResult.nextState;
21613
+ if (event.kind === "error") {
21614
+ const classified = classifyRuntimeError(event.message);
21615
+ log9.info(`steering: error classified as ${classified.errorClass}: ${scrubDiagnosticText(event.message)}`);
21616
+ const errResult = reduceApmGatedError(apmState, { disableToolBoundaryFlush: true });
21617
+ apmState = errResult.nextState;
21618
+ }
21619
+ switch (event.kind) {
21620
+ case "tool_call":
21621
+ case "thinking":
21622
+ case "compaction_started":
21623
+ turnState.markToolBoundary();
21624
+ break;
21625
+ case "text":
21626
+ case "tool_output":
21627
+ case "compaction_finished":
21628
+ turnState.markProgress();
21629
+ break;
21630
+ }
21631
+ switch (event.kind) {
21632
+ case "session_init":
21633
+ turnState.markTurnStarted(event.sessionId);
21634
+ break;
21635
+ case "text":
21636
+ if (!turnState.isInTurn)
21637
+ turnState.markTurnStarted();
21638
+ break;
21639
+ case "tool_call": {
21640
+ if (!turnState.isInTurn)
21641
+ turnState.markTurnStarted();
21642
+ const result2 = reduceApmGatedToolUse(apmState, { kind: "tool_call" });
21643
+ apmState = result2.nextState;
21644
+ break;
21645
+ }
21646
+ case "tool_output": {
21647
+ const result2 = reduceApmGatedToolUse(apmState, { kind: "tool_output" });
21648
+ apmState = result2.nextState;
21649
+ if (result2.shouldFlushToolBatch && session2.send && apmState.pendingMessages.length > 0) {
21650
+ const readiness = reduceApmGatedFlushReadiness(apmState, {
21651
+ isGated: descriptor?.busyDeliveryMode === "gated",
21652
+ hasSession: !!earlySessionId,
21653
+ inboxLength: apmState.pendingMessages.length,
21654
+ reason: "tool_batch_complete"
21655
+ });
21656
+ if (readiness.shouldNotify) {
21657
+ let allSent = true;
21658
+ for (const msg of apmState.pendingMessages) {
21659
+ const sendResult = session2.send(msg, "busy");
21660
+ if (!sendResult.ok) {
21661
+ allSent = false;
21662
+ break;
21663
+ }
21664
+ }
21665
+ if (allSent) {
21666
+ apmState = { ...apmState, pendingMessages: [] };
21667
+ for (const ack of pendingAcks) {
21668
+ notificationState.recordNoticeWritten(String(ack.seq), ack.sessionId, [{ id: String(ack.seq) }]);
21669
+ writeAck(agentBaseDir, task.contextKey, ack.seq);
21670
+ }
21671
+ pendingAcks.length = 0;
21672
+ }
21673
+ }
21674
+ }
21675
+ break;
21676
+ }
21677
+ case "compaction_started":
21678
+ case "compaction_finished": {
21679
+ const result2 = reduceApmGatedCompaction(apmState, { kind: event.kind });
21680
+ apmState = result2.nextState;
21681
+ if (event.kind === "compaction_finished" && session2.send && apmState.pendingMessages.length > 0) {
21682
+ const readiness = reduceApmGatedFlushReadiness(apmState, {
21683
+ isGated: descriptor?.busyDeliveryMode === "gated",
21684
+ hasSession: !!earlySessionId,
21685
+ inboxLength: apmState.pendingMessages.length,
21686
+ reason: "compaction_finished"
21687
+ });
21688
+ if (readiness.shouldNotify) {
21689
+ let allSent = true;
21690
+ for (const msg of apmState.pendingMessages) {
21691
+ const sendResult = session2.send(msg, "busy");
21692
+ if (!sendResult.ok) {
21693
+ allSent = false;
21694
+ break;
21695
+ }
21696
+ }
21697
+ if (allSent) {
21698
+ apmState = { ...apmState, pendingMessages: [] };
21699
+ for (const ack of pendingAcks) {
21700
+ notificationState.recordNoticeWritten(String(ack.seq), ack.sessionId, [{ id: String(ack.seq) }]);
21701
+ writeAck(agentBaseDir, task.contextKey, ack.seq);
21702
+ }
21703
+ pendingAcks.length = 0;
21704
+ }
21705
+ }
21706
+ }
21707
+ break;
21708
+ }
21709
+ case "turn_end": {
21710
+ const result2 = reduceApmGatedTurnEnd(apmState, {
21711
+ inboxLength: apmState.pendingMessages.length,
21712
+ supportsStdinNotification: descriptor?.supportsStdinNotification,
21713
+ hasSession: !!earlySessionId
21714
+ });
21715
+ apmState = result2.nextState;
21716
+ let flushedOk = false;
21717
+ for (const eff of result2.effects) {
21718
+ if (eff.kind === "deliver_stdin" && session2.send) {
21719
+ let allSent = true;
21720
+ for (const msg of apmState.pendingMessages) {
21721
+ const sendResult = session2.send(msg, eff.stdinMode);
21722
+ if (!sendResult.ok) {
21723
+ log9.warn("steering: send failed during turn_end flush", { reason: sendResult.reason });
21724
+ allSent = false;
21725
+ break;
21726
+ }
21727
+ }
21728
+ if (allSent) {
21729
+ apmState = { ...apmState, pendingMessages: [] };
21730
+ flushedOk = true;
21731
+ }
21732
+ }
21733
+ }
21734
+ if (flushedOk && pendingAcks.length > 0) {
21735
+ for (const ack of pendingAcks) {
21736
+ notificationState.recordNoticeWritten(String(ack.seq), ack.sessionId, [{ id: String(ack.seq) }]);
21737
+ writeAck(agentBaseDir, task.contextKey, ack.seq);
21738
+ }
21739
+ pendingAcks.length = 0;
21740
+ }
21741
+ if (flushedOk || apmState.pendingMessages.length === 0) {
21742
+ for (const steeredId of pendingSteeredTasks) {
21743
+ client.completeTask(token, steeredId, { output: "" }).catch((e) => {
21744
+ log9.debug(`steering: failed to complete steered task ${steeredId}`, e);
21745
+ });
21746
+ }
21747
+ pendingSteeredTasks.clear();
21748
+ }
21749
+ turnState.markTurnCompleted();
21750
+ break;
21751
+ }
21752
+ }
21753
+ }
21754
+ } catch (err) {
21755
+ log9.warn("steering: consumeParsedEvents error", { err: err instanceof Error ? err.message : String(err) });
21756
+ }
21757
+ };
21758
+ consumeParsedEvents().catch((err) => {
21759
+ log9.error("steering: consumeParsedEvents unhandled error", { err: err instanceof Error ? err.message : String(err) });
21760
+ });
21761
+ }
21762
+ stalledRecoveryTimer = setInterval(() => {
21763
+ if (killed)
21764
+ return;
21765
+ if (!hasReceivedProgressEvent) {
21766
+ const startupResult = reduceApmStartupTimeoutTermination(apmState, {
21767
+ hasRuntimeProgressEvent: hasReceivedProgressEvent
21768
+ });
21769
+ apmState = startupResult.nextState;
21770
+ if (startupResult.shouldTerminate) {
21771
+ log9.warn("steering: startup timeout — no progress events received, killing agent");
21772
+ if (agentPid !== undefined)
21773
+ killProcessTree(agentPid);
21774
+ return;
21775
+ }
21776
+ }
21777
+ const staleForMs = progressState.ageMs();
21778
+ if (staleForMs > STALLED_THRESHOLD_MS && !progressState.isStale) {
21779
+ progressState.markStale();
21780
+ }
21781
+ const stalledResult = reduceApmStalledRecoveryTermination(apmState, {
21782
+ inboxLength: apmState.pendingMessages.length,
21783
+ staleForMs,
21784
+ staleThresholdMs: STALLED_THRESHOLD_MS,
21785
+ runtimeProgressIsStale: progressState.isStale,
21786
+ hasSession: !!earlySessionId,
21787
+ busyDeliveryMode: descriptor?.busyDeliveryMode ?? "none",
21788
+ hasDirectStdinRecoveryEvidence: false
21789
+ });
21790
+ apmState = stalledResult.nextState;
21791
+ if (stalledResult.shouldTerminate) {
21792
+ log9.warn(`steering: stalled recovery — agent stale for ${(staleForMs / 1000).toFixed(1)}s with ${apmState.pendingMessages.length} pending messages, killing`);
21793
+ if (agentPid !== undefined)
21794
+ killProcessTree(agentPid);
21795
+ }
21796
+ }, STALLED_CHECK_INTERVAL_MS);
21797
+ mailboxWatcher = watchInbox(agentBaseDir, task.contextKey, (seq2, message2) => {
21798
+ const sessionId = earlySessionId || "";
21799
+ if (notificationState.isDuplicateNotice(String(seq2), sessionId)) {
21800
+ writeAck(agentBaseDir, task.contextKey, seq2);
21801
+ cleanupInboxFile(agentBaseDir, task.contextKey, seq2);
21802
+ return;
21803
+ }
21804
+ const busyMode = session2.descriptor?.busyDeliveryMode;
21805
+ let delivered = false;
21806
+ if (busyMode === "direct" && session2.send) {
21807
+ const result2 = session2.send(message2.text, turnState.isInTurn ? "busy" : "idle");
21808
+ if (result2.ok) {
21809
+ notificationState.recordNoticeWritten(String(seq2), sessionId, [{ id: String(seq2) }]);
21810
+ writeAck(agentBaseDir, task.contextKey, seq2);
21811
+ delivered = true;
21812
+ } else {
21813
+ writeNack(agentBaseDir, task.contextKey, seq2, result2.reason || "send failed");
21814
+ }
21815
+ } else if (busyMode === "gated") {
21816
+ const enqueueResult = reduceApmGatedEnqueue(apmState, message2.text);
21817
+ apmState = enqueueResult.nextState;
21818
+ if (turnState.canSteerBusy && session2.send && apmState.pendingMessages.length > 0) {
21819
+ const readiness = reduceApmGatedFlushReadiness(apmState, {
21820
+ isGated: true,
21821
+ hasSession: !!earlySessionId,
21822
+ inboxLength: apmState.pendingMessages.length,
21823
+ reason: "enqueue"
21824
+ });
21825
+ if (readiness.shouldNotify) {
21826
+ let allSent = true;
21827
+ for (const msg of apmState.pendingMessages) {
21828
+ const sendResult = session2.send(msg, "busy");
21829
+ if (!sendResult.ok) {
21830
+ allSent = false;
21831
+ break;
21832
+ }
21833
+ }
21834
+ if (allSent) {
21835
+ apmState = { ...apmState, pendingMessages: [] };
21836
+ }
21837
+ }
21838
+ }
21839
+ if (apmState.pendingMessages.length === 0) {
21840
+ notificationState.recordNoticeWritten(String(seq2), sessionId, [{ id: String(seq2) }]);
21841
+ writeAck(agentBaseDir, task.contextKey, seq2);
21842
+ } else {
21843
+ pendingAcks.push({ seq: seq2, sessionId });
21844
+ }
21845
+ delivered = true;
21846
+ } else {
21847
+ writeNack(agentBaseDir, task.contextKey, seq2, "unsupported backend");
21848
+ }
21849
+ if (delivered && message2.taskId) {
21850
+ pendingSteeredTasks.add(message2.taskId);
21851
+ client.startTask(token, message2.taskId).catch((e) => {
21852
+ log9.debug(`steering: failed to start steered task ${message2.taskId}`, e);
21853
+ });
21854
+ }
21855
+ cleanupInboxFile(agentBaseDir, task.contextKey, seq2);
21856
+ });
21857
+ }
19668
21858
  const INACTIVITY_TIMEOUT_MS = messageInactivityTimeout ?? 5 * 60 * 1000;
19669
21859
  let inactivityTimedOut = false;
19670
21860
  try {
@@ -19680,7 +21870,7 @@ async function runSession(input) {
19680
21870
  ]) : next);
19681
21871
  if (raceResult === "timeout") {
19682
21872
  inactivityTimedOut = true;
19683
- log6.warn(`message inactivity timeout (${INACTIVITY_TIMEOUT_MS / 1000}s) — killing agent`);
21873
+ log9.warn(`message inactivity timeout (${INACTIVITY_TIMEOUT_MS / 1000}s) — killing agent`);
19684
21874
  if (session2.pid !== undefined) {
19685
21875
  await killProcessTree(session2.pid);
19686
21876
  }
@@ -19695,9 +21885,9 @@ async function runSession(input) {
19695
21885
  if (msg.type === "tool-use")
19696
21886
  toolCount++;
19697
21887
  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)` }));
21888
+ log9.info(JSON.stringify({ role: "assistant", ...msg, output: msg.output.slice(0, 500) + `... (${msg.output.length} chars)` }));
19699
21889
  } else {
19700
- log6.info(JSON.stringify({ role: "assistant", ...msg }));
21890
+ log9.info(JSON.stringify({ role: "assistant", ...msg }));
19701
21891
  }
19702
21892
  if (msg.type === "status" || msg.type === "log")
19703
21893
  continue;
@@ -19736,6 +21926,13 @@ async function runSession(input) {
19736
21926
  result.status = "failed";
19737
21927
  result.error = `message inactivity timeout (no messages for ${INACTIVITY_TIMEOUT_MS / 1000}s)`;
19738
21928
  }
21929
+ if (stalledRecoveryTimer)
21930
+ clearInterval(stalledRecoveryTimer);
21931
+ if (mailboxWatcher) {
21932
+ mailboxWatcher.stop();
21933
+ if (task.contextKey)
21934
+ cleanupSteeringDir(agentBaseDir, task.contextKey);
21935
+ }
19739
21936
  await cleanupAttachments(task.id);
19740
21937
  if (result.status === "completed") {
19741
21938
  updateEntry(timelineDir, task.id, (entry) => {
@@ -19758,18 +21955,18 @@ async function runSession(input) {
19758
21955
  body.session_id = result.sessionId;
19759
21956
  await reportToServer(() => client.completeTask(token, task.id, body), { taskId: task.id, type: "complete", payload: body, token, serverURL, createdAt: new Date().toISOString() }, workspacesRoot);
19760
21957
  const dur = (result.durationMs / 1000).toFixed(1);
19761
- log6.info(`completed (duration=${dur}s, messages=${seq}, tools=${toolCount})`);
21958
+ log9.info(`completed (duration=${dur}s, messages=${seq}, tools=${toolCount})`);
19762
21959
  } else {
19763
21960
  const errorMsg = result.error || "agent exited unexpectedly";
19764
21961
  await reportToServer(() => client.failTask(token, task.id, errorMsg), { taskId: task.id, type: "fail", payload: { error: errorMsg }, token, serverURL, createdAt: new Date().toISOString() }, workspacesRoot);
19765
21962
  const dur = (result.durationMs / 1000).toFixed(1);
19766
- log6.info(`failed (duration=${dur}s, messages=${seq}, tools=${toolCount}) — ${result.error}`);
21963
+ log9.info(`failed (duration=${dur}s, messages=${seq}, tools=${toolCount}) — ${result.error}`);
19767
21964
  }
19768
21965
  }
19769
21966
  async function main() {
19770
21967
  const encoded = process.argv[2];
19771
21968
  if (!encoded) {
19772
- log6.error("session-runner: missing base64-encoded input argument");
21969
+ log9.error("session-runner: missing base64-encoded input argument");
19773
21970
  process.exit(1);
19774
21971
  }
19775
21972
  let input;
@@ -19777,14 +21974,14 @@ async function main() {
19777
21974
  const json2 = Buffer.from(encoded, "base64").toString("utf-8");
19778
21975
  input = JSON.parse(json2);
19779
21976
  } catch (e) {
19780
- log6.error("session-runner: failed to parse input", e);
21977
+ log9.error("session-runner: failed to parse input", e);
19781
21978
  process.exit(1);
19782
21979
  }
19783
21980
  const client = new DaemonClient(input.serverURL);
19784
21981
  try {
19785
21982
  await runSession(input);
19786
21983
  } catch (e) {
19787
- log6.error(`session-runner: unhandled error for task ${input.task.id}`, e);
21984
+ log9.error(`session-runner: unhandled error for task ${input.task.id}`, e);
19788
21985
  await cleanupAttachments(input.task.id);
19789
21986
  const timelineDir = path.join(input.workspacesRoot, input.task.workspaceId, input.task.agentId, "workdir", ".context_timeline").replace(/\\/g, "/");
19790
21987
  updateEntry(timelineDir, input.task.id, (entry) => {
@@ -19803,7 +22000,7 @@ if (isDirectExecution) {
19803
22000
  }
19804
22001
 
19805
22002
  // daemon/ws-client.ts
19806
- var log7 = createLogger2({ module: "ws-client" });
22003
+ var log10 = createLogger2({ module: "ws-client" });
19807
22004
  var WS_RECONNECT_INIT = 1000;
19808
22005
  var WS_RECONNECT_MAX = 30000;
19809
22006
  var WS_PING_INTERVAL = 25000;
@@ -19840,11 +22037,11 @@ class DaemonWsClient {
19840
22037
  return;
19841
22038
  this.cleanup();
19842
22039
  const wsUrl = this.getUrl();
19843
- log7.info("connecting", { url: wsUrl });
22040
+ log10.info("connecting", { url: wsUrl });
19844
22041
  try {
19845
22042
  this.ws = new WebSocket(wsUrl);
19846
22043
  } catch (err) {
19847
- log7.warn("ws creation failed", { err: String(err) });
22044
+ log10.warn("ws creation failed", { err: String(err) });
19848
22045
  this.scheduleReconnect();
19849
22046
  return;
19850
22047
  }
@@ -19866,23 +22063,23 @@ class DaemonWsClient {
19866
22063
  try {
19867
22064
  const msg = JSON.parse(str);
19868
22065
  if (msg.type === "auth.ok") {
19869
- log7.info("authenticated");
22066
+ log10.info("authenticated");
19870
22067
  this.connected = true;
19871
22068
  this.opts.onConnected();
19872
22069
  return;
19873
22070
  }
19874
22071
  const parsed = DaemonPushMessageSchema.safeParse(msg);
19875
22072
  if (!parsed.success) {
19876
- log7.warn("invalid push message", { err: parsed.error.message });
22073
+ log10.warn("invalid push message", { err: parsed.error.message });
19877
22074
  return;
19878
22075
  }
19879
22076
  this.opts.onMessage(parsed.data);
19880
22077
  } catch (err) {
19881
- log7.debug("message parse error", { err: String(err) });
22078
+ log10.debug("message parse error", { err: String(err) });
19882
22079
  }
19883
22080
  });
19884
22081
  this.ws.addEventListener("error", () => {
19885
- log7.debug("ws error");
22082
+ log10.debug("ws error");
19886
22083
  });
19887
22084
  this.ws.addEventListener("close", () => {
19888
22085
  const wasConnected = this.connected;
@@ -19920,7 +22117,7 @@ class DaemonWsClient {
19920
22117
  const delay = Math.min(this.reconnectDelay, WS_RECONNECT_MAX);
19921
22118
  this.reconnectDelay = Math.min(delay * 2, WS_RECONNECT_MAX);
19922
22119
  const jitter = Math.random() * 500;
19923
- log7.debug("reconnecting", { delayMs: Math.round(delay + jitter) });
22120
+ log10.debug("reconnecting", { delayMs: Math.round(delay + jitter) });
19924
22121
  this.reconnectTimer = setTimeout(() => {
19925
22122
  this.reconnectTimer = null;
19926
22123
  this.connect();
@@ -19934,7 +22131,7 @@ class DaemonWsClient {
19934
22131
  }, WS_PING_INTERVAL);
19935
22132
  this.livenessInterval = setInterval(() => {
19936
22133
  if (Date.now() - this.lastMessageAt > WS_LIVENESS_TIMEOUT) {
19937
- log7.warn("liveness timeout, closing");
22134
+ log10.warn("liveness timeout, closing");
19938
22135
  this.ws?.close();
19939
22136
  }
19940
22137
  }, 5000);
@@ -19952,7 +22149,7 @@ class DaemonWsClient {
19952
22149
  }
19953
22150
 
19954
22151
  // daemon/update-handler.ts
19955
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync6, unlinkSync as unlinkSync4 } from "fs";
22152
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, unlinkSync as unlinkSync5 } from "fs";
19956
22153
 
19957
22154
  // lib/update.ts
19958
22155
  import { spawn as spawn4 } from "child_process";
@@ -19982,7 +22179,7 @@ function runNpmUpdate(targetVersion) {
19982
22179
  }
19983
22180
 
19984
22181
  // daemon/update-handler.ts
19985
- var log8 = createLogger2({ module: "updater" });
22182
+ var log11 = createLogger2({ module: "updater" });
19986
22183
  var updating = false;
19987
22184
  var retryCount = 0;
19988
22185
  var MAX_RETRIES = 3;
@@ -19991,19 +22188,19 @@ function isUpdating() {
19991
22188
  }
19992
22189
  function readUpdateMarker(profile) {
19993
22190
  try {
19994
- return readFileSync7(lastUpdateMarkerPath(profile), "utf-8").trim() || null;
22191
+ return readFileSync8(lastUpdateMarkerPath(profile), "utf-8").trim() || null;
19995
22192
  } catch {
19996
22193
  return null;
19997
22194
  }
19998
22195
  }
19999
22196
  function writeUpdateMarker(version3, profile) {
20000
22197
  try {
20001
- writeFileSync6(lastUpdateMarkerPath(profile), version3, { mode: 384 });
22198
+ writeFileSync7(lastUpdateMarkerPath(profile), version3, { mode: 384 });
20002
22199
  } catch {}
20003
22200
  }
20004
22201
  function clearUpdateMarker(profile) {
20005
22202
  try {
20006
- unlinkSync4(lastUpdateMarkerPath(profile));
22203
+ unlinkSync5(lastUpdateMarkerPath(profile));
20007
22204
  } catch {}
20008
22205
  }
20009
22206
  async function handleCliUpdate(version3, onSuccess, profile) {
@@ -20012,29 +22209,29 @@ async function handleCliUpdate(version3, onSuccess, profile) {
20012
22209
  if (retryCount >= MAX_RETRIES)
20013
22210
  return;
20014
22211
  if (process.env.ALOOK_CMD_PREFIX) {
20015
- log8.info(`Skipping auto-update in app mode — user should run: npx @alook/app@latest update`);
22212
+ log11.info(`Skipping auto-update in app mode — user should run: npx @alook/app@latest update`);
20016
22213
  return;
20017
22214
  }
20018
22215
  const marker = readUpdateMarker(profile);
20019
22216
  if (marker === version3) {
20020
- log8.info(`Skipping update to v${version3} — already attempted (marker exists)`);
22217
+ log11.info(`Skipping update to v${version3} — already attempted (marker exists)`);
20021
22218
  return;
20022
22219
  }
20023
22220
  updating = true;
20024
22221
  try {
20025
- log8.info(`Updating CLI to v${version3}...`);
22222
+ log11.info(`Updating CLI to v${version3}...`);
20026
22223
  const result = await runNpmUpdate(version3);
20027
22224
  if (result.success) {
20028
22225
  writeUpdateMarker(version3, profile);
20029
- log8.info(`CLI updated to v${version3} — restarting`);
22226
+ log11.info(`CLI updated to v${version3} — restarting`);
20030
22227
  onSuccess();
20031
22228
  } else {
20032
22229
  retryCount++;
20033
- log8.error(`CLI update failed (attempt ${retryCount}/${MAX_RETRIES}): ${result.output}`);
22230
+ log11.error(`CLI update failed (attempt ${retryCount}/${MAX_RETRIES}): ${result.output}`);
20034
22231
  }
20035
22232
  } catch (e) {
20036
22233
  retryCount++;
20037
- log8.error(`CLI update error (attempt ${retryCount}/${MAX_RETRIES})`, e);
22234
+ log11.error(`CLI update error (attempt ${retryCount}/${MAX_RETRIES})`, e);
20038
22235
  } finally {
20039
22236
  updating = false;
20040
22237
  }
@@ -20042,7 +22239,7 @@ async function handleCliUpdate(version3, onSuccess, profile) {
20042
22239
 
20043
22240
  // daemon/workspace-files.ts
20044
22241
  import { readdir, stat, readFile } from "fs/promises";
20045
- import { join as join9, resolve, extname, relative, sep as sep2 } from "path";
22242
+ import { join as join10, resolve, extname, relative, sep as sep2 } from "path";
20046
22243
  var SKIP_DIRS = new Set([".git", "node_modules", ".next", ".wrangler", "__pycache__", ".venv"]);
20047
22244
  var TEXT_EXTENSIONS = new Set([
20048
22245
  ".md",
@@ -20101,7 +22298,7 @@ async function readDirectoryTree(dirPath, basePath) {
20101
22298
  if (ext !== "" && !TEXT_EXTENSIONS.has(ext))
20102
22299
  continue;
20103
22300
  }
20104
- const fullPath = join9(dirPath, entry.name);
22301
+ const fullPath = join10(dirPath, entry.name);
20105
22302
  let info;
20106
22303
  try {
20107
22304
  info = await stat(fullPath);
@@ -20139,13 +22336,13 @@ function validatePath(agentWorkdir, requestedPath) {
20139
22336
  }
20140
22337
 
20141
22338
  // 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";
22339
+ import { existsSync as existsSync3, mkdirSync as mkdirSync8, readFileSync as readFileSync9, writeFileSync as writeFileSync8, readdirSync as readdirSync3, statSync as statSync3, realpathSync } from "fs";
22340
+ import { join as join11, basename } from "path";
20144
22341
  import { homedir as homedir2 } from "os";
20145
22342
  import { createHash as createHash2 } from "crypto";
20146
- var log9 = createLogger2({ module: "skill-scanner" });
22343
+ var log12 = createLogger2({ module: "skill-scanner" });
20147
22344
  function getCacheDir() {
20148
- return join10(configDir(), "skills");
22345
+ return join11(configDir(), "skills");
20149
22346
  }
20150
22347
  function parseFrontmatter(content) {
20151
22348
  const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
@@ -20163,22 +22360,22 @@ function parseFrontmatter(content) {
20163
22360
  }
20164
22361
  function safeReadDir(dir) {
20165
22362
  try {
20166
- if (!existsSync2(dir))
22363
+ if (!existsSync3(dir))
20167
22364
  return [];
20168
- return readdirSync2(dir);
22365
+ return readdirSync3(dir);
20169
22366
  } catch {
20170
22367
  return [];
20171
22368
  }
20172
22369
  }
20173
22370
  function findSkillFiles(baseDir, pattern) {
20174
22371
  const results = [];
20175
- if (!existsSync2(baseDir))
22372
+ if (!existsSync3(baseDir))
20176
22373
  return results;
20177
22374
  if (pattern === "*/SKILL.md") {
20178
22375
  for (const entry of safeReadDir(baseDir)) {
20179
- const skillPath = join10(baseDir, entry, "SKILL.md");
22376
+ const skillPath = join11(baseDir, entry, "SKILL.md");
20180
22377
  try {
20181
- if (existsSync2(skillPath) && statSync3(skillPath).isFile()) {
22378
+ if (existsSync3(skillPath) && statSync3(skillPath).isFile()) {
20182
22379
  results.push(skillPath);
20183
22380
  }
20184
22381
  } catch {}
@@ -20188,7 +22385,7 @@ function findSkillFiles(baseDir, pattern) {
20188
22385
  } else if (pattern === "*.md") {
20189
22386
  for (const entry of safeReadDir(baseDir)) {
20190
22387
  if (entry.endsWith(".md")) {
20191
- const filePath = join10(baseDir, entry);
22388
+ const filePath = join11(baseDir, entry);
20192
22389
  try {
20193
22390
  if (statSync3(filePath).isFile()) {
20194
22391
  results.push(filePath);
@@ -20203,16 +22400,16 @@ function walkForSkills(dir, results, depth = 0) {
20203
22400
  if (depth > 5)
20204
22401
  return;
20205
22402
  try {
20206
- for (const entry of readdirSync2(dir)) {
20207
- const full = join10(dir, entry);
22403
+ for (const entry of readdirSync3(dir)) {
22404
+ const full = join11(dir, entry);
20208
22405
  try {
20209
22406
  const st = statSync3(full);
20210
22407
  if (st.isDirectory()) {
20211
22408
  if (entry === "skills") {
20212
22409
  for (const skillDir of safeReadDir(full)) {
20213
- const skillPath = join10(full, skillDir, "SKILL.md");
22410
+ const skillPath = join11(full, skillDir, "SKILL.md");
20214
22411
  try {
20215
- if (existsSync2(skillPath) && statSync3(skillPath).isFile()) {
22412
+ if (existsSync3(skillPath) && statSync3(skillPath).isFile()) {
20216
22413
  results.push(skillPath);
20217
22414
  }
20218
22415
  } catch {}
@@ -20229,7 +22426,7 @@ function scanFrontmatterSkills(paths) {
20229
22426
  const skills = new Map;
20230
22427
  for (const filePath of paths) {
20231
22428
  try {
20232
- const content = readFileSync8(filePath, "utf-8");
22429
+ const content = readFileSync9(filePath, "utf-8");
20233
22430
  const meta3 = parseFrontmatter(content);
20234
22431
  if (meta3 && !skills.has(meta3.name)) {
20235
22432
  skills.set(meta3.name, meta3);
@@ -20241,14 +22438,14 @@ function scanFrontmatterSkills(paths) {
20241
22438
  function scanClaudeGlobalSkills() {
20242
22439
  const home = homedir2();
20243
22440
  const allSkills = [];
20244
- const directPaths = findSkillFiles(join10(home, ".claude", "skills"), "*/SKILL.md");
22441
+ const directPaths = findSkillFiles(join11(home, ".claude", "skills"), "*/SKILL.md");
20245
22442
  allSkills.push(...scanFrontmatterSkills(directPaths));
20246
- const pluginCacheDir = join10(home, ".claude", "plugins", "cache");
22443
+ const pluginCacheDir = join11(home, ".claude", "plugins", "cache");
20247
22444
  const pluginPaths = findSkillFiles(pluginCacheDir, "**/skills/*/SKILL.md");
20248
22445
  const names = new Set(allSkills.map((s) => s.name));
20249
22446
  for (const filePath of pluginPaths) {
20250
22447
  try {
20251
- const content = readFileSync8(filePath, "utf-8");
22448
+ const content = readFileSync9(filePath, "utf-8");
20252
22449
  const meta3 = parseFrontmatter(content);
20253
22450
  if (meta3 && !names.has(meta3.name)) {
20254
22451
  names.add(meta3.name);
@@ -20259,23 +22456,23 @@ function scanClaudeGlobalSkills() {
20259
22456
  return allSkills;
20260
22457
  }
20261
22458
  function scanClaudeAgentSkills(workdir) {
20262
- const paths = findSkillFiles(join10(workdir, ".claude", "skills"), "*/SKILL.md");
22459
+ const paths = findSkillFiles(join11(workdir, ".claude", "skills"), "*/SKILL.md");
20263
22460
  return scanFrontmatterSkills(paths);
20264
22461
  }
20265
22462
  function scanCodexGlobalSkills() {
20266
22463
  const home = homedir2();
20267
22464
  const allSkills = [];
20268
22465
  const paths = [
20269
- ...findSkillFiles(join10(home, ".agents", "skills"), "*/SKILL.md"),
20270
- ...findSkillFiles(join10(home, ".codex", "skills", ".system"), "*/SKILL.md")
22466
+ ...findSkillFiles(join11(home, ".agents", "skills"), "*/SKILL.md"),
22467
+ ...findSkillFiles(join11(home, ".codex", "skills", ".system"), "*/SKILL.md")
20271
22468
  ];
20272
22469
  allSkills.push(...scanFrontmatterSkills(paths));
20273
- const codexPluginDir = join10(home, ".codex", "plugins", "cache");
22470
+ const codexPluginDir = join11(home, ".codex", "plugins", "cache");
20274
22471
  const pluginPaths = findSkillFiles(codexPluginDir, "**/skills/*/SKILL.md");
20275
22472
  const names = new Set(allSkills.map((s) => s.name));
20276
22473
  for (const filePath of pluginPaths) {
20277
22474
  try {
20278
- const content = readFileSync8(filePath, "utf-8");
22475
+ const content = readFileSync9(filePath, "utf-8");
20279
22476
  const meta3 = parseFrontmatter(content);
20280
22477
  if (meta3 && !names.has(meta3.name)) {
20281
22478
  names.add(meta3.name);
@@ -20286,7 +22483,7 @@ function scanCodexGlobalSkills() {
20286
22483
  return allSkills;
20287
22484
  }
20288
22485
  function scanCodexAgentSkills(workdir) {
20289
- const paths = findSkillFiles(join10(workdir, ".agents", "skills"), "*/SKILL.md");
22486
+ const paths = findSkillFiles(join11(workdir, ".agents", "skills"), "*/SKILL.md");
20290
22487
  return scanFrontmatterSkills(paths);
20291
22488
  }
20292
22489
  function scanOpenCodeMdFiles(dir) {
@@ -20294,7 +22491,7 @@ function scanOpenCodeMdFiles(dir) {
20294
22491
  const files = findSkillFiles(dir, "*.md");
20295
22492
  for (const filePath of files) {
20296
22493
  try {
20297
- const content = readFileSync8(filePath, "utf-8");
22494
+ const content = readFileSync9(filePath, "utf-8");
20298
22495
  const name = basename(filePath, ".md");
20299
22496
  const firstLine = content.split(`
20300
22497
  `).find((l) => l.trim().length > 0) ?? "";
@@ -20307,13 +22504,13 @@ function scanOpenCodeGlobalSkills() {
20307
22504
  const home = homedir2();
20308
22505
  const skills = [];
20309
22506
  const names = new Set;
20310
- for (const s of scanOpenCodeMdFiles(join10(home, ".config", "opencode", "commands"))) {
22507
+ for (const s of scanOpenCodeMdFiles(join11(home, ".config", "opencode", "commands"))) {
20311
22508
  if (!names.has(s.name)) {
20312
22509
  names.add(s.name);
20313
22510
  skills.push(s);
20314
22511
  }
20315
22512
  }
20316
- for (const s of scanOpenCodeMdFiles(join10(home, ".config", "opencode", "skills"))) {
22513
+ for (const s of scanOpenCodeMdFiles(join11(home, ".config", "opencode", "skills"))) {
20317
22514
  if (!names.has(s.name)) {
20318
22515
  names.add(s.name);
20319
22516
  skills.push(s);
@@ -20324,13 +22521,13 @@ function scanOpenCodeGlobalSkills() {
20324
22521
  function scanOpenCodeAgentSkills(workdir) {
20325
22522
  const skills = [];
20326
22523
  const names = new Set;
20327
- for (const s of scanOpenCodeMdFiles(join10(workdir, ".opencode", "commands"))) {
22524
+ for (const s of scanOpenCodeMdFiles(join11(workdir, ".opencode", "commands"))) {
20328
22525
  if (!names.has(s.name)) {
20329
22526
  names.add(s.name);
20330
22527
  skills.push(s);
20331
22528
  }
20332
22529
  }
20333
- for (const s of scanOpenCodeMdFiles(join10(workdir, ".opencode", "skills"))) {
22530
+ for (const s of scanOpenCodeMdFiles(join11(workdir, ".opencode", "skills"))) {
20334
22531
  if (!names.has(s.name)) {
20335
22532
  names.add(s.name);
20336
22533
  skills.push(s);
@@ -20342,26 +22539,26 @@ function computeHash(skills) {
20342
22539
  return createHash2("md5").update(JSON.stringify(skills)).digest("hex");
20343
22540
  }
20344
22541
  function globalCachePath(daemonId, runtime) {
20345
- return join10(getCacheDir(), "global", daemonId, `${runtime}.json`);
22542
+ return join11(getCacheDir(), "global", daemonId, `${runtime}.json`);
20346
22543
  }
20347
22544
  function agentCachePath(agentId, runtime) {
20348
- return join10(getCacheDir(), "agents", agentId, `${runtime}.json`);
22545
+ return join11(getCacheDir(), "agents", agentId, `${runtime}.json`);
20349
22546
  }
20350
22547
  function readCacheHash(filePath) {
20351
22548
  try {
20352
- if (!existsSync2(filePath))
22549
+ if (!existsSync3(filePath))
20353
22550
  return null;
20354
- const data = JSON.parse(readFileSync8(filePath, "utf-8"));
22551
+ const data = JSON.parse(readFileSync9(filePath, "utf-8"));
20355
22552
  return data.hash ?? null;
20356
22553
  } catch {
20357
22554
  return null;
20358
22555
  }
20359
22556
  }
20360
22557
  function writeCacheFile(filePath, hash2, skills) {
20361
- const dir = join10(filePath, "..");
20362
- mkdirSync7(dir, { recursive: true });
22558
+ const dir = join11(filePath, "..");
22559
+ mkdirSync8(dir, { recursive: true });
20363
22560
  const data = { hash: hash2, skills };
20364
- writeFileSync7(filePath, JSON.stringify(data, null, 2), "utf-8");
22561
+ writeFileSync8(filePath, JSON.stringify(data, null, 2), "utf-8");
20365
22562
  }
20366
22563
  function isClientError2(err) {
20367
22564
  if (err instanceof Error) {
@@ -20379,17 +22576,17 @@ var clientRef = null;
20379
22576
  function discoverTargets() {
20380
22577
  if (!scannerConfig)
20381
22578
  return [];
20382
- const rootExists = existsSync2(scannerConfig.workspacesRoot);
22579
+ const rootExists = existsSync3(scannerConfig.workspacesRoot);
20383
22580
  const rootReal = rootExists ? realpathSync(scannerConfig.workspacesRoot) : null;
20384
22581
  const targets = [];
20385
22582
  for (const ws of scannerConfig.workspaces) {
20386
22583
  const agentIds = new Set(ws.agentIds);
20387
22584
  if (rootReal) {
20388
- const wsDir = join10(scannerConfig.workspacesRoot, ws.workspaceId);
22585
+ const wsDir = join11(scannerConfig.workspacesRoot, ws.workspaceId);
20389
22586
  try {
20390
- if (existsSync2(wsDir)) {
20391
- for (const dir of readdirSync2(wsDir)) {
20392
- if (existsSync2(join10(wsDir, dir, "workdir")))
22587
+ if (existsSync3(wsDir)) {
22588
+ for (const dir of readdirSync3(wsDir)) {
22589
+ if (existsSync3(join11(wsDir, dir, "workdir")))
20393
22590
  agentIds.add(dir);
20394
22591
  }
20395
22592
  }
@@ -20398,8 +22595,8 @@ function discoverTargets() {
20398
22595
  for (const agentId of agentIds) {
20399
22596
  let validWorkdir = null;
20400
22597
  if (rootReal) {
20401
- const workdir = join10(scannerConfig.workspacesRoot, ws.workspaceId, agentId, "workdir");
20402
- if (existsSync2(workdir)) {
22598
+ const workdir = join11(scannerConfig.workspacesRoot, ws.workspaceId, agentId, "workdir");
22599
+ if (existsSync3(workdir)) {
20403
22600
  try {
20404
22601
  if (realpathSync(workdir).startsWith(rootReal))
20405
22602
  validWorkdir = workdir;
@@ -20439,7 +22636,7 @@ function runScan() {
20439
22636
  const prevHash = readCacheHash(globalCachePath(scannerConfig.daemonId, runtime));
20440
22637
  if (prevHash !== hash2) {
20441
22638
  const skillItems = skills.map((s) => ({ name: s.name, description: s.description }));
20442
- log9.debug(`Syncing global ${runtime} — ${skills.length} skills`);
22639
+ log12.debug(`Syncing global ${runtime} — ${skills.length} skills`);
20443
22640
  const daemonId = scannerConfig.daemonId;
20444
22641
  const syncPromises = scannerConfig.workspaces.map((ws) => clientRef.syncSkills(ws.token, {
20445
22642
  scope: "global",
@@ -20453,11 +22650,11 @@ function runScan() {
20453
22650
  if (isClientError2(e)) {
20454
22651
  writeCacheFile(globalCachePath(daemonId, runtime), hash2, skills);
20455
22652
  }
20456
- log9.debug("Global skill sync failed", e);
22653
+ log12.debug("Global skill sync failed", e);
20457
22654
  });
20458
22655
  }
20459
22656
  } catch (e) {
20460
- log9.debug(`Global scan error for ${runtime}`, e);
22657
+ log12.debug(`Global scan error for ${runtime}`, e);
20461
22658
  }
20462
22659
  }
20463
22660
  const targets = discoverTargets();
@@ -20470,7 +22667,7 @@ function runScan() {
20470
22667
  const prevHash = readCacheHash(agentCachePath(target.agentId, target.runtime));
20471
22668
  if (prevHash !== hash2) {
20472
22669
  const skillItems = skills.map((s) => ({ name: s.name, description: s.description }));
20473
- log9.debug(`Syncing ${target.agentId}:${target.runtime} — ${skills.length} agent skills`);
22670
+ log12.debug(`Syncing ${target.agentId}:${target.runtime} — ${skills.length} agent skills`);
20474
22671
  clientRef.syncSkills(target.token, {
20475
22672
  scope: "agent",
20476
22673
  agent_id: target.agentId,
@@ -20482,11 +22679,11 @@ function runScan() {
20482
22679
  if (isClientError2(e)) {
20483
22680
  writeCacheFile(agentCachePath(target.agentId, target.runtime), hash2, skills);
20484
22681
  }
20485
- log9.debug("Agent skill sync failed", e);
22682
+ log12.debug("Agent skill sync failed", e);
20486
22683
  });
20487
22684
  }
20488
22685
  } catch (e) {
20489
- log9.debug(`Agent scan error for ${target.agentId}:${target.runtime}`, e);
22686
+ log12.debug(`Agent scan error for ${target.agentId}:${target.runtime}`, e);
20490
22687
  }
20491
22688
  }
20492
22689
  }
@@ -20537,15 +22734,15 @@ function resolveLoginShellEnv() {
20537
22734
  }
20538
22735
 
20539
22736
  // daemon/daemon.ts
20540
- import { existsSync as existsSync3, mkdirSync as mkdirSync8, openSync, closeSync, readdirSync as readdirSync3, statSync as statSync4, unlinkSync as unlinkSync5 } from "fs";
22737
+ import { existsSync as existsSync4, mkdirSync as mkdirSync9, openSync, closeSync, readdirSync as readdirSync4, statSync as statSync4, unlinkSync as unlinkSync6 } from "fs";
20541
22738
  import { readdir as readdir2, readFile as readFile2, unlink, stat as fsStat } from "fs/promises";
20542
22739
  import { execSync as execSync4, spawn as spawn5 } from "child_process";
20543
22740
  import { fileURLToPath as fileURLToPath2 } from "url";
20544
- import { dirname as dirname3, join as join11 } from "path";
20545
- var log10 = createLogger2({ module: "daemon" });
22741
+ import { dirname as dirname3, join as join12 } from "path";
22742
+ var log13 = createLogger2({ module: "daemon" });
20546
22743
  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");
22744
+ var sessionRunnerPath = existsSync4(join12(_dir, "session-runner.js")) ? join12(_dir, "session-runner.js") : join12(_dir, "session-runner.ts");
22745
+ var meetingRunnerPath = existsSync4(join12(_dir, "meeting-runner.js")) ? join12(_dir, "meeting-runner.js") : join12(_dir, "meeting-runner.ts");
20549
22746
  function isCommandAvailable(cmd) {
20550
22747
  try {
20551
22748
  const check2 = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
@@ -20560,14 +22757,14 @@ function pruneSessionRunnerLogs() {
20560
22757
  const logDir = sessionRunnerLogDir();
20561
22758
  let entries;
20562
22759
  try {
20563
- entries = readdirSync3(logDir).filter((f) => f.endsWith(".log"));
22760
+ entries = readdirSync4(logDir).filter((f) => f.endsWith(".log"));
20564
22761
  } catch {
20565
22762
  return;
20566
22763
  }
20567
22764
  if (entries.length <= MAX_SESSION_RUNNER_LOGS)
20568
22765
  return;
20569
22766
  const withMtime = entries.map((name) => {
20570
- const full = join11(logDir, name);
22767
+ const full = join12(logDir, name);
20571
22768
  try {
20572
22769
  return { name, mtime: statSync4(full).mtimeMs };
20573
22770
  } catch {
@@ -20577,7 +22774,7 @@ function pruneSessionRunnerLogs() {
20577
22774
  withMtime.sort((a, b) => b.mtime - a.mtime);
20578
22775
  for (const entry of withMtime.slice(MAX_SESSION_RUNNER_LOGS)) {
20579
22776
  try {
20580
- unlinkSync5(join11(logDir, entry.name));
22777
+ unlinkSync6(join12(logDir, entry.name));
20581
22778
  } catch {}
20582
22779
  }
20583
22780
  }
@@ -20618,7 +22815,7 @@ function isValidMarker(data) {
20618
22815
  var MARKER_STALE_MS = 24 * 60 * 60 * 1000;
20619
22816
  var TMP_STALE_MS = 60 * 60 * 1000;
20620
22817
  async function reconcilePendingCompletions(workspacesRoot) {
20621
- const dir = join11(workspacesRoot, ".pending_completions");
22818
+ const dir = join12(workspacesRoot, ".pending_completions");
20622
22819
  let entries;
20623
22820
  try {
20624
22821
  entries = await readdir2(dir);
@@ -20629,15 +22826,15 @@ async function reconcilePendingCompletions(workspacesRoot) {
20629
22826
  if (!name.endsWith(".tmp"))
20630
22827
  continue;
20631
22828
  try {
20632
- const s = await fsStat(join11(dir, name));
22829
+ const s = await fsStat(join12(dir, name));
20633
22830
  if (Date.now() - s.mtimeMs > TMP_STALE_MS) {
20634
- await unlink(join11(dir, name));
22831
+ await unlink(join12(dir, name));
20635
22832
  }
20636
22833
  } catch {}
20637
22834
  }
20638
22835
  const jsonFiles = entries.filter((f) => f.endsWith(".json"));
20639
22836
  for (const name of jsonFiles) {
20640
- const filePath = join11(dir, name);
22837
+ const filePath = join12(dir, name);
20641
22838
  try {
20642
22839
  let raw;
20643
22840
  try {
@@ -20649,14 +22846,14 @@ async function reconcilePendingCompletions(workspacesRoot) {
20649
22846
  try {
20650
22847
  parsed = JSON.parse(raw);
20651
22848
  } catch {
20652
- log10.warn(`reconcile: malformed marker ${name}, deleting`);
22849
+ log13.warn(`reconcile: malformed marker ${name}, deleting`);
20653
22850
  try {
20654
22851
  await unlink(filePath);
20655
22852
  } catch {}
20656
22853
  continue;
20657
22854
  }
20658
22855
  if (!isValidMarker(parsed)) {
20659
- log10.warn(`reconcile: invalid marker structure ${name}, deleting`);
22856
+ log13.warn(`reconcile: invalid marker structure ${name}, deleting`);
20660
22857
  try {
20661
22858
  await unlink(filePath);
20662
22859
  } catch {}
@@ -20665,7 +22862,7 @@ async function reconcilePendingCompletions(workspacesRoot) {
20665
22862
  const marker = parsed;
20666
22863
  const age = Date.now() - new Date(marker.createdAt).getTime();
20667
22864
  if (age > MARKER_STALE_MS) {
20668
- log10.warn(`reconcile: stale marker ${name} (${Math.round(age / 3600000)}h old), deleting`);
22865
+ log13.warn(`reconcile: stale marker ${name} (${Math.round(age / 3600000)}h old), deleting`);
20669
22866
  try {
20670
22867
  await unlink(filePath);
20671
22868
  } catch {}
@@ -20681,7 +22878,7 @@ async function reconcilePendingCompletions(workspacesRoot) {
20681
22878
  try {
20682
22879
  await unlink(filePath);
20683
22880
  } catch (delErr) {
20684
- log10.warn(`reconcile: delivered marker ${name} but failed to delete: ${delErr}`);
22881
+ log13.warn(`reconcile: delivered marker ${name} but failed to delete: ${delErr}`);
20685
22882
  }
20686
22883
  } catch (deliverErr) {
20687
22884
  if (isClientError3(deliverErr)) {
@@ -20689,11 +22886,11 @@ async function reconcilePendingCompletions(workspacesRoot) {
20689
22886
  await unlink(filePath);
20690
22887
  } catch {}
20691
22888
  } else {
20692
- log10.debug(`reconcile: delivery failed for ${name}, will retry next cycle`);
22889
+ log13.debug(`reconcile: delivery failed for ${name}, will retry next cycle`);
20693
22890
  }
20694
22891
  }
20695
22892
  } catch (e) {
20696
- log10.debug(`reconcile: error processing ${name}`, e);
22893
+ log13.debug(`reconcile: error processing ${name}`, e);
20697
22894
  }
20698
22895
  }
20699
22896
  }
@@ -20704,7 +22901,7 @@ async function startDaemon(profile, serverUrl) {
20704
22901
  }
20705
22902
  process.once("exit", () => releaseDaemonPid(profile));
20706
22903
  const bailOnUnexpected = (label, err) => {
20707
- log10.error(`${label} — shutting down`, err);
22904
+ log13.error(`${label} — shutting down`, err);
20708
22905
  releaseDaemonPid(profile);
20709
22906
  process.exit(1);
20710
22907
  };
@@ -20717,21 +22914,21 @@ async function startDaemon(profile, serverUrl) {
20717
22914
  if (marker) {
20718
22915
  clearUpdateMarker(profile);
20719
22916
  if (marker === config2.cliVersion) {
20720
- log10.info(`Cleared update marker — now running v${config2.cliVersion}`);
22917
+ log13.info(`Cleared update marker — now running v${config2.cliVersion}`);
20721
22918
  } else {
20722
- log10.info(`Cleared stale update marker (was v${marker}, running v${config2.cliVersion}) — update will be retried`);
22919
+ log13.info(`Cleared stale update marker (was v${marker}, running v${config2.cliVersion}) — update will be retried`);
20723
22920
  }
20724
22921
  }
20725
22922
  const cliConfig = loadCLIConfigForProfile(profile);
20726
22923
  const allEntries = cliConfig.watched_workspaces || [];
20727
22924
  const workspaces = allEntries.filter((ws) => ws.status !== "deleted" && !!ws.id);
20728
22925
  if (workspaces.length === 0) {
20729
- log10.info("No workspaces configured — daemon starting in standby mode. Register a workspace to begin.");
22926
+ log13.info("No workspaces configured — daemon starting in standby mode. Register a workspace to begin.");
20730
22927
  }
20731
22928
  if (workspaces.length > 0) {
20732
22929
  const hasPerWorkspaceTokens = workspaces.every((ws) => !!ws.token);
20733
22930
  if (!hasPerWorkspaceTokens) {
20734
- log10.error(`Config uses old format. Run '${cmdPrefix()} register --token <token>' for each workspace to upgrade.`);
22931
+ log13.error(`Config uses old format. Run '${cmdPrefix()} register --token <token>' for each workspace to upgrade.`);
20735
22932
  process.exit(1);
20736
22933
  return;
20737
22934
  }
@@ -20752,11 +22949,11 @@ async function startDaemon(profile, serverUrl) {
20752
22949
  }
20753
22950
  }
20754
22951
  if (providers.length === 0) {
20755
- log10.error("No agent CLI tools found on PATH.");
22952
+ log13.error("No agent CLI tools found on PATH.");
20756
22953
  process.exit(1);
20757
22954
  return;
20758
22955
  }
20759
- log10.info(`Detected providers: ${providers.map((p) => `${p.type}@${p.version}`).join(", ")}`);
22956
+ log13.info(`Detected providers: ${providers.map((p) => `${p.type}@${p.version}`).join(", ")}`);
20760
22957
  const workspaceStates = [];
20761
22958
  const runtimeIndex = new Map;
20762
22959
  let hadWorkspaces = workspaces.length > 0;
@@ -20765,7 +22962,7 @@ async function startDaemon(profile, serverUrl) {
20765
22962
  type: p.type,
20766
22963
  version: p.version
20767
22964
  }));
20768
- log10.info(`Registering workspace ${ws.id} (${ws.name ?? "unnamed"}) with ${runtimes.length} runtime(s)...`);
22965
+ log13.info(`Registering workspace ${ws.id} (${ws.name ?? "unnamed"}) with ${runtimes.length} runtime(s)...`);
20769
22966
  let resp;
20770
22967
  try {
20771
22968
  resp = await client.register(ws.token, {
@@ -20778,13 +22975,13 @@ async function startDaemon(profile, serverUrl) {
20778
22975
  });
20779
22976
  } catch (e) {
20780
22977
  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)`);
22978
+ log13.warn(`Workspace ${ws.id} token invalid — skipping (run '${cmdPrefix()} register --token <token>' to fix)`);
20782
22979
  } else {
20783
- log10.error(`Failed to register workspace ${ws.id}, skipping`, e);
22980
+ log13.error(`Failed to register workspace ${ws.id}, skipping`, e);
20784
22981
  }
20785
22982
  continue;
20786
22983
  }
20787
- log10.info(`Workspace ${ws.id} registered — ${resp.runtimes.length} runtime(s)`);
22984
+ log13.info(`Workspace ${ws.id} registered — ${resp.runtimes.length} runtime(s)`);
20788
22985
  const runtimeIds = resp.runtimes.map((r) => r.id);
20789
22986
  workspaceStates.push({ workspaceId: ws.id, token: ws.token, runtimeIds });
20790
22987
  for (let i = 0;i < runtimeIds.length; i++) {
@@ -20796,13 +22993,13 @@ async function startDaemon(profile, serverUrl) {
20796
22993
  }
20797
22994
  }
20798
22995
  if (workspaceStates.length === 0 && hadWorkspaces) {
20799
- log10.error("No workspaces registered successfully.");
22996
+ log13.error("No workspaces registered successfully.");
20800
22997
  process.exit(1);
20801
22998
  return;
20802
22999
  }
20803
23000
  const allRuntimeIds = workspaceStates.flatMap((ws) => ws.runtimeIds);
20804
23001
  health.setRuntimeCount(allRuntimeIds.length);
20805
- log10.info(`Daemon started — ${allRuntimeIds.length} runtime(s) across ${workspaceStates.length} workspace(s)`);
23002
+ log13.info(`Daemon started — ${allRuntimeIds.length} runtime(s) across ${workspaceStates.length} workspace(s)`);
20806
23003
  const activeTasks = new Set;
20807
23004
  const pendingSteer = new Map;
20808
23005
  const knownAgentIds = new Set(workspaces.flatMap((ws) => ws.agent_ids ?? []));
@@ -20838,7 +23035,7 @@ async function startDaemon(profile, serverUrl) {
20838
23035
  cfg.watched_workspaces = (cfg.watched_workspaces || []).filter((w) => w.id !== workspaceId);
20839
23036
  saveCLIConfigForProfile(profile, cfg);
20840
23037
  } catch {}
20841
- log10.info(`Workspace ${workspaceId} deleted server-side — removed from config`);
23038
+ log13.info(`Workspace ${workspaceId} deleted server-side — removed from config`);
20842
23039
  }
20843
23040
  const pollCycle = async () => {
20844
23041
  let remaining = config2.maxConcurrentTasks - activeTasks.size;
@@ -20864,7 +23061,7 @@ async function startDaemon(profile, serverUrl) {
20864
23061
  handleCliUpdate(pending_update.version, () => requestRestart(), profile);
20865
23062
  }
20866
23063
  if (pending_rescan) {
20867
- log10.info("Rescan requested — restarting daemon to re-detect runtimes");
23064
+ log13.info("Rescan requested — restarting daemon to re-detect runtimes");
20868
23065
  for (const id of evictedIds) {
20869
23066
  evictWorkspace(id);
20870
23067
  }
@@ -20877,19 +23074,19 @@ async function startDaemon(profile, serverUrl) {
20877
23074
  activeTasks.add(task.id);
20878
23075
  remaining--;
20879
23076
  handleTask(client, config2, runtimeIndex, task, ws.token, activeTasks, pendingSteer).catch((e) => {
20880
- log10.error("Task error", e);
23077
+ log13.error("Task error", e);
20881
23078
  activeTasks.delete(task.id);
20882
23079
  });
20883
23080
  }
20884
23081
  if (file_requests) {
20885
23082
  for (const req of file_requests) {
20886
- handleFileRequest(client, config2, ws.workspaceId, req, ws.token).catch((e) => log10.debug("File request error", e));
23083
+ handleFileRequest(client, config2, ws.workspaceId, req, ws.token).catch((e) => log13.debug("File request error", e));
20887
23084
  }
20888
23085
  }
20889
23086
  if (meetings) {
20890
23087
  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");
23088
+ const agentBaseDir = join12(config2.workspacesRoot, m.workspace_id, m.agent_id, "workdir");
23089
+ const timelineDir = join12(agentBaseDir, ".context_timeline");
20893
23090
  spawnMeetingRunner({
20894
23091
  meetingId: m.id,
20895
23092
  meetingUrl: m.meeting_url,
@@ -20906,9 +23103,9 @@ async function startDaemon(profile, serverUrl) {
20906
23103
  }
20907
23104
  } catch (e) {
20908
23105
  if (e instanceof Error && e.message.startsWith("HTTP 401")) {
20909
- log10.warn(`Workspace ${ws.workspaceId} poll returned 401 — will retry next cycle`);
23106
+ log13.warn(`Workspace ${ws.workspaceId} poll returned 401 — will retry next cycle`);
20910
23107
  } else {
20911
- log10.debug("Poll error", e);
23108
+ log13.debug("Poll error", e);
20912
23109
  }
20913
23110
  }
20914
23111
  }
@@ -20916,7 +23113,7 @@ async function startDaemon(profile, serverUrl) {
20916
23113
  evictWorkspace(id);
20917
23114
  }
20918
23115
  if (workspaceStates.length === 0 && hadWorkspaces) {
20919
- log10.info("All workspaces evicted — shutting down");
23116
+ log13.info("All workspaces evicted — shutting down");
20920
23117
  shutdown();
20921
23118
  }
20922
23119
  };
@@ -20924,7 +23121,7 @@ async function startDaemon(profile, serverUrl) {
20924
23121
  const heartbeatPing = () => {
20925
23122
  for (const ws of workspaceStates) {
20926
23123
  client.heartbeat(ws.token, config2.daemonId).catch((e) => {
20927
- log10.debug("heartbeat failed", { workspaceId: ws.workspaceId, err: String(e) });
23124
+ log13.debug("heartbeat failed", { workspaceId: ws.workspaceId, err: String(e) });
20928
23125
  });
20929
23126
  }
20930
23127
  };
@@ -20950,7 +23147,7 @@ async function startDaemon(profile, serverUrl) {
20950
23147
  syncAgentId(task.agentId, ws.workspaceId);
20951
23148
  activeTasks.add(task.id);
20952
23149
  handleTask(client, config2, runtimeIndex, task, ws.token, activeTasks, pendingSteer).catch((e) => {
20953
- log10.error("WS task error", e);
23150
+ log13.error("WS task error", e);
20954
23151
  activeTasks.delete(task.id);
20955
23152
  });
20956
23153
  }
@@ -20959,7 +23156,7 @@ async function startDaemon(profile, serverUrl) {
20959
23156
  const ws = wsMap.get(msg.workspaceId);
20960
23157
  if (ws) {
20961
23158
  for (const req of msg.requests) {
20962
- handleFileRequest(client, config2, ws.workspaceId, req, ws.token).catch((e) => log10.debug("WS file request error", e));
23159
+ handleFileRequest(client, config2, ws.workspaceId, req, ws.token).catch((e) => log13.debug("WS file request error", e));
20963
23160
  }
20964
23161
  }
20965
23162
  break;
@@ -20969,8 +23166,8 @@ async function startDaemon(profile, serverUrl) {
20969
23166
  const ws = wsMap.get(m.workspace_id);
20970
23167
  if (!ws)
20971
23168
  continue;
20972
- const agentBaseDir = join11(config2.workspacesRoot, m.workspace_id, m.agent_id, "workdir");
20973
- const timelineDir = join11(agentBaseDir, ".context_timeline");
23169
+ const agentBaseDir = join12(config2.workspacesRoot, m.workspace_id, m.agent_id, "workdir");
23170
+ const timelineDir = join12(agentBaseDir, ".context_timeline");
20974
23171
  spawnMeetingRunner({
20975
23172
  meetingId: m.id,
20976
23173
  meetingUrl: m.meeting_url,
@@ -20994,7 +23191,7 @@ async function startDaemon(profile, serverUrl) {
20994
23191
  }
20995
23192
  break;
20996
23193
  case "daemon.rescan":
20997
- log10.info("WS rescan requested — restarting daemon");
23194
+ log13.info("WS rescan requested — restarting daemon");
20998
23195
  requestRestart();
20999
23196
  break;
21000
23197
  case "daemon.kill": {
@@ -21022,7 +23219,7 @@ async function startDaemon(profile, serverUrl) {
21022
23219
  });
21023
23220
  activeTasks.add(killTask.id);
21024
23221
  handleTask(client, config2, runtimeIndex, killTask, ws.token, activeTasks, pendingSteer).catch((e) => {
21025
- log10.error("WS kill task error", e);
23222
+ log13.error("WS kill task error", e);
21026
23223
  activeTasks.delete(killTask.id);
21027
23224
  });
21028
23225
  }
@@ -21037,11 +23234,11 @@ async function startDaemon(profile, serverUrl) {
21037
23234
  machineToken: wsToken,
21038
23235
  onMessage: handleWsPush,
21039
23236
  onConnected: () => {
21040
- log10.info("WS connected — switching to low-frequency poll");
23237
+ log13.info("WS connected — switching to low-frequency poll");
21041
23238
  updatePollInterval(config2.wsPollInterval);
21042
23239
  },
21043
23240
  onDisconnected: () => {
21044
- log10.info("WS disconnected — reverting to high-frequency poll");
23241
+ log13.info("WS disconnected — reverting to high-frequency poll");
21045
23242
  updatePollInterval(config2.pollInterval);
21046
23243
  }
21047
23244
  }) : null;
@@ -21049,13 +23246,13 @@ async function startDaemon(profile, serverUrl) {
21049
23246
  const sweepTick = async () => {
21050
23247
  for (const ws of workspaceStates) {
21051
23248
  client.sweep(ws.token, config2.daemonId).catch((e) => {
21052
- log10.debug("sweep ping failed", { workspaceId: ws.workspaceId, err: String(e) });
23249
+ log13.debug("sweep ping failed", { workspaceId: ws.workspaceId, err: String(e) });
21053
23250
  });
21054
23251
  }
21055
23252
  try {
21056
23253
  await reconcilePendingCompletions(config2.workspacesRoot);
21057
23254
  } catch (e) {
21058
- log10.debug("reconciliation error", e);
23255
+ log13.debug("reconciliation error", e);
21059
23256
  }
21060
23257
  };
21061
23258
  const sweepTimer = setInterval(sweepTick, config2.sweepInterval);
@@ -21079,7 +23276,7 @@ async function startDaemon(profile, serverUrl) {
21079
23276
  if (shuttingDown)
21080
23277
  return;
21081
23278
  shuttingDown = true;
21082
- log10.info(restartRequested ? "Restarting..." : "Shutting down...");
23279
+ log13.info(restartRequested ? "Restarting..." : "Shutting down...");
21083
23280
  clearInterval(pollTimer);
21084
23281
  clearInterval(heartbeatTimer);
21085
23282
  clearInterval(sweepTimer);
@@ -21104,10 +23301,10 @@ async function startDaemon(profile, serverUrl) {
21104
23301
  const logPath = daemonLogFilePath();
21105
23302
  let logFd;
21106
23303
  try {
21107
- mkdirSync8(dirname3(logPath), { recursive: true, mode: 448 });
23304
+ mkdirSync9(dirname3(logPath), { recursive: true, mode: 448 });
21108
23305
  logFd = openSync(logPath, "a", 384);
21109
23306
  } catch (e) {
21110
- log10.error(`Failed to open daemon log file ${logPath}`, e);
23307
+ log13.error(`Failed to open daemon log file ${logPath}`, e);
21111
23308
  }
21112
23309
  const child = spawn5(process.execPath, args, {
21113
23310
  detached: true,
@@ -21117,7 +23314,7 @@ async function startDaemon(profile, serverUrl) {
21117
23314
  child.unref();
21118
23315
  if (logFd != null)
21119
23316
  closeSync(logFd);
21120
- log10.info(`Spawned new daemon (pid=${child.pid}), logs: ${logPath}`);
23317
+ log13.info(`Spawned new daemon (pid=${child.pid}), logs: ${logPath}`);
21121
23318
  }
21122
23319
  clearTimeout(timeout);
21123
23320
  process.exit(0);
@@ -21128,7 +23325,7 @@ async function startDaemon(profile, serverUrl) {
21128
23325
  process.on("SIGHUP", async () => {
21129
23326
  if (shuttingDown)
21130
23327
  return;
21131
- log10.info("SIGHUP received — reloading config...");
23328
+ log13.info("SIGHUP received — reloading config...");
21132
23329
  try {
21133
23330
  const freshConfig = loadCLIConfigForProfile(profile);
21134
23331
  const freshWorkspaces = (freshConfig.watched_workspaces || []).filter((ws) => ws.status !== "deleted" && !!ws.id);
@@ -21136,7 +23333,7 @@ async function startDaemon(profile, serverUrl) {
21136
23333
  const newWorkspaces = freshWorkspaces.filter((ws) => ws.token && !existingIds.has(ws.id));
21137
23334
  for (const ws of newWorkspaces) {
21138
23335
  const runtimes = providers.map((p) => ({ type: p.type, version: p.version }));
21139
- log10.info(`Registering new workspace ${ws.id} (${ws.name ?? "unnamed"})...`);
23336
+ log13.info(`Registering new workspace ${ws.id} (${ws.name ?? "unnamed"})...`);
21140
23337
  try {
21141
23338
  const resp = await client.register(ws.token, {
21142
23339
  workspace_id: ws.id,
@@ -21155,9 +23352,9 @@ async function startDaemon(profile, serverUrl) {
21155
23352
  provider: providers[i].type
21156
23353
  });
21157
23354
  }
21158
- log10.info(`Workspace ${ws.id} added — ${runtimeIds.length} runtime(s)`);
23355
+ log13.info(`Workspace ${ws.id} added — ${runtimeIds.length} runtime(s)`);
21159
23356
  } catch (e) {
21160
- log10.error(`Failed to register new workspace ${ws.id}`, e);
23357
+ log13.error(`Failed to register new workspace ${ws.id}`, e);
21161
23358
  }
21162
23359
  }
21163
23360
  if (newWorkspaces.length > 0) {
@@ -21171,38 +23368,38 @@ async function startDaemon(profile, serverUrl) {
21171
23368
  machineToken: token,
21172
23369
  onMessage: handleWsPush,
21173
23370
  onConnected: () => {
21174
- log10.info("WS connected — switching to low-frequency poll");
23371
+ log13.info("WS connected — switching to low-frequency poll");
21175
23372
  updatePollInterval(config2.wsPollInterval);
21176
23373
  },
21177
23374
  onDisconnected: () => {
21178
- log10.info("WS disconnected — reverting to high-frequency poll");
23375
+ log13.info("WS disconnected — reverting to high-frequency poll");
21179
23376
  updatePollInterval(config2.pollInterval);
21180
23377
  }
21181
23378
  });
21182
23379
  wsClient.connect();
21183
- log10.info("WS push client initialized after SIGHUP reload");
23380
+ log13.info("WS push client initialized after SIGHUP reload");
21184
23381
  }
21185
- log10.info(`Reload complete — now polling ${workspaceStates.length} workspace(s)`);
23382
+ log13.info(`Reload complete — now polling ${workspaceStates.length} workspace(s)`);
21186
23383
  } else {
21187
- log10.info("Reload complete — no new workspaces found");
23384
+ log13.info("Reload complete — no new workspaces found");
21188
23385
  }
21189
23386
  } catch (e) {
21190
- log10.error("Failed to reload config", e);
23387
+ log13.error("Failed to reload config", e);
21191
23388
  }
21192
23389
  });
21193
23390
  await pollCycle();
21194
23391
  }
21195
23392
  function spawnSessionRunner(input) {
21196
23393
  const logDir = sessionRunnerLogDir();
21197
- mkdirSync8(logDir, { recursive: true });
21198
- const logFilePath = join11(logDir, `${input.task.id}.log`);
23394
+ mkdirSync9(logDir, { recursive: true });
23395
+ const logFilePath = join12(logDir, `${input.task.id}.log`);
21199
23396
  input.logFilePath = logFilePath;
21200
23397
  const encoded = Buffer.from(JSON.stringify(input)).toString("base64");
21201
23398
  let fd;
21202
23399
  try {
21203
23400
  fd = openSync(logFilePath, "a");
21204
23401
  } catch (e) {
21205
- log10.error(`Failed to open log file ${logFilePath}`, e);
23402
+ log13.error(`Failed to open log file ${logFilePath}`, e);
21206
23403
  }
21207
23404
  const child = spawn5(process.execPath, [sessionRunnerPath, encoded], {
21208
23405
  detached: true,
@@ -21215,14 +23412,14 @@ function spawnSessionRunner(input) {
21215
23412
  }
21216
23413
  function spawnMeetingRunner(input) {
21217
23414
  const logDir = sessionRunnerLogDir();
21218
- mkdirSync8(logDir, { recursive: true });
21219
- const logFilePath = join11(logDir, `meeting-${input.meetingId}.log`);
23415
+ mkdirSync9(logDir, { recursive: true });
23416
+ const logFilePath = join12(logDir, `meeting-${input.meetingId}.log`);
21220
23417
  const encoded = Buffer.from(JSON.stringify(input)).toString("base64");
21221
23418
  let fd;
21222
23419
  try {
21223
23420
  fd = openSync(logFilePath, "a");
21224
23421
  } catch (e) {
21225
- log10.error(`Failed to open meeting log file ${logFilePath}`, e);
23422
+ log13.error(`Failed to open meeting log file ${logFilePath}`, e);
21226
23423
  }
21227
23424
  const child = spawn5(process.execPath, [meetingRunnerPath, encoded], {
21228
23425
  detached: true,
@@ -21231,11 +23428,11 @@ function spawnMeetingRunner(input) {
21231
23428
  child.unref();
21232
23429
  if (fd != null)
21233
23430
  closeSync(fd);
21234
- log10.info(`Spawned meeting runner for ${input.meetingId} (pid=${child.pid})`);
23431
+ log13.info(`Spawned meeting runner for ${input.meetingId} (pid=${child.pid})`);
21235
23432
  return child;
21236
23433
  }
21237
23434
  async function handleFileRequest(client, config2, workspaceId, req, token) {
21238
- const agentWorkdir = join11(config2.workspacesRoot, workspaceId, req.agent_id, "workdir");
23435
+ const agentWorkdir = join12(config2.workspacesRoot, workspaceId, req.agent_id, "workdir");
21239
23436
  const resolved = validatePath(agentWorkdir, req.path);
21240
23437
  if (!resolved) {
21241
23438
  await client.reportFileData(token, { request_id: req.id, error: "invalid path", path: req.path });
@@ -21273,7 +23470,7 @@ async function killAndVerify(pid) {
21273
23470
  await new Promise((r) => setTimeout(r, 100));
21274
23471
  }
21275
23472
  if (isAlive(pid)) {
21276
- log10.warn(`session-runner pid=${pid} survived SIGTERM after ${verifyMs}ms — escalating to SIGKILL`);
23473
+ log13.warn(`session-runner pid=${pid} survived SIGTERM after ${verifyMs}ms — escalating to SIGKILL`);
21277
23474
  try {
21278
23475
  process.kill(pid, "SIGKILL");
21279
23476
  } catch {}
@@ -21281,7 +23478,7 @@ async function killAndVerify(pid) {
21281
23478
  return true;
21282
23479
  }
21283
23480
  async function handleTask(client, config2, runtimeIndex, task, token, activeTasks, pendingSteer) {
21284
- log10.info(`Task ${task.id} claimed agent=${task.agentId}`);
23481
+ log13.info(`Task ${task.id} claimed agent=${task.agentId}`);
21285
23482
  if (task.type === TASK_TYPES.KILL_TASK) {
21286
23483
  const targetTaskId = task.context?.target_task_id;
21287
23484
  if (!targetTaskId) {
@@ -21289,8 +23486,8 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21289
23486
  activeTasks.delete(task.id);
21290
23487
  return;
21291
23488
  }
21292
- const agentBaseDir = join11(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
21293
- const timelineDir = join11(agentBaseDir, ".context_timeline");
23489
+ const agentBaseDir = join12(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
23490
+ const timelineDir = join12(agentBaseDir, ".context_timeline");
21294
23491
  const MAX_WAIT_MS = Number(process.env.ALOOK_KILL_TASK_MAX_WAIT_MS) || 15000;
21295
23492
  const POLL_MS2 = Number(process.env.ALOOK_KILL_TASK_POLL_MS) || 200;
21296
23493
  const waitStart = Date.now();
@@ -21311,17 +23508,17 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21311
23508
  const delivered = await killAndVerify(pid);
21312
23509
  if (delivered) {
21313
23510
  await client.failTask(token, task.id, "killed");
21314
- log10.info(`Kill task ${task.id}: terminated pid=${pid} for target=${targetTaskId}`);
23511
+ log13.info(`Kill task ${task.id}: terminated pid=${pid} for target=${targetTaskId}`);
21315
23512
  } else {
21316
23513
  await client.failTask(token, task.id, "target process already exited");
21317
- log10.info(`Kill task ${task.id}: target pid=${pid} already exited`);
23514
+ log13.info(`Kill task ${task.id}: target pid=${pid} already exited`);
21318
23515
  }
21319
23516
  } catch (e) {
21320
23517
  await client.failTask(token, task.id, `kill failed: ${e}`);
21321
23518
  }
21322
23519
  } else {
21323
23520
  await client.failTask(token, task.id, "target not found in timeline");
21324
- log10.info(`Kill task ${task.id}: target ${targetTaskId} not found in timeline`);
23521
+ log13.info(`Kill task ${task.id}: target ${targetTaskId} not found in timeline`);
21325
23522
  }
21326
23523
  activeTasks.delete(task.id);
21327
23524
  return;
@@ -21342,9 +23539,9 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21342
23539
  const provider = runtimeData.provider;
21343
23540
  let promptOverride;
21344
23541
  if (task.contextKey) {
21345
- const agentBaseDir = join11(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
23542
+ const agentBaseDir = join12(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
21346
23543
  cleanupStaleIntents(agentBaseDir);
21347
- const timelineDir = join11(agentBaseDir, ".context_timeline");
23544
+ const timelineDir = join12(agentBaseDir, ".context_timeline");
21348
23545
  const ctxKey = task.contextKey;
21349
23546
  let lockAcquired = acquireSteeringLock(agentBaseDir, ctxKey);
21350
23547
  if (!lockAcquired) {
@@ -21363,7 +23560,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21363
23560
  }
21364
23561
  existing.tasks.push(task);
21365
23562
  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)`);
23563
+ log13.info(`Steering: ${task.id} merged into pending entry (lock contention) for context_key=${ctxKey} (${existing.tasks.length} tasks)`);
21367
23564
  existing.wake();
21368
23565
  try {
21369
23566
  await client.supersedeTask(token, task.id);
@@ -21377,7 +23574,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21377
23574
  await new Promise((r) => setTimeout(r, MERGE_POLL_MS));
21378
23575
  }
21379
23576
  if (!lockAcquired) {
21380
- log10.warn(`Steering lock contention for context_key=${ctxKey}, proceeding without steering`);
23577
+ log13.warn(`Steering lock contention for context_key=${ctxKey}, proceeding without steering`);
21381
23578
  }
21382
23579
  }
21383
23580
  if (lockAcquired) {
@@ -21392,7 +23589,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21392
23589
  try {
21393
23590
  myAttachments = await downloadAttachments(client, token, task.workspaceId, task.id, attachmentIds);
21394
23591
  } catch (e) {
21395
- log10.warn(`Steering: failed to download attachments for ${task.id}`, e);
23592
+ log13.warn(`Steering: failed to download attachments for ${task.id}`, e);
21396
23593
  }
21397
23594
  }
21398
23595
  let ownerWake;
@@ -21408,7 +23605,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21408
23605
  pendingSteer.set(ctxKey, entry);
21409
23606
  let predecessor = "entry" in result ? result.entry : null;
21410
23607
  if (!predecessor) {
21411
- log10.info(`Steering: predecessor ${result.pending.task_id} warming up; ${task.id} waiting`);
23608
+ log13.info(`Steering: predecessor ${result.pending.task_id} warming up; ${task.id} waiting`);
21412
23609
  const POLL_MS2 = 200;
21413
23610
  const MAX_WAIT_MS = steerWarmupGraceMs();
21414
23611
  const waitStart = Date.now();
@@ -21419,7 +23616,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21419
23616
  continue;
21420
23617
  const r = findSupersedablePredecessor(timelineDir, ctxKey, provider, steerWarmupGraceMs(), Date.now());
21421
23618
  if (!r) {
21422
- log10.info(`Steering: predecessor vanished; ${task.id} proceeding`);
23619
+ log13.info(`Steering: predecessor vanished; ${task.id} proceeding`);
21423
23620
  break;
21424
23621
  }
21425
23622
  if ("entry" in r) {
@@ -21437,14 +23634,51 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21437
23634
  }
21438
23635
  }
21439
23636
  if (predecessor && predecessor.task_id !== task.id) {
21440
- log10.info(`Steering: task ${task.id} supersedes predecessor ${predecessor.task_id} (context_key=${ctxKey})`);
23637
+ const backendInst = createBackend(provider, "");
23638
+ const isPersistent = backendInst.lifecycle?.kind === "persistent";
23639
+ if (config2.enableSteering && isPersistent && predecessor.pid != null) {
23640
+ log13.info(`Steering: task ${task.id} steering into predecessor ${predecessor.task_id} via mailbox (context_key=${ctxKey})`);
23641
+ try {
23642
+ ensureMailboxDirs(agentBaseDir, ctxKey);
23643
+ const attachmentIds2 = task.context?.attachment_ids ?? [];
23644
+ let steerAttachments = [];
23645
+ if (attachmentIds2.length > 0) {
23646
+ try {
23647
+ const downloaded = await downloadAttachments(client, token, task.workspaceId, task.id, attachmentIds2);
23648
+ steerAttachments = downloaded.map((a) => ({ localPath: a.path, filename: a.filename, contentType: a.content_type }));
23649
+ } catch (e) {
23650
+ log13.warn(`Steering mailbox: failed to download attachments for ${task.id}`, e);
23651
+ }
23652
+ }
23653
+ const seq = writeSteerMessage(agentBaseDir, ctxKey, {
23654
+ taskId: task.id,
23655
+ text: buildPrompt(task),
23656
+ attachments: steerAttachments,
23657
+ createdAt: new Date().toISOString()
23658
+ });
23659
+ const ackResult = await waitForAck(agentBaseDir, ctxKey, seq);
23660
+ if (ackResult.acked) {
23661
+ log13.info(`Steering: task ${task.id} steered into predecessor ${predecessor.task_id} (acked)`);
23662
+ try {
23663
+ await client.startTask(token, task.id);
23664
+ } catch {}
23665
+ pendingSteer.delete(ctxKey);
23666
+ activeTasks.delete(task.id);
23667
+ return;
23668
+ }
23669
+ log13.info(`Steering: mailbox delivery failed for ${task.id} (${ackResult.nackReason}), falling back to kill-and-respawn`);
23670
+ } catch (e) {
23671
+ log13.warn(`Steering: mailbox error for ${task.id}, falling back to kill-and-respawn`, e);
23672
+ }
23673
+ }
23674
+ log13.info(`Steering: task ${task.id} supersedes predecessor ${predecessor.task_id} (context_key=${ctxKey})`);
21441
23675
  if (predecessor.pid != null) {
21442
23676
  writeKillIntent(agentBaseDir, { reason: "superseded", targetTaskId: predecessor.task_id, expectedPid: predecessor.pid, successorTaskId: task.id });
21443
23677
  try {
21444
23678
  const delivered = await killAndVerify(predecessor.pid);
21445
- log10.info(delivered ? `Steering: terminated predecessor pid=${predecessor.pid}` : `Steering: predecessor pid=${predecessor.pid} already exited`);
23679
+ log13.info(delivered ? `Steering: terminated predecessor pid=${predecessor.pid}` : `Steering: predecessor pid=${predecessor.pid} already exited`);
21446
23680
  } catch (e) {
21447
- log10.warn(`Steering: kill failed for pid=${predecessor.pid}`, e);
23681
+ log13.warn(`Steering: kill failed for pid=${predecessor.pid}`, e);
21448
23682
  }
21449
23683
  const killWaitStart = Date.now();
21450
23684
  while (Date.now() - killWaitStart < 15000) {
@@ -21460,7 +23694,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21460
23694
  const finalEntry = pendingSteer.get(ctxKey);
21461
23695
  if (finalEntry && finalEntry.tasks.length > 1) {
21462
23696
  promptOverride = buildMergedPrompt(finalEntry.tasks, finalEntry.attachments);
21463
- log10.info(`Steering: merged ${finalEntry.tasks.length} tasks for context_key=${ctxKey}`);
23697
+ log13.info(`Steering: merged ${finalEntry.tasks.length} tasks for context_key=${ctxKey}`);
21464
23698
  } else if (finalEntry && finalEntry.tasks.length === 1) {
21465
23699
  const att = finalEntry.attachments.get(task.id);
21466
23700
  if (att && att.length > 0) {
@@ -21475,7 +23709,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21475
23709
  try {
21476
23710
  myAttachments = await downloadAttachments(client, token, task.workspaceId, task.id, attachmentIds);
21477
23711
  } catch (e) {
21478
- log10.warn(`Steering: failed to download attachments for ${task.id}`, e);
23712
+ log13.warn(`Steering: failed to download attachments for ${task.id}`, e);
21479
23713
  }
21480
23714
  }
21481
23715
  for (const prev of existing.tasks) {
@@ -21487,7 +23721,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21487
23721
  }
21488
23722
  existing.tasks.push(task);
21489
23723
  existing.attachments.set(task.id, myAttachments);
21490
- log10.info(`Steering: ${task.id} merged into pending entry for context_key=${ctxKey} (${existing.tasks.length} tasks)`);
23724
+ log13.info(`Steering: ${task.id} merged into pending entry for context_key=${ctxKey} (${existing.tasks.length} tasks)`);
21491
23725
  existing.wake();
21492
23726
  try {
21493
23727
  await client.supersedeTask(token, task.id);
@@ -21505,6 +23739,14 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21505
23739
  const configModel = provider === "claude" ? config2.claudeModel : provider === "codex" ? config2.codexModel : config2.opencodeModel;
21506
23740
  const agentModel = task.agent?.runtimeConfig?.model;
21507
23741
  const model = typeof agentModel === "string" && agentModel ? agentModel : configModel;
23742
+ const backendForInput = createBackend(provider, "");
23743
+ const steeringEligible = config2.enableSteering && backendForInput.lifecycle?.kind === "persistent" && !!task.contextKey;
23744
+ let steeringMailboxDir;
23745
+ if (steeringEligible) {
23746
+ const agentBaseDirForSteering = join12(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
23747
+ ensureMailboxDirs(agentBaseDirForSteering, task.contextKey);
23748
+ steeringMailboxDir = inboxDir(agentBaseDirForSteering, task.contextKey);
23749
+ }
21508
23750
  const input = {
21509
23751
  task,
21510
23752
  provider,
@@ -21515,24 +23757,26 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21515
23757
  workspacesRoot: config2.workspacesRoot,
21516
23758
  agentTimeout: config2.agentTimeout,
21517
23759
  messageInactivityTimeout: config2.messageInactivityTimeout,
21518
- ...promptOverride && { promptOverride }
23760
+ ...promptOverride && { promptOverride },
23761
+ ...steeringEligible && { steeringEnabled: true },
23762
+ ...steeringMailboxDir && { steeringMailboxDir }
21519
23763
  };
21520
23764
  const child = spawnSessionRunner(input);
21521
23765
  child.on("close", async (code) => {
21522
23766
  activeTasks.delete(task.id);
21523
23767
  if (code !== 0) {
21524
- const agentBaseDir = join11(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
23768
+ const agentBaseDir = join12(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
21525
23769
  const killIntent = readKillIntent(agentBaseDir, task.id);
21526
23770
  if (killIntent) {
21527
- log10.info(`Task ${task.id} exited (${killIntent.reason}) — expected, skipping failTask`);
23771
+ log13.info(`Task ${task.id} exited (${killIntent.reason}) — expected, skipping failTask`);
21528
23772
  clearKillIntent(agentBaseDir, task.id);
21529
23773
  return;
21530
23774
  }
21531
23775
  const errorMsg = code === null ? "killed by signal" : `session-runner exited with code ${code}`;
21532
23776
  try {
21533
23777
  await client.failTask(token, task.id, errorMsg);
21534
- log10.warn(`session-runner crashed (${errorMsg}, task ${task.id})`);
21535
- const timelineDir = join11(agentBaseDir, ".context_timeline");
23778
+ log13.warn(`session-runner crashed (${errorMsg}, task ${task.id})`);
23779
+ const timelineDir = join12(agentBaseDir, ".context_timeline");
21536
23780
  updateEntry(timelineDir, task.id, (entry) => {
21537
23781
  entry.pid = null;
21538
23782
  entry.status = "failed";
@@ -21540,10 +23784,10 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21540
23784
  });
21541
23785
  } catch (e) {
21542
23786
  if (isClientError3(e)) {
21543
- log10.info(`Task ${task.id} exited (already terminal) — session-runner handled cleanup`);
23787
+ log13.info(`Task ${task.id} exited (already terminal) — session-runner handled cleanup`);
21544
23788
  return;
21545
23789
  }
21546
- log10.error(`Failed to report crash for task ${task.id}`, e);
23790
+ log13.error(`Failed to report crash for task ${task.id}`, e);
21547
23791
  try {
21548
23792
  await writeMarkerFile(config2.workspacesRoot, {
21549
23793
  taskId: task.id,
@@ -21557,7 +23801,7 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
21557
23801
  }
21558
23802
  }
21559
23803
  });
21560
- log10.info(`Task ${task.id} dispatched to session-runner (pid=${child.pid})`);
23804
+ log13.info(`Task ${task.id} dispatched to session-runner (pid=${child.pid})`);
21561
23805
  }
21562
23806
 
21563
23807
  // lib/runtimes.ts
@@ -21669,7 +23913,7 @@ Starting daemon...`);
21669
23913
  args.push("--profile", profile);
21670
23914
  args.push("daemon", "start", "--foreground");
21671
23915
  const logPath = daemonLogFilePath();
21672
- mkdirSync9(dirname4(logPath), { recursive: true, mode: 448 });
23916
+ mkdirSync10(dirname4(logPath), { recursive: true, mode: 448 });
21673
23917
  const logFd = openSync2(logPath, "a", 384);
21674
23918
  const child = spawn6(process.execPath, args, {
21675
23919
  detached: true,
@@ -21992,7 +24236,7 @@ function statusCommand() {
21992
24236
  // commands/daemon.ts
21993
24237
  import { Command as Command4 } from "commander";
21994
24238
  import { spawn as spawn8 } from "child_process";
21995
- import { openSync as openSync3, closeSync as closeSync3, mkdirSync as mkdirSync10 } from "fs";
24239
+ import { openSync as openSync3, closeSync as closeSync3, mkdirSync as mkdirSync11 } from "fs";
21996
24240
  import { dirname as dirname5 } from "path";
21997
24241
  var PID_POLL_INTERVAL_MS = 200;
21998
24242
  var PID_POLL_TIMEOUT_MS = 2000;
@@ -22028,7 +24272,7 @@ async function startInBackground(profile, serverUrl) {
22028
24272
  return;
22029
24273
  }
22030
24274
  const logPath = daemonLogFilePath();
22031
- mkdirSync10(dirname5(logPath), { recursive: true, mode: 448 });
24275
+ mkdirSync11(dirname5(logPath), { recursive: true, mode: 448 });
22032
24276
  const logFd = openSync3(logPath, "a", 384);
22033
24277
  const child = spawn8(process.execPath, buildChildArgs(profile, serverUrl), {
22034
24278
  detached: true,
@@ -22149,12 +24393,12 @@ function configCommand() {
22149
24393
 
22150
24394
  // commands/email.ts
22151
24395
  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";
24396
+ import { writeFileSync as writeFileSync9, mkdirSync as mkdirSync12, readFileSync as readFileSync12 } from "fs";
24397
+ import { join as join13 } from "path";
22154
24398
  import PostalMime from "postal-mime";
22155
24399
 
22156
24400
  // lib/flags.ts
22157
- import { readFileSync as readFileSync9 } from "fs";
24401
+ import { readFileSync as readFileSync10 } from "fs";
22158
24402
  function resolveAgentId(opts) {
22159
24403
  const id = opts.agent_id || process.env.ALOOK_AGENT_ID;
22160
24404
  if (!id) {
@@ -22172,7 +24416,7 @@ function readBody(opts) {
22172
24416
  process.exit(1);
22173
24417
  }
22174
24418
  if (opts.bodyFile)
22175
- return readFileSync9(opts.bodyFile, "utf-8");
24419
+ return readFileSync10(opts.bodyFile, "utf-8");
22176
24420
  return opts.body ?? "";
22177
24421
  }
22178
24422
 
@@ -22235,7 +24479,7 @@ function resolveClientOptsPartial(command, opts = {}) {
22235
24479
  }
22236
24480
 
22237
24481
  // lib/file-utils.ts
22238
- import { readFileSync as readFileSync10, statSync as statSync5 } from "fs";
24482
+ import { readFileSync as readFileSync11, statSync as statSync5 } from "fs";
22239
24483
  import { basename as basename2 } from "path";
22240
24484
  var MIME_BY_EXT = {
22241
24485
  ".pdf": "application/pdf",
@@ -22277,7 +24521,7 @@ async function uploadFile(client, filePath, endpoint) {
22277
24521
  let bytes;
22278
24522
  let size;
22279
24523
  try {
22280
- bytes = readFileSync10(filePath);
24524
+ bytes = readFileSync11(filePath);
22281
24525
  size = statSync5(filePath).size;
22282
24526
  } catch (err) {
22283
24527
  throw new Error(`cannot read file "${filePath}": ${err instanceof Error ? err.message : err}`);
@@ -22304,7 +24548,7 @@ function gatherContextEnvVars() {
22304
24548
  }
22305
24549
 
22306
24550
  // commands/email.ts
22307
- var log11 = createLogger2({ module: "email" });
24551
+ var log14 = createLogger2({ module: "email" });
22308
24552
  var VALID_STATUSES = ["unread", "read", "archived", "sent"];
22309
24553
  var VALID_FOLDERS = ["inbox", "sent", "untrust"];
22310
24554
  var EMAIL_BASE = tempDir("alook-emails");
@@ -22340,7 +24584,7 @@ function emailCommand() {
22340
24584
  process.exit(1);
22341
24585
  }
22342
24586
  }
22343
- const emailDir_base = join12(EMAIL_BASE, workspaceId, agentId);
24587
+ const emailDir_base = join13(EMAIL_BASE, workspaceId, agentId);
22344
24588
  try {
22345
24589
  let emails2;
22346
24590
  if (opts.email_id) {
@@ -22366,11 +24610,11 @@ function emailCommand() {
22366
24610
  printJSON(emails2);
22367
24611
  return;
22368
24612
  }
22369
- mkdirSync11(emailDir_base, { recursive: true });
24613
+ mkdirSync12(emailDir_base, { recursive: true });
22370
24614
  const downloadedPaths = [];
22371
24615
  for (const email3 of emails2) {
22372
- const emailDir = join12(emailDir_base, email3.id);
22373
- mkdirSync11(emailDir, { recursive: true });
24616
+ const emailDir = join13(emailDir_base, email3.id);
24617
+ mkdirSync12(emailDir, { recursive: true });
22374
24618
  const metadata = {
22375
24619
  id: email3.id,
22376
24620
  from: email3.from_email,
@@ -22382,8 +24626,8 @@ function emailCommand() {
22382
24626
  in_reply_to: email3.in_reply_to || "",
22383
24627
  references: email3.references || ""
22384
24628
  };
22385
- const metadataPath = join12(emailDir, "metadata.json");
22386
- writeFileSync8(metadataPath, JSON.stringify(metadata, null, 2));
24629
+ const metadataPath = join13(emailDir, "metadata.json");
24630
+ writeFileSync9(metadataPath, JSON.stringify(metadata, null, 2));
22387
24631
  downloadedPaths.push(metadataPath);
22388
24632
  let rawMime;
22389
24633
  try {
@@ -22391,25 +24635,25 @@ function emailCommand() {
22391
24635
  } catch (err) {
22392
24636
  const msg = err instanceof Error ? err.message : String(err);
22393
24637
  if (msg.includes("404")) {
22394
- log11.warn(`email body not available for ${email3.id}, skipping`);
24638
+ log14.warn(`email body not available for ${email3.id}, skipping`);
22395
24639
  continue;
22396
24640
  }
22397
24641
  throw err;
22398
24642
  }
22399
24643
  const parsed = await new PostalMime().parse(rawMime);
22400
24644
  if (parsed.text) {
22401
- const bodyPath = join12(emailDir, "body.txt");
22402
- writeFileSync8(bodyPath, parsed.text);
24645
+ const bodyPath = join13(emailDir, "body.txt");
24646
+ writeFileSync9(bodyPath, parsed.text);
22403
24647
  downloadedPaths.push(bodyPath);
22404
24648
  }
22405
24649
  if (parsed.html) {
22406
- const htmlPath = join12(emailDir, "body.html");
22407
- writeFileSync8(htmlPath, parsed.html);
24650
+ const htmlPath = join13(emailDir, "body.html");
24651
+ writeFileSync9(htmlPath, parsed.html);
22408
24652
  downloadedPaths.push(htmlPath);
22409
24653
  }
22410
24654
  if (parsed.attachments && parsed.attachments.length > 0) {
22411
- const attDir = join12(emailDir, "attachments");
22412
- mkdirSync11(attDir, { recursive: true });
24655
+ const attDir = join13(emailDir, "attachments");
24656
+ mkdirSync12(attDir, { recursive: true });
22413
24657
  const usedFilenames = new Set;
22414
24658
  for (let i = 0;i < parsed.attachments.length; i++) {
22415
24659
  const att = parsed.attachments[i];
@@ -22418,8 +24662,8 @@ function emailCommand() {
22418
24662
  filename = `${i}-${filename}`;
22419
24663
  }
22420
24664
  usedFilenames.add(filename);
22421
- const attPath = join12(attDir, filename);
22422
- writeFileSync8(attPath, contentToBuffer(att.content));
24665
+ const attPath = join13(attDir, filename);
24666
+ writeFileSync9(attPath, contentToBuffer(att.content));
22423
24667
  downloadedPaths.push(attPath);
22424
24668
  }
22425
24669
  }
@@ -22460,7 +24704,7 @@ function emailCommand() {
22460
24704
  const client = new APIClient(serverUrl, token, workspaceId);
22461
24705
  let htmlBody;
22462
24706
  try {
22463
- htmlBody = readFileSync11(opts.bodyFile, "utf-8");
24707
+ htmlBody = readFileSync12(opts.bodyFile, "utf-8");
22464
24708
  } catch (err) {
22465
24709
  console.error(`Error: cannot read body file "${opts.bodyFile}": ${err instanceof Error ? err.message : err}`);
22466
24710
  process.exit(1);
@@ -22485,7 +24729,7 @@ function emailCommand() {
22485
24729
  references = [parentEmail.references, parentEmail.message_id].filter(Boolean).join(" ").trim() || undefined;
22486
24730
  }
22487
24731
  } catch {
22488
- log11.warn(`could not fetch parent email ${opts.inReplyTo}, sending without threading`);
24732
+ log14.warn(`could not fetch parent email ${opts.inReplyTo}, sending without threading`);
22489
24733
  }
22490
24734
  }
22491
24735
  const ctx = gatherContextEnvVars();
@@ -23024,14 +25268,14 @@ function issueCommand() {
23024
25268
 
23025
25269
  // commands/agent.ts
23026
25270
  import { Command as Command9 } from "commander";
23027
- import { readFileSync as readFileSync12 } from "fs";
25271
+ import { readFileSync as readFileSync13 } from "fs";
23028
25272
  function readField(opts, inlineName, fileName) {
23029
25273
  if (opts.inline && opts.file) {
23030
25274
  console.error(`Error: --${inlineName} and --${fileName} are mutually exclusive`);
23031
25275
  process.exit(1);
23032
25276
  }
23033
25277
  if (opts.file)
23034
- return readFileSync12(opts.file, "utf-8");
25278
+ return readFileSync13(opts.file, "utf-8");
23035
25279
  return opts.inline ?? null;
23036
25280
  }
23037
25281
  function agentCommand() {
@@ -23171,7 +25415,7 @@ ${result.output}`);
23171
25415
 
23172
25416
  // commands/sync.ts
23173
25417
  import { Command as Command12 } from "commander";
23174
- import { readFileSync as readFileSync13 } from "fs";
25418
+ import { readFileSync as readFileSync14 } from "fs";
23175
25419
  import { basename as basename3 } from "path";
23176
25420
  function syncCommand() {
23177
25421
  const cmd = new Command12("sync").description("Sync info with the user (files, messages)");
@@ -23181,7 +25425,7 @@ function syncCommand() {
23181
25425
  const client = new APIClient(serverUrl, token, workspaceId);
23182
25426
  let bytes;
23183
25427
  try {
23184
- bytes = readFileSync13(opts.file);
25428
+ bytes = readFileSync14(opts.file);
23185
25429
  } catch (err) {
23186
25430
  console.error(`Error: cannot read file "${opts.file}": ${err.message}`);
23187
25431
  process.exit(1);
@@ -23222,7 +25466,7 @@ function syncCommand() {
23222
25466
  let content;
23223
25467
  if (opts.messageFile) {
23224
25468
  try {
23225
- content = readFileSync13(opts.messageFile, "utf-8");
25469
+ content = readFileSync14(opts.messageFile, "utf-8");
23226
25470
  } catch (err) {
23227
25471
  console.error(`Error: cannot read file "${opts.messageFile}": ${err.message}`);
23228
25472
  process.exit(1);
@@ -23256,7 +25500,7 @@ function syncCommand() {
23256
25500
 
23257
25501
  // commands/workspace.ts
23258
25502
  import { Command as Command13 } from "commander";
23259
- import { readFileSync as readFileSync14 } from "fs";
25503
+ import { readFileSync as readFileSync15 } from "fs";
23260
25504
  function slugify2(name) {
23261
25505
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
23262
25506
  }
@@ -23296,7 +25540,7 @@ function workspaceCommand() {
23296
25540
  const client = new APIClient(serverUrl, token, resolvedWorkspaceId);
23297
25541
  let configJson;
23298
25542
  try {
23299
- configJson = readFileSync14(opts.jsonFile, "utf-8");
25543
+ configJson = readFileSync15(opts.jsonFile, "utf-8");
23300
25544
  } catch (err) {
23301
25545
  console.error(`Error: cannot read file '${opts.jsonFile}': ${err instanceof Error ? err.message : err}`);
23302
25546
  process.exit(1);