@alook/cli 0.0.148 → 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.
@@ -12,10 +12,45 @@ var __export = (target, all) => {
12
12
  set: __exportSetter.bind(all, name)
13
13
  });
14
14
  };
15
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
16
+
17
+ // ../../node_modules/.pnpm/nanoid@5.1.16/node_modules/nanoid/url-alphabet/index.js
18
+ var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
19
+
20
+ // ../../node_modules/.pnpm/nanoid@5.1.16/node_modules/nanoid/index.js
21
+ import { webcrypto as crypto2 } from "node:crypto";
22
+ function fillPool(bytes) {
23
+ if (bytes < 0)
24
+ throw new RangeError("Wrong ID size");
25
+ try {
26
+ if (!pool || pool.length < bytes) {
27
+ pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
28
+ crypto2.getRandomValues(pool);
29
+ poolOffset = 0;
30
+ } else if (poolOffset + bytes > pool.length) {
31
+ crypto2.getRandomValues(pool);
32
+ poolOffset = 0;
33
+ }
34
+ } catch (e) {
35
+ pool = undefined;
36
+ throw e;
37
+ }
38
+ poolOffset += bytes;
39
+ }
40
+ function nanoid3(size = 21) {
41
+ fillPool(size |= 0);
42
+ let id = "";
43
+ for (let i = poolOffset - size;i < poolOffset; i++) {
44
+ id += urlAlphabet[pool[i] & 63];
45
+ }
46
+ return id;
47
+ }
48
+ var POOL_SIZE_MULTIPLIER = 128, pool, poolOffset;
49
+ var init_nanoid = () => {};
15
50
 
16
51
  // daemon/session-runner.ts
17
52
  import { mkdir, writeFile, rm, rename } from "fs/promises";
18
- import { mkdirSync as mkdirSync4 } from "fs";
53
+ import { mkdirSync as mkdirSync5 } from "fs";
19
54
  import path from "path";
20
55
 
21
56
  // ../shared/src/constants.ts
@@ -63,6 +98,7 @@ var TERMINAL_ISSUE_STATUSES = [
63
98
  ];
64
99
  var POLL_INTERVAL_MS = Number(process.env.POLL_INTERVAL_MS) || 3000;
65
100
  var OFFLINE_THRESHOLD_MS = Number(process.env.OFFLINE_THRESHOLD_MS) || 30000;
101
+ var COMMUNITY_MACHINE_PAIR_TOKEN_TTL_MS = 15 * 60000;
66
102
  var EVENT_POLL_INTERVAL_MS = Number(process.env.EVENT_POLL_INTERVAL_MS) || 2000;
67
103
  var MeetingStatus = {
68
104
  PENDING: "pending",
@@ -76,9 +112,16 @@ var TERMINAL_MEETING_STATUSES = [
76
112
  MeetingStatus.COMPLETED,
77
113
  MeetingStatus.FAILED
78
114
  ];
115
+ var COMMUNITY_BOT_NAME_MIN = 1;
116
+ var COMMUNITY_BOT_NAME_MAX = 32;
117
+ var COMMUNITY_BOT_DESCRIPTION_MAX = 1024;
118
+ var COMMUNITY_BOT_IMAGE_URL_MAX = 2048;
79
119
  var DEV_WEB_URL = process.env.ALOOK_SERVER_URL || "http://localhost:3000";
80
120
  var DEV_WS_DO_URL = process.env.DEV_WS_DO_URL || "http://localhost:8789";
81
121
  var DEV_EMAIL_WORKER_URL = process.env.DEV_EMAIL_WORKER_URL || "http://localhost:8787";
122
+ // ../shared/src/constants/community.ts
123
+ var MAX_ATTACHMENT_SIZE_BYTES = 25 * 1024 * 1024;
124
+ var MAX_SERVER_ICON_SIZE_BYTES = 5 * 1024 * 1024;
82
125
  // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
83
126
  var exports_external = {};
84
127
  __export(exports_external, {
@@ -14843,7 +14886,126 @@ var CreateThreadRequestSchema = exports_external.object({
14843
14886
  content: exports_external.string().optional().default(""),
14844
14887
  attachment_ids: exports_external.array(exports_external.string()).optional()
14845
14888
  });
14846
- // ../../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
14889
+ var COMMUNITY_RUNTIME_ID_MAX = 64;
14890
+ var COMMUNITY_RUNTIME_VERSION_MAX = 64;
14891
+ var COMMUNITY_RUNTIME_LIST_MAX = 64;
14892
+ var RUNTIME_ID_RE = /^[A-Za-z0-9._@/-]+$/;
14893
+ var CommunityMachineRuntimeSchema = exports_external.object({
14894
+ id: exports_external.string().min(1).max(COMMUNITY_RUNTIME_ID_MAX).regex(RUNTIME_ID_RE, "invalid runtime id charset"),
14895
+ version: exports_external.string().max(COMMUNITY_RUNTIME_VERSION_MAX).optional(),
14896
+ status: exports_external.enum(["healthy", "unhealthy"]).catch("healthy").default("healthy"),
14897
+ lastError: exports_external.string().max(128).optional(),
14898
+ lastErrorAt: exports_external.string().optional()
14899
+ });
14900
+ var CommunityMachineRuntimeListSchema = exports_external.array(CommunityMachineRuntimeSchema).max(COMMUNITY_RUNTIME_LIST_MAX).transform((list) => {
14901
+ const seen = new Set;
14902
+ const out = [];
14903
+ for (const r of list) {
14904
+ if (seen.has(r.id))
14905
+ continue;
14906
+ seen.add(r.id);
14907
+ out.push(r);
14908
+ }
14909
+ return out;
14910
+ });
14911
+ var CommunityMachineSummarySchema = exports_external.object({
14912
+ id: exports_external.string(),
14913
+ hostname: exports_external.string(),
14914
+ displayName: exports_external.string(),
14915
+ platform: exports_external.string(),
14916
+ arch: exports_external.string(),
14917
+ osRelease: exports_external.string(),
14918
+ daemonVersion: exports_external.string(),
14919
+ lastSeenAt: exports_external.string().nullable(),
14920
+ status: exports_external.enum(["online", "offline"]),
14921
+ availableRuntimes: exports_external.array(CommunityMachineRuntimeSchema).default([]),
14922
+ lastRuntimeError: exports_external.object({
14923
+ requested: exports_external.string(),
14924
+ available: exports_external.array(exports_external.string()),
14925
+ at: exports_external.string()
14926
+ }).optional(),
14927
+ createdAt: exports_external.string(),
14928
+ updatedAt: exports_external.string()
14929
+ });
14930
+ var HostReadyMessageSchema = exports_external.object({
14931
+ type: exports_external.literal("ready"),
14932
+ runtimeReport: CommunityMachineRuntimeListSchema,
14933
+ runningAgents: exports_external.array(exports_external.string()).default([]),
14934
+ hostname: exports_external.string().optional(),
14935
+ platform: exports_external.string().optional(),
14936
+ arch: exports_external.string().optional(),
14937
+ osRelease: exports_external.string().optional(),
14938
+ daemonVersion: exports_external.string().optional()
14939
+ });
14940
+ var CommunityDaemonReadySchema = exports_external.object({
14941
+ runtimeReport: CommunityMachineRuntimeListSchema.optional(),
14942
+ runningAgents: exports_external.array(exports_external.string()).default([]),
14943
+ hostname: exports_external.string().optional(),
14944
+ os: exports_external.string().optional(),
14945
+ arch: exports_external.string().optional(),
14946
+ osRelease: exports_external.string().optional(),
14947
+ daemonVersion: exports_external.string().optional()
14948
+ });
14949
+ var SessionErrorFrameSchema = exports_external.object({
14950
+ type: exports_external.literal("session.error"),
14951
+ code: exports_external.enum(["runtime_not_available"]),
14952
+ agentId: exports_external.string().optional(),
14953
+ payload: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
14954
+ });
14955
+ var CommunityPairTokenResponseSchema = exports_external.object({
14956
+ tokenId: exports_external.string(),
14957
+ expiresAt: exports_external.string()
14958
+ });
14959
+ var CommunityDaemonActivateRequestSchema = exports_external.object({
14960
+ hostname: exports_external.string(),
14961
+ platform: exports_external.string(),
14962
+ arch: exports_external.string(),
14963
+ osRelease: exports_external.string().optional(),
14964
+ daemonVersion: exports_external.string().optional(),
14965
+ runtimeReport: CommunityMachineRuntimeListSchema.optional()
14966
+ });
14967
+ var CommunityDaemonActivateResponseSchema = exports_external.object({
14968
+ credential: exports_external.string(),
14969
+ machineId: exports_external.string(),
14970
+ expiresAt: exports_external.string().nullable()
14971
+ });
14972
+ var CommunityDaemonEnrollAgentRequestSchema = exports_external.object({
14973
+ agentId: exports_external.string().min(1).max(128)
14974
+ });
14975
+ var CommunityDaemonEnrollAgentResponseSchema = exports_external.object({
14976
+ runnerKey: exports_external.string(),
14977
+ expiresAt: exports_external.string().nullable()
14978
+ });
14979
+ var BotImageUrlSchema = exports_external.string().max(COMMUNITY_BOT_IMAGE_URL_MAX).refine((v) => v.startsWith("https://") || v.startsWith("avatar:"), {
14980
+ message: "image must be an https URL or an avatar: config"
14981
+ });
14982
+ var CommunityBotCreateRequestSchema = exports_external.object({
14983
+ name: exports_external.string().trim().min(COMMUNITY_BOT_NAME_MIN).max(COMMUNITY_BOT_NAME_MAX),
14984
+ description: exports_external.string().max(COMMUNITY_BOT_DESCRIPTION_MAX).optional(),
14985
+ machineId: exports_external.string().min(1),
14986
+ runtime: exports_external.string().min(1),
14987
+ image: BotImageUrlSchema.optional()
14988
+ });
14989
+ var CommunityBotPatchRequestSchema = exports_external.object({
14990
+ name: exports_external.string().trim().min(COMMUNITY_BOT_NAME_MIN).max(COMMUNITY_BOT_NAME_MAX).optional(),
14991
+ description: exports_external.string().max(COMMUNITY_BOT_DESCRIPTION_MAX).optional(),
14992
+ image: BotImageUrlSchema.nullable().optional()
14993
+ }).refine((v) => v.name !== undefined || v.description !== undefined || v.image !== undefined, {
14994
+ message: "at least one field must be provided"
14995
+ });
14996
+ var CommunityBotAddToServerRequestSchema = exports_external.object({
14997
+ botId: exports_external.string().min(1)
14998
+ });
14999
+ var CommunityDaemonSendAsBotRequestSchema = exports_external.object({
15000
+ target: exports_external.enum(["channel", "dm"]),
15001
+ targetId: exports_external.string().min(1),
15002
+ content: exports_external.string().max(4000),
15003
+ replyToId: exports_external.string().optional(),
15004
+ mentionType: exports_external.enum(["everyone", "here", "user"]).optional(),
15005
+ embeds: exports_external.array(exports_external.unknown()).optional(),
15006
+ attachments: exports_external.array(exports_external.unknown()).optional()
15007
+ });
15008
+ // ../../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
14847
15009
  var entityKind = Symbol.for("drizzle:entityKind");
14848
15010
  var hasOwnEntityKind = Symbol.for("drizzle:hasOwnEntityKind");
14849
15011
  function is(value, type) {
@@ -14868,10 +15030,10 @@ function is(value, type) {
14868
15030
  return false;
14869
15031
  }
14870
15032
 
14871
- // ../../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
15033
+ // ../../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
14872
15034
  var TableName = Symbol.for("drizzle:Name");
14873
15035
 
14874
- // ../../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
15036
+ // ../../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
14875
15037
  var Schema = Symbol.for("drizzle:Schema");
14876
15038
  var Columns = Symbol.for("drizzle:Columns");
14877
15039
  var ExtraConfigColumns = Symbol.for("drizzle:ExtraConfigColumns");
@@ -14909,7 +15071,7 @@ class Table {
14909
15071
  }
14910
15072
  }
14911
15073
 
14912
- // ../../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
15074
+ // ../../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
14913
15075
  class Column {
14914
15076
  constructor(table, config2) {
14915
15077
  this.table = table;
@@ -14959,7 +15121,7 @@ class Column {
14959
15121
  }
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/column-builder.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/column-builder.js
14963
15125
  class ColumnBuilder {
14964
15126
  static [entityKind] = "ColumnBuilder";
14965
15127
  config;
@@ -15015,17 +15177,17 @@ class ColumnBuilder {
15015
15177
  }
15016
15178
  }
15017
15179
 
15018
- // ../../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
15180
+ // ../../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
15019
15181
  function iife(fn, ...args) {
15020
15182
  return fn(...args);
15021
15183
  }
15022
15184
 
15023
- // ../../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
15185
+ // ../../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
15024
15186
  function uniqueKeyName(table, columns) {
15025
15187
  return `${table[TableName]}_${columns.join("_")}_unique`;
15026
15188
  }
15027
15189
 
15028
- // ../../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
15190
+ // ../../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
15029
15191
  class PgColumn extends Column {
15030
15192
  constructor(table, config2) {
15031
15193
  if (!config2.uniqueName) {
@@ -15074,7 +15236,7 @@ class ExtraConfigColumn extends PgColumn {
15074
15236
  }
15075
15237
  }
15076
15238
 
15077
- // ../../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
15239
+ // ../../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
15078
15240
  class PgEnumObjectColumn extends PgColumn {
15079
15241
  static [entityKind] = "PgEnumObjectColumn";
15080
15242
  enum;
@@ -15104,7 +15266,7 @@ class PgEnumColumn extends PgColumn {
15104
15266
  }
15105
15267
  }
15106
15268
 
15107
- // ../../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
15269
+ // ../../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
15108
15270
  class Subquery {
15109
15271
  static [entityKind] = "Subquery";
15110
15272
  constructor(sql, fields, alias, isWith = false, usedTables = []) {
@@ -15119,10 +15281,10 @@ class Subquery {
15119
15281
  }
15120
15282
  }
15121
15283
 
15122
- // ../../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
15284
+ // ../../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
15123
15285
  var version2 = "0.45.2";
15124
15286
 
15125
- // ../../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
15287
+ // ../../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
15126
15288
  var otel;
15127
15289
  var rawTracer;
15128
15290
  var tracer = {
@@ -15149,10 +15311,10 @@ var tracer = {
15149
15311
  }
15150
15312
  };
15151
15313
 
15152
- // ../../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
15314
+ // ../../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
15153
15315
  var ViewBaseConfig = Symbol.for("drizzle:ViewBaseConfig");
15154
15316
 
15155
- // ../../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
15317
+ // ../../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
15156
15318
  function isSQLWrapper(value) {
15157
15319
  return value !== null && value !== undefined && typeof value.getSQL === "function";
15158
15320
  }
@@ -15512,7 +15674,7 @@ Subquery.prototype.getSQL = function() {
15512
15674
  return new SQL([this]);
15513
15675
  };
15514
15676
 
15515
- // ../../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
15677
+ // ../../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
15516
15678
  function getColumnNameAndConfig(a, b) {
15517
15679
  return {
15518
15680
  name: typeof a === "string" && a.length > 0 ? a : "",
@@ -15521,7 +15683,7 @@ function getColumnNameAndConfig(a, b) {
15521
15683
  }
15522
15684
  var textDecoder = typeof TextDecoder === "undefined" ? null : new TextDecoder;
15523
15685
 
15524
- // ../../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
15686
+ // ../../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
15525
15687
  class ForeignKeyBuilder {
15526
15688
  static [entityKind] = "SQLiteForeignKeyBuilder";
15527
15689
  reference;
@@ -15589,7 +15751,7 @@ function foreignKey(config2) {
15589
15751
  return new ForeignKeyBuilder(mappedConfig);
15590
15752
  }
15591
15753
 
15592
- // ../../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
15754
+ // ../../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
15593
15755
  function uniqueKeyName2(table, columns) {
15594
15756
  return `${table[TableName]}_${columns.join("_")}_unique`;
15595
15757
  }
@@ -15634,7 +15796,7 @@ class UniqueConstraint {
15634
15796
  }
15635
15797
  }
15636
15798
 
15637
- // ../../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
15799
+ // ../../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
15638
15800
  class SQLiteColumnBuilder extends ColumnBuilder {
15639
15801
  static [entityKind] = "SQLiteColumnBuilder";
15640
15802
  foreignKeyConfigs = [];
@@ -15685,7 +15847,7 @@ class SQLiteColumn extends Column {
15685
15847
  static [entityKind] = "SQLiteColumn";
15686
15848
  }
15687
15849
 
15688
- // ../../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
15850
+ // ../../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
15689
15851
  class SQLiteBigIntBuilder extends SQLiteColumnBuilder {
15690
15852
  static [entityKind] = "SQLiteBigIntBuilder";
15691
15853
  constructor(name) {
@@ -15773,7 +15935,7 @@ function blob(a, b) {
15773
15935
  return new SQLiteBlobBufferBuilder(name);
15774
15936
  }
15775
15937
 
15776
- // ../../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
15938
+ // ../../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
15777
15939
  class SQLiteCustomColumnBuilder extends SQLiteColumnBuilder {
15778
15940
  static [entityKind] = "SQLiteCustomColumnBuilder";
15779
15941
  constructor(name, fieldConfig, customTypeParams) {
@@ -15814,7 +15976,7 @@ function customType(customTypeParams) {
15814
15976
  };
15815
15977
  }
15816
15978
 
15817
- // ../../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
15979
+ // ../../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
15818
15980
  class SQLiteBaseIntegerBuilder extends SQLiteColumnBuilder {
15819
15981
  static [entityKind] = "SQLiteBaseIntegerBuilder";
15820
15982
  constructor(name, dataType, columnType) {
@@ -15916,7 +16078,7 @@ function integer2(a, b) {
15916
16078
  return new SQLiteIntegerBuilder(name);
15917
16079
  }
15918
16080
 
15919
- // ../../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
16081
+ // ../../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
15920
16082
  class SQLiteNumericBuilder extends SQLiteColumnBuilder {
15921
16083
  static [entityKind] = "SQLiteNumericBuilder";
15922
16084
  constructor(name) {
@@ -15986,7 +16148,7 @@ function numeric(a, b) {
15986
16148
  return mode === "number" ? new SQLiteNumericNumberBuilder(name) : mode === "bigint" ? new SQLiteNumericBigIntBuilder(name) : new SQLiteNumericBuilder(name);
15987
16149
  }
15988
16150
 
15989
- // ../../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
16151
+ // ../../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
15990
16152
  class SQLiteRealBuilder extends SQLiteColumnBuilder {
15991
16153
  static [entityKind] = "SQLiteRealBuilder";
15992
16154
  constructor(name) {
@@ -16007,7 +16169,7 @@ function real(name) {
16007
16169
  return new SQLiteRealBuilder(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/text.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/text.js
16011
16173
  class SQLiteTextBuilder extends SQLiteColumnBuilder {
16012
16174
  static [entityKind] = "SQLiteTextBuilder";
16013
16175
  constructor(name, config2) {
@@ -16062,7 +16224,7 @@ function text(a, b = {}) {
16062
16224
  return new SQLiteTextBuilder(name, config2);
16063
16225
  }
16064
16226
 
16065
- // ../../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
16227
+ // ../../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
16066
16228
  function getSQLiteColumnBuilders() {
16067
16229
  return {
16068
16230
  blob,
@@ -16074,7 +16236,7 @@ function getSQLiteColumnBuilders() {
16074
16236
  };
16075
16237
  }
16076
16238
 
16077
- // ../../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
16239
+ // ../../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
16078
16240
  var InlineForeignKeys = Symbol.for("drizzle:SQLiteInlineForeignKeys");
16079
16241
 
16080
16242
  class SQLiteTable extends Table {
@@ -16108,7 +16270,7 @@ var sqliteTable = (name, columns, extraConfig) => {
16108
16270
  return sqliteTableBase(name, columns, extraConfig);
16109
16271
  };
16110
16272
 
16111
- // ../../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
16273
+ // ../../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
16112
16274
  class IndexBuilderOn {
16113
16275
  constructor(name, unique2) {
16114
16276
  this.name = name;
@@ -16150,8 +16312,11 @@ class Index {
16150
16312
  function index(name) {
16151
16313
  return new IndexBuilderOn(name, false);
16152
16314
  }
16315
+ function uniqueIndex(name) {
16316
+ return new IndexBuilderOn(name, true);
16317
+ }
16153
16318
 
16154
- // ../../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
16319
+ // ../../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
16155
16320
  function primaryKey(...config2) {
16156
16321
  if (config2[0].columns) {
16157
16322
  return new PrimaryKeyBuilder(config2[0].columns, config2[0].name);
@@ -16186,44 +16351,45 @@ class PrimaryKey {
16186
16351
  }
16187
16352
  }
16188
16353
 
16189
- // ../../node_modules/.pnpm/nanoid@5.1.15/node_modules/nanoid/index.js
16190
- import { webcrypto as crypto } from "node:crypto";
16191
-
16192
- // ../../node_modules/.pnpm/nanoid@5.1.15/node_modules/nanoid/url-alphabet/index.js
16193
- var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
16194
-
16195
- // ../../node_modules/.pnpm/nanoid@5.1.15/node_modules/nanoid/index.js
16196
- var POOL_SIZE_MULTIPLIER = 128;
16197
- var pool;
16198
- var poolOffset;
16199
- function fillPool(bytes) {
16200
- if (bytes < 0)
16201
- throw new RangeError("Wrong ID size");
16202
- try {
16203
- if (!pool || pool.length < bytes) {
16204
- pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
16205
- crypto.getRandomValues(pool);
16206
- poolOffset = 0;
16207
- } else if (poolOffset + bytes > pool.length) {
16208
- crypto.getRandomValues(pool);
16209
- poolOffset = 0;
16210
- }
16211
- } catch (e) {
16212
- pool = undefined;
16213
- throw e;
16214
- }
16215
- poolOffset += bytes;
16216
- }
16217
- function nanoid3(size = 21) {
16218
- fillPool(size |= 0);
16219
- let id = "";
16220
- for (let i = poolOffset - size;i < poolOffset; i++) {
16221
- id += urlAlphabet[pool[i] & 63];
16222
- }
16223
- return id;
16224
- }
16225
-
16226
16354
  // ../shared/src/db/schema.ts
16355
+ var exports_schema = {};
16356
+ __export(exports_schema, {
16357
+ workspaceInvite: () => workspaceInvite,
16358
+ workspaceFileRequest: () => workspaceFileRequest,
16359
+ workspace: () => workspace,
16360
+ verification: () => verification,
16361
+ user: () => user,
16362
+ taskMessage: () => taskMessage,
16363
+ session: () => session,
16364
+ messageFlag: () => messageFlag,
16365
+ message: () => message,
16366
+ member: () => member,
16367
+ meetingSession: () => meetingSession,
16368
+ machineToken: () => machineToken,
16369
+ machine: () => machine,
16370
+ issueComment: () => issueComment,
16371
+ issue: () => issue2,
16372
+ inboxUnread: () => inboxUnread,
16373
+ emails: () => emails,
16374
+ conversationReadState: () => conversationReadState,
16375
+ conversationMap: () => conversationMap,
16376
+ conversation: () => conversation,
16377
+ channel: () => channel,
16378
+ calendarEvent: () => calendarEvent,
16379
+ artifact: () => artifact,
16380
+ agentWhitelist: () => agentWhitelist,
16381
+ agentTaskQueue: () => agentTaskQueue,
16382
+ agentSkill: () => agentSkill,
16383
+ agentSidebarOrder: () => agentSidebarOrder,
16384
+ agentRuntime: () => agentRuntime,
16385
+ agentPin: () => agentPin,
16386
+ agentLink: () => agentLink,
16387
+ agentEmailAccount: () => agentEmailAccount,
16388
+ agentAccess: () => agentAccess,
16389
+ agent: () => agent,
16390
+ account: () => account
16391
+ });
16392
+ init_nanoid();
16227
16393
  var user = sqliteTable("user", {
16228
16394
  id: text("id").primaryKey().$defaultFn(() => nanoid3()),
16229
16395
  name: text("name").notNull().default(""),
@@ -16231,8 +16397,12 @@ var user = sqliteTable("user", {
16231
16397
  emailVerified: integer2("emailVerified", { mode: "boolean" }),
16232
16398
  image: text("image"),
16233
16399
  createdAt: text("createdAt").notNull().$defaultFn(() => new Date().toISOString()),
16234
- updatedAt: text("updatedAt").notNull().$defaultFn(() => new Date().toISOString())
16235
- });
16400
+ updatedAt: text("updatedAt").notNull().$defaultFn(() => new Date().toISOString()),
16401
+ isBot: integer2("isBot", { mode: "boolean" }).notNull().default(false),
16402
+ ownerUserId: text("ownerUserId"),
16403
+ deletedAt: text("deletedAt"),
16404
+ discriminator: text("discriminator").notNull().default("0000")
16405
+ }, (t) => [index("idx_user_ownerUserId_isBot").on(t.ownerUserId, t.isBot)]);
16236
16406
  var session = sqliteTable("session", {
16237
16407
  id: text("id").primaryKey().$defaultFn(() => nanoid3()),
16238
16408
  userId: text("userId").notNull().references(() => user.id, { onDelete: "cascade" }),
@@ -16768,6 +16938,353 @@ var inboxUnread = sqliteTable("inbox_unread", {
16768
16938
  unique("inbox_unread_conv_user").on(t.conversationId, t.userId),
16769
16939
  index("idx_inbox_unread_user_ws").on(t.userId, t.workspaceId, t.taskType, t.completedAt)
16770
16940
  ]);
16941
+
16942
+ // ../shared/src/db/community-schema.ts
16943
+ var exports_community_schema = {};
16944
+ __export(exports_community_schema, {
16945
+ communityUserProfile: () => communityUserProfile,
16946
+ communityServerMember: () => communityServerMember,
16947
+ communityServerInvite: () => communityServerInvite,
16948
+ communityServerFolderItem: () => communityServerFolderItem,
16949
+ communityServerFolder: () => communityServerFolder,
16950
+ communityServer: () => communityServer,
16951
+ communityReadState: () => communityReadState,
16952
+ communityReaction: () => communityReaction,
16953
+ communityPin: () => communityPin,
16954
+ communityNotificationSetting: () => communityNotificationSetting,
16955
+ communityMessage: () => communityMessage,
16956
+ communityMention: () => communityMention,
16957
+ communityInboxDismissal: () => communityInboxDismissal,
16958
+ communityFriendship: () => communityFriendship,
16959
+ communityDmConversation: () => communityDmConversation,
16960
+ communityChannel: () => communityChannel,
16961
+ communityCategory: () => communityCategory,
16962
+ communityBotApprovalRequest: () => communityBotApprovalRequest,
16963
+ communityAuditLog: () => communityAuditLog,
16964
+ communityAttachment: () => communityAttachment
16965
+ });
16966
+ init_nanoid();
16967
+ var communityServer = sqliteTable("community_server", {
16968
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
16969
+ name: text("name").notNull(),
16970
+ description: text("description").default(""),
16971
+ icon: text("icon"),
16972
+ ownerId: text("owner_id").notNull().references(() => user.id, { onDelete: "restrict" }),
16973
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
16974
+ });
16975
+ var communityCategory = sqliteTable("community_category", {
16976
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
16977
+ serverId: text("server_id").notNull().references(() => communityServer.id, { onDelete: "cascade" }),
16978
+ name: text("name").notNull(),
16979
+ position: integer2("position").default(0),
16980
+ private: integer2("private").default(0),
16981
+ creatorId: text("creator_id").references(() => user.id, { onDelete: "set null" })
16982
+ }, (t) => [unique("uq_category_server_name").on(t.serverId, t.name)]);
16983
+ var communityChannel = sqliteTable("community_channel", {
16984
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
16985
+ serverId: text("server_id").notNull().references(() => communityServer.id, { onDelete: "cascade" }),
16986
+ categoryId: text("category_id").references(() => communityCategory.id, {
16987
+ onDelete: "set null"
16988
+ }),
16989
+ name: text("name").notNull(),
16990
+ type: text("type").notNull().default("text"),
16991
+ topic: text("topic").default(""),
16992
+ position: integer2("position").default(0),
16993
+ forumTags: text("forum_tags"),
16994
+ parentChannelId: text("parent_channel_id").references(() => communityChannel.id, {
16995
+ onDelete: "cascade"
16996
+ }),
16997
+ creatorId: text("creator_id").references(() => user.id, { onDelete: "set null" }),
16998
+ messageCount: integer2("message_count").default(0),
16999
+ archived: integer2("archived").default(0),
17000
+ parentMessageId: text("parent_message_id"),
17001
+ lastMessageAt: text("last_message_at"),
17002
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17003
+ }, (t) => [
17004
+ index("idx_channel_server_position").on(t.serverId, t.position),
17005
+ index("idx_channel_server_last_message").on(t.serverId, t.lastMessageAt),
17006
+ index("idx_channel_parent").on(t.parentChannelId)
17007
+ ]);
17008
+ var communityDmConversation = sqliteTable("community_dm_conversation", {
17009
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17010
+ user1Id: text("user1_id").references(() => user.id, { onDelete: "set null" }),
17011
+ user2Id: text("user2_id").references(() => user.id, { onDelete: "set null" }),
17012
+ lastMessageAt: text("last_message_at"),
17013
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17014
+ }, (t) => [
17015
+ unique("uq_dm_conversation_users").on(t.user1Id, t.user2Id),
17016
+ index("idx_dm_conversation_user1_last_message").on(t.user1Id, t.lastMessageAt),
17017
+ index("idx_dm_conversation_user2_last_message").on(t.user2Id, t.lastMessageAt)
17018
+ ]);
17019
+ var communityMessage = sqliteTable("community_message", {
17020
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17021
+ authorId: text("author_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17022
+ content: text("content").notNull().default(""),
17023
+ type: text("type").notNull().default("default"),
17024
+ mentionType: text("mention_type"),
17025
+ replyToId: text("reply_to_id"),
17026
+ embeds: text("embeds"),
17027
+ flags: integer2("flags").default(0),
17028
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17029
+ channelId: text("channel_id").references(() => communityChannel.id, {
17030
+ onDelete: "cascade"
17031
+ }),
17032
+ dmConversationId: text("dm_conversation_id").references(() => communityDmConversation.id, { onDelete: "cascade" })
17033
+ }, (t) => [
17034
+ index("idx_message_channel_created").on(t.channelId, t.createdAt),
17035
+ index("idx_message_channel_mention_created").on(t.channelId, t.mentionType, t.createdAt),
17036
+ index("idx_message_dm_created").on(t.dmConversationId, t.createdAt)
17037
+ ]);
17038
+ var communityServerMember = sqliteTable("community_server_member", {
17039
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17040
+ serverId: text("server_id").notNull().references(() => communityServer.id, { onDelete: "cascade" }),
17041
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17042
+ role: text("role").default("member"),
17043
+ nickname: text("nickname"),
17044
+ railOrder: integer2("rail_order").default(0),
17045
+ joinedAt: text("joined_at").notNull().$defaultFn(() => new Date().toISOString())
17046
+ }, (t) => [
17047
+ unique("uq_server_member_server_user").on(t.serverId, t.userId),
17048
+ index("idx_server_member_user").on(t.userId),
17049
+ index("idx_server_member_user_rail_order").on(t.userId, t.railOrder)
17050
+ ]);
17051
+ var communityServerFolder = sqliteTable("community_server_folder", {
17052
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17053
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17054
+ name: text("name").notNull(),
17055
+ position: integer2("position").default(0)
17056
+ }, (t) => [index("idx_server_folder_user_position").on(t.userId, t.position)]);
17057
+ var communityServerFolderItem = sqliteTable("community_server_folder_item", {
17058
+ folderId: text("folder_id").notNull().references(() => communityServerFolder.id, { onDelete: "cascade" }),
17059
+ serverId: text("server_id").notNull().references(() => communityServer.id, { onDelete: "cascade" }),
17060
+ position: integer2("position").default(0)
17061
+ }, (t) => [
17062
+ primaryKey({ columns: [t.folderId, t.serverId] }),
17063
+ index("idx_server_folder_item_folder_position").on(t.folderId, t.position)
17064
+ ]);
17065
+ var communityServerInvite = sqliteTable("community_server_invite", {
17066
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17067
+ serverId: text("server_id").notNull().references(() => communityServer.id, { onDelete: "cascade" }),
17068
+ createdBy: text("created_by").references(() => user.id, { onDelete: "set null" }),
17069
+ token: text("token").unique().notNull().$defaultFn(() => nanoid3(10)),
17070
+ maxUses: integer2("max_uses"),
17071
+ uses: integer2("uses").default(0),
17072
+ expiresAt: text("expires_at"),
17073
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17074
+ });
17075
+ var communityFriendship = sqliteTable("community_friendship", {
17076
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17077
+ requesterId: text("requester_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17078
+ addresseeId: text("addressee_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17079
+ status: text("status").notNull().default("pending"),
17080
+ blockerId: text("blocker_id"),
17081
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17082
+ updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString())
17083
+ }, (t) => [
17084
+ unique("uq_friendship_requester_addressee").on(t.requesterId, t.addresseeId),
17085
+ index("idx_friendship_addressee_status").on(t.addresseeId, t.status),
17086
+ index("idx_friendship_requester_status").on(t.requesterId, t.status)
17087
+ ]);
17088
+ var communityReadState = sqliteTable("community_read_state", {
17089
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17090
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17091
+ channelId: text("channel_id").references(() => communityChannel.id, {
17092
+ onDelete: "cascade"
17093
+ }),
17094
+ dmConversationId: text("dm_conversation_id").references(() => communityDmConversation.id, { onDelete: "cascade" }),
17095
+ lastReadAt: text("last_read_at").notNull(),
17096
+ lastReadMessageId: text("last_read_message_id")
17097
+ }, (t) => [index("idx_read_state_user").on(t.userId)]);
17098
+ var communityReaction = sqliteTable("community_reaction", {
17099
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17100
+ messageId: text("message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
17101
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17102
+ emoji: text("emoji").notNull(),
17103
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17104
+ }, (t) => [
17105
+ unique("uq_reaction_message_user_emoji").on(t.messageId, t.userId, t.emoji),
17106
+ index("idx_reaction_message").on(t.messageId)
17107
+ ]);
17108
+ var communityAttachment = sqliteTable("community_attachment", {
17109
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17110
+ messageId: text("message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
17111
+ filename: text("filename").notNull(),
17112
+ url: text("url").notNull(),
17113
+ contentType: text("content_type"),
17114
+ size: integer2("size"),
17115
+ width: integer2("width"),
17116
+ height: integer2("height"),
17117
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17118
+ }, (t) => [index("idx_attachment_message").on(t.messageId)]);
17119
+ var communityPin = sqliteTable("community_pin", {
17120
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17121
+ channelId: text("channel_id").notNull().references(() => communityChannel.id, { onDelete: "cascade" }),
17122
+ messageId: text("message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
17123
+ pinnedBy: text("pinned_by").references(() => user.id, { onDelete: "set null" }),
17124
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17125
+ }, (t) => [
17126
+ unique("uq_pin_channel_message").on(t.channelId, t.messageId),
17127
+ index("idx_pin_channel").on(t.channelId)
17128
+ ]);
17129
+ var communityMention = sqliteTable("community_mention", {
17130
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17131
+ messageId: text("message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
17132
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17133
+ kind: text("kind").notNull().default("mention"),
17134
+ read: integer2("read").default(0)
17135
+ }, (t) => [
17136
+ index("idx_mention_user_read").on(t.userId, t.read),
17137
+ index("idx_mention_message").on(t.messageId)
17138
+ ]);
17139
+ var communityUserProfile = sqliteTable("community_user_profile", {
17140
+ userId: text("user_id").primaryKey().references(() => user.id, { onDelete: "cascade" }),
17141
+ aboutMe: text("about_me").default(""),
17142
+ bannerColor: text("banner_color")
17143
+ });
17144
+ var communityNotificationSetting = sqliteTable("community_notification_setting", {
17145
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17146
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17147
+ serverId: text("server_id").references(() => communityServer.id, {
17148
+ onDelete: "cascade"
17149
+ }),
17150
+ channelId: text("channel_id").references(() => communityChannel.id, {
17151
+ onDelete: "cascade"
17152
+ }),
17153
+ level: text("level").notNull().default("all")
17154
+ }, (t) => [index("idx_notification_setting_user").on(t.userId)]);
17155
+ var communityAuditLog = sqliteTable("community_audit_log", {
17156
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17157
+ serverId: text("server_id").references(() => communityServer.id, {
17158
+ onDelete: "cascade"
17159
+ }),
17160
+ actorId: text("actor_id").references(() => user.id, { onDelete: "set null" }),
17161
+ action: text("action").notNull(),
17162
+ targetType: text("target_type").notNull(),
17163
+ targetId: text("target_id").notNull(),
17164
+ changes: text("changes"),
17165
+ reason: text("reason"),
17166
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17167
+ }, (t) => [
17168
+ index("idx_audit_log_server_created").on(t.serverId, t.createdAt),
17169
+ index("idx_audit_log_server_action").on(t.serverId, t.action),
17170
+ index("idx_audit_log_actor_created").on(t.actorId, t.createdAt)
17171
+ ]);
17172
+ var communityBotApprovalRequest = sqliteTable("community_bot_approval_request", {
17173
+ id: text("id").primaryKey().$defaultFn(() => "bar_" + nanoid3()),
17174
+ botId: text("bot_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17175
+ kind: text("kind").notNull(),
17176
+ serverId: text("server_id").references(() => communityServer.id, {
17177
+ onDelete: "cascade"
17178
+ }),
17179
+ requestedByUserId: text("requested_by_user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17180
+ dmMessageId: text("dm_message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
17181
+ status: text("status").notNull().default("pending"),
17182
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17183
+ resolvedAt: text("resolved_at")
17184
+ }, (t) => [index("idx_community_bot_approval_bot").on(t.botId, t.status)]);
17185
+ var communityInboxDismissal = sqliteTable("community_inbox_dismissal", {
17186
+ id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17187
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17188
+ eventKey: text("event_key").notNull(),
17189
+ dismissedAt: text("dismissed_at").notNull().$defaultFn(() => new Date().toISOString())
17190
+ }, (t) => [
17191
+ unique("uq_inbox_dismissal_user_event").on(t.userId, t.eventKey),
17192
+ index("idx_inbox_dismissal_user").on(t.userId)
17193
+ ]);
17194
+
17195
+ // ../shared/src/db/community-machine-schema.ts
17196
+ var exports_community_machine_schema = {};
17197
+ __export(exports_community_machine_schema, {
17198
+ communityMachineToken: () => communityMachineToken,
17199
+ communityMachineCredential: () => communityMachineCredential,
17200
+ communityMachine: () => communityMachine,
17201
+ communityBotBinding: () => communityBotBinding,
17202
+ communityAgentRunnerKey: () => communityAgentRunnerKey
17203
+ });
17204
+ init_nanoid();
17205
+ var communityMachineToken = sqliteTable("community_machine_token", {
17206
+ id: text("id").primaryKey().$defaultFn(() => "cmt_" + nanoid3(32)),
17207
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17208
+ machineId: text("machine_id"),
17209
+ status: text("status").notNull().default("pending"),
17210
+ expiresAt: text("expires_at").notNull(),
17211
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17212
+ lastUsedAt: text("last_used_at")
17213
+ }, (t) => [
17214
+ index("idx_community_machine_token_user_status").on(t.userId, t.status),
17215
+ uniqueIndex("uq_community_machine_token_user_pending").on(t.userId).where(sql`status = 'pending'`)
17216
+ ]);
17217
+ var communityMachine = sqliteTable("community_machine", {
17218
+ id: text("id").primaryKey().$defaultFn(() => "cm_" + nanoid3()),
17219
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17220
+ displayName: text("display_name").notNull().default(""),
17221
+ hostname: text("hostname").notNull().default(""),
17222
+ platform: text("platform").notNull().default(""),
17223
+ arch: text("arch").notNull().default(""),
17224
+ osRelease: text("os_release").notNull().default(""),
17225
+ daemonVersion: text("daemon_version").notNull().default(""),
17226
+ metadata: text("metadata"),
17227
+ availableRuntimes: text("available_runtimes", { mode: "json" }).$type().notNull().default([]),
17228
+ status: text("status").notNull().default("offline"),
17229
+ lastSeenAt: text("last_seen_at"),
17230
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17231
+ updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString())
17232
+ }, (t) => [
17233
+ index("idx_community_machine_user_last_seen").on(t.userId, t.lastSeenAt),
17234
+ index("idx_community_machine_user_updated").on(t.userId, t.updatedAt),
17235
+ index("idx_community_machine_user_status").on(t.userId, t.status)
17236
+ ]);
17237
+ var communityMachineCredential = sqliteTable("community_machine_credential", {
17238
+ id: text("id").primaryKey().$defaultFn(() => "cmkid_" + nanoid3()),
17239
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17240
+ machineId: text("machine_id").notNull().references(() => communityMachine.id, { onDelete: "cascade" }),
17241
+ credentialHash: text("credential_hash").notNull().unique(),
17242
+ doName: text("do_name").notNull().unique(),
17243
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17244
+ lastUsedAt: text("last_used_at"),
17245
+ revokedAt: text("revoked_at")
17246
+ }, (t) => [
17247
+ index("idx_community_machine_credential_user").on(t.userId),
17248
+ index("idx_community_machine_credential_machine").on(t.machineId)
17249
+ ]);
17250
+ var communityBotBinding = sqliteTable("community_bot_binding", {
17251
+ userId: text("user_id").primaryKey().references(() => user.id, { onDelete: "cascade" }),
17252
+ machineId: text("machine_id").notNull().references(() => communityMachine.id, { onDelete: "restrict" }),
17253
+ runtime: text("runtime").notNull(),
17254
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
17255
+ }, (t) => [index("idx_community_bot_binding_machine").on(t.machineId)]);
17256
+ var communityAgentRunnerKey = sqliteTable("community_agent_runner_key", {
17257
+ id: text("id").primaryKey().$defaultFn(() => "crkid_" + nanoid3()),
17258
+ userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
17259
+ machineId: text("machine_id").notNull().references(() => communityMachine.id, { onDelete: "cascade" }),
17260
+ agentId: text("agent_id").notNull(),
17261
+ runnerKeyHash: text("runner_key_hash").notNull().unique(),
17262
+ doName: text("do_name").notNull().unique(),
17263
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
17264
+ revokedAt: text("revoked_at")
17265
+ }, (t) => [
17266
+ index("idx_community_agent_runner_key_machine_agent").on(t.machineId, t.agentId)
17267
+ ]);
17268
+
17269
+ // ../shared/src/db/index.ts
17270
+ var allSchema = { ...exports_schema, ...exports_community_schema, ...exports_community_machine_schema };
17271
+ // ../shared/src/db/queries/user.ts
17272
+ var publicUserColumns = {
17273
+ id: user.id,
17274
+ name: user.name,
17275
+ email: user.email,
17276
+ emailVerified: user.emailVerified,
17277
+ image: user.image,
17278
+ createdAt: user.createdAt,
17279
+ updatedAt: user.updatedAt,
17280
+ discriminator: user.discriminator
17281
+ };
17282
+ var internalUserColumns = {
17283
+ ...publicUserColumns,
17284
+ isBot: user.isBot,
17285
+ ownerUserId: user.ownerUserId,
17286
+ deletedAt: user.deletedAt
17287
+ };
16771
17288
  // ../shared/src/db/queries/task.ts
16772
17289
  var DEFAULT_STALE_SECONDS = Number(process.env.ALOOK_STALE_DISPATCH_TIMEOUT_S) || 20;
16773
17290
  var DEFAULT_STALE_RUNNING_SECONDS = Number(process.env.ALOOK_STALE_RUNNING_TIMEOUT_S) || 3600;
@@ -16793,6 +17310,109 @@ var RESERVED_HANDLES = new Set([
16793
17310
  function toAlookAddress(h) {
16794
17311
  return `${h}${DOMAIN}`;
16795
17312
  }
17313
+ // ../shared/src/logger.ts
17314
+ var LEVELS = {
17315
+ debug: 0,
17316
+ info: 1,
17317
+ warn: 2,
17318
+ error: 3,
17319
+ silent: 4
17320
+ };
17321
+
17322
+ class Logger {
17323
+ service;
17324
+ level;
17325
+ pretty;
17326
+ fields;
17327
+ constructor(opts, fields) {
17328
+ this.service = opts.service;
17329
+ this.level = LEVELS[opts.level ?? "info"];
17330
+ this.pretty = opts.pretty ?? false;
17331
+ this.fields = fields ?? {};
17332
+ }
17333
+ debug(msg, ctx) {
17334
+ this.write("debug", msg, ctx);
17335
+ }
17336
+ info(msg, ctx) {
17337
+ this.write("info", msg, ctx);
17338
+ }
17339
+ warn(msg, ctx) {
17340
+ this.write("warn", msg, ctx);
17341
+ }
17342
+ error(msg, ctx) {
17343
+ this.write("error", msg, ctx);
17344
+ }
17345
+ child(fields) {
17346
+ const merged = { ...this.fields, ...fields };
17347
+ const child = new Logger({ service: this.service, level: this.levelName(), pretty: this.pretty }, merged);
17348
+ return child;
17349
+ }
17350
+ levelName() {
17351
+ for (const [name, num] of Object.entries(LEVELS)) {
17352
+ if (num === this.level)
17353
+ return name;
17354
+ }
17355
+ return "info";
17356
+ }
17357
+ write(level, msg, ctx) {
17358
+ if (LEVELS[level] < this.level)
17359
+ return;
17360
+ const entry = {
17361
+ level,
17362
+ msg,
17363
+ service: this.service,
17364
+ ...this.fields,
17365
+ ...ctx,
17366
+ ts: new Date().toISOString()
17367
+ };
17368
+ for (const [k, v] of Object.entries(entry)) {
17369
+ if (v instanceof Error) {
17370
+ entry[k] = { message: v.message, stack: v.stack };
17371
+ }
17372
+ }
17373
+ let line;
17374
+ if (this.pretty) {
17375
+ const ts = entry.ts.replace("T", " ").replace("Z", "");
17376
+ const lvl = entry.level.toUpperCase().padEnd(5);
17377
+ 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(" ");
17378
+ line = `${ts} ${lvl} [${entry.service}] ${entry.msg}${pairs ? " " + pairs : ""}`;
17379
+ } else {
17380
+ line = JSON.stringify(entry);
17381
+ }
17382
+ if (level === "error") {
17383
+ console.error(line);
17384
+ } else {
17385
+ console.log(line);
17386
+ }
17387
+ }
17388
+ }
17389
+ function createLogger(opts) {
17390
+ return new Logger(opts);
17391
+ }
17392
+
17393
+ // ../shared/src/db/queries/community/channel.ts
17394
+ var log = createLogger({ service: "community-queries" });
17395
+ var CHANNEL_COLUMNS = {
17396
+ id: communityChannel.id,
17397
+ serverId: communityChannel.serverId,
17398
+ categoryId: communityChannel.categoryId,
17399
+ name: communityChannel.name,
17400
+ type: communityChannel.type,
17401
+ topic: communityChannel.topic,
17402
+ position: communityChannel.position,
17403
+ forumTags: communityChannel.forumTags,
17404
+ parentChannelId: communityChannel.parentChannelId,
17405
+ creatorId: communityChannel.creatorId,
17406
+ messageCount: communityChannel.messageCount,
17407
+ archived: communityChannel.archived,
17408
+ parentMessageId: communityChannel.parentMessageId,
17409
+ lastMessageAt: communityChannel.lastMessageAt,
17410
+ createdAt: communityChannel.createdAt
17411
+ };
17412
+ // ../shared/src/db/queries/community/message.ts
17413
+ var log2 = createLogger({ service: "community-queries" });
17414
+ // ../shared/src/db/queries/community/search.ts
17415
+ var FTS_KEYWORDS = new Set(["and", "or", "not", "near"]);
16796
17416
  // ../shared/src/mode.ts
16797
17417
  function isLocalUrl(url2) {
16798
17418
  try {
@@ -16972,7 +17592,7 @@ import { createInterface } from "readline";
16972
17592
  import { execSync } from "child_process";
16973
17593
 
16974
17594
  // lib/logger.ts
16975
- var LEVELS = {
17595
+ var LEVELS2 = {
16976
17596
  debug: 0,
16977
17597
  info: 1,
16978
17598
  warn: 2,
@@ -17018,12 +17638,12 @@ class Logger2 {
17018
17638
  module;
17019
17639
  constructor(opts = {}) {
17020
17640
  const envLevel = process.env.ALOOK_LOG_LEVEL;
17021
- this.level = LEVELS[opts.level ?? envLevel ?? "info"];
17641
+ this.level = LEVELS2[opts.level ?? envLevel ?? "info"];
17022
17642
  this.color = useColor();
17023
17643
  this.module = opts.module;
17024
17644
  }
17025
17645
  setLevel(level) {
17026
- this.level = LEVELS[level];
17646
+ this.level = LEVELS2[level];
17027
17647
  }
17028
17648
  child(module) {
17029
17649
  const child = new Logger2({ level: this.levelName(), module });
@@ -17042,14 +17662,14 @@ class Logger2 {
17042
17662
  this.write("error", msg, args);
17043
17663
  }
17044
17664
  levelName() {
17045
- for (const [name, num] of Object.entries(LEVELS)) {
17665
+ for (const [name, num] of Object.entries(LEVELS2)) {
17046
17666
  if (num === this.level)
17047
17667
  return name;
17048
17668
  }
17049
17669
  return "info";
17050
17670
  }
17051
17671
  write(level, msg, args) {
17052
- if (LEVELS[level] < this.level)
17672
+ if (LEVELS2[level] < this.level)
17053
17673
  return;
17054
17674
  const ts = timestamp();
17055
17675
  const label = LABELS[level];
@@ -17070,7 +17690,7 @@ class Logger2 {
17070
17690
  if (a instanceof Error) {
17071
17691
  dest.write(` ${a.message}
17072
17692
  `);
17073
- if (a.stack && this.level <= LEVELS.debug) {
17693
+ if (a.stack && this.level <= LEVELS2.debug) {
17074
17694
  dest.write(` ${a.stack}
17075
17695
  `);
17076
17696
  }
@@ -17089,10 +17709,10 @@ class Logger2 {
17089
17709
  function createLogger2(opts) {
17090
17710
  return new Logger2(opts);
17091
17711
  }
17092
- var log = createLogger2();
17712
+ var log3 = createLogger2();
17093
17713
 
17094
17714
  // daemon/kill-tree.ts
17095
- var log2 = createLogger2({ module: "kill-tree" });
17715
+ var log4 = createLogger2({ module: "kill-tree" });
17096
17716
  function killGraceMs() {
17097
17717
  return Number(process.env.ALOOK_KILL_GRACE_MS) || 2000;
17098
17718
  }
@@ -17146,7 +17766,7 @@ async function killProcessTree(pid, opts) {
17146
17766
  await new Promise((r) => setTimeout(r, POLL_MS));
17147
17767
  }
17148
17768
  if (isAlive(pid)) {
17149
- log2.warn(`pid=${pid} survived SIGTERM after ${graceMs}ms — escalating to SIGKILL`);
17769
+ log4.warn(`pid=${pid} survived SIGTERM after ${graceMs}ms — escalating to SIGKILL`);
17150
17770
  signalTree(pid, "SIGKILL");
17151
17771
  }
17152
17772
  }
@@ -17155,41 +17775,157 @@ async function killProcessTree(pid, opts) {
17155
17775
  class ClaudeBackend {
17156
17776
  cliPath;
17157
17777
  name = "claude";
17778
+ lifecycle = { kind: "persistent", stdin: "gated", inFlightWake: "queue" };
17779
+ busyDeliveryMode = "gated";
17780
+ supportsStdinNotification = true;
17158
17781
  constructor(cliPath) {
17159
17782
  this.cliPath = cliPath;
17160
17783
  }
17161
- execute(prompt, options) {
17162
- const args = [
17163
- "-p",
17164
- prompt,
17165
- "--output-format",
17166
- "stream-json",
17167
- "--verbose",
17168
- "--permission-mode",
17169
- "bypassPermissions"
17170
- ];
17171
- if (options.model) {
17172
- args.push("--model", options.model);
17173
- }
17174
- if (options.maxTurns) {
17175
- args.push("--max-turns", String(options.maxTurns));
17176
- }
17177
- if (options.resumeSessionId) {
17178
- args.push("--resume", options.resumeSessionId);
17179
- }
17180
- const proc = spawn(this.cliPath, args, {
17181
- cwd: options.cwd,
17182
- stdio: ["pipe", "pipe", "pipe"],
17183
- env: { ...process.env, ...options.env },
17184
- shell: process.platform === "win32",
17185
- windowsHide: true,
17186
- detached: process.platform !== "win32"
17187
- });
17188
- if (!proc.pid) {
17189
- const error51 = `Failed to start ${this.cliPath}: binary not found or not executable. Is 'claude' installed and on PATH?`;
17190
- const failedResult = { status: "failed", output: "", error: error51, durationMs: 0, sessionId: "" };
17191
- const emptyMessages = { [Symbol.asyncIterator]() {
17192
- return { async next() {
17784
+ parseLine(line) {
17785
+ if (!line.trim())
17786
+ return [];
17787
+ let event;
17788
+ try {
17789
+ event = JSON.parse(line);
17790
+ } catch {
17791
+ return [{ kind: "log", content: line, level: "debug" }];
17792
+ }
17793
+ const events = [];
17794
+ const eventType = event.type;
17795
+ switch (eventType) {
17796
+ case "assistant": {
17797
+ const message2 = event.message;
17798
+ if (!message2)
17799
+ break;
17800
+ const content = message2.content;
17801
+ if (!Array.isArray(content))
17802
+ break;
17803
+ for (const block of content) {
17804
+ if (block.type === "text") {
17805
+ events.push({ kind: "text", text: block.text || "" });
17806
+ } else if (block.type === "thinking") {
17807
+ events.push({ kind: "thinking", text: block.text || "" });
17808
+ } else if (block.type === "tool_use") {
17809
+ events.push({ kind: "tool_call", name: block.name || "", input: block.input, callId: block.id });
17810
+ }
17811
+ }
17812
+ break;
17813
+ }
17814
+ case "result": {
17815
+ const result = event.result;
17816
+ const isError = event.is_error;
17817
+ if (isError) {
17818
+ events.push({ kind: "error", message: result || "unknown error" });
17819
+ }
17820
+ const resultSessionId = event.session_id;
17821
+ events.push({ kind: "turn_end", sessionId: resultSessionId || undefined });
17822
+ const usage = event.usage;
17823
+ if (usage || event.total_cost_usd != null) {
17824
+ events.push({
17825
+ kind: "telemetry",
17826
+ name: "token_usage",
17827
+ source: "claude_result_usage",
17828
+ usageKind: "per_turn",
17829
+ attrs: {
17830
+ inputTokens: usage?.input_tokens,
17831
+ outputTokens: usage?.output_tokens,
17832
+ cachedInputTokens: usage?.cache_read_input_tokens,
17833
+ cacheCreationInputTokens: usage?.cache_creation_input_tokens,
17834
+ totalCostUsd: event.total_cost_usd,
17835
+ durationMs: event.duration_ms,
17836
+ durationApiMs: event.duration_api_ms,
17837
+ numTurns: event.num_turns,
17838
+ resultSubtype: event.subtype,
17839
+ resultIsError: event.is_error,
17840
+ serviceTier: usage?.service_tier
17841
+ }
17842
+ });
17843
+ }
17844
+ break;
17845
+ }
17846
+ case "tool_result": {
17847
+ const toolUseId = event.tool_use_id;
17848
+ const content = event.content;
17849
+ events.push({ kind: "tool_output", callId: toolUseId, output: content });
17850
+ break;
17851
+ }
17852
+ case "system": {
17853
+ const subtype = event.subtype;
17854
+ if (subtype === "init") {
17855
+ const sid = event.session_id;
17856
+ events.push({ kind: "session_init", sessionId: sid || "" });
17857
+ } else if (subtype === "context_pruning" || subtype === "compaction") {
17858
+ events.push({ kind: "compaction_started" });
17859
+ } else if (subtype === "compaction_finished" || subtype === "context_pruning_finished") {
17860
+ events.push({ kind: "compaction_finished" });
17861
+ } else if (subtype === "status" || subtype === "stream_event") {
17862
+ events.push({
17863
+ kind: "internal_progress",
17864
+ source: "claude_system",
17865
+ itemType: subtype,
17866
+ payloadBytes: line.length
17867
+ });
17868
+ }
17869
+ break;
17870
+ }
17871
+ case "control_request": {
17872
+ const requestId = event.request_id;
17873
+ if (requestId) {
17874
+ events.push({ kind: "permission_request", requestId, payload: event.payload });
17875
+ }
17876
+ break;
17877
+ }
17878
+ default: {
17879
+ events.push({ kind: "log", content: line, level: "debug" });
17880
+ }
17881
+ }
17882
+ return events;
17883
+ }
17884
+ encodeStdinMessage(text2, mode, opts) {
17885
+ const msg = {
17886
+ type: "user",
17887
+ message: {
17888
+ role: "user",
17889
+ content: [{ type: "text", text: text2 }]
17890
+ }
17891
+ };
17892
+ if (opts?.sessionId) {
17893
+ msg.session_id = opts.sessionId;
17894
+ }
17895
+ return JSON.stringify(msg);
17896
+ }
17897
+ execute(prompt, options) {
17898
+ const useStdinPrompt = options.steeringEnabled === true;
17899
+ const args = [];
17900
+ if (!useStdinPrompt) {
17901
+ args.push("-p", prompt);
17902
+ }
17903
+ args.push("--output-format", "stream-json", "--verbose", "--permission-mode", "bypassPermissions");
17904
+ if (useStdinPrompt) {
17905
+ args.push("--input-format", "stream-json");
17906
+ }
17907
+ if (options.model) {
17908
+ args.push("--model", options.model);
17909
+ }
17910
+ if (options.maxTurns) {
17911
+ args.push("--max-turns", String(options.maxTurns));
17912
+ }
17913
+ if (options.resumeSessionId) {
17914
+ args.push("--resume", options.resumeSessionId);
17915
+ }
17916
+ const proc = spawn(this.cliPath, args, {
17917
+ cwd: options.cwd,
17918
+ stdio: ["pipe", "pipe", "pipe"],
17919
+ env: { ...process.env, ...options.env },
17920
+ shell: process.platform === "win32",
17921
+ windowsHide: true,
17922
+ detached: process.platform !== "win32"
17923
+ });
17924
+ if (!proc.pid) {
17925
+ const error51 = `Failed to start ${this.cliPath}: binary not found or not executable. Is 'claude' installed and on PATH?`;
17926
+ const failedResult = { status: "failed", output: "", error: error51, durationMs: 0, sessionId: "" };
17927
+ const emptyMessages = { [Symbol.asyncIterator]() {
17928
+ return { async next() {
17193
17929
  return { value: undefined, done: true };
17194
17930
  } };
17195
17931
  } };
@@ -17224,15 +17960,58 @@ class ClaudeBackend {
17224
17960
  r();
17225
17961
  }
17226
17962
  };
17963
+ const parsedEventQueue = [];
17964
+ let parsedEventResolve = null;
17965
+ let parsedEventDone = false;
17966
+ const pushParsedEvent = (evt) => {
17967
+ parsedEventQueue.push(evt);
17968
+ if (parsedEventResolve) {
17969
+ const r = parsedEventResolve;
17970
+ parsedEventResolve = null;
17971
+ r();
17972
+ }
17973
+ };
17974
+ const stdinWriteQueue = [];
17975
+ let stdinDraining = false;
17976
+ const enqueueStdinWrite = (data) => {
17977
+ stdinWriteQueue.push(data);
17978
+ drainStdinQueue();
17979
+ };
17980
+ const drainStdinQueue = () => {
17981
+ if (stdinDraining)
17982
+ return;
17983
+ stdinDraining = true;
17984
+ while (stdinWriteQueue.length > 0) {
17985
+ const line = stdinWriteQueue.shift();
17986
+ try {
17987
+ proc.stdin?.write(line + `
17988
+ `);
17989
+ } catch {}
17990
+ }
17991
+ stdinDraining = false;
17992
+ };
17227
17993
  const resultPromise = new Promise((resolve) => {
17228
17994
  const stderrChunks = [];
17229
17995
  proc.stderr?.on("data", (chunk) => {
17230
17996
  stderrChunks.push(chunk.toString());
17231
17997
  });
17232
17998
  const rl = createInterface({ input: proc.stdout });
17999
+ if (useStdinPrompt) {
18000
+ const initialMsg = JSON.stringify({
18001
+ type: "user",
18002
+ message: {
18003
+ role: "user",
18004
+ content: [{ type: "text", text: prompt }]
18005
+ }
18006
+ });
18007
+ enqueueStdinWrite(initialMsg);
18008
+ }
17233
18009
  rl.on("line", (line) => {
17234
18010
  if (!line.trim())
17235
18011
  return;
18012
+ const parsed = this.parseLine(line);
18013
+ for (const pe of parsed)
18014
+ pushParsedEvent(pe);
17236
18015
  let event;
17237
18016
  try {
17238
18017
  event = JSON.parse(line);
@@ -17278,6 +18057,13 @@ class ClaudeBackend {
17278
18057
  resultStatus = "failed";
17279
18058
  lastError = result || "unknown error";
17280
18059
  }
18060
+ if (useStdinPrompt) {
18061
+ setTimeout(() => {
18062
+ try {
18063
+ proc.stdin?.end();
18064
+ } catch {}
18065
+ }, 100);
18066
+ }
17281
18067
  break;
17282
18068
  }
17283
18069
  case "tool_result": {
@@ -17302,7 +18088,7 @@ class ClaudeBackend {
17302
18088
  break;
17303
18089
  }
17304
18090
  case "control_request": {
17305
- handleControlRequest(proc, event);
18091
+ handleControlRequest(proc, event, enqueueStdinWrite);
17306
18092
  break;
17307
18093
  }
17308
18094
  default: {
@@ -17319,11 +18105,17 @@ class ClaudeBackend {
17319
18105
  lastError = `spawn error: ${err.message}`;
17320
18106
  resolveSessionId(lastSessionId);
17321
18107
  messageDone = true;
18108
+ parsedEventDone = true;
17322
18109
  if (messageResolve) {
17323
18110
  const r = messageResolve;
17324
18111
  messageResolve = null;
17325
18112
  r();
17326
18113
  }
18114
+ if (parsedEventResolve) {
18115
+ const r = parsedEventResolve;
18116
+ parsedEventResolve = null;
18117
+ r();
18118
+ }
17327
18119
  resolve({
17328
18120
  status: "failed",
17329
18121
  output: "",
@@ -17346,11 +18138,17 @@ class ClaudeBackend {
17346
18138
  }
17347
18139
  resolveSessionId(lastSessionId);
17348
18140
  messageDone = true;
18141
+ parsedEventDone = true;
17349
18142
  if (messageResolve) {
17350
18143
  const r = messageResolve;
17351
18144
  messageResolve = null;
17352
18145
  r();
17353
18146
  }
18147
+ if (parsedEventResolve) {
18148
+ const r = parsedEventResolve;
18149
+ parsedEventResolve = null;
18150
+ r();
18151
+ }
17354
18152
  resolve({
17355
18153
  status: resultStatus,
17356
18154
  output: lastOutput,
@@ -17377,10 +18175,47 @@ class ClaudeBackend {
17377
18175
  };
17378
18176
  }
17379
18177
  };
17380
- return { pid: proc.pid, messages, sessionId: sessionIdPromise, result: resultPromise };
18178
+ const parsedEvents = {
18179
+ [Symbol.asyncIterator]() {
18180
+ return {
18181
+ async next() {
18182
+ while (parsedEventQueue.length === 0 && !parsedEventDone) {
18183
+ await new Promise((resolve) => {
18184
+ parsedEventResolve = resolve;
18185
+ });
18186
+ }
18187
+ if (parsedEventQueue.length > 0) {
18188
+ return { value: parsedEventQueue.shift(), done: false };
18189
+ }
18190
+ return { value: undefined, done: true };
18191
+ }
18192
+ };
18193
+ }
18194
+ };
18195
+ const send = (text2, mode) => {
18196
+ const encoded = this.encodeStdinMessage(text2, mode, { sessionId: lastSessionId || undefined });
18197
+ if (!encoded)
18198
+ return { ok: false, reason: "encoding failed" };
18199
+ if (!proc.stdin || proc.stdin.destroyed)
18200
+ return { ok: false, reason: "stdin closed" };
18201
+ enqueueStdinWrite(encoded);
18202
+ return { ok: true };
18203
+ };
18204
+ const descriptor = {
18205
+ lifecycle: this.lifecycle,
18206
+ busyDeliveryMode: this.busyDeliveryMode,
18207
+ supportsStdinNotification: this.supportsStdinNotification
18208
+ };
18209
+ const closeStdin = () => {
18210
+ try {
18211
+ if (proc.stdin && !proc.stdin.destroyed)
18212
+ proc.stdin.end();
18213
+ } catch {}
18214
+ };
18215
+ return { pid: proc.pid, messages, parsedEvents, sessionId: sessionIdPromise, result: resultPromise, send, closeStdin, descriptor };
17381
18216
  }
17382
18217
  }
17383
- function handleControlRequest(proc, event) {
18218
+ function handleControlRequest(proc, event, enqueueStdinWrite) {
17384
18219
  const requestId = event.request_id;
17385
18220
  if (!requestId)
17386
18221
  return;
@@ -17409,10 +18244,14 @@ function handleControlRequest(proc, event) {
17409
18244
  }
17410
18245
  }
17411
18246
  });
17412
- try {
17413
- proc.stdin?.write(approval + `
18247
+ if (enqueueStdinWrite) {
18248
+ enqueueStdinWrite(approval);
18249
+ } else {
18250
+ try {
18251
+ proc.stdin?.write(approval + `
17414
18252
  `);
17415
- } catch {}
18253
+ } catch {}
18254
+ }
17416
18255
  }
17417
18256
 
17418
18257
  // daemon/agent/codex.ts
@@ -17444,9 +18283,196 @@ function extractThreadID(response) {
17444
18283
  class CodexBackend {
17445
18284
  cliPath;
17446
18285
  name = "codex";
18286
+ lifecycle = { kind: "persistent", stdin: "direct", inFlightWake: "steer" };
18287
+ busyDeliveryMode = "direct";
18288
+ supportsStdinNotification = true;
18289
+ _rpcId = 0;
17447
18290
  constructor(cliPath) {
17448
18291
  this.cliPath = cliPath;
17449
18292
  }
18293
+ parseLine(line) {
18294
+ if (!line.trim())
18295
+ return [];
18296
+ let msg;
18297
+ try {
18298
+ msg = JSON.parse(line);
18299
+ } catch {
18300
+ return [{ kind: "log", content: line, level: "debug" }];
18301
+ }
18302
+ if (msg.id !== undefined && !msg.method)
18303
+ return [];
18304
+ if (msg.id !== undefined && msg.method)
18305
+ return [];
18306
+ if (!msg.method)
18307
+ return [{ kind: "log", content: line, level: "debug" }];
18308
+ const method = msg.method;
18309
+ const params = msg.params || {};
18310
+ if (method === "codex/event") {
18311
+ return this.parseLegacyEvent(params);
18312
+ }
18313
+ const events = [];
18314
+ switch (method) {
18315
+ case "turn/started":
18316
+ break;
18317
+ case "turn/completed": {
18318
+ const turn = params.turn;
18319
+ const status = turn?.status || params.status || "";
18320
+ if (status === "error" || status === "failed") {
18321
+ const turnErr = turn?.error;
18322
+ events.push({ kind: "error", message: turnErr?.message || "codex turn failed" });
18323
+ }
18324
+ events.push({ kind: "turn_end" });
18325
+ break;
18326
+ }
18327
+ case "error": {
18328
+ const errObj = params.error;
18329
+ const errMsg = errObj?.message || params.message || "";
18330
+ const willRetry = params.willRetry === true;
18331
+ if (errMsg && !willRetry) {
18332
+ events.push({ kind: "error", message: errMsg });
18333
+ }
18334
+ break;
18335
+ }
18336
+ case "thread/status/changed": {
18337
+ const statusObj = params.status;
18338
+ const statusType = typeof statusObj === "object" && statusObj !== null ? statusObj.type || "" : statusObj || "";
18339
+ if (statusType === "idle") {
18340
+ events.push({ kind: "turn_end" });
18341
+ }
18342
+ break;
18343
+ }
18344
+ case "item/started": {
18345
+ const item = params.item;
18346
+ if (!item)
18347
+ break;
18348
+ const itemType = item.type;
18349
+ if (itemType === "commandExecution" || itemType === "fileChange") {
18350
+ events.push({
18351
+ kind: "tool_call",
18352
+ name: itemType === "commandExecution" ? "exec_command" : "patch_apply",
18353
+ callId: item.id,
18354
+ input: item
18355
+ });
18356
+ } else if (itemType === "mcpToolCall") {
18357
+ events.push({
18358
+ kind: "tool_call",
18359
+ name: `mcp_${item.name || "tool"}`,
18360
+ callId: item.id,
18361
+ input: item
18362
+ });
18363
+ } else if (itemType === "webSearch") {
18364
+ events.push({
18365
+ kind: "tool_call",
18366
+ name: "web_search",
18367
+ callId: item.id,
18368
+ input: item
18369
+ });
18370
+ } else if (itemType === "collabAgentToolCall") {
18371
+ events.push({
18372
+ kind: "tool_call",
18373
+ name: "collab_agent",
18374
+ callId: item.id,
18375
+ input: item
18376
+ });
18377
+ } else if (itemType === "contextCompaction") {
18378
+ events.push({ kind: "compaction_started" });
18379
+ }
18380
+ break;
18381
+ }
18382
+ case "item/completed": {
18383
+ const item = params.item;
18384
+ if (!item)
18385
+ break;
18386
+ const itemType = item.type;
18387
+ if (itemType === "commandExecution") {
18388
+ events.push({ kind: "tool_output", callId: item.id, output: item.aggregatedOutput || "" });
18389
+ } else if (itemType === "fileChange") {
18390
+ events.push({ kind: "tool_output", callId: item.id, output: "" });
18391
+ } else if (itemType === "mcpToolCall") {
18392
+ events.push({ kind: "tool_output", callId: item.id, name: `mcp_${item.name || "tool"}`, output: item.output || "" });
18393
+ } else if (itemType === "agentMessage") {
18394
+ const flatText = item.text;
18395
+ if (flatText) {
18396
+ events.push({ kind: "text", text: flatText });
18397
+ } else {
18398
+ const content = item.content;
18399
+ if (Array.isArray(content)) {
18400
+ for (const block of content) {
18401
+ if ((block.type === "output_text" || block.type === "text") && block.text) {
18402
+ events.push({ kind: "text", text: block.text });
18403
+ }
18404
+ }
18405
+ }
18406
+ }
18407
+ } else if (itemType === "reasoning") {
18408
+ events.push({ kind: "thinking", text: item.text || "" });
18409
+ } else if (itemType === "contextCompaction") {
18410
+ events.push({ kind: "compaction_finished" });
18411
+ }
18412
+ break;
18413
+ }
18414
+ case "item/agentMessage/delta": {
18415
+ const delta = params.delta;
18416
+ if (delta)
18417
+ events.push({ kind: "text", text: delta });
18418
+ break;
18419
+ }
18420
+ default:
18421
+ events.push({ kind: "log", content: JSON.stringify(msg), level: "debug" });
18422
+ }
18423
+ return events;
18424
+ }
18425
+ parseLegacyEvent(params) {
18426
+ const eventType = params.type;
18427
+ if (!eventType)
18428
+ return [];
18429
+ const events = [];
18430
+ switch (eventType) {
18431
+ case "agent_message": {
18432
+ const text2 = params.text || params.message || "";
18433
+ if (text2)
18434
+ events.push({ kind: "text", text: text2 });
18435
+ break;
18436
+ }
18437
+ case "exec_command_begin":
18438
+ events.push({ kind: "tool_call", name: "exec_command", callId: params.id, input: params });
18439
+ break;
18440
+ case "exec_command_end":
18441
+ events.push({ kind: "tool_output", callId: params.id, output: params.output || "" });
18442
+ break;
18443
+ case "patch_apply_begin":
18444
+ events.push({ kind: "tool_call", name: "patch_apply", callId: params.id, input: params });
18445
+ break;
18446
+ case "patch_apply_end":
18447
+ events.push({ kind: "tool_output", callId: params.id, output: params.output || "" });
18448
+ break;
18449
+ case "task_complete":
18450
+ events.push({ kind: "turn_end" });
18451
+ break;
18452
+ case "turn_aborted":
18453
+ events.push({ kind: "turn_end" });
18454
+ break;
18455
+ default:
18456
+ break;
18457
+ }
18458
+ return events;
18459
+ }
18460
+ encodeStdinMessage(text2, mode, opts) {
18461
+ const threadId = opts?.threadId;
18462
+ if (!threadId)
18463
+ return null;
18464
+ const id = opts?.requestId ?? ++this._rpcId;
18465
+ const method = mode === "busy" ? "turn/steer" : "turn/start";
18466
+ return JSON.stringify({
18467
+ jsonrpc: "2.0",
18468
+ id,
18469
+ method,
18470
+ params: {
18471
+ threadId,
18472
+ input: [{ type: "text", text: text2 }]
18473
+ }
18474
+ });
18475
+ }
17450
18476
  execute(prompt, options) {
17451
18477
  const proc = spawn2(this.cliPath, ["app-server", "--listen", "stdio://", "--config", "sandbox_mode=danger-full-access"], {
17452
18478
  cwd: options.cwd,
@@ -17495,6 +18521,9 @@ class CodexBackend {
17495
18521
  const messageQueue = [];
17496
18522
  let messageResolve = null;
17497
18523
  let messageDone = false;
18524
+ const parsedEventQueue = [];
18525
+ let parsedEventResolve = null;
18526
+ let parsedEventDone = false;
17498
18527
  const pushMessage = (msg) => {
17499
18528
  messageQueue.push(msg);
17500
18529
  if (messageResolve) {
@@ -17503,6 +18532,14 @@ class CodexBackend {
17503
18532
  r();
17504
18533
  }
17505
18534
  };
18535
+ const pushParsedEvent = (evt) => {
18536
+ parsedEventQueue.push(evt);
18537
+ if (parsedEventResolve) {
18538
+ const r = parsedEventResolve;
18539
+ parsedEventResolve = null;
18540
+ r();
18541
+ }
18542
+ };
17506
18543
  const writeStdin = (data) => {
17507
18544
  try {
17508
18545
  proc.stdin?.write(data + `
@@ -17535,17 +18572,20 @@ class CodexBackend {
17535
18572
  if (msg && !turnError)
17536
18573
  turnError = msg;
17537
18574
  };
18575
+ const steeringKeepAlive = options.steeringEnabled === true;
17538
18576
  const triggerTurnDone = (aborted2) => {
17539
18577
  if (turnDoneTriggered)
17540
18578
  return;
17541
18579
  turnDoneTriggered = true;
17542
18580
  resultStatus = aborted2 ? "aborted" : "completed";
17543
- try {
17544
- proc.stdin?.end();
17545
- } catch {}
17546
- try {
17547
- proc.kill("SIGTERM");
17548
- } catch {}
18581
+ if (!steeringKeepAlive) {
18582
+ try {
18583
+ proc.stdin?.end();
18584
+ } catch {}
18585
+ try {
18586
+ proc.kill("SIGTERM");
18587
+ } catch {}
18588
+ }
17549
18589
  };
17550
18590
  const handleServerRequest = (msg) => {
17551
18591
  const method = msg.method;
@@ -17766,6 +18806,9 @@ class CodexBackend {
17766
18806
  rl.on("line", (line) => {
17767
18807
  if (!line.trim())
17768
18808
  return;
18809
+ const parsed = this.parseLine(line);
18810
+ for (const pe of parsed)
18811
+ pushParsedEvent(pe);
17769
18812
  let msg;
17770
18813
  try {
17771
18814
  msg = JSON.parse(line);
@@ -17852,11 +18895,17 @@ class CodexBackend {
17852
18895
  closeAllPending("spawn error");
17853
18896
  resolveSessionId(sessionId);
17854
18897
  messageDone = true;
18898
+ parsedEventDone = true;
17855
18899
  if (messageResolve) {
17856
18900
  const r = messageResolve;
17857
18901
  messageResolve = null;
17858
18902
  r();
17859
18903
  }
18904
+ if (parsedEventResolve) {
18905
+ const r = parsedEventResolve;
18906
+ parsedEventResolve = null;
18907
+ r();
18908
+ }
17860
18909
  resolve({
17861
18910
  status: "failed",
17862
18911
  output: "",
@@ -17886,11 +18935,17 @@ class CodexBackend {
17886
18935
  }
17887
18936
  resolveSessionId(sessionId);
17888
18937
  messageDone = true;
18938
+ parsedEventDone = true;
17889
18939
  if (messageResolve) {
17890
18940
  const r = messageResolve;
17891
18941
  messageResolve = null;
17892
18942
  r();
17893
18943
  }
18944
+ if (parsedEventResolve) {
18945
+ const r = parsedEventResolve;
18946
+ parsedEventResolve = null;
18947
+ r();
18948
+ }
17894
18949
  resolve({
17895
18950
  status: resultStatus,
17896
18951
  output: lastOutput,
@@ -17917,7 +18972,44 @@ class CodexBackend {
17917
18972
  };
17918
18973
  }
17919
18974
  };
17920
- return { pid: proc.pid, messages, sessionId: sessionIdPromise, result: resultPromise };
18975
+ const parsedEvents = {
18976
+ [Symbol.asyncIterator]() {
18977
+ return {
18978
+ async next() {
18979
+ while (parsedEventQueue.length === 0 && !parsedEventDone) {
18980
+ await new Promise((resolve) => {
18981
+ parsedEventResolve = resolve;
18982
+ });
18983
+ }
18984
+ if (parsedEventQueue.length > 0) {
18985
+ return { value: parsedEventQueue.shift(), done: false };
18986
+ }
18987
+ return { value: undefined, done: true };
18988
+ }
18989
+ };
18990
+ }
18991
+ };
18992
+ const send = (text2, mode) => {
18993
+ if (!proc.stdin || proc.stdin.destroyed)
18994
+ return { ok: false, reason: "stdin closed" };
18995
+ const encoded = this.encodeStdinMessage(text2, mode, { threadId: sessionId, requestId: ++requestId });
18996
+ if (!encoded)
18997
+ return { ok: false, reason: "encoding failed (no threadId)" };
18998
+ writeStdin(encoded);
18999
+ return { ok: true };
19000
+ };
19001
+ const descriptor = {
19002
+ lifecycle: this.lifecycle,
19003
+ busyDeliveryMode: this.busyDeliveryMode,
19004
+ supportsStdinNotification: this.supportsStdinNotification
19005
+ };
19006
+ const closeStdin = () => {
19007
+ try {
19008
+ if (proc.stdin && !proc.stdin.destroyed)
19009
+ proc.stdin.end();
19010
+ } catch {}
19011
+ };
19012
+ return { pid: proc.pid, messages, parsedEvents, sessionId: sessionIdPromise, result: resultPromise, send, closeStdin, descriptor };
17921
19013
  }
17922
19014
  }
17923
19015
 
@@ -17927,9 +19019,102 @@ import { createInterface as createInterface3 } from "readline";
17927
19019
  class OpenCodeBackend {
17928
19020
  cliPath;
17929
19021
  name = "opencode";
19022
+ lifecycle = { kind: "per_turn", inFlightWake: "coalesce_into_pending" };
19023
+ busyDeliveryMode = "none";
19024
+ supportsStdinNotification = false;
17930
19025
  constructor(cliPath) {
17931
19026
  this.cliPath = cliPath;
17932
19027
  }
19028
+ parseLine(line) {
19029
+ if (!line.trim())
19030
+ return [];
19031
+ let event;
19032
+ try {
19033
+ event = JSON.parse(line);
19034
+ } catch {
19035
+ return [{ kind: "log", content: line, level: "debug" }];
19036
+ }
19037
+ const events = [];
19038
+ const eventType = event.type;
19039
+ const part = event.part;
19040
+ const eventSessionId = event.sessionID || event.session_id;
19041
+ switch (eventType) {
19042
+ case "session": {
19043
+ const sessionId = event.session_id;
19044
+ if (sessionId)
19045
+ events.push({ kind: "session_init", sessionId });
19046
+ break;
19047
+ }
19048
+ case "message": {
19049
+ const role = event.role;
19050
+ const content = event.content;
19051
+ if (role === "assistant" && content) {
19052
+ events.push({ kind: "text", text: content });
19053
+ }
19054
+ break;
19055
+ }
19056
+ case "text": {
19057
+ const text2 = part?.text || event.content || "";
19058
+ if (text2)
19059
+ events.push({ kind: "text", text: text2 });
19060
+ break;
19061
+ }
19062
+ case "thinking": {
19063
+ const content = part?.thinking || event.content || "";
19064
+ events.push({ kind: "thinking", text: content });
19065
+ break;
19066
+ }
19067
+ case "tool_call":
19068
+ events.push({
19069
+ kind: "tool_call",
19070
+ name: event.name || part?.name || "",
19071
+ callId: event.call_id || part?.id || "",
19072
+ input: event.input || part?.input
19073
+ });
19074
+ break;
19075
+ case "tool_result":
19076
+ events.push({
19077
+ kind: "tool_output",
19078
+ callId: event.call_id || part?.id || "",
19079
+ output: event.output || part?.output || ""
19080
+ });
19081
+ break;
19082
+ case "error": {
19083
+ const content = event.message || event.content || part?.error || "";
19084
+ events.push({ kind: "error", message: content });
19085
+ events.push({ kind: "turn_end" });
19086
+ break;
19087
+ }
19088
+ case "step_start":
19089
+ break;
19090
+ case "step_finish": {
19091
+ const reason = part?.reason;
19092
+ if (reason === "stop" || reason === "end_turn") {
19093
+ events.push({ kind: "turn_end" });
19094
+ }
19095
+ break;
19096
+ }
19097
+ case "done":
19098
+ case "complete": {
19099
+ const status = event.status;
19100
+ if (status === "error" || status === "failed") {
19101
+ const output = event.output;
19102
+ events.push({ kind: "error", message: output || "task failed" });
19103
+ }
19104
+ events.push({ kind: "turn_end" });
19105
+ break;
19106
+ }
19107
+ default:
19108
+ events.push({ kind: "log", content: line, level: "debug" });
19109
+ }
19110
+ if (eventSessionId && events.length > 0 && events[0].kind !== "session_init") {
19111
+ events.unshift({ kind: "session_init", sessionId: eventSessionId });
19112
+ }
19113
+ return events;
19114
+ }
19115
+ encodeStdinMessage() {
19116
+ return null;
19117
+ }
17933
19118
  execute(prompt, options) {
17934
19119
  const args = ["run", "--format", "json", "--dir", options.cwd];
17935
19120
  if (options.model) {
@@ -17987,6 +19172,9 @@ class OpenCodeBackend {
17987
19172
  const messageQueue = [];
17988
19173
  let messageResolve = null;
17989
19174
  let messageDone = false;
19175
+ const parsedEventQueue = [];
19176
+ let parsedEventResolve = null;
19177
+ let parsedEventDone = false;
17990
19178
  const pushMessage = (msg) => {
17991
19179
  messageQueue.push(msg);
17992
19180
  if (messageResolve) {
@@ -17995,6 +19183,14 @@ class OpenCodeBackend {
17995
19183
  r();
17996
19184
  }
17997
19185
  };
19186
+ const pushParsedEvent = (evt) => {
19187
+ parsedEventQueue.push(evt);
19188
+ if (parsedEventResolve) {
19189
+ const r = parsedEventResolve;
19190
+ parsedEventResolve = null;
19191
+ r();
19192
+ }
19193
+ };
17998
19194
  const resultPromise = new Promise((resolve) => {
17999
19195
  const stderrChunks = [];
18000
19196
  proc.stderr?.on("data", (chunk) => {
@@ -18004,6 +19200,9 @@ class OpenCodeBackend {
18004
19200
  rl.on("line", (line) => {
18005
19201
  if (!line.trim())
18006
19202
  return;
19203
+ const parsed = this.parseLine(line);
19204
+ for (const pe of parsed)
19205
+ pushParsedEvent(pe);
18007
19206
  let event;
18008
19207
  try {
18009
19208
  event = JSON.parse(line);
@@ -18115,11 +19314,17 @@ class OpenCodeBackend {
18115
19314
  lastError = `spawn error: ${err.message}`;
18116
19315
  resolveSessionId(lastSessionId);
18117
19316
  messageDone = true;
19317
+ parsedEventDone = true;
18118
19318
  if (messageResolve) {
18119
19319
  const r = messageResolve;
18120
19320
  messageResolve = null;
18121
19321
  r();
18122
19322
  }
19323
+ if (parsedEventResolve) {
19324
+ const r = parsedEventResolve;
19325
+ parsedEventResolve = null;
19326
+ r();
19327
+ }
18123
19328
  resolve({
18124
19329
  status: "failed",
18125
19330
  output: "",
@@ -18144,11 +19349,17 @@ class OpenCodeBackend {
18144
19349
  }
18145
19350
  resolveSessionId(lastSessionId);
18146
19351
  messageDone = true;
19352
+ parsedEventDone = true;
18147
19353
  if (messageResolve) {
18148
19354
  const r = messageResolve;
18149
19355
  messageResolve = null;
18150
19356
  r();
18151
19357
  }
19358
+ if (parsedEventResolve) {
19359
+ const r = parsedEventResolve;
19360
+ parsedEventResolve = null;
19361
+ r();
19362
+ }
18152
19363
  resolve({
18153
19364
  status: resultStatus,
18154
19365
  output: lastOutput,
@@ -18175,7 +19386,32 @@ class OpenCodeBackend {
18175
19386
  };
18176
19387
  }
18177
19388
  };
18178
- return { pid: proc.pid, messages, sessionId: sessionIdPromise, result: resultPromise };
19389
+ const parsedEvents = {
19390
+ [Symbol.asyncIterator]() {
19391
+ return {
19392
+ async next() {
19393
+ while (parsedEventQueue.length === 0 && !parsedEventDone) {
19394
+ await new Promise((resolve) => {
19395
+ parsedEventResolve = resolve;
19396
+ });
19397
+ }
19398
+ if (parsedEventQueue.length > 0) {
19399
+ return { value: parsedEventQueue.shift(), done: false };
19400
+ }
19401
+ return { value: undefined, done: true };
19402
+ }
19403
+ };
19404
+ }
19405
+ };
19406
+ const send = () => {
19407
+ return { ok: false, reason: "unsupported" };
19408
+ };
19409
+ const descriptor = {
19410
+ lifecycle: this.lifecycle,
19411
+ busyDeliveryMode: this.busyDeliveryMode,
19412
+ supportsStdinNotification: this.supportsStdinNotification
19413
+ };
19414
+ return { pid: proc.pid, messages, parsedEvents, sessionId: sessionIdPromise, result: resultPromise, send, descriptor };
18179
19415
  }
18180
19416
  }
18181
19417
 
@@ -18658,7 +19894,7 @@ function releaseLock(lockPath) {
18658
19894
  }
18659
19895
 
18660
19896
  // daemon/execenv/timeline.ts
18661
- var log3 = createLogger2({ module: "timeline" });
19897
+ var log5 = createLogger2({ module: "timeline" });
18662
19898
  function readJsonl(filePath) {
18663
19899
  let content;
18664
19900
  try {
@@ -18727,7 +19963,7 @@ async function initEntryAsync(timelineDir, entry) {
18727
19963
  acquired = acquireLock(lockPath);
18728
19964
  }
18729
19965
  if (!acquired) {
18730
- log3.debug(`Timeline initEntry: could not acquire lock for ${filename}`);
19966
+ log5.debug(`Timeline initEntry: could not acquire lock for ${filename}`);
18731
19967
  return;
18732
19968
  }
18733
19969
  try {
@@ -18737,7 +19973,7 @@ async function initEntryAsync(timelineDir, entry) {
18737
19973
  releaseLock(lockPath);
18738
19974
  }
18739
19975
  } catch (err) {
18740
- log3.debug("Timeline initEntry failed", err);
19976
+ log5.debug("Timeline initEntry failed", err);
18741
19977
  }
18742
19978
  }
18743
19979
  function updateEntry(timelineDir, taskId, updater) {
@@ -18747,7 +19983,7 @@ function updateEntry(timelineDir, taskId, updater) {
18747
19983
  try {
18748
19984
  const acquired = acquireLock(lockPath);
18749
19985
  if (!acquired) {
18750
- log3.debug(`Timeline updateEntry: lock held for ${filename}, skipping`);
19986
+ log5.debug(`Timeline updateEntry: lock held for ${filename}, skipping`);
18751
19987
  continue;
18752
19988
  }
18753
19989
  try {
@@ -18780,10 +20016,10 @@ function updateEntry(timelineDir, taskId, updater) {
18780
20016
  releaseLock(lockPath);
18781
20017
  }
18782
20018
  } catch (err) {
18783
- log3.debug(`Timeline updateEntry failed for ${filename}`, err);
20019
+ log5.debug(`Timeline updateEntry failed for ${filename}`, err);
18784
20020
  }
18785
20021
  }
18786
- log3.debug(`Timeline updateEntry: task_id ${taskId} not found in last 7 days`);
20022
+ log5.debug(`Timeline updateEntry: task_id ${taskId} not found in last 7 days`);
18787
20023
  }
18788
20024
  function createTimelineEntry(taskId, prompt, type, sessionId, pid, provider, contextKey, detailedLog) {
18789
20025
  return {
@@ -18818,7 +20054,7 @@ function findResumableSessionByContextKey(timelineDir, contextKey, provider) {
18818
20054
  // daemon/execenv/steering.ts
18819
20055
  import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3, readFileSync as readFileSync3, unlinkSync as unlinkSync2, readdirSync, statSync as statSync2 } from "fs";
18820
20056
  import { join as join5 } from "path";
18821
- var log4 = createLogger2({ module: "steering" });
20057
+ var log6 = createLogger2({ module: "steering" });
18822
20058
  var INTENT_DIR_NAME = ".kill_intents";
18823
20059
  var INTENT_STALE_MS = 10 * 60 * 1000;
18824
20060
  function intentFilePath(baseDir, taskId) {
@@ -18840,6 +20076,636 @@ function clearKillIntent(baseDir, taskId) {
18840
20076
  } catch {}
18841
20077
  }
18842
20078
 
20079
+ // daemon/steering/mailbox.ts
20080
+ import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, readFileSync as readFileSync4, renameSync as renameSync2, readdirSync as readdirSync2, unlinkSync as unlinkSync3, rmSync, existsSync as existsSync2, watch } from "fs";
20081
+ import { join as join6 } from "path";
20082
+ var log7 = createLogger2({ module: "mailbox" });
20083
+ function inboxDir(baseDir, contextKey) {
20084
+ const safeKey = contextKey.replace(/[^a-zA-Z0-9_:-]/g, "_");
20085
+ return join6(baseDir, ".steering", safeKey, "inbox");
20086
+ }
20087
+ function ackDir(baseDir, contextKey) {
20088
+ const safeKey = contextKey.replace(/[^a-zA-Z0-9_:-]/g, "_");
20089
+ return join6(baseDir, ".steering", safeKey, "ack");
20090
+ }
20091
+ function steeringDir(baseDir, contextKey) {
20092
+ const safeKey = contextKey.replace(/[^a-zA-Z0-9_:-]/g, "_");
20093
+ return join6(baseDir, ".steering", safeKey);
20094
+ }
20095
+ function readSteerMessage(filePath) {
20096
+ try {
20097
+ const content = readFileSync4(filePath, "utf-8");
20098
+ return JSON.parse(content);
20099
+ } catch {
20100
+ return null;
20101
+ }
20102
+ }
20103
+ function writeAck(baseDir, contextKey, seq) {
20104
+ const ack = ackDir(baseDir, contextKey);
20105
+ mkdirSync4(ack, { recursive: true });
20106
+ writeFileSync4(join6(ack, `${seq}.ack`), "");
20107
+ }
20108
+ function writeNack(baseDir, contextKey, seq, reason) {
20109
+ const ack = ackDir(baseDir, contextKey);
20110
+ mkdirSync4(ack, { recursive: true });
20111
+ writeFileSync4(join6(ack, `${seq}.nack`), JSON.stringify({ reason }));
20112
+ }
20113
+ function cleanupInboxFile(baseDir, contextKey, seq) {
20114
+ try {
20115
+ unlinkSync3(join6(inboxDir(baseDir, contextKey), `${seq}.json`));
20116
+ } catch {}
20117
+ }
20118
+ function cleanupSteeringDir(baseDir, contextKey) {
20119
+ const dir = steeringDir(baseDir, contextKey);
20120
+ try {
20121
+ rmSync(dir, { recursive: true, force: true });
20122
+ } catch {}
20123
+ }
20124
+ function watchInbox(baseDir, contextKey, onMessage) {
20125
+ const inbox = inboxDir(baseDir, contextKey);
20126
+ mkdirSync4(inbox, { recursive: true });
20127
+ const seen = new Set;
20128
+ let stopped = false;
20129
+ const scan = () => {
20130
+ if (stopped)
20131
+ return;
20132
+ try {
20133
+ const files = readdirSync2(inbox).filter((f) => f.endsWith(".json") && !f.endsWith(".tmp")).sort();
20134
+ for (const file2 of files) {
20135
+ if (seen.has(file2))
20136
+ continue;
20137
+ const seq = file2.replace(/\.json$/, "");
20138
+ const srcPath = join6(inbox, file2);
20139
+ const claimPath = join6(inbox, `${seq}.processing`);
20140
+ try {
20141
+ renameSync2(srcPath, claimPath);
20142
+ } catch {
20143
+ continue;
20144
+ }
20145
+ seen.add(file2);
20146
+ const msg = readSteerMessage(claimPath);
20147
+ try {
20148
+ unlinkSync3(claimPath);
20149
+ } catch {}
20150
+ if (msg) {
20151
+ onMessage(seq, msg);
20152
+ }
20153
+ }
20154
+ } catch {}
20155
+ };
20156
+ scan();
20157
+ let watcher = null;
20158
+ try {
20159
+ watcher = watch(inbox, () => {
20160
+ if (!stopped)
20161
+ scan();
20162
+ });
20163
+ } catch {
20164
+ log7.debug("fs.watch failed, relying on polling only");
20165
+ }
20166
+ const pollTimer = setInterval(scan, 200);
20167
+ return {
20168
+ stop() {
20169
+ stopped = true;
20170
+ clearInterval(pollTimer);
20171
+ watcher?.close();
20172
+ }
20173
+ };
20174
+ }
20175
+
20176
+ // daemon/steering/turnState.ts
20177
+ class RuntimeTurnState {
20178
+ currentTurnId = null;
20179
+ steeringGateActive = false;
20180
+ get isInTurn() {
20181
+ return this.currentTurnId !== null;
20182
+ }
20183
+ get turnId() {
20184
+ return this.currentTurnId;
20185
+ }
20186
+ get canSteerBusy() {
20187
+ return Boolean(this.currentTurnId && !this.steeringGateActive);
20188
+ }
20189
+ markTurnStarted(turnId) {
20190
+ if (turnId !== undefined && turnId !== null) {
20191
+ this.currentTurnId = turnId;
20192
+ }
20193
+ this.steeringGateActive = false;
20194
+ }
20195
+ adoptTurnId(turnId) {
20196
+ this.currentTurnId = turnId;
20197
+ }
20198
+ markToolBoundary() {
20199
+ this.steeringGateActive = true;
20200
+ }
20201
+ markProgress() {
20202
+ this.steeringGateActive = false;
20203
+ }
20204
+ markTurnCompleted() {
20205
+ this.currentTurnId = null;
20206
+ this.steeringGateActive = false;
20207
+ }
20208
+ reset() {
20209
+ this.currentTurnId = null;
20210
+ this.steeringGateActive = false;
20211
+ }
20212
+ }
20213
+
20214
+ // daemon/steering/apmStateMachine.ts
20215
+ var MAX_APM_GATED_STEERING_EVENTS = 12;
20216
+ function createInitialApmState() {
20217
+ return {
20218
+ isIdle: false,
20219
+ expectedTerminationReason: null,
20220
+ phase: "idle",
20221
+ outstandingToolUses: 0,
20222
+ compacting: false,
20223
+ toolBoundaryFlushDisabled: false,
20224
+ lastFlushReason: null,
20225
+ recentEvents: [],
20226
+ pendingMessages: []
20227
+ };
20228
+ }
20229
+ function reduceApmGatedToolUse(state, input) {
20230
+ if (input.kind === "tool_call") {
20231
+ return {
20232
+ nextState: {
20233
+ ...state,
20234
+ isIdle: false,
20235
+ phase: "tool_wait",
20236
+ outstandingToolUses: state.outstandingToolUses + 1
20237
+ },
20238
+ hadOutstandingToolUse: state.outstandingToolUses > 0,
20239
+ shouldFlushToolBatch: false
20240
+ };
20241
+ }
20242
+ const hadOutstandingToolUse = state.outstandingToolUses > 0;
20243
+ const outstandingToolUses = Math.max(0, state.outstandingToolUses - 1);
20244
+ return {
20245
+ nextState: {
20246
+ ...state,
20247
+ isIdle: false,
20248
+ phase: "tool_boundary",
20249
+ outstandingToolUses
20250
+ },
20251
+ hadOutstandingToolUse,
20252
+ shouldFlushToolBatch: hadOutstandingToolUse && outstandingToolUses === 0
20253
+ };
20254
+ }
20255
+ function reduceApmGatedCompaction(state, input) {
20256
+ if (input.kind === "compaction_started") {
20257
+ return { nextState: { ...state, isIdle: false, phase: "compacting", compacting: true } };
20258
+ }
20259
+ if (input.kind === "compaction_interrupted") {
20260
+ return { nextState: { ...state, isIdle: false, compacting: false } };
20261
+ }
20262
+ return {
20263
+ nextState: { ...state, isIdle: false, phase: "assistant_continuation", compacting: false }
20264
+ };
20265
+ }
20266
+ function reduceApmGatedFlushReadiness(state, input) {
20267
+ if (!input.isGated)
20268
+ return { shouldNotify: false, blockedReason: "non_gated", effects: [] };
20269
+ if (!input.hasSession)
20270
+ return { shouldNotify: false, blockedReason: "missing_session", effects: [] };
20271
+ if (input.inboxLength === 0)
20272
+ return { shouldNotify: false, blockedReason: "empty_inbox", effects: [] };
20273
+ if (state.toolBoundaryFlushDisabled) {
20274
+ return { shouldNotify: false, blockedReason: "tool_boundary_flush_disabled", effects: [] };
20275
+ }
20276
+ if (state.compacting)
20277
+ return { shouldNotify: false, blockedReason: "compacting", effects: [] };
20278
+ if (state.outstandingToolUses > 0) {
20279
+ return { shouldNotify: false, blockedReason: "outstanding_tool_uses", effects: [] };
20280
+ }
20281
+ return {
20282
+ shouldNotify: true,
20283
+ blockedReason: null,
20284
+ effects: [{ kind: "notify_stdin", reason: input.reason, stdinMode: "busy", clauseId: "SMR-002" }]
20285
+ };
20286
+ }
20287
+ function reduceApmGatedTurnEnd(state, input = {}) {
20288
+ const shouldDeliverQueuedMessages = Boolean(input.inboxLength && input.inboxLength > 0 && input.supportsStdinNotification && input.hasSession);
20289
+ return {
20290
+ nextState: {
20291
+ ...state,
20292
+ isIdle: !shouldDeliverQueuedMessages,
20293
+ phase: "idle",
20294
+ outstandingToolUses: 0,
20295
+ compacting: false,
20296
+ pendingMessages: shouldDeliverQueuedMessages ? state.pendingMessages : []
20297
+ },
20298
+ effects: shouldDeliverQueuedMessages ? [{ kind: "deliver_stdin", reason: "turn_end", stdinMode: "idle", clauseId: "SMR-002" }] : []
20299
+ };
20300
+ }
20301
+ function reduceApmGatedError(state, input = {}) {
20302
+ const shouldDisableToolBoundaryFlush = input.disableToolBoundaryFlush === true;
20303
+ return {
20304
+ nextState: {
20305
+ ...state,
20306
+ phase: "error",
20307
+ compacting: false,
20308
+ toolBoundaryFlushDisabled: state.toolBoundaryFlushDisabled || shouldDisableToolBoundaryFlush
20309
+ },
20310
+ shouldDisableToolBoundaryFlush
20311
+ };
20312
+ }
20313
+ function reduceApmGatedRecentEvent(state, input) {
20314
+ const summary = `${input.event}:${state.phase}:tools=${state.outstandingToolUses}:compact=${state.compacting}`;
20315
+ return {
20316
+ nextState: {
20317
+ ...state,
20318
+ recentEvents: [...state.recentEvents, summary].slice(-MAX_APM_GATED_STEERING_EVENTS)
20319
+ }
20320
+ };
20321
+ }
20322
+ function reduceApmGatedEnqueue(state, message2) {
20323
+ return {
20324
+ nextState: {
20325
+ ...state,
20326
+ pendingMessages: [...state.pendingMessages, message2]
20327
+ }
20328
+ };
20329
+ }
20330
+ function reduceApmStalledRecoveryTermination(state, input) {
20331
+ if (input.inboxLength === 0) {
20332
+ return { nextState: state, shouldTerminate: false, alreadyRecovering: false, blockedReason: "empty_inbox" };
20333
+ }
20334
+ if (state.expectedTerminationReason === "stalled_recovery") {
20335
+ return { nextState: state, shouldTerminate: false, alreadyRecovering: true, blockedReason: null };
20336
+ }
20337
+ const supportsStdinNotification = input.busyDeliveryMode !== "none";
20338
+ const directStdinRuntime = supportsStdinNotification && input.busyDeliveryMode === "direct";
20339
+ const canRestartDirectStdinProcess = directStdinRuntime && input.hasSession && (state.outstandingToolUses === 0 || input.hasDirectStdinRecoveryEvidence);
20340
+ const canRestartStalledProcess = !supportsStdinNotification || canRestartDirectStdinProcess;
20341
+ if (!canRestartStalledProcess) {
20342
+ return {
20343
+ nextState: state,
20344
+ shouldTerminate: false,
20345
+ alreadyRecovering: false,
20346
+ blockedReason: "runtime_not_restartable"
20347
+ };
20348
+ }
20349
+ if (input.staleForMs < input.staleThresholdMs && !input.runtimeProgressIsStale) {
20350
+ return {
20351
+ nextState: state,
20352
+ shouldTerminate: false,
20353
+ alreadyRecovering: false,
20354
+ blockedReason: "runtime_progress_recent"
20355
+ };
20356
+ }
20357
+ return {
20358
+ nextState: { ...state, expectedTerminationReason: "stalled_recovery" },
20359
+ shouldTerminate: true,
20360
+ alreadyRecovering: false,
20361
+ blockedReason: null
20362
+ };
20363
+ }
20364
+ function reduceApmStartupTimeoutTermination(state, input) {
20365
+ if (input.hasRuntimeProgressEvent) {
20366
+ return { nextState: state, shouldTerminate: false, blockedReason: "runtime_progress_started" };
20367
+ }
20368
+ return {
20369
+ nextState: { ...state, isIdle: false, expectedTerminationReason: "startup_timeout" },
20370
+ shouldTerminate: true,
20371
+ blockedReason: null
20372
+ };
20373
+ }
20374
+
20375
+ // daemon/steering/notificationState.ts
20376
+ function inboxNoticeMessageIdentity(message2) {
20377
+ const seq = typeof message2.seq === "number" && Number.isFinite(message2.seq) && message2.seq > 0 ? Math.floor(message2.seq) : null;
20378
+ if (seq !== null)
20379
+ return `s:${seq}`;
20380
+ 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 : "";
20381
+ return id.length > 0 ? `m:${id}` : "";
20382
+ }
20383
+ class RuntimeNotificationState {
20384
+ pendingCountValue = 0;
20385
+ timerValue = null;
20386
+ lastNoticeFingerprint = null;
20387
+ lastNoticeSessionId = null;
20388
+ lastEncodeFailedFingerprint = null;
20389
+ lastEncodeFailedSessionId = null;
20390
+ contributedIdentities = new Set;
20391
+ contributionSessionId = null;
20392
+ get pendingCount() {
20393
+ return this.pendingCountValue;
20394
+ }
20395
+ isDuplicateNotice(fingerprint, sessionId) {
20396
+ if (fingerprint.length === 0)
20397
+ return false;
20398
+ return this.lastNoticeFingerprint === fingerprint && this.lastNoticeSessionId === sessionId;
20399
+ }
20400
+ recordNoticeWritten(fingerprint, sessionId, messages = []) {
20401
+ this.lastNoticeFingerprint = fingerprint;
20402
+ this.lastNoticeSessionId = sessionId;
20403
+ this.lastEncodeFailedFingerprint = null;
20404
+ this.lastEncodeFailedSessionId = null;
20405
+ this.ensureContributionSession(sessionId);
20406
+ for (const message2 of messages) {
20407
+ const identity = inboxNoticeMessageIdentity(message2);
20408
+ if (identity.length > 0)
20409
+ this.contributedIdentities.add(identity);
20410
+ }
20411
+ }
20412
+ recordNoticeEncodeFailed(fingerprint, sessionId) {
20413
+ if (fingerprint.length === 0)
20414
+ return;
20415
+ this.lastEncodeFailedFingerprint = fingerprint;
20416
+ this.lastEncodeFailedSessionId = sessionId;
20417
+ }
20418
+ isDuplicateEncodeFailedNotice(fingerprint, sessionId) {
20419
+ if (fingerprint.length === 0)
20420
+ return false;
20421
+ return this.lastEncodeFailedFingerprint === fingerprint && this.lastEncodeFailedSessionId === sessionId;
20422
+ }
20423
+ filterUncontributedMessages(messages, sessionId) {
20424
+ if (this.contributionSessionId !== sessionId)
20425
+ return messages;
20426
+ return messages.filter((m) => {
20427
+ const identity = inboxNoticeMessageIdentity(m);
20428
+ return identity.length === 0 || !this.contributedIdentities.has(identity);
20429
+ });
20430
+ }
20431
+ add(count = 1) {
20432
+ this.pendingCountValue += count;
20433
+ }
20434
+ schedule(callback, delayMs) {
20435
+ if (this.timerValue)
20436
+ return false;
20437
+ this.timerValue = setTimeout(() => {
20438
+ this.timerValue = null;
20439
+ callback();
20440
+ }, delayMs);
20441
+ this.timerValue.unref?.();
20442
+ return true;
20443
+ }
20444
+ takePendingAndClearTimer() {
20445
+ const count = this.pendingCountValue;
20446
+ this.pendingCountValue = 0;
20447
+ if (this.timerValue) {
20448
+ clearTimeout(this.timerValue);
20449
+ this.timerValue = null;
20450
+ }
20451
+ return count;
20452
+ }
20453
+ ensureContributionSession(sessionId) {
20454
+ if (this.contributionSessionId !== sessionId) {
20455
+ this.contributionSessionId = sessionId;
20456
+ this.contributedIdentities = new Set;
20457
+ }
20458
+ }
20459
+ }
20460
+
20461
+ // daemon/steering/progressState.ts
20462
+ class RuntimeProgressState {
20463
+ lastEventAt;
20464
+ lastEventKind = null;
20465
+ _staleSince = null;
20466
+ _isStale = false;
20467
+ constructor(now = Date.now()) {
20468
+ this.lastEventAt = now;
20469
+ }
20470
+ get isStale() {
20471
+ return this._isStale;
20472
+ }
20473
+ get staleSince() {
20474
+ return this._staleSince;
20475
+ }
20476
+ get lastActivity() {
20477
+ return this.lastEventAt;
20478
+ }
20479
+ ageMs(nowMs = Date.now()) {
20480
+ return nowMs - this.lastEventAt;
20481
+ }
20482
+ recordRealEvent(kind, now = Date.now()) {
20483
+ this.lastEventAt = now;
20484
+ this.lastEventKind = kind;
20485
+ this._isStale = false;
20486
+ this._staleSince = null;
20487
+ }
20488
+ recordInternalProgress(kind, now = Date.now()) {
20489
+ this.lastEventAt = now;
20490
+ this.lastEventKind = kind;
20491
+ }
20492
+ markStale(now = Date.now()) {
20493
+ if (this._isStale)
20494
+ return;
20495
+ this._isStale = true;
20496
+ this._staleSince = now;
20497
+ }
20498
+ shouldMarkStale(thresholdMs, now = Date.now()) {
20499
+ if (this._isStale)
20500
+ return false;
20501
+ return this.ageMs(now) > thresholdMs;
20502
+ }
20503
+ processEvent(event, now = Date.now()) {
20504
+ switch (event.kind) {
20505
+ case "text":
20506
+ case "tool_call":
20507
+ case "tool_output":
20508
+ case "turn_end":
20509
+ case "session_init":
20510
+ case "error":
20511
+ this.recordRealEvent(event.kind, now);
20512
+ break;
20513
+ case "internal_progress":
20514
+ case "compaction_started":
20515
+ case "compaction_finished":
20516
+ case "telemetry":
20517
+ case "thinking":
20518
+ this.recordInternalProgress(event.kind, now);
20519
+ break;
20520
+ default:
20521
+ this.recordInternalProgress(event.kind, now);
20522
+ }
20523
+ }
20524
+ }
20525
+
20526
+ // daemon/steering/errorDiagnostics.ts
20527
+ var ACTION_BY_CLASS = {
20528
+ RateLimitError: "retry_backoff",
20529
+ AuthError: "abort",
20530
+ NotFoundError: "report",
20531
+ ModelConfigError: "abort",
20532
+ TimeoutError: "retry",
20533
+ ProviderConnectionError: "retry_jitter",
20534
+ ProviderStreamError: "retry",
20535
+ ProviderServerError: "retry",
20536
+ ProviderApiError: "report",
20537
+ RuntimeError: "report"
20538
+ };
20539
+ var EXPLICIT_TOKEN_RE = /\b([A-Z][A-Za-z0-9_]*(?:Error|Exception))\b/;
20540
+ var EXPLICIT_TOKEN_MAP = {
20541
+ RateLimitError: "RateLimitError",
20542
+ TooManyRequestsError: "RateLimitError",
20543
+ AuthenticationError: "AuthError",
20544
+ AuthorizationError: "AuthError",
20545
+ PermissionError: "AuthError",
20546
+ NotFoundError: "NotFoundError",
20547
+ ModelNotFoundError: "ModelConfigError",
20548
+ TimeoutError: "TimeoutError",
20549
+ ConnectionError: "ProviderConnectionError",
20550
+ APIConnectionError: "ProviderConnectionError",
20551
+ StreamError: "ProviderStreamError",
20552
+ InternalServerError: "ProviderServerError",
20553
+ APIError: "ProviderApiError",
20554
+ BadRequestError: "ProviderApiError"
20555
+ };
20556
+ function extractHttpStatus(message2) {
20557
+ const labeled = /\b(?:HTTP|status(?:\s+code)?|API\s+Error)[:\s]+([45]\d{2})\b/i.exec(message2);
20558
+ if (labeled)
20559
+ return Number(labeled[1]);
20560
+ 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);
20561
+ return semantic ? Number(semantic[1]) : null;
20562
+ }
20563
+ var AUTH_ACTION_REQUIRED_PATTERNS = [
20564
+ /access token could not be refreshed/i,
20565
+ /\btoken_(?:revoked|invalidated)\b/i,
20566
+ /refresh token was already used/i,
20567
+ /access token.*invalidated/i,
20568
+ /authentication token has been invalidated/i,
20569
+ /logged out or signed in to another account/i,
20570
+ /not logged in/i,
20571
+ /not signed in/i,
20572
+ /login required/i,
20573
+ /log in first/i,
20574
+ /please log in/i,
20575
+ /authentication failed/i,
20576
+ /auth(?:entication)? failed/i,
20577
+ /authentication timed out/i,
20578
+ /missing (?:api )?token/i,
20579
+ /no (?:api )?token/i,
20580
+ /missing credentials/i,
20581
+ /credentials? not found/i,
20582
+ /invalid api key/i,
20583
+ /api key (?:is )?not set/i,
20584
+ /token revoked/i,
20585
+ /refresh token expired/i,
20586
+ /session expired/i,
20587
+ /unauthorized/i,
20588
+ /forbidden/i,
20589
+ /invalid.?token/i
20590
+ ];
20591
+ var RATE_LIMIT_PATTERNS = [
20592
+ /too many requests/i,
20593
+ /rate.?limit/i,
20594
+ /quota.?exceeded/i,
20595
+ /overloaded/i
20596
+ ];
20597
+ var MODEL_CONFIG_PATTERNS = [
20598
+ /model.?not.?(?:found|supported|available)/i,
20599
+ /invalid.?model/i,
20600
+ /does not exist/i
20601
+ ];
20602
+ var TIMEOUT_PATTERNS = [
20603
+ /timeout/i,
20604
+ /ETIMEDOUT/,
20605
+ /timed.?out/i,
20606
+ /deadline.?exceeded/i
20607
+ ];
20608
+ var CONNECTION_PATTERNS = [
20609
+ /ECONNREFUSED/,
20610
+ /ECONNRESET/,
20611
+ /ENETUNREACH/,
20612
+ /EHOSTUNREACH/,
20613
+ /EAI_AGAIN/,
20614
+ /ENOTFOUND/,
20615
+ /connection.?refused/i,
20616
+ /connection.?reset/i,
20617
+ /network.?error/i,
20618
+ /Unable to connect to API/i
20619
+ ];
20620
+ var STREAM_PATTERNS = [
20621
+ /stream.?error/i,
20622
+ /stream closed before response/i,
20623
+ /error decoding response body/i,
20624
+ /premature.?close/i,
20625
+ /aborted/i
20626
+ ];
20627
+ var SERVER_PATTERNS = [
20628
+ /internal.?server/i,
20629
+ /bad.?gateway/i,
20630
+ /service.?unavailable/i
20631
+ ];
20632
+ function classifyByExplicitToken(message2) {
20633
+ const match = EXPLICIT_TOKEN_RE.exec(message2);
20634
+ if (!match)
20635
+ return null;
20636
+ const token = match[1];
20637
+ return EXPLICIT_TOKEN_MAP[token] ?? null;
20638
+ }
20639
+ function classifyByHttpStatus(httpStatus) {
20640
+ if (httpStatus === 429)
20641
+ return "RateLimitError";
20642
+ if (httpStatus === 401 || httpStatus === 403)
20643
+ return "AuthError";
20644
+ if (httpStatus === 404)
20645
+ return "NotFoundError";
20646
+ if (httpStatus >= 500)
20647
+ return "ProviderServerError";
20648
+ return "ProviderApiError";
20649
+ }
20650
+ function classifyByTextPatterns(message2) {
20651
+ for (const pat of RATE_LIMIT_PATTERNS) {
20652
+ if (pat.test(message2))
20653
+ return "RateLimitError";
20654
+ }
20655
+ for (const pat of AUTH_ACTION_REQUIRED_PATTERNS) {
20656
+ if (pat.test(message2))
20657
+ return "AuthError";
20658
+ }
20659
+ for (const pat of MODEL_CONFIG_PATTERNS) {
20660
+ if (pat.test(message2))
20661
+ return "ModelConfigError";
20662
+ }
20663
+ for (const pat of TIMEOUT_PATTERNS) {
20664
+ if (pat.test(message2))
20665
+ return "TimeoutError";
20666
+ }
20667
+ for (const pat of CONNECTION_PATTERNS) {
20668
+ if (pat.test(message2))
20669
+ return "ProviderConnectionError";
20670
+ }
20671
+ for (const pat of STREAM_PATTERNS) {
20672
+ if (pat.test(message2))
20673
+ return "ProviderStreamError";
20674
+ }
20675
+ for (const pat of SERVER_PATTERNS) {
20676
+ if (pat.test(message2))
20677
+ return "ProviderServerError";
20678
+ }
20679
+ return null;
20680
+ }
20681
+ function classifyRuntimeError(message2, httpStatus) {
20682
+ const byToken = classifyByExplicitToken(message2);
20683
+ if (byToken) {
20684
+ return { errorClass: byToken, action: ACTION_BY_CLASS[byToken], reason: message2 };
20685
+ }
20686
+ const status = httpStatus ?? extractHttpStatus(message2);
20687
+ if (status !== null && status !== undefined) {
20688
+ const cls = classifyByHttpStatus(status);
20689
+ return { errorClass: cls, action: ACTION_BY_CLASS[cls], reason: message2 };
20690
+ }
20691
+ const byPattern = classifyByTextPatterns(message2);
20692
+ if (byPattern) {
20693
+ return { errorClass: byPattern, action: ACTION_BY_CLASS[byPattern], reason: message2 };
20694
+ }
20695
+ return { errorClass: "RuntimeError", action: "report", reason: message2 };
20696
+ }
20697
+ function scrubDiagnosticText(text2) {
20698
+ let scrubbed = text2;
20699
+ scrubbed = scrubbed.replace(/sk-ant-[a-zA-Z0-9_-]+/g, "sk-ant-***");
20700
+ scrubbed = scrubbed.replace(/sk-proj-[a-zA-Z0-9_-]+/g, "sk-proj-***");
20701
+ scrubbed = scrubbed.replace(/sk-[a-zA-Z0-9_-]{20,}/g, "sk-***");
20702
+ scrubbed = scrubbed.replace(/Bearer\s+[a-zA-Z0-9._-]+/gi, "Bearer ***");
20703
+ scrubbed = scrubbed.replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, "***@***.***");
20704
+ scrubbed = scrubbed.replace(/:\/\/[^:@\s]+:[^@\s]+@/g, "://***:***@");
20705
+ scrubbed = scrubbed.replace(/\/(?:Users|home)\/[a-zA-Z0-9._-]+/g, "/***");
20706
+ return scrubbed;
20707
+ }
20708
+
18843
20709
  // daemon/prompt.ts
18844
20710
  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.";
18845
20711
  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.";
@@ -18935,7 +20801,7 @@ function buildPrompt(task, attachments) {
18935
20801
  }
18936
20802
 
18937
20803
  // daemon/session-runner.ts
18938
- var log5 = createLogger2({ module: "session-runner" });
20804
+ var log8 = createLogger2({ module: "session-runner" });
18939
20805
  var ATTACHMENTS_BASE = tempDir("alook-attachments");
18940
20806
  async function writeMarkerFile(workspacesRoot, marker) {
18941
20807
  const dir = path.join(workspacesRoot, ".pending_completions");
@@ -18983,20 +20849,20 @@ async function reportToServer(fn, markerData, workspacesRoot) {
18983
20849
  } catch (e) {
18984
20850
  lastErr = e;
18985
20851
  if (isClientError(e)) {
18986
- log5.info(`server report for task ${markerData.taskId}: task already in terminal state (${e})`);
20852
+ log8.info(`server report for task ${markerData.taskId}: task already in terminal state (${e})`);
18987
20853
  return;
18988
20854
  }
18989
20855
  if (attempt < RETRY_DELAYS.length && isRetryableError(e)) {
18990
- log5.debug(`server report attempt ${attempt + 1} failed for task ${markerData.taskId}, retrying in ${RETRY_DELAYS[attempt]}ms`);
20856
+ log8.debug(`server report attempt ${attempt + 1} failed for task ${markerData.taskId}, retrying in ${RETRY_DELAYS[attempt]}ms`);
18991
20857
  await new Promise((r) => setTimeout(r, RETRY_DELAYS[attempt]));
18992
20858
  }
18993
20859
  }
18994
20860
  }
18995
- log5.warn(`server report failed for task ${markerData.taskId} after retries, writing marker: ${lastErr}`);
20861
+ log8.warn(`server report failed for task ${markerData.taskId} after retries, writing marker: ${lastErr}`);
18996
20862
  try {
18997
20863
  await writeMarkerFile(workspacesRoot, markerData);
18998
20864
  } catch (writeErr) {
18999
- log5.error(`marker write also failed for task ${markerData.taskId}: ${writeErr}`);
20865
+ log8.error(`marker write also failed for task ${markerData.taskId}: ${writeErr}`);
19000
20866
  }
19001
20867
  }
19002
20868
  function sanitizeFilename(name) {
@@ -19027,12 +20893,12 @@ async function downloadAttachments(client, token, workspaceId, taskId, attachmen
19027
20893
  }
19028
20894
  async function runSession(input) {
19029
20895
  const { task, provider, cliPath, model, serverURL, token, workspacesRoot, agentTimeout, messageInactivityTimeout } = input;
19030
- log5.info(`starting (task=${task.id}, type=${task.type}, agent=${task.agentId}, provider=${provider}, model=${model || "default"})`);
20896
+ log8.info(`starting (task=${task.id}, type=${task.type}, agent=${task.agentId}, provider=${provider}, model=${model || "default"})`);
19031
20897
  const client = new DaemonClient(serverURL);
19032
20898
  const backend = createBackend(provider, cliPath);
19033
20899
  const agentBaseDir = path.join(workspacesRoot, task.workspaceId, task.agentId, "workdir");
19034
20900
  const timelineDir = path.join(agentBaseDir, ".context_timeline").replace(/\\/g, "/");
19035
- mkdirSync4(timelineDir, { recursive: true });
20901
+ mkdirSync5(timelineDir, { recursive: true });
19036
20902
  await initEntryAsync(timelineDir, createTimelineEntry(task.id, task.prompt, task.type, undefined, process.pid, provider, task.contextKey, input.logFilePath));
19037
20903
  const { workDir, env } = prepare({ workspacesRoot, token }, task);
19038
20904
  let killed = false;
@@ -19050,16 +20916,22 @@ async function runSession(input) {
19050
20916
  try {
19051
20917
  await client.reportMessages(token, task.id, batch);
19052
20918
  } catch (e) {
19053
- log5.debug("message report failed", e);
20919
+ log8.debug("message report failed", e);
19054
20920
  }
19055
20921
  };
20922
+ let mailboxWatcher = null;
20923
+ let stalledRecoveryTimer;
19056
20924
  const onKill = async () => {
19057
20925
  if (killed)
19058
20926
  return;
19059
20927
  killed = true;
19060
- log5.info(`killed by signal (messages=${seq}, tools=${toolCount})`);
20928
+ log8.info(`killed by signal (messages=${seq}, tools=${toolCount})`);
20929
+ if (mailboxWatcher)
20930
+ mailboxWatcher.stop();
20931
+ if (stalledRecoveryTimer)
20932
+ clearInterval(stalledRecoveryTimer);
19061
20933
  if (agentPid !== undefined) {
19062
- log5.info(`killing inner agent group (pid=${agentPid})`);
20934
+ log8.info(`killing inner agent group (pid=${agentPid})`);
19063
20935
  await killProcessTree(agentPid);
19064
20936
  }
19065
20937
  if (flushTimer)
@@ -19102,14 +20974,14 @@ async function runSession(input) {
19102
20974
  const attachmentIds = task.context?.attachment_ids ?? [];
19103
20975
  let attachments;
19104
20976
  if (attachmentIds.length > 0) {
19105
- log5.info(`downloading ${attachmentIds.length} attachment(s)`);
20977
+ log8.info(`downloading ${attachmentIds.length} attachment(s)`);
19106
20978
  try {
19107
20979
  attachments = await downloadAttachments(client, token, task.workspaceId, task.id, attachmentIds);
19108
- log5.info(`attachments ready (${attachments.length} file(s))`);
20980
+ log8.info(`attachments ready (${attachments.length} file(s))`);
19109
20981
  } catch (e) {
19110
20982
  await cleanupAttachments(task.id);
19111
20983
  const errMsg = `failed to download attachments: ${e}`;
19112
- log5.error(errMsg);
20984
+ log8.error(errMsg);
19113
20985
  updateEntry(timelineDir, task.id, (entry) => {
19114
20986
  entry.pid = null;
19115
20987
  entry.status = "failed";
@@ -19126,32 +20998,301 @@ async function runSession(input) {
19126
20998
  const prompt = input.promptOverride ?? buildPrompt(task, attachments);
19127
20999
  const resumeSessionId = task.contextKey ? findResumableSessionByContextKey(timelineDir, task.contextKey, provider) ?? undefined : undefined;
19128
21000
  if (resumeSessionId) {
19129
- log5.info(`resuming session ${resumeSessionId} (context_key: ${task.contextKey})`);
21001
+ log8.info(`resuming session ${resumeSessionId} (context_key: ${task.contextKey})`);
19130
21002
  }
19131
21003
  const session2 = backend.execute(prompt, {
19132
21004
  cwd: workDir,
19133
21005
  model: model || undefined,
19134
21006
  env,
19135
21007
  timeout: agentTimeout,
19136
- resumeSessionId
21008
+ resumeSessionId,
21009
+ steeringEnabled: input.steeringEnabled
19137
21010
  });
19138
21011
  agentPid = session2.pid;
19139
21012
  if (killed) {
19140
21013
  if (agentPid !== undefined) {
19141
- log5.info(`kill landed during spawn — reaping inner agent group (pid=${agentPid})`);
21014
+ log8.info(`kill landed during spawn — reaping inner agent group (pid=${agentPid})`);
19142
21015
  await killProcessTree(agentPid);
19143
21016
  }
19144
21017
  process.exit(1);
19145
21018
  }
19146
21019
  const earlySessionId = await session2.sessionId;
19147
- log5.info(`agent started (pid=${agentPid ?? "unknown"}, session=${earlySessionId})`);
19148
- log5.info(JSON.stringify({ role: "user", type: "text", content: prompt }));
21020
+ log8.info(`agent started (pid=${agentPid ?? "unknown"}, session=${earlySessionId})`);
21021
+ log8.info(JSON.stringify({ role: "user", type: "text", content: prompt }));
19149
21022
  updateEntry(timelineDir, task.id, (entry) => {
19150
21023
  entry.session_id = earlySessionId || null;
19151
21024
  if (earlySessionId)
19152
21025
  entry.agent_started = true;
19153
21026
  });
19154
21027
  flushTimer = setInterval(flushMessages, FLUSH_INTERVAL_MS);
21028
+ const turnState = new RuntimeTurnState;
21029
+ let apmState = createInitialApmState();
21030
+ const notificationState = new RuntimeNotificationState;
21031
+ const progressState = new RuntimeProgressState;
21032
+ const pendingSteeredTasks = new Set;
21033
+ const pendingAcks = [];
21034
+ let hasReceivedProgressEvent = false;
21035
+ if (input.steeringEnabled && input.steeringMailboxDir && task.contextKey) {
21036
+ const descriptor = session2.descriptor;
21037
+ const STALLED_THRESHOLD_MS = 120000;
21038
+ const STALLED_CHECK_INTERVAL_MS = 30000;
21039
+ if (session2.parsedEvents) {
21040
+ const parsedIter = session2.parsedEvents[Symbol.asyncIterator]();
21041
+ const consumeParsedEvents = async () => {
21042
+ try {
21043
+ while (!killed) {
21044
+ const { value: event, done } = await parsedIter.next();
21045
+ if (done)
21046
+ break;
21047
+ hasReceivedProgressEvent = true;
21048
+ progressState.processEvent(event);
21049
+ const recentResult = reduceApmGatedRecentEvent(apmState, { event: event.kind });
21050
+ apmState = recentResult.nextState;
21051
+ if (event.kind === "error") {
21052
+ const classified = classifyRuntimeError(event.message);
21053
+ log8.info(`steering: error classified as ${classified.errorClass}: ${scrubDiagnosticText(event.message)}`);
21054
+ const errResult = reduceApmGatedError(apmState, { disableToolBoundaryFlush: true });
21055
+ apmState = errResult.nextState;
21056
+ }
21057
+ switch (event.kind) {
21058
+ case "tool_call":
21059
+ case "thinking":
21060
+ case "compaction_started":
21061
+ turnState.markToolBoundary();
21062
+ break;
21063
+ case "text":
21064
+ case "tool_output":
21065
+ case "compaction_finished":
21066
+ turnState.markProgress();
21067
+ break;
21068
+ }
21069
+ switch (event.kind) {
21070
+ case "session_init":
21071
+ turnState.markTurnStarted(event.sessionId);
21072
+ break;
21073
+ case "text":
21074
+ if (!turnState.isInTurn)
21075
+ turnState.markTurnStarted();
21076
+ break;
21077
+ case "tool_call": {
21078
+ if (!turnState.isInTurn)
21079
+ turnState.markTurnStarted();
21080
+ const result2 = reduceApmGatedToolUse(apmState, { kind: "tool_call" });
21081
+ apmState = result2.nextState;
21082
+ break;
21083
+ }
21084
+ case "tool_output": {
21085
+ const result2 = reduceApmGatedToolUse(apmState, { kind: "tool_output" });
21086
+ apmState = result2.nextState;
21087
+ if (result2.shouldFlushToolBatch && session2.send && apmState.pendingMessages.length > 0) {
21088
+ const readiness = reduceApmGatedFlushReadiness(apmState, {
21089
+ isGated: descriptor?.busyDeliveryMode === "gated",
21090
+ hasSession: !!earlySessionId,
21091
+ inboxLength: apmState.pendingMessages.length,
21092
+ reason: "tool_batch_complete"
21093
+ });
21094
+ if (readiness.shouldNotify) {
21095
+ let allSent = true;
21096
+ for (const msg of apmState.pendingMessages) {
21097
+ const sendResult = session2.send(msg, "busy");
21098
+ if (!sendResult.ok) {
21099
+ allSent = false;
21100
+ break;
21101
+ }
21102
+ }
21103
+ if (allSent) {
21104
+ apmState = { ...apmState, pendingMessages: [] };
21105
+ for (const ack of pendingAcks) {
21106
+ notificationState.recordNoticeWritten(String(ack.seq), ack.sessionId, [{ id: String(ack.seq) }]);
21107
+ writeAck(agentBaseDir, task.contextKey, ack.seq);
21108
+ }
21109
+ pendingAcks.length = 0;
21110
+ }
21111
+ }
21112
+ }
21113
+ break;
21114
+ }
21115
+ case "compaction_started":
21116
+ case "compaction_finished": {
21117
+ const result2 = reduceApmGatedCompaction(apmState, { kind: event.kind });
21118
+ apmState = result2.nextState;
21119
+ if (event.kind === "compaction_finished" && session2.send && apmState.pendingMessages.length > 0) {
21120
+ const readiness = reduceApmGatedFlushReadiness(apmState, {
21121
+ isGated: descriptor?.busyDeliveryMode === "gated",
21122
+ hasSession: !!earlySessionId,
21123
+ inboxLength: apmState.pendingMessages.length,
21124
+ reason: "compaction_finished"
21125
+ });
21126
+ if (readiness.shouldNotify) {
21127
+ let allSent = true;
21128
+ for (const msg of apmState.pendingMessages) {
21129
+ const sendResult = session2.send(msg, "busy");
21130
+ if (!sendResult.ok) {
21131
+ allSent = false;
21132
+ break;
21133
+ }
21134
+ }
21135
+ if (allSent) {
21136
+ apmState = { ...apmState, pendingMessages: [] };
21137
+ for (const ack of pendingAcks) {
21138
+ notificationState.recordNoticeWritten(String(ack.seq), ack.sessionId, [{ id: String(ack.seq) }]);
21139
+ writeAck(agentBaseDir, task.contextKey, ack.seq);
21140
+ }
21141
+ pendingAcks.length = 0;
21142
+ }
21143
+ }
21144
+ }
21145
+ break;
21146
+ }
21147
+ case "turn_end": {
21148
+ const result2 = reduceApmGatedTurnEnd(apmState, {
21149
+ inboxLength: apmState.pendingMessages.length,
21150
+ supportsStdinNotification: descriptor?.supportsStdinNotification,
21151
+ hasSession: !!earlySessionId
21152
+ });
21153
+ apmState = result2.nextState;
21154
+ let flushedOk = false;
21155
+ for (const eff of result2.effects) {
21156
+ if (eff.kind === "deliver_stdin" && session2.send) {
21157
+ let allSent = true;
21158
+ for (const msg of apmState.pendingMessages) {
21159
+ const sendResult = session2.send(msg, eff.stdinMode);
21160
+ if (!sendResult.ok) {
21161
+ log8.warn("steering: send failed during turn_end flush", { reason: sendResult.reason });
21162
+ allSent = false;
21163
+ break;
21164
+ }
21165
+ }
21166
+ if (allSent) {
21167
+ apmState = { ...apmState, pendingMessages: [] };
21168
+ flushedOk = true;
21169
+ }
21170
+ }
21171
+ }
21172
+ if (flushedOk && pendingAcks.length > 0) {
21173
+ for (const ack of pendingAcks) {
21174
+ notificationState.recordNoticeWritten(String(ack.seq), ack.sessionId, [{ id: String(ack.seq) }]);
21175
+ writeAck(agentBaseDir, task.contextKey, ack.seq);
21176
+ }
21177
+ pendingAcks.length = 0;
21178
+ }
21179
+ if (flushedOk || apmState.pendingMessages.length === 0) {
21180
+ for (const steeredId of pendingSteeredTasks) {
21181
+ client.completeTask(token, steeredId, { output: "" }).catch((e) => {
21182
+ log8.debug(`steering: failed to complete steered task ${steeredId}`, e);
21183
+ });
21184
+ }
21185
+ pendingSteeredTasks.clear();
21186
+ }
21187
+ turnState.markTurnCompleted();
21188
+ break;
21189
+ }
21190
+ }
21191
+ }
21192
+ } catch (err) {
21193
+ log8.warn("steering: consumeParsedEvents error", { err: err instanceof Error ? err.message : String(err) });
21194
+ }
21195
+ };
21196
+ consumeParsedEvents().catch((err) => {
21197
+ log8.error("steering: consumeParsedEvents unhandled error", { err: err instanceof Error ? err.message : String(err) });
21198
+ });
21199
+ }
21200
+ stalledRecoveryTimer = setInterval(() => {
21201
+ if (killed)
21202
+ return;
21203
+ if (!hasReceivedProgressEvent) {
21204
+ const startupResult = reduceApmStartupTimeoutTermination(apmState, {
21205
+ hasRuntimeProgressEvent: hasReceivedProgressEvent
21206
+ });
21207
+ apmState = startupResult.nextState;
21208
+ if (startupResult.shouldTerminate) {
21209
+ log8.warn("steering: startup timeout — no progress events received, killing agent");
21210
+ if (agentPid !== undefined)
21211
+ killProcessTree(agentPid);
21212
+ return;
21213
+ }
21214
+ }
21215
+ const staleForMs = progressState.ageMs();
21216
+ if (staleForMs > STALLED_THRESHOLD_MS && !progressState.isStale) {
21217
+ progressState.markStale();
21218
+ }
21219
+ const stalledResult = reduceApmStalledRecoveryTermination(apmState, {
21220
+ inboxLength: apmState.pendingMessages.length,
21221
+ staleForMs,
21222
+ staleThresholdMs: STALLED_THRESHOLD_MS,
21223
+ runtimeProgressIsStale: progressState.isStale,
21224
+ hasSession: !!earlySessionId,
21225
+ busyDeliveryMode: descriptor?.busyDeliveryMode ?? "none",
21226
+ hasDirectStdinRecoveryEvidence: false
21227
+ });
21228
+ apmState = stalledResult.nextState;
21229
+ if (stalledResult.shouldTerminate) {
21230
+ log8.warn(`steering: stalled recovery — agent stale for ${(staleForMs / 1000).toFixed(1)}s with ${apmState.pendingMessages.length} pending messages, killing`);
21231
+ if (agentPid !== undefined)
21232
+ killProcessTree(agentPid);
21233
+ }
21234
+ }, STALLED_CHECK_INTERVAL_MS);
21235
+ mailboxWatcher = watchInbox(agentBaseDir, task.contextKey, (seq2, message2) => {
21236
+ const sessionId = earlySessionId || "";
21237
+ if (notificationState.isDuplicateNotice(String(seq2), sessionId)) {
21238
+ writeAck(agentBaseDir, task.contextKey, seq2);
21239
+ cleanupInboxFile(agentBaseDir, task.contextKey, seq2);
21240
+ return;
21241
+ }
21242
+ const busyMode = session2.descriptor?.busyDeliveryMode;
21243
+ let delivered = false;
21244
+ if (busyMode === "direct" && session2.send) {
21245
+ const result2 = session2.send(message2.text, turnState.isInTurn ? "busy" : "idle");
21246
+ if (result2.ok) {
21247
+ notificationState.recordNoticeWritten(String(seq2), sessionId, [{ id: String(seq2) }]);
21248
+ writeAck(agentBaseDir, task.contextKey, seq2);
21249
+ delivered = true;
21250
+ } else {
21251
+ writeNack(agentBaseDir, task.contextKey, seq2, result2.reason || "send failed");
21252
+ }
21253
+ } else if (busyMode === "gated") {
21254
+ const enqueueResult = reduceApmGatedEnqueue(apmState, message2.text);
21255
+ apmState = enqueueResult.nextState;
21256
+ if (turnState.canSteerBusy && session2.send && apmState.pendingMessages.length > 0) {
21257
+ const readiness = reduceApmGatedFlushReadiness(apmState, {
21258
+ isGated: true,
21259
+ hasSession: !!earlySessionId,
21260
+ inboxLength: apmState.pendingMessages.length,
21261
+ reason: "enqueue"
21262
+ });
21263
+ if (readiness.shouldNotify) {
21264
+ let allSent = true;
21265
+ for (const msg of apmState.pendingMessages) {
21266
+ const sendResult = session2.send(msg, "busy");
21267
+ if (!sendResult.ok) {
21268
+ allSent = false;
21269
+ break;
21270
+ }
21271
+ }
21272
+ if (allSent) {
21273
+ apmState = { ...apmState, pendingMessages: [] };
21274
+ }
21275
+ }
21276
+ }
21277
+ if (apmState.pendingMessages.length === 0) {
21278
+ notificationState.recordNoticeWritten(String(seq2), sessionId, [{ id: String(seq2) }]);
21279
+ writeAck(agentBaseDir, task.contextKey, seq2);
21280
+ } else {
21281
+ pendingAcks.push({ seq: seq2, sessionId });
21282
+ }
21283
+ delivered = true;
21284
+ } else {
21285
+ writeNack(agentBaseDir, task.contextKey, seq2, "unsupported backend");
21286
+ }
21287
+ if (delivered && message2.taskId) {
21288
+ pendingSteeredTasks.add(message2.taskId);
21289
+ client.startTask(token, message2.taskId).catch((e) => {
21290
+ log8.debug(`steering: failed to start steered task ${message2.taskId}`, e);
21291
+ });
21292
+ }
21293
+ cleanupInboxFile(agentBaseDir, task.contextKey, seq2);
21294
+ });
21295
+ }
19155
21296
  const INACTIVITY_TIMEOUT_MS = messageInactivityTimeout ?? 5 * 60 * 1000;
19156
21297
  let inactivityTimedOut = false;
19157
21298
  try {
@@ -19167,7 +21308,7 @@ async function runSession(input) {
19167
21308
  ]) : next);
19168
21309
  if (raceResult === "timeout") {
19169
21310
  inactivityTimedOut = true;
19170
- log5.warn(`message inactivity timeout (${INACTIVITY_TIMEOUT_MS / 1000}s) — killing agent`);
21311
+ log8.warn(`message inactivity timeout (${INACTIVITY_TIMEOUT_MS / 1000}s) — killing agent`);
19171
21312
  if (session2.pid !== undefined) {
19172
21313
  await killProcessTree(session2.pid);
19173
21314
  }
@@ -19182,9 +21323,9 @@ async function runSession(input) {
19182
21323
  if (msg.type === "tool-use")
19183
21324
  toolCount++;
19184
21325
  if (msg.type === "tool-result" && msg.output && msg.output.length > 500) {
19185
- log5.info(JSON.stringify({ role: "assistant", ...msg, output: msg.output.slice(0, 500) + `... (${msg.output.length} chars)` }));
21326
+ log8.info(JSON.stringify({ role: "assistant", ...msg, output: msg.output.slice(0, 500) + `... (${msg.output.length} chars)` }));
19186
21327
  } else {
19187
- log5.info(JSON.stringify({ role: "assistant", ...msg }));
21328
+ log8.info(JSON.stringify({ role: "assistant", ...msg }));
19188
21329
  }
19189
21330
  if (msg.type === "status" || msg.type === "log")
19190
21331
  continue;
@@ -19223,6 +21364,13 @@ async function runSession(input) {
19223
21364
  result.status = "failed";
19224
21365
  result.error = `message inactivity timeout (no messages for ${INACTIVITY_TIMEOUT_MS / 1000}s)`;
19225
21366
  }
21367
+ if (stalledRecoveryTimer)
21368
+ clearInterval(stalledRecoveryTimer);
21369
+ if (mailboxWatcher) {
21370
+ mailboxWatcher.stop();
21371
+ if (task.contextKey)
21372
+ cleanupSteeringDir(agentBaseDir, task.contextKey);
21373
+ }
19226
21374
  await cleanupAttachments(task.id);
19227
21375
  if (result.status === "completed") {
19228
21376
  updateEntry(timelineDir, task.id, (entry) => {
@@ -19245,18 +21393,18 @@ async function runSession(input) {
19245
21393
  body.session_id = result.sessionId;
19246
21394
  await reportToServer(() => client.completeTask(token, task.id, body), { taskId: task.id, type: "complete", payload: body, token, serverURL, createdAt: new Date().toISOString() }, workspacesRoot);
19247
21395
  const dur = (result.durationMs / 1000).toFixed(1);
19248
- log5.info(`completed (duration=${dur}s, messages=${seq}, tools=${toolCount})`);
21396
+ log8.info(`completed (duration=${dur}s, messages=${seq}, tools=${toolCount})`);
19249
21397
  } else {
19250
21398
  const errorMsg = result.error || "agent exited unexpectedly";
19251
21399
  await reportToServer(() => client.failTask(token, task.id, errorMsg), { taskId: task.id, type: "fail", payload: { error: errorMsg }, token, serverURL, createdAt: new Date().toISOString() }, workspacesRoot);
19252
21400
  const dur = (result.durationMs / 1000).toFixed(1);
19253
- log5.info(`failed (duration=${dur}s, messages=${seq}, tools=${toolCount}) — ${result.error}`);
21401
+ log8.info(`failed (duration=${dur}s, messages=${seq}, tools=${toolCount}) — ${result.error}`);
19254
21402
  }
19255
21403
  }
19256
21404
  async function main() {
19257
21405
  const encoded = process.argv[2];
19258
21406
  if (!encoded) {
19259
- log5.error("session-runner: missing base64-encoded input argument");
21407
+ log8.error("session-runner: missing base64-encoded input argument");
19260
21408
  process.exit(1);
19261
21409
  }
19262
21410
  let input;
@@ -19264,14 +21412,14 @@ async function main() {
19264
21412
  const json2 = Buffer.from(encoded, "base64").toString("utf-8");
19265
21413
  input = JSON.parse(json2);
19266
21414
  } catch (e) {
19267
- log5.error("session-runner: failed to parse input", e);
21415
+ log8.error("session-runner: failed to parse input", e);
19268
21416
  process.exit(1);
19269
21417
  }
19270
21418
  const client = new DaemonClient(input.serverURL);
19271
21419
  try {
19272
21420
  await runSession(input);
19273
21421
  } catch (e) {
19274
- log5.error(`session-runner: unhandled error for task ${input.task.id}`, e);
21422
+ log8.error(`session-runner: unhandled error for task ${input.task.id}`, e);
19275
21423
  await cleanupAttachments(input.task.id);
19276
21424
  const timelineDir = path.join(input.workspacesRoot, input.task.workspaceId, input.task.agentId, "workdir", ".context_timeline").replace(/\\/g, "/");
19277
21425
  updateEntry(timelineDir, input.task.id, (entry) => {