@cydm/happy-elves 0.1.0-beta.285 → 0.1.0-beta.289

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cydm/happy-elves-cli",
3
- "version": "0.1.0-beta.285",
3
+ "version": "0.1.0-beta.289",
4
4
  "private": true,
5
5
  "type": "module"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cydm/happy-elves-daemon",
3
- "version": "0.1.0-beta.285",
3
+ "version": "0.1.0-beta.289",
4
4
  "private": true,
5
5
  "type": "module"
6
6
  }
@@ -35,7 +35,7 @@ type ControllerHandlerContext = {
35
35
  sessionId: string;
36
36
  requestId?: string;
37
37
  turnId?: string;
38
- terminalStatus: "completed" | "cancelled" | "failed" | "error";
38
+ terminalStatus: "completed" | "cancelled" | "failed" | "error" | "unknown";
39
39
  errorCode?: string;
40
40
  finishedAt?: number;
41
41
  }): unknown;
@@ -16,7 +16,7 @@ type MachineHandlerContext = {
16
16
  sessionId: string;
17
17
  requestId?: string;
18
18
  turnId?: string;
19
- terminalStatus: "completed" | "cancelled" | "failed" | "error";
19
+ terminalStatus: "completed" | "cancelled" | "failed" | "error" | "unknown";
20
20
  errorCode?: string;
21
21
  finishedAt?: number;
22
22
  }): {
@@ -208,6 +208,11 @@ export function handleMachineMessage(context, connection, message) {
208
208
  broadcastControllers(connection.accountId, { type: "server:session", session: sessionSnapshot(row) });
209
209
  }
210
210
  if (message.result.status === "terminal" && message.result.terminalStatus) {
211
+ const activeClaim = activePromptClaim(db, connection.accountId, message.result.sessionId, connection.machineId);
212
+ const terminalMatchesActiveClaim = Boolean(activeClaim) &&
213
+ (!message.result.requestId || message.result.requestId === activeClaim?.request_id) &&
214
+ (!message.result.turnId || message.result.turnId === activeClaim?.turn_id);
215
+ const shouldProjectTerminal = !activeClaim || terminalMatchesActiveClaim;
211
216
  if (message.result.turnId || message.result.lastTurnId || message.result.currentHead || message.result.providerTurnId) {
212
217
  recordTurnAlias({
213
218
  accountId: connection.accountId,
@@ -218,12 +223,14 @@ export function handleMachineMessage(context, connection, message) {
218
223
  requestId: message.result.requestId,
219
224
  });
220
225
  }
221
- db.prepare(`UPDATE sessions
222
- SET status = ?,
223
- current_head = COALESCE(?, current_head),
224
- last_turn_id = COALESCE(?, last_turn_id),
225
- updated_at = ?
226
- WHERE id = ? AND account_id = ? AND machine_id = ? AND status != 'closed'`).run(message.result.terminalStatus, message.result.currentHead ?? null, message.result.lastTurnId ?? message.result.turnId ?? null, ts, message.result.sessionId, connection.accountId, connection.machineId);
226
+ if (shouldProjectTerminal) {
227
+ db.prepare(`UPDATE sessions
228
+ SET status = ?,
229
+ current_head = COALESCE(?, current_head),
230
+ last_turn_id = COALESCE(?, last_turn_id),
231
+ updated_at = ?
232
+ WHERE id = ? AND account_id = ? AND machine_id = ? AND status != 'closed'`).run(message.result.terminalStatus, message.result.currentHead ?? null, message.result.lastTurnId ?? message.result.turnId ?? null, ts, message.result.sessionId, connection.accountId, connection.machineId);
233
+ }
227
234
  finishSessionClaim({
228
235
  accountId: connection.accountId,
229
236
  sessionId: message.result.sessionId,
@@ -233,9 +240,11 @@ export function handleMachineMessage(context, connection, message) {
233
240
  ...(message.result.error ? { errorCode: "TURN_ERROR" } : {}),
234
241
  finishedAt: ts,
235
242
  });
236
- const row = db.prepare("SELECT * FROM sessions WHERE id = ?").get(message.result.sessionId);
237
- if (row)
238
- broadcastControllers(connection.accountId, { type: "server:session", session: sessionSnapshot(row) });
243
+ if (shouldProjectTerminal) {
244
+ const row = db.prepare("SELECT * FROM sessions WHERE id = ?").get(message.result.sessionId);
245
+ if (row)
246
+ broadcastControllers(connection.accountId, { type: "server:session", session: sessionSnapshot(row) });
247
+ }
239
248
  }
240
249
  if (message.result.status === "unknown" || message.result.status === "not_found" || message.result.status === "uninspectable") {
241
250
  const claim = activePromptClaim(db, connection.accountId, message.result.sessionId, connection.machineId);
@@ -251,11 +260,15 @@ export function handleMachineMessage(context, connection, message) {
251
260
  last_turn_id = COALESCE(last_turn_id, ?),
252
261
  updated_at = ?
253
262
  WHERE id = ? AND account_id = ? AND machine_id = ? AND status != 'closed'`).run(turnId, turnId, ts, message.result.sessionId, connection.accountId, connection.machineId);
254
- if (requestId) {
255
- db.prepare(`UPDATE relay_admissions
256
- SET last_error_code = COALESCE(last_error_code, ?), updated_at = ?
257
- WHERE account_id = ? AND session_id = ? AND request_id = ?`).run(message.result.status === "not_found" ? "EXECUTION_NOT_FOUND" : "EXECUTION_UNKNOWN", ts, connection.accountId, message.result.sessionId, requestId);
258
- }
263
+ finishSessionClaim({
264
+ accountId: connection.accountId,
265
+ sessionId: message.result.sessionId,
266
+ requestId,
267
+ turnId,
268
+ terminalStatus: "unknown",
269
+ errorCode: message.result.status === "not_found" ? "EXECUTION_NOT_FOUND" : "EXECUTION_UNKNOWN",
270
+ finishedAt: ts,
271
+ });
259
272
  const row = db.prepare("SELECT * FROM sessions WHERE id = ?").get(message.result.sessionId);
260
273
  if (row)
261
274
  broadcastControllers(connection.accountId, { type: "server:session", session: sessionSnapshot(row) });
@@ -109,7 +109,7 @@ export declare function createRelayContext(options: CreateRelayContextOptions):
109
109
  sessionId: string;
110
110
  requestId?: string;
111
111
  turnId?: string;
112
- terminalStatus: "completed" | "cancelled" | "failed" | "error";
112
+ terminalStatus: "completed" | "cancelled" | "failed" | "error" | "unknown";
113
113
  errorCode?: string;
114
114
  finishedAt?: number;
115
115
  }) => RelaySessionClaimRow | undefined;
@@ -224,12 +224,15 @@ export function createRelayContext(options) {
224
224
  }
225
225
  function staleSessionClaimResolution(claim) {
226
226
  const admission = options.db
227
- .prepare(`SELECT dispatch, finished_at, terminal_status
227
+ .prepare(`SELECT dispatch, finished_at, terminal_status, last_error_code
228
228
  FROM relay_admissions
229
229
  WHERE account_id = ? AND request_id = ?`)
230
230
  .get(claim.account_id, claim.request_id);
231
231
  if (admission && (admission.finished_at !== null || admission.terminal_status !== null))
232
232
  return {};
233
+ if (admission && isExecutionUnknownError(admission.last_error_code) && sessionIsExecutionUnknown(claim)) {
234
+ return { terminalStatus: "unknown", errorCode: admission.last_error_code ?? undefined };
235
+ }
233
236
  const newerTerminal = options.db
234
237
  .prepare(`SELECT 1
235
238
  FROM relay_admissions
@@ -244,6 +247,15 @@ export function createRelayContext(options) {
244
247
  .get(claim.account_id, claim.session_id, claim.request_id, claim.created_at);
245
248
  return newerTerminal ? {} : undefined;
246
249
  }
250
+ function isExecutionUnknownError(code) {
251
+ return code === "EXECUTION_UNKNOWN" || code === "EXECUTION_NOT_FOUND";
252
+ }
253
+ function sessionIsExecutionUnknown(claim) {
254
+ const row = options.db
255
+ .prepare("SELECT status FROM sessions WHERE account_id = ? AND id = ? AND machine_id = ?")
256
+ .get(claim.account_id, claim.session_id, claim.machine_id);
257
+ return row?.status === "unknown";
258
+ }
247
259
  function claimSessionTurn(params) {
248
260
  const existing = activeSessionClaim(params.accountId, params.sessionId);
249
261
  if (existing && existing.request_id !== params.requestId)
@@ -97,7 +97,7 @@ export type RelayAdmissionRow = {
97
97
  dispatch: "queued" | "delivered";
98
98
  started_at: number | null;
99
99
  finished_at: number | null;
100
- terminal_status: "completed" | "cancelled" | "failed" | "error" | null;
100
+ terminal_status: "completed" | "cancelled" | "failed" | "error" | "unknown" | null;
101
101
  last_error_code: string | null;
102
102
  created_at: number;
103
103
  updated_at: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cydm/happy-elves",
3
- "version": "0.1.0-beta.285",
3
+ "version": "0.1.0-beta.289",
4
4
  "description": "Remote controller for local coding agents with hosted or self-hosted relay support.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,7 +16,7 @@ export function isSessionClosed(status) {
16
16
  return status === "closed";
17
17
  }
18
18
  export function isSessionBusy(status) {
19
- return status === "running" || status === "unknown";
19
+ return status === "running";
20
20
  }
21
21
  export function controllerSessionCommandDecision(status, command) {
22
22
  if (command === "close" && status === "closed")
@@ -32,7 +32,7 @@ export function controllerSessionCommandDecision(status, command) {
32
32
  return {
33
33
  allowed: false,
34
34
  code: "SESSION_BUSY",
35
- message: status === "unknown" ? "Session has a turn whose execution status is unknown" : "Session already has a running turn",
35
+ message: "Session already has a running turn",
36
36
  };
37
37
  }
38
38
  return { allowed: true };