@seele00/seele 0.1.60

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.
Files changed (129) hide show
  1. package/LEGAL.md +7 -0
  2. package/README.md +76 -0
  3. package/bin/seele-codex +58 -0
  4. package/codex/dist/app-server.js +63 -0
  5. package/codex/dist/errors.js +16 -0
  6. package/codex/dist/index.js +4 -0
  7. package/codex/dist/rpc-client.js +96 -0
  8. package/codex/dist/transports/stdio.js +81 -0
  9. package/codex/dist/types.js +1 -0
  10. package/codex/package.json +12 -0
  11. package/package.json +24 -0
  12. package/scripts/deploy/bootstrap.sh +318 -0
  13. package/scripts/deploy/npm/postinstall.mjs +10 -0
  14. package/scripts/deploy/prepare-proxy.sh +273 -0
  15. package/scripts/deploy/seele.env.example +75 -0
  16. package/scripts/deploy/start.sh +101 -0
  17. package/server/dist/auth/session.js +71 -0
  18. package/server/dist/auth/users.js +192 -0
  19. package/server/dist/codex-runtime/run-streamed-turn.js +587 -0
  20. package/server/dist/config/config.js +71 -0
  21. package/server/dist/contracts/artifact-rendering.js +14 -0
  22. package/server/dist/contracts/global-environment.js +23 -0
  23. package/server/dist/contracts/index.js +114 -0
  24. package/server/dist/contracts/managed-assets.js +13 -0
  25. package/server/dist/contracts/response-style.js +23 -0
  26. package/server/dist/contracts/task-clarification.js +13 -0
  27. package/server/dist/contracts/types.js +1 -0
  28. package/server/dist/contracts/wakeup.js +13 -0
  29. package/server/dist/contracts/workspace-boundary.js +20 -0
  30. package/server/dist/contracts/workspace-knowledge.js +48 -0
  31. package/server/dist/contracts/workspace-memory.js +32 -0
  32. package/server/dist/contracts/workspace-responsibility.js +23 -0
  33. package/server/dist/contracts/workspace-transcript.js +26 -0
  34. package/server/dist/conversations/knowledge.js +380 -0
  35. package/server/dist/conversations/store.js +2376 -0
  36. package/server/dist/doctor.js +105 -0
  37. package/server/dist/realtime/sse.js +12 -0
  38. package/server/dist/runtime-worker/client.js +405 -0
  39. package/server/dist/runtime-worker/process.js +216 -0
  40. package/server/dist/runtime-worker/protocol.js +1 -0
  41. package/server/dist/server.js +4570 -0
  42. package/server/dist/storage/sqlite.js +39 -0
  43. package/web/dist/assets/abnfDiagram-VRR7QNED-DevTexTl.js +1 -0
  44. package/web/dist/assets/arc-WlXuN6B_.js +1 -0
  45. package/web/dist/assets/architectureDiagram-ZJ3FMSHR-DJYRAqSp.js +36 -0
  46. package/web/dist/assets/bash-BELqPA7S.js +1 -0
  47. package/web/dist/assets/blockDiagram-677ZJIJ3-CsjO1oTv.js +132 -0
  48. package/web/dist/assets/c4Diagram-LMCZKHZV-DjUCYgVk.js +10 -0
  49. package/web/dist/assets/channel-DGnywxBx.js +1 -0
  50. package/web/dist/assets/chunk-2Q5K7J3B-By6S-6eo.js +1 -0
  51. package/web/dist/assets/chunk-32BRIVSS-Cl-hXbZD.js +1 -0
  52. package/web/dist/assets/chunk-5VM5RSS4--cWPnxlT.js +15 -0
  53. package/web/dist/assets/chunk-EX3LRPZG-PakDrWLX.js +231 -0
  54. package/web/dist/assets/chunk-JWPE2WC7-DMfuuvGl.js +1 -0
  55. package/web/dist/assets/chunk-MOJQB5TN-BHD_IRop.js +88 -0
  56. package/web/dist/assets/chunk-RYQCIY6F-T4jqSvsD.js +1 -0
  57. package/web/dist/assets/chunk-V7JOEXUC-C4paE6t8.js +206 -0
  58. package/web/dist/assets/chunk-VR4S4FIN-F5foapWH.js +1 -0
  59. package/web/dist/assets/chunk-XXDRQBXY-Dp4WIFPJ.js +1 -0
  60. package/web/dist/assets/classDiagram-OUVF2IWQ-DjHXtkKr.js +1 -0
  61. package/web/dist/assets/classDiagram-v2-EOCWNBFH-DjHXtkKr.js +1 -0
  62. package/web/dist/assets/core-CGjsG6g4.js +12 -0
  63. package/web/dist/assets/cose-bilkent-JH36ORCC-DcMU2oKv.js +1 -0
  64. package/web/dist/assets/css-CLj8gQPS.js +1 -0
  65. package/web/dist/assets/cynefin-VYW2F7L2-SiDUbAfJ.js +178 -0
  66. package/web/dist/assets/cynefinDiagram-TSTJHNR4-DhkNlW7i.js +62 -0
  67. package/web/dist/assets/cytoscape.esm-DTSO7Bv0.js +331 -0
  68. package/web/dist/assets/dagre-VKFMJZFB-Co--CY4-.js +4 -0
  69. package/web/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  70. package/web/dist/assets/diagram-FQU43EPY-BZs6G_Wi.js +3 -0
  71. package/web/dist/assets/diagram-G47NLZAW-C6SAe39v.js +24 -0
  72. package/web/dist/assets/diagram-NH7WQ7WH-D6EoRzQM.js +24 -0
  73. package/web/dist/assets/diagram-OA4YK3LP-kHe4KJ_b.js +30 -0
  74. package/web/dist/assets/diagram-WEI45ONY-BM-NnNEq.js +41 -0
  75. package/web/dist/assets/diff-D97Zzqfu.js +1 -0
  76. package/web/dist/assets/dockerfile-BcOcwvcX.js +1 -0
  77. package/web/dist/assets/ebnfDiagram-CCIWWBDH-BfwqR7DU.js +1 -0
  78. package/web/dist/assets/engine-javascript-DBd1bXLz.js +141 -0
  79. package/web/dist/assets/erDiagram-Q63AITRT-BwUkv7nL.js +85 -0
  80. package/web/dist/assets/flowDiagram-23GEKE2U-Cn0zH9bm.js +156 -0
  81. package/web/dist/assets/ganttDiagram-NO4QXBWP-BY_VLaEQ.js +292 -0
  82. package/web/dist/assets/gitGraphDiagram-IHSO6WYX-D0xpVnfm.js +106 -0
  83. package/web/dist/assets/github-light-DAi9KRSo.js +1 -0
  84. package/web/dist/assets/graph-C9eacEi8.js +1 -0
  85. package/web/dist/assets/html-pp8916En.js +1 -0
  86. package/web/dist/assets/index-Bl4JO4M7.css +1 -0
  87. package/web/dist/assets/index-D9Ao6WQl.js +111 -0
  88. package/web/dist/assets/infoDiagram-FWYZ7A6U-DnmnPGAH.js +2 -0
  89. package/web/dist/assets/init-Gi6I4Gst.js +1 -0
  90. package/web/dist/assets/ishikawaDiagram-FXEZZL3T-DTWLm3ZQ.js +70 -0
  91. package/web/dist/assets/java-CylS5w8V.js +1 -0
  92. package/web/dist/assets/javascript-wDzz0qaB.js +1 -0
  93. package/web/dist/assets/journeyDiagram-5HDEW3XC-RN13a5iK.js +139 -0
  94. package/web/dist/assets/json-Cp-IABpG.js +1 -0
  95. package/web/dist/assets/jsonc-Des-eS-w.js +1 -0
  96. package/web/dist/assets/jsx-g9-lgVsj.js +1 -0
  97. package/web/dist/assets/kanban-definition-HUTT4EX6-CvmlJTH9.js +89 -0
  98. package/web/dist/assets/katex-C5jXJg4s.js +257 -0
  99. package/web/dist/assets/layout-DEXfKzaS.js +1 -0
  100. package/web/dist/assets/linear-zHsglUI0.js +1 -0
  101. package/web/dist/assets/map-Czzmt4hB.js +1 -0
  102. package/web/dist/assets/markdown-Cvjx9yec.js +1 -0
  103. package/web/dist/assets/mermaid.core-Bfj9YagN.js +314 -0
  104. package/web/dist/assets/mindmap-definition-LN4V7U3C-CkcLeMWS.js +96 -0
  105. package/web/dist/assets/ordinal-Cboi1Yqb.js +1 -0
  106. package/web/dist/assets/pegDiagram-2B236MQR-eturQJg0.js +1 -0
  107. package/web/dist/assets/pieDiagram-ENE6RG2P-DJmmSZSO.js +39 -0
  108. package/web/dist/assets/python-B6aJPvgy.js +1 -0
  109. package/web/dist/assets/quadrantDiagram-ABIIQ3AL-Br5y_5ZO.js +7 -0
  110. package/web/dist/assets/railroadDiagram-RFXS5EU6-DwnwvUqm.js +1 -0
  111. package/web/dist/assets/requirementDiagram-TGXJPOKE-CMMKGrPQ.js +84 -0
  112. package/web/dist/assets/sankeyDiagram-HTMAVEWB-BKP-cLrV.js +40 -0
  113. package/web/dist/assets/sequenceDiagram-DBY2YBRQ-YgkgEj_6.js +162 -0
  114. package/web/dist/assets/sizeCapture-X5ZJPWSS-nkigHDeZ.js +1 -0
  115. package/web/dist/assets/sql-CRqJ_cUM.js +1 -0
  116. package/web/dist/assets/stateDiagram-2N3HPSRC-CEoMK2Kt.js +1 -0
  117. package/web/dist/assets/stateDiagram-v2-6OUMAXLB--iEtUEGo.js +1 -0
  118. package/web/dist/assets/swimlanes-5IMT3BWC-Co9CmBP_.js +2 -0
  119. package/web/dist/assets/swimlanesDiagram-G3AALYLV-BzapPKvi.js +8 -0
  120. package/web/dist/assets/timeline-definition-FHXFAJF6-C5njALNw.js +120 -0
  121. package/web/dist/assets/toml-vGWfd6FD.js +1 -0
  122. package/web/dist/assets/tsx-COt5Ahok.js +1 -0
  123. package/web/dist/assets/typescript-BPQ3VLAy.js +1 -0
  124. package/web/dist/assets/vennDiagram-L72KCM5P-BpvLQRHS.js +34 -0
  125. package/web/dist/assets/wardleyDiagram-EHGQE667-CWINCOno.js +78 -0
  126. package/web/dist/assets/xml-sdJ4AIDG.js +1 -0
  127. package/web/dist/assets/xychartDiagram-FW5EYKEG-xDH3ABG4.js +7 -0
  128. package/web/dist/assets/yaml-Buea-lGh.js +1 -0
  129. package/web/dist/index.html +13 -0
@@ -0,0 +1,105 @@
1
+ import { constants as fsConstants } from "node:fs";
2
+ import fs from "node:fs/promises";
3
+ import { loadConfig } from "./config/config.js";
4
+ import { UserStore } from "./auth/users.js";
5
+ import { getConversationStoreDiagnostics, initializeConversationStore, } from "./conversations/store.js";
6
+ const config = loadConfig();
7
+ const users = new UserStore(config.centerDbPath, {
8
+ username: config.authUsername,
9
+ password: config.authPassword,
10
+ });
11
+ let store = null;
12
+ let initializationError = null;
13
+ try {
14
+ initializeConversationStore({
15
+ centerDbPath: config.centerDbPath,
16
+ workspaceRoot: config.workspaceRoot,
17
+ defaultSandbox: config.defaultSandbox,
18
+ defaultOwnerId: users.listUsers().find((user) => user.role === "admin")?.id ?? "local-admin",
19
+ });
20
+ store = getConversationStoreDiagnostics();
21
+ }
22
+ catch (error) {
23
+ initializationError = error instanceof Error ? error.message : String(error);
24
+ }
25
+ const paths = {
26
+ seeleRoot: await checkPath(config.seeleRoot),
27
+ workspaceRoot: await checkPath(config.workspaceRoot),
28
+ webDistPath: await checkPath(config.webDistPath, { requireWrite: false }),
29
+ };
30
+ const centerDbOk = store !== null &&
31
+ store.centerSchemaVersion === store.expectedCenterSchemaVersion;
32
+ const workspaceSchemasOk = store !== null && store.workspaceDatabases.every((workspace) => workspace.schemaVersion === store.expectedWorkspaceSchemaVersion);
33
+ const pathsOk = Object.values(paths).every((check) => check.ok);
34
+ const ok = initializationError === null && centerDbOk && workspaceSchemasOk && pathsOk;
35
+ const report = {
36
+ ok,
37
+ config: {
38
+ seeleRoot: config.seeleRoot,
39
+ centerDbPath: config.centerDbPath,
40
+ workspaceRoot: config.workspaceRoot,
41
+ defaultSandbox: config.defaultSandbox,
42
+ defaultModel: config.defaultModel ?? null,
43
+ codexBin: config.codexBin ?? null,
44
+ },
45
+ checks: {
46
+ initialization: {
47
+ ok: initializationError === null,
48
+ error: initializationError,
49
+ },
50
+ centerDb: {
51
+ ok: centerDbOk,
52
+ schemaVersion: store?.centerSchemaVersion ?? null,
53
+ expected: store?.expectedCenterSchemaVersion ?? null,
54
+ },
55
+ workspaceSchemas: {
56
+ ok: workspaceSchemasOk,
57
+ expected: store?.expectedWorkspaceSchemaVersion ?? null,
58
+ workspaces: (store?.workspaceDatabases ?? []).map((workspace) => ({
59
+ id: workspace.id,
60
+ title: workspace.title,
61
+ schemaVersion: workspace.schemaVersion,
62
+ messages: workspace.messages,
63
+ events: workspace.events,
64
+ turns: workspace.turns,
65
+ })),
66
+ },
67
+ paths,
68
+ },
69
+ summary: {
70
+ workspaces: store?.workspaces ?? 0,
71
+ groups: store?.groups ?? 0,
72
+ activeConversations: store?.activeConversations ?? 0,
73
+ },
74
+ };
75
+ console.log(JSON.stringify(report, null, 2));
76
+ process.exitCode = ok ? 0 : 1;
77
+ async function checkPath(targetPath, options = {}) {
78
+ const requireWrite = options.requireWrite ?? true;
79
+ let readable = false;
80
+ let writable = requireWrite ? false : null;
81
+ let error = null;
82
+ try {
83
+ await fs.access(targetPath, fsConstants.R_OK);
84
+ readable = true;
85
+ }
86
+ catch (accessError) {
87
+ error = accessError instanceof Error ? accessError.message : String(accessError);
88
+ }
89
+ if (requireWrite) {
90
+ try {
91
+ await fs.access(targetPath, fsConstants.W_OK);
92
+ writable = true;
93
+ }
94
+ catch (accessError) {
95
+ error = accessError instanceof Error ? accessError.message : String(accessError);
96
+ }
97
+ }
98
+ return {
99
+ ok: readable && (writable ?? true),
100
+ path: targetPath,
101
+ readable,
102
+ writable,
103
+ error,
104
+ };
105
+ }
@@ -0,0 +1,12 @@
1
+ export function openSse(response) {
2
+ response.writeHead(200, {
3
+ "Content-Type": "text/event-stream",
4
+ "Cache-Control": "no-cache, no-transform",
5
+ Connection: "keep-alive",
6
+ "X-Accel-Buffering": "no",
7
+ });
8
+ }
9
+ export function sendSse(response, event, data) {
10
+ response.write(`event: ${event}\n`);
11
+ response.write(`data: ${JSON.stringify(data)}\n\n`);
12
+ }
@@ -0,0 +1,405 @@
1
+ import { fork } from "node:child_process";
2
+ import { randomUUID } from "node:crypto";
3
+ import { fileURLToPath } from "node:url";
4
+ const WORKER_HARD_KILL_AFTER_MS = 5_000;
5
+ const WORKER_STALE_AFTER_MS = 45_000;
6
+ export class RuntimeWorkerClient {
7
+ handlers;
8
+ workers = new Map();
9
+ pendingThreadReads = new Map();
10
+ pendingThreadRebuilds = new Map();
11
+ pendingModelLists = new Map();
12
+ pendingRateLimitReads = new Map();
13
+ constructor(handlers) {
14
+ this.handlers = handlers;
15
+ }
16
+ getDiagnostics() {
17
+ const now = Date.now();
18
+ const workers = [...this.workers.entries()]
19
+ .map(([turnId, entry]) => ({
20
+ turnId,
21
+ pid: entry.process.pid ?? null,
22
+ state: entry.state,
23
+ uptimeMs: Math.max(0, now - entry.startedAt),
24
+ eventCount: entry.eventCount,
25
+ lastMessageAt: formatTimestamp(entry.lastMessageAt),
26
+ lastEventAt: formatTimestamp(entry.lastEventAt),
27
+ lastHeartbeatAt: formatTimestamp(entry.lastHeartbeatAt),
28
+ stopRequestedAt: formatTimestamp(entry.stopRequestedAt),
29
+ stale: isWorkerStale(entry, now),
30
+ }))
31
+ .sort((left, right) => left.turnId.localeCompare(right.turnId));
32
+ return {
33
+ workerCount: this.workers.size,
34
+ workers,
35
+ turnIds: workers.map((worker) => worker.turnId),
36
+ staleWorkerCount: workers.filter((worker) => worker.stale).length,
37
+ };
38
+ }
39
+ startTurn(turnId, config, request) {
40
+ this.send(turnId, {
41
+ type: "turn.start",
42
+ payload: {
43
+ turnId,
44
+ config,
45
+ request,
46
+ },
47
+ });
48
+ }
49
+ stopTurn(turnId) {
50
+ const entry = this.workers.get(turnId);
51
+ if (entry) {
52
+ entry.state = "stopping";
53
+ entry.stopRequestedAt = Date.now();
54
+ this.scheduleHardKill(turnId, entry);
55
+ }
56
+ this.sendToExisting(turnId, {
57
+ type: "turn.stop",
58
+ payload: { turnId },
59
+ });
60
+ }
61
+ steerTurn(turnId, message) {
62
+ this.sendToExisting(turnId, {
63
+ type: "turn.steer",
64
+ payload: { turnId, message },
65
+ });
66
+ }
67
+ respondApproval(turnId, requestId, decision) {
68
+ this.sendToExisting(turnId, {
69
+ type: "turn.approval.respond",
70
+ payload: { turnId, requestId, decision },
71
+ });
72
+ }
73
+ readThread(config, request) {
74
+ const operationId = `thread-read:${randomUUID()}`;
75
+ return new Promise((resolve, reject) => {
76
+ this.pendingThreadReads.set(operationId, { resolve, reject });
77
+ this.send(operationId, {
78
+ type: "thread.read",
79
+ payload: {
80
+ operationId,
81
+ config,
82
+ request,
83
+ },
84
+ });
85
+ });
86
+ }
87
+ rebuildThread(config, request, injectedItems) {
88
+ const operationId = `thread-rebuild:${randomUUID()}`;
89
+ return new Promise((resolve, reject) => {
90
+ this.pendingThreadRebuilds.set(operationId, { resolve, reject });
91
+ this.send(operationId, {
92
+ type: "thread.rebuild",
93
+ payload: {
94
+ operationId,
95
+ config,
96
+ request,
97
+ injectedItems,
98
+ },
99
+ });
100
+ });
101
+ }
102
+ listModels(config) {
103
+ const operationId = `models-list:${randomUUID()}`;
104
+ return new Promise((resolve, reject) => {
105
+ this.pendingModelLists.set(operationId, { resolve, reject });
106
+ this.send(operationId, {
107
+ type: "runtime.models.list",
108
+ payload: { operationId, config },
109
+ });
110
+ });
111
+ }
112
+ readRateLimits(config) {
113
+ const operationId = `rate-limits-read:${randomUUID()}`;
114
+ return new Promise((resolve, reject) => {
115
+ this.pendingRateLimitReads.set(operationId, { resolve, reject });
116
+ this.send(operationId, {
117
+ type: "runtime.rate_limits.read",
118
+ payload: { operationId, config },
119
+ });
120
+ });
121
+ }
122
+ send(turnId, message) {
123
+ const entry = this.ensureWorker(turnId);
124
+ this.sendToEntry(turnId, entry, message);
125
+ if (message.type === "turn.start" ||
126
+ message.type === "thread.read" ||
127
+ message.type === "thread.rebuild" ||
128
+ message.type === "runtime.models.list" ||
129
+ message.type === "runtime.rate_limits.read") {
130
+ entry.state = "running";
131
+ }
132
+ }
133
+ sendToExisting(turnId, message) {
134
+ const entry = this.workers.get(turnId);
135
+ if (!entry) {
136
+ throw new Error(`runtime worker not found: ${turnId}`);
137
+ }
138
+ this.sendToEntry(turnId, entry, message);
139
+ }
140
+ sendToEntry(turnId, entry, message) {
141
+ if (!entry.process.connected) {
142
+ throw new Error(`runtime worker is not connected: ${turnId}`);
143
+ }
144
+ entry.process.send(message);
145
+ }
146
+ ensureWorker(turnId) {
147
+ const existing = this.workers.get(turnId);
148
+ if (existing?.process.connected) {
149
+ return existing;
150
+ }
151
+ const workerEntry = resolveWorkerEntry();
152
+ const worker = fork(workerEntry.path, [], {
153
+ execArgv: workerEntry.execArgv,
154
+ stdio: ["ignore", "inherit", "inherit", "ipc"],
155
+ });
156
+ const entry = {
157
+ process: worker,
158
+ startedAt: Date.now(),
159
+ state: "starting",
160
+ hardKillTimer: null,
161
+ eventCount: 0,
162
+ lastMessageAt: null,
163
+ lastEventAt: null,
164
+ lastHeartbeatAt: null,
165
+ stopRequestedAt: null,
166
+ };
167
+ this.workers.set(turnId, entry);
168
+ worker.on("message", (message) => {
169
+ this.handleWorkerMessage(message);
170
+ });
171
+ worker.on("exit", (code, signal) => {
172
+ if (this.workers.get(turnId)?.process === worker) {
173
+ const state = this.workers.get(turnId)?.state ?? "failed";
174
+ this.workers.delete(turnId);
175
+ this.clearHardKill(entry);
176
+ this.rejectPendingOperation(turnId, new Error(`runtime worker exited: code=${code} signal=${signal}`));
177
+ if (!isRuntimeOperationId(turnId) &&
178
+ state !== "completed" &&
179
+ state !== "failed" &&
180
+ state !== "stopping") {
181
+ this.handlers.onFailed({
182
+ turnId,
183
+ message: `runtime worker exited: code=${code} signal=${signal}`,
184
+ });
185
+ }
186
+ }
187
+ });
188
+ worker.on("error", (error) => {
189
+ if (this.workers.get(turnId)?.process === worker) {
190
+ entry.state = "failed";
191
+ this.workers.delete(turnId);
192
+ this.clearHardKill(entry);
193
+ this.rejectPendingOperation(turnId, error);
194
+ if (!isRuntimeOperationId(turnId)) {
195
+ this.handlers.onFailed({
196
+ turnId,
197
+ message: error.message,
198
+ });
199
+ }
200
+ }
201
+ });
202
+ return entry;
203
+ }
204
+ handleWorkerMessage(message) {
205
+ this.touchWorkerMessage(message);
206
+ if (message.type === "worker.ready") {
207
+ const entry = this.workers.get(message.turnId);
208
+ if (entry && entry.state === "starting") {
209
+ entry.state = "running";
210
+ }
211
+ this.handlers.onEvent({
212
+ turnId: message.turnId,
213
+ event: "runtime.worker_ready",
214
+ data: {},
215
+ });
216
+ return;
217
+ }
218
+ if (message.type === "worker.heartbeat") {
219
+ const entry = this.workers.get(message.turnId);
220
+ if (entry) {
221
+ entry.lastHeartbeatAt = Date.now();
222
+ }
223
+ return;
224
+ }
225
+ if (message.type === "turn.event") {
226
+ const entry = this.workers.get(message.turnId);
227
+ if (entry) {
228
+ entry.eventCount += 1;
229
+ entry.lastEventAt = Date.now();
230
+ }
231
+ this.handlers.onEvent(message);
232
+ return;
233
+ }
234
+ if (message.type === "turn.completed") {
235
+ const entry = this.workers.get(message.turnId);
236
+ if (entry) {
237
+ entry.state = "completed";
238
+ }
239
+ this.forgetWorker(message.turnId);
240
+ this.handlers.onCompleted(message);
241
+ return;
242
+ }
243
+ if (message.type === "turn.failed") {
244
+ const entry = this.workers.get(message.turnId);
245
+ if (entry) {
246
+ entry.state = "failed";
247
+ }
248
+ this.forgetWorker(message.turnId);
249
+ this.handlers.onFailed(message);
250
+ return;
251
+ }
252
+ if (message.type === "turn.worker_error") {
253
+ if (message.turnId) {
254
+ this.handlers.onEvent({
255
+ turnId: message.turnId,
256
+ event: "runtime.worker_error",
257
+ data: { message: message.message },
258
+ });
259
+ }
260
+ }
261
+ if (message.type === "thread.read.completed") {
262
+ const pending = this.pendingThreadReads.get(message.operationId);
263
+ this.pendingThreadReads.delete(message.operationId);
264
+ this.forgetWorker(message.operationId);
265
+ pending?.resolve(message.result);
266
+ return;
267
+ }
268
+ if (message.type === "thread.rebuild.completed") {
269
+ const pending = this.pendingThreadRebuilds.get(message.operationId);
270
+ this.pendingThreadRebuilds.delete(message.operationId);
271
+ this.forgetWorker(message.operationId);
272
+ pending?.resolve(message.result);
273
+ return;
274
+ }
275
+ if (message.type === "runtime.models.list.completed") {
276
+ const pending = this.pendingModelLists.get(message.operationId);
277
+ this.pendingModelLists.delete(message.operationId);
278
+ this.forgetWorker(message.operationId);
279
+ pending?.resolve(message.result);
280
+ return;
281
+ }
282
+ if (message.type === "runtime.rate_limits.read.completed") {
283
+ const pending = this.pendingRateLimitReads.get(message.operationId);
284
+ this.pendingRateLimitReads.delete(message.operationId);
285
+ this.forgetWorker(message.operationId);
286
+ pending?.resolve(message.result);
287
+ return;
288
+ }
289
+ if (message.type === "runtime.operation_failed") {
290
+ const error = new Error(message.message);
291
+ const readPending = this.pendingThreadReads.get(message.operationId);
292
+ if (readPending) {
293
+ this.pendingThreadReads.delete(message.operationId);
294
+ this.forgetWorker(message.operationId);
295
+ readPending.reject(error);
296
+ return;
297
+ }
298
+ const rebuildPending = this.pendingThreadRebuilds.get(message.operationId);
299
+ if (rebuildPending) {
300
+ this.pendingThreadRebuilds.delete(message.operationId);
301
+ this.forgetWorker(message.operationId);
302
+ rebuildPending.reject(error);
303
+ return;
304
+ }
305
+ const modelListPending = this.pendingModelLists.get(message.operationId);
306
+ if (modelListPending) {
307
+ this.pendingModelLists.delete(message.operationId);
308
+ this.forgetWorker(message.operationId);
309
+ modelListPending.reject(error);
310
+ return;
311
+ }
312
+ const rateLimitPending = this.pendingRateLimitReads.get(message.operationId);
313
+ if (rateLimitPending) {
314
+ this.pendingRateLimitReads.delete(message.operationId);
315
+ this.forgetWorker(message.operationId);
316
+ rateLimitPending.reject(error);
317
+ }
318
+ }
319
+ }
320
+ forgetWorker(turnId) {
321
+ const entry = this.workers.get(turnId);
322
+ if (entry) {
323
+ this.clearHardKill(entry);
324
+ }
325
+ this.workers.delete(turnId);
326
+ }
327
+ rejectPendingOperation(operationId, error) {
328
+ const readPending = this.pendingThreadReads.get(operationId);
329
+ if (readPending) {
330
+ this.pendingThreadReads.delete(operationId);
331
+ readPending.reject(error);
332
+ }
333
+ const rebuildPending = this.pendingThreadRebuilds.get(operationId);
334
+ if (rebuildPending) {
335
+ this.pendingThreadRebuilds.delete(operationId);
336
+ rebuildPending.reject(error);
337
+ }
338
+ const modelListPending = this.pendingModelLists.get(operationId);
339
+ if (modelListPending) {
340
+ this.pendingModelLists.delete(operationId);
341
+ modelListPending.reject(error);
342
+ }
343
+ const rateLimitPending = this.pendingRateLimitReads.get(operationId);
344
+ if (rateLimitPending) {
345
+ this.pendingRateLimitReads.delete(operationId);
346
+ rateLimitPending.reject(error);
347
+ }
348
+ }
349
+ scheduleHardKill(turnId, entry) {
350
+ if (entry.hardKillTimer) {
351
+ return;
352
+ }
353
+ entry.hardKillTimer = setTimeout(() => {
354
+ if (this.workers.get(turnId) !== entry) {
355
+ return;
356
+ }
357
+ this.handlers.onEvent({
358
+ turnId,
359
+ event: "runtime.worker_hard_kill",
360
+ data: { timeoutMs: WORKER_HARD_KILL_AFTER_MS },
361
+ });
362
+ entry.process.kill("SIGKILL");
363
+ }, WORKER_HARD_KILL_AFTER_MS);
364
+ entry.hardKillTimer.unref?.();
365
+ }
366
+ clearHardKill(entry) {
367
+ if (entry.hardKillTimer) {
368
+ clearTimeout(entry.hardKillTimer);
369
+ entry.hardKillTimer = null;
370
+ }
371
+ }
372
+ touchWorkerMessage(message) {
373
+ if (!("turnId" in message) || !message.turnId) {
374
+ return;
375
+ }
376
+ const entry = this.workers.get(message.turnId);
377
+ if (entry) {
378
+ entry.lastMessageAt = Date.now();
379
+ }
380
+ }
381
+ }
382
+ function isWorkerStale(entry, now) {
383
+ if (entry.state === "stopping") {
384
+ return false;
385
+ }
386
+ const lastSignal = Math.max(entry.startedAt, entry.lastMessageAt ?? 0, entry.lastEventAt ?? 0, entry.lastHeartbeatAt ?? 0);
387
+ return now - lastSignal > WORKER_STALE_AFTER_MS;
388
+ }
389
+ function isRuntimeOperationId(value) {
390
+ return (value.startsWith("thread-read:") ||
391
+ value.startsWith("thread-rebuild:") ||
392
+ value.startsWith("models-list:") ||
393
+ value.startsWith("rate-limits-read:"));
394
+ }
395
+ function formatTimestamp(value) {
396
+ return value === null ? null : new Date(value).toISOString();
397
+ }
398
+ function resolveWorkerEntry() {
399
+ const currentPath = fileURLToPath(import.meta.url);
400
+ const isTypeScriptRuntime = currentPath.endsWith(".ts");
401
+ return {
402
+ path: fileURLToPath(new URL(`./process.${isTypeScriptRuntime ? "ts" : "js"}`, import.meta.url)),
403
+ execArgv: isTypeScriptRuntime ? ["--import", "tsx"] : [],
404
+ };
405
+ }