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