@grackle-ai/server 0.66.0 → 0.68.0

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.
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Knowledge graph subsystem initialization and lifecycle management.
3
+ *
4
+ * Wires Neo4j, the local embedder, and event-driven reference node sync
5
+ * into the Grackle server. Opt-in via `GRACKLE_KNOWLEDGE_ENABLED=true`.
6
+ *
7
+ * @module
8
+ */
9
+ import { openNeo4j, initSchema, closeNeo4j, createLocalEmbedder, syncReferenceNode, deleteReferenceNodeBySource, findReferenceNodeBySource, createEdge, deriveTaskText, deriveFindingText, EDGE_TYPE, } from "@grackle-ai/knowledge";
10
+ import { subscribe } from "./event-bus.js";
11
+ import * as taskStore from "./task-store.js";
12
+ import * as findingStore from "./finding-store.js";
13
+ import { safeParseJsonArray } from "./json-helpers.js";
14
+ import { logger } from "./logger.js";
15
+ // ---------------------------------------------------------------------------
16
+ // Configuration
17
+ // ---------------------------------------------------------------------------
18
+ /** Whether the knowledge graph subsystem is enabled. */
19
+ export function isKnowledgeEnabled() {
20
+ return process.env.GRACKLE_KNOWLEDGE_ENABLED === "true";
21
+ }
22
+ /** Module-level embedder, available after initKnowledge() completes. */
23
+ let knowledgeEmbedder;
24
+ /** Get the knowledge embedder. Returns undefined if knowledge is not initialized. */
25
+ export function getKnowledgeEmbedder() {
26
+ return knowledgeEmbedder;
27
+ }
28
+ // ---------------------------------------------------------------------------
29
+ // Event handler
30
+ // ---------------------------------------------------------------------------
31
+ /**
32
+ * Create an event bus subscriber that syncs reference nodes.
33
+ *
34
+ * Sync is fire-and-forget — errors are logged but never propagated.
35
+ */
36
+ function createEntitySyncHandler(embedder) {
37
+ return (event) => {
38
+ // Fire-and-forget async — errors handled inside handleEvent
39
+ handleEvent(embedder, event).catch(() => { });
40
+ };
41
+ }
42
+ /**
43
+ * Ensure a task's reference node exists in the knowledge graph.
44
+ *
45
+ * If the node already exists, returns its ID. Otherwise syncs it from
46
+ * the task store and returns the new ID. Returns `undefined` if the
47
+ * task is not found in the store.
48
+ */
49
+ async function ensureTaskReferenceNode(embedder, taskId) {
50
+ const existing = await findReferenceNodeBySource("task", taskId);
51
+ if (existing) {
52
+ return existing.id;
53
+ }
54
+ const task = taskStore.getTask(taskId);
55
+ if (!task) {
56
+ return undefined;
57
+ }
58
+ return syncReferenceNode(embedder, {
59
+ sourceType: "task",
60
+ sourceId: taskId,
61
+ label: task.title,
62
+ text: deriveTaskText(task.title, task.description),
63
+ workspaceId: task.workspaceId ?? "",
64
+ });
65
+ }
66
+ /**
67
+ * Create edges from a task reference node to its parent and dependencies.
68
+ *
69
+ * Best-effort — edge creation failures are logged but don't block sync.
70
+ */
71
+ async function syncTaskEdges(embedder, taskNodeId, task) {
72
+ // Parent task → PART_OF edge
73
+ if (task.parentTaskId) {
74
+ try {
75
+ const parentNodeId = await ensureTaskReferenceNode(embedder, task.parentTaskId);
76
+ if (parentNodeId) {
77
+ await createEdge(taskNodeId, parentNodeId, EDGE_TYPE.PART_OF);
78
+ }
79
+ }
80
+ catch (err) {
81
+ logger.warn({ taskNodeId, parentTaskId: task.parentTaskId, err }, "Failed to create PART_OF edge");
82
+ }
83
+ }
84
+ // Dependencies → DEPENDS_ON edges
85
+ const deps = safeParseJsonArray(task.dependsOn);
86
+ for (const depId of deps) {
87
+ try {
88
+ const depNodeId = await ensureTaskReferenceNode(embedder, depId);
89
+ if (depNodeId) {
90
+ await createEdge(taskNodeId, depNodeId, EDGE_TYPE.DEPENDS_ON);
91
+ }
92
+ }
93
+ catch (err) {
94
+ logger.warn({ taskNodeId, depId, err }, "Failed to create DEPENDS_ON edge");
95
+ }
96
+ }
97
+ }
98
+ /** Handle a single entity event. */
99
+ async function handleEvent(embedder, event) {
100
+ try {
101
+ const payload = event.payload;
102
+ switch (event.type) {
103
+ case "task.created":
104
+ case "task.updated": {
105
+ const taskId = payload.taskId;
106
+ if (typeof taskId !== "string" || !taskId) {
107
+ return;
108
+ }
109
+ const task = taskStore.getTask(taskId);
110
+ if (!task) {
111
+ logger.warn({ taskId }, "Knowledge sync: task not found, skipping");
112
+ return;
113
+ }
114
+ const taskNodeId = await syncReferenceNode(embedder, {
115
+ sourceType: "task",
116
+ sourceId: taskId,
117
+ label: task.title,
118
+ text: deriveTaskText(task.title, task.description),
119
+ workspaceId: task.workspaceId ?? "",
120
+ });
121
+ await syncTaskEdges(embedder, taskNodeId, task);
122
+ break;
123
+ }
124
+ case "task.deleted": {
125
+ const taskId = payload.taskId;
126
+ if (typeof taskId !== "string" || !taskId) {
127
+ return;
128
+ }
129
+ await deleteReferenceNodeBySource("task", taskId);
130
+ break;
131
+ }
132
+ case "finding.posted": {
133
+ const findingId = payload.findingId;
134
+ if (typeof findingId !== "string" || !findingId) {
135
+ return;
136
+ }
137
+ const workspaceId = typeof payload.workspaceId === "string" ? payload.workspaceId : "";
138
+ const findings = findingStore.queryFindings(workspaceId);
139
+ const finding = findings.find((f) => f.id === findingId);
140
+ if (!finding) {
141
+ logger.warn({ findingId }, "Knowledge sync: finding not found, skipping");
142
+ return;
143
+ }
144
+ const tags = safeParseJsonArray(typeof finding.tags === "string" ? finding.tags : null);
145
+ const findingNodeId = await syncReferenceNode(embedder, {
146
+ sourceType: "finding",
147
+ sourceId: findingId,
148
+ label: finding.title,
149
+ text: deriveFindingText(finding.title, finding.content, tags),
150
+ workspaceId,
151
+ });
152
+ // Link finding to its task
153
+ if (finding.taskId) {
154
+ try {
155
+ const taskNodeId = await ensureTaskReferenceNode(embedder, finding.taskId);
156
+ if (taskNodeId) {
157
+ await createEdge(findingNodeId, taskNodeId, EDGE_TYPE.DERIVED_FROM);
158
+ }
159
+ }
160
+ catch (err) {
161
+ logger.warn({ findingNodeId, taskId: finding.taskId, err }, "Failed to create DERIVED_FROM edge");
162
+ }
163
+ }
164
+ break;
165
+ }
166
+ default:
167
+ // Ignore events we don't handle
168
+ break;
169
+ }
170
+ }
171
+ catch (err) {
172
+ logger.error({ err, eventType: event.type, eventId: event.id }, "Knowledge sync failed for entity event");
173
+ }
174
+ }
175
+ // ---------------------------------------------------------------------------
176
+ // Lifecycle
177
+ // ---------------------------------------------------------------------------
178
+ /**
179
+ * Initialize the knowledge graph subsystem.
180
+ *
181
+ * Opens Neo4j, initializes the schema, creates the local embedder,
182
+ * injects it into MCP tools, and subscribes to the event bus for
183
+ * automatic reference node sync.
184
+ *
185
+ * If any step after Neo4j connection fails, cleans up the connection
186
+ * before re-throwing.
187
+ *
188
+ * @returns A cleanup function that closes Neo4j and unsubscribes from events.
189
+ */
190
+ export async function initKnowledge() {
191
+ logger.info("Initializing knowledge graph subsystem");
192
+ await openNeo4j();
193
+ try {
194
+ await initSchema();
195
+ const embedder = createLocalEmbedder();
196
+ knowledgeEmbedder = embedder;
197
+ const unsubscribe = subscribe(createEntitySyncHandler(embedder));
198
+ logger.info("Knowledge graph subsystem ready");
199
+ return async () => {
200
+ logger.info("Shutting down knowledge graph subsystem");
201
+ unsubscribe();
202
+ knowledgeEmbedder = undefined;
203
+ await closeNeo4j();
204
+ logger.info("Knowledge graph subsystem stopped");
205
+ };
206
+ }
207
+ catch (err) {
208
+ // Clean up Neo4j if a later step fails
209
+ knowledgeEmbedder = undefined;
210
+ await closeNeo4j().catch(() => { });
211
+ throw err;
212
+ }
213
+ }
214
+ //# sourceMappingURL=knowledge-init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge-init.js","sourceRoot":"","sources":["../src/knowledge-init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { PowerLineConnection } from "@grackle-ai/adapter-sdk";
2
+ /**
3
+ * Recover disconnected sessions for a newly reconnected environment.
4
+ *
5
+ * Finds sessions in SUSPENDED, RUNNING, or IDLE state (RUNNING/IDLE handles
6
+ * the "server died" scenario where sessions never got suspended). Drains
7
+ * buffered events from PowerLine, writes them to the session JSONL, then
8
+ * reanimates the first recoverable session. Remaining sessions are left
9
+ * SUSPENDED for later recovery (only one active session per environment).
10
+ *
11
+ * Fire-and-forget: logs errors but does not throw.
12
+ */
13
+ export declare function recoverSuspendedSessions(environmentId: string, connection: PowerLineConnection): Promise<void>;
14
+ /** @internal Reset the recovery lock for testing. */
15
+ export declare function _resetForTesting(): void;
16
+ //# sourceMappingURL=session-recovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-recovery.d.ts","sourceRoot":"","sources":["../src/session-recovery.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAanE;;;;;;;;;;GAUG;AACH,wBAAsB,wBAAwB,CAC5C,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,mBAAmB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA6Ff;AAWD,qDAAqD;AACrD,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC"}
@@ -0,0 +1,115 @@
1
+ import { create } from "@bufbuild/protobuf";
2
+ import { grackle, powerline, eventTypeToEnum, SESSION_STATUS, LOGS_DIR } from "@grackle-ai/common";
3
+ import { join } from "node:path";
4
+ import * as sessionStore from "./session-store.js";
5
+ import * as taskStore from "./task-store.js";
6
+ import * as logWriter from "./log-writer.js";
7
+ import { reanimateAgent } from "./reanimate-agent.js";
8
+ import { grackleHome } from "./paths.js";
9
+ import { logger } from "./logger.js";
10
+ import { emit } from "./event-bus.js";
11
+ /** Set of environment IDs currently undergoing recovery to prevent concurrent attempts. */
12
+ const recoveringEnvironments = new Set();
13
+ /**
14
+ * Recover disconnected sessions for a newly reconnected environment.
15
+ *
16
+ * Finds sessions in SUSPENDED, RUNNING, or IDLE state (RUNNING/IDLE handles
17
+ * the "server died" scenario where sessions never got suspended). Drains
18
+ * buffered events from PowerLine, writes them to the session JSONL, then
19
+ * reanimates the first recoverable session. Remaining sessions are left
20
+ * SUSPENDED for later recovery (only one active session per environment).
21
+ *
22
+ * Fire-and-forget: logs errors but does not throw.
23
+ */
24
+ export async function recoverSuspendedSessions(environmentId, connection) {
25
+ if (recoveringEnvironments.has(environmentId)) {
26
+ logger.warn({ environmentId }, "Recovery already in progress — skipping");
27
+ return;
28
+ }
29
+ // Find sessions that need recovery: SUSPENDED (normal path) plus
30
+ // RUNNING/IDLE (server-died path where sessions were never suspended).
31
+ const suspended = sessionStore.getSuspendedForEnv(environmentId);
32
+ const active = sessionStore.getActiveForEnv(environmentId);
33
+ // Transition any stale active session to SUSPENDED first so reanimate accepts it.
34
+ if (active) {
35
+ sessionStore.suspendSession(active.id);
36
+ suspended.unshift(active);
37
+ }
38
+ if (suspended.length === 0) {
39
+ return;
40
+ }
41
+ recoveringEnvironments.add(environmentId);
42
+ logger.info({ environmentId, count: suspended.length }, "Beginning recovery of suspended sessions");
43
+ try {
44
+ // Only reanimate the first session — the one-active-session-per-env
45
+ // constraint means subsequent sessions would fail. Leave the rest
46
+ // SUSPENDED for manual reanimate or future recovery.
47
+ const session = suspended[0];
48
+ try {
49
+ // Step 1: Drain buffered events from PowerLine and append to JSONL
50
+ const logPath = session.logPath || join(grackleHome, LOGS_DIR, session.id);
51
+ const drainReq = create(powerline.DrainRequestSchema, {
52
+ sessionId: session.id,
53
+ });
54
+ let drainedCount = 0;
55
+ try {
56
+ const drainStream = connection.client.drainBufferedEvents(drainReq);
57
+ logWriter.ensureLogInitialized(logPath);
58
+ for await (const event of drainStream) {
59
+ // Skip internal events (e.g. runtime_session_id) that would map
60
+ // to UNSPECIFIED — those are handled by processEventStream, not the drain.
61
+ const eventType = eventTypeToEnum(event.type);
62
+ if (eventType === grackle.EventType.UNSPECIFIED) {
63
+ continue;
64
+ }
65
+ const sessionEvent = create(grackle.SessionEventSchema, {
66
+ sessionId: session.id,
67
+ type: eventType,
68
+ timestamp: event.timestamp,
69
+ content: event.content,
70
+ raw: event.raw,
71
+ });
72
+ logWriter.writeEvent(logPath, sessionEvent);
73
+ drainedCount++;
74
+ }
75
+ }
76
+ catch (drainErr) {
77
+ // Drain may fail if PowerLine was restarted (no parked events).
78
+ // This is expected — continue to reanimate anyway.
79
+ logger.info({ sessionId: session.id, err: drainErr }, "Drain returned no buffered events (PowerLine may have restarted)");
80
+ }
81
+ finally {
82
+ // Always close the log stream to avoid leaking file descriptors.
83
+ logWriter.endSession(logPath);
84
+ }
85
+ if (drainedCount > 0) {
86
+ logger.info({ sessionId: session.id, drainedCount }, "Drained buffered events for suspended session");
87
+ }
88
+ // Step 2: Reanimate the session (starts resume stream + processEventStream)
89
+ reanimateAgent(session.id);
90
+ logger.info({ sessionId: session.id }, "Successfully reanimated suspended session");
91
+ emitTaskUpdated(session.taskId);
92
+ }
93
+ catch (err) {
94
+ logger.error({ sessionId: session.id, err }, "Failed to recover suspended session — marking failed");
95
+ sessionStore.updateSession(session.id, SESSION_STATUS.FAILED, undefined, `Recovery failed: ${String(err)}`);
96
+ emitTaskUpdated(session.taskId);
97
+ }
98
+ }
99
+ finally {
100
+ recoveringEnvironments.delete(environmentId);
101
+ }
102
+ }
103
+ /** Emit a task.updated event with the correct workspaceId, if the session has a task. */
104
+ function emitTaskUpdated(taskId) {
105
+ if (!taskId) {
106
+ return;
107
+ }
108
+ const task = taskStore.getTask(taskId);
109
+ emit("task.updated", { taskId, workspaceId: task?.workspaceId || "" });
110
+ }
111
+ /** @internal Reset the recovery lock for testing. */
112
+ export function _resetForTesting() {
113
+ recoveringEnvironments.clear();
114
+ }
115
+ //# sourceMappingURL=session-recovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-recovery.js","sourceRoot":"","sources":["../src/session-recovery.ts"],"names":[],"mappings":"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"}
@@ -37,6 +37,10 @@ export declare function deleteByEnvironment(environmentId: string): void;
37
37
  export declare function setSessionTask(id: string, taskId: string): void;
38
38
  /** Persist the runtime-native session ID returned by the PowerLine. */
39
39
  export declare function updateRuntimeSessionId(id: string, runtimeSessionId: string): void;
40
+ /** Transition a session to SUSPENDED — transport lost, pending auto-recovery on reconnect. */
41
+ export declare function suspendSession(id: string): void;
42
+ /** Get all SUSPENDED sessions for an environment, ordered by startedAt (oldest first). */
43
+ export declare function getSuspendedForEnv(environmentId: string): SessionRow[];
40
44
  /** Clear terminal state for reanimate — reset status to running, clear endedAt/error/suspendedAt. */
41
45
  export declare function reanimateSession(id: string): void;
42
46
  /** List all sessions for a specific task, ordered chronologically (oldest first). */
@@ -1 +1 @@
1
- {"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"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"}
@@ -136,6 +136,24 @@ export function updateRuntimeSessionId(id, runtimeSessionId) {
136
136
  .where(eq(sessions.id, id))
137
137
  .run();
138
138
  }
139
+ /** Transition a session to SUSPENDED — transport lost, pending auto-recovery on reconnect. */
140
+ export function suspendSession(id) {
141
+ db.update(sessions)
142
+ .set({
143
+ status: SESSION_STATUS.SUSPENDED,
144
+ suspendedAt: new Date().toISOString(),
145
+ error: null,
146
+ })
147
+ .where(eq(sessions.id, id))
148
+ .run();
149
+ }
150
+ /** Get all SUSPENDED sessions for an environment, ordered by startedAt (oldest first). */
151
+ export function getSuspendedForEnv(environmentId) {
152
+ return db.select().from(sessions)
153
+ .where(and(eq(sessions.environmentId, environmentId), eq(sessions.status, SESSION_STATUS.SUSPENDED)))
154
+ .orderBy(asc(sessions.startedAt))
155
+ .all();
156
+ }
139
157
  /** Clear terminal state for reanimate — reset status to running, clear endedAt/error/suspendedAt. */
140
158
  export function reanimateSession(id) {
141
159
  db.update(sessions)
@@ -1 +1 @@
1
- {"version":3,"file":"session-store.js","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-store.js","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ws-bridge.d.ts","sourceRoot":"","sources":["../src/ws-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AAetD,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAC;AAkD7C,wGAAwG;AACxG,wBAAgB,cAAc,CAC5B,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,EACxC,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,GACjD,eAAe,CA0CjB;AAyHD,8GAA8G;AAC9G,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,SAAS,GAAG,SAAS,EACzB,IAAI,EAAE,SAAS,CAAC,OAAO,EACvB,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACvE,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA6I7B"}
1
+ {"version":3,"file":"ws-bridge.d.ts","sourceRoot":"","sources":["../src/ws-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AAetD,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAC;AAoD7C,wGAAwG;AACxG,wBAAgB,cAAc,CAC5B,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,EACxC,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,GACjD,eAAe,CA0CjB;AA6HD,8GAA8G;AAC9G,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,SAAS,GAAG,SAAS,EACzB,IAAI,EAAE,SAAS,CAAC,OAAO,EACvB,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACvE,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA6I7B"}
package/dist/ws-bridge.js CHANGED
@@ -29,6 +29,8 @@ import { processEventStream } from "./event-processor.js";
29
29
  import * as processorRegistry from "./processor-registry.js";
30
30
  import { setWssInstance, envRowToWs } from "./ws-broadcast.js";
31
31
  import { emit } from "./event-bus.js";
32
+ import { recoverSuspendedSessions } from "./session-recovery.js";
33
+ import { clearReconnectState } from "./auto-reconnect.js";
32
34
  import { buildMcpServersJson, toDialableHost } from "./grpc-service.js";
33
35
  import { createScopedToken } from "@grackle-ai/mcp";
34
36
  import { loadOrCreateApiKey } from "./api-key.js";
@@ -138,6 +140,10 @@ async function autoProvisionEnvironment(ws, environmentId, env, logContext) {
138
140
  envRegistry.updateEnvironmentStatus(environmentId, "connected");
139
141
  envRegistry.markBootstrapped(environmentId);
140
142
  emit("environment.changed", {});
143
+ // Auto-recover suspended sessions (fire-and-forget)
144
+ recoverSuspendedSessions(environmentId, conn).catch((err) => {
145
+ logger.error({ environmentId, err }, "Session recovery failed");
146
+ });
141
147
  logger.info({ environmentId, ...logContext }, "Auto-provision complete");
142
148
  emit("environment.provision_progress", {
143
149
  environmentId,
@@ -447,17 +453,6 @@ async function handleMessage(ws, msg, subscriptions) {
447
453
  logPath,
448
454
  systemContext: finalSystemContext,
449
455
  prompt,
450
- onError: (err) => {
451
- sendWs(ws, {
452
- type: "session_event",
453
- payload: {
454
- sessionId,
455
- eventType: "error",
456
- timestamp: new Date().toISOString(),
457
- content: `Spawn failed: ${err instanceof Error ? err.message : String(err)}`,
458
- },
459
- });
460
- },
461
456
  });
462
457
  break;
463
458
  }
@@ -1304,6 +1299,8 @@ async function handleMessage(ws, msg, subscriptions) {
1304
1299
  });
1305
1300
  return;
1306
1301
  }
1302
+ // Manual provision overrides auto-reconnect
1303
+ clearReconnectState(environmentId);
1307
1304
  const env = envRegistry.getEnvironment(environmentId);
1308
1305
  if (!env) {
1309
1306
  sendWs(ws, {
@@ -1346,6 +1343,10 @@ async function handleMessage(ws, msg, subscriptions) {
1346
1343
  await tokenBroker.pushToEnv(environmentId);
1347
1344
  envRegistry.updateEnvironmentStatus(environmentId, "connected");
1348
1345
  envRegistry.markBootstrapped(environmentId);
1346
+ // Auto-recover suspended sessions (fire-and-forget)
1347
+ recoverSuspendedSessions(environmentId, conn).catch((err) => {
1348
+ logger.error({ environmentId, err }, "Session recovery failed");
1349
+ });
1349
1350
  logger.info({ environmentId }, "Environment connected");
1350
1351
  emit("environment.provision_progress", {
1351
1352
  environmentId,
@@ -1531,6 +1532,7 @@ async function handleMessage(ws, msg, subscriptions) {
1531
1532
  });
1532
1533
  return;
1533
1534
  }
1535
+ clearReconnectState(environmentId);
1534
1536
  // Block deletion if workspaces still reference this environment
1535
1537
  const wsCount = workspaceStore.countWorkspacesByEnvironment(environmentId);
1536
1538
  if (wsCount > 0) {