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