@adhdev/daemon-standalone 1.0.18-rc.18 → 1.0.18-rc.2

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.
@@ -25,7 +25,6 @@ import * as fs3 from "fs";
25
25
  import * as net from "net";
26
26
  import {
27
27
  SessionHostRegistry,
28
- classifyTermination,
29
28
  createLineParser,
30
29
  createResponseEnvelope,
31
30
  getDefaultSessionHostEndpoint
@@ -269,16 +268,13 @@ var PtySessionRuntime = class {
269
268
  this.respondToTerminalQueries(data);
270
269
  this.onDataCallback(data);
271
270
  });
272
- this.ptyProcess.onExit(({ exitCode, signal }) => {
271
+ this.ptyProcess.onExit(({ exitCode }) => {
273
272
  this.ptyProcess = null;
274
273
  this.screenMirror?.dispose();
275
274
  this.screenMirror = null;
276
275
  this.pendingQueryScanTail = "";
277
276
  this.terminalModeScanTail = "";
278
- this.onExitCallback(
279
- typeof exitCode === "number" ? exitCode : null,
280
- typeof signal === "number" ? signal : null
281
- );
277
+ this.onExitCallback(exitCode ?? null);
282
278
  });
283
279
  return this.ptyProcess.pid;
284
280
  }
@@ -390,12 +386,10 @@ import * as path from "path";
390
386
  var SessionHostStorage = class {
391
387
  rootDir;
392
388
  runtimesDir;
393
- tombstonesDir;
394
389
  constructor(options = {}) {
395
390
  const appName = options.appName || "adhdev";
396
391
  this.rootDir = path.join(os2.homedir(), ".adhdev", "session-host", appName);
397
392
  this.runtimesDir = path.join(this.rootDir, "runtimes");
398
- this.tombstonesDir = path.join(this.rootDir, "tombstones");
399
393
  }
400
394
  loadAll() {
401
395
  if (!fs2.existsSync(this.runtimesDir)) return [];
@@ -431,52 +425,6 @@ var SessionHostStorage = class {
431
425
  } catch {
432
426
  }
433
427
  }
434
- /**
435
- * Persist a compact termination tombstone. Kept in a separate directory from
436
- * live runtimes so it survives the post-exit cleanup of the runtime file and
437
- * remains inspectable for post-mortem diagnostics.
438
- */
439
- saveTombstone(sessionId, termination) {
440
- fs2.mkdirSync(this.tombstonesDir, { recursive: true });
441
- const filePath = path.join(this.tombstonesDir, `${sessionId}.json`);
442
- const payload = {
443
- sessionId,
444
- termination,
445
- updatedAt: Date.now()
446
- };
447
- fs2.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
448
- }
449
- loadTombstone(sessionId) {
450
- const filePath = path.join(this.tombstonesDir, `${sessionId}.json`);
451
- try {
452
- const parsed = JSON.parse(fs2.readFileSync(filePath, "utf8"));
453
- return parsed?.sessionId ? parsed : null;
454
- } catch {
455
- return null;
456
- }
457
- }
458
- loadAllTombstones() {
459
- if (!fs2.existsSync(this.tombstonesDir)) return [];
460
- const entries = fs2.readdirSync(this.tombstonesDir, { withFileTypes: true });
461
- const states = [];
462
- for (const entry of entries) {
463
- if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
464
- const fullPath = path.join(this.tombstonesDir, entry.name);
465
- try {
466
- const parsed = JSON.parse(fs2.readFileSync(fullPath, "utf8"));
467
- if (parsed?.sessionId) states.push(parsed);
468
- } catch {
469
- }
470
- }
471
- return states.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
472
- }
473
- removeTombstone(sessionId) {
474
- const filePath = path.join(this.tombstonesDir, `${sessionId}.json`);
475
- try {
476
- fs2.unlinkSync(filePath);
477
- } catch {
478
- }
479
- }
480
428
  };
481
429
 
482
430
  // src/session-diagnostics.ts
@@ -692,9 +640,6 @@ var SessionHostServer = class extends EventEmitter {
692
640
  recentTransitions = [];
693
641
  exitWaiters = /* @__PURE__ */ new Map();
694
642
  lastNoOutputInputWarnAt = /* @__PURE__ */ new Map();
695
- // Records the most recent explicit stop/delete/restart/prune request per
696
- // session so the termination diagnostic can attribute the exit to it.
697
- stopRequests = /* @__PURE__ */ new Map();
698
643
  constructor(options = {}) {
699
644
  super();
700
645
  this.endpoint = options.endpoint || getDefaultSessionHostEndpoint(options.appName || "adhdev");
@@ -892,7 +837,6 @@ var SessionHostServer = class extends EventEmitter {
892
837
  return { success: true, result: this.registry.getSession(request.payload.sessionId) };
893
838
  }
894
839
  case "stop_session": {
895
- this.stopRequests.set(request.payload.sessionId, "stop");
896
840
  this.registry.setLifecycle(request.payload.sessionId, "stopping");
897
841
  this.persistNow(request.payload.sessionId);
898
842
  this.requireRuntime(request.payload.sessionId).stop();
@@ -907,7 +851,6 @@ var SessionHostServer = class extends EventEmitter {
907
851
  if (!request.payload.force) {
908
852
  return { success: false, error: `Session ${record.sessionId} is still running; pass force to stop and delete it` };
909
853
  }
910
- this.stopRequests.set(record.sessionId, "delete");
911
854
  this.registry.setLifecycle(record.sessionId, "stopping");
912
855
  this.persistNow(record.sessionId);
913
856
  this.requireRuntime(record.sessionId).stop();
@@ -917,8 +860,6 @@ var SessionHostServer = class extends EventEmitter {
917
860
  }
918
861
  this.registry.deleteSession(record.sessionId);
919
862
  this.storage.remove(record.sessionId);
920
- this.storage.removeTombstone(record.sessionId);
921
- this.stopRequests.delete(record.sessionId);
922
863
  this.emitEvent({ type: "session_deleted", sessionId: record.sessionId });
923
864
  this.recordRuntimeTransition(record.sessionId, "delete_session", record.lifecycle, void 0, true);
924
865
  return { success: true, result: { sessionId: record.sessionId, deleted: true } };
@@ -1226,7 +1167,6 @@ var SessionHostServer = class extends EventEmitter {
1226
1167
  throw new Error(`Unknown session: ${sessionId}`);
1227
1168
  }
1228
1169
  if (this.runtimes.has(sessionId)) {
1229
- this.stopRequests.set(sessionId, "restart");
1230
1170
  this.registry.setLifecycle(sessionId, "stopping");
1231
1171
  this.persistNow(sessionId);
1232
1172
  this.recordRuntimeTransition(sessionId, "restart_requested", "stopping", void 0, true);
@@ -1297,7 +1237,6 @@ var SessionHostServer = class extends EventEmitter {
1297
1237
  true
1298
1238
  );
1299
1239
  if (this.runtimes.has(record.sessionId)) {
1300
- this.stopRequests.set(record.sessionId, "prune");
1301
1240
  this.registry.setLifecycle(record.sessionId, "stopping");
1302
1241
  this.persistNow(record.sessionId);
1303
1242
  this.requireRuntime(record.sessionId).stop();
@@ -1307,8 +1246,6 @@ var SessionHostServer = class extends EventEmitter {
1307
1246
  }
1308
1247
  this.registry.deleteSession(record.sessionId);
1309
1248
  this.storage.remove(record.sessionId);
1310
- this.storage.removeTombstone(record.sessionId);
1311
- this.stopRequests.delete(record.sessionId);
1312
1249
  }
1313
1250
  startRuntime(record, payload, startEventType) {
1314
1251
  const runtime = new PtySessionRuntime({
@@ -1319,7 +1256,22 @@ var SessionHostServer = class extends EventEmitter {
1319
1256
  this.schedulePersist(record.sessionId);
1320
1257
  this.emitEvent({ type: "session_output", sessionId: record.sessionId, seq, data });
1321
1258
  },
1322
- onExit: (exitCode, signal) => this.handleRuntimeExit(record, exitCode, signal)
1259
+ onExit: (exitCode) => {
1260
+ this.registry.markStopped(record.sessionId, exitCode === 0 ? "stopped" : "failed");
1261
+ this.runtimes.delete(record.sessionId);
1262
+ this.resolveExitWaiters(record.sessionId, exitCode);
1263
+ this.persistNow(record.sessionId);
1264
+ this.emitEvent({ type: "session_exit", sessionId: record.sessionId, exitCode });
1265
+ this.recordRuntimeTransition(
1266
+ record.sessionId,
1267
+ "session_exit",
1268
+ exitCode === 0 ? "stopped" : "failed",
1269
+ void 0,
1270
+ exitCode === 0,
1271
+ exitCode === 0 ? void 0 : `exitCode=${exitCode}`
1272
+ );
1273
+ setTimeout(() => this.storage.remove(record.sessionId), 5e3);
1274
+ }
1323
1275
  });
1324
1276
  this.registry.setLifecycle(record.sessionId, "starting");
1325
1277
  const pid = runtime.start();
@@ -1330,58 +1282,6 @@ var SessionHostServer = class extends EventEmitter {
1330
1282
  this.recordRuntimeTransition(record.sessionId, startEventType, startedRecord.lifecycle, `pid=${pid}`, true);
1331
1283
  return startedRecord;
1332
1284
  }
1333
- /**
1334
- * Handle a PTY termination: classify the (exitCode, signal) pair, stamp the
1335
- * record + tombstone, emit exactly one structured diagnostic, and schedule
1336
- * cleanup of the live persistence file (the tombstone is retained).
1337
- */
1338
- handleRuntimeExit(record, exitCode, signal) {
1339
- const priorRecord = this.registry.getSession(record.sessionId);
1340
- const termination = classifyTermination({
1341
- exitCode,
1342
- signal,
1343
- osPid: priorRecord?.osPid,
1344
- previousLifecycle: priorRecord?.lifecycle,
1345
- lastOutputAt: priorRecord?.lastActivityAt,
1346
- requestedStop: this.stopRequests.get(record.sessionId),
1347
- terminatedAt: Date.now()
1348
- });
1349
- this.stopRequests.delete(record.sessionId);
1350
- this.registry.markStopped(record.sessionId, termination.lifecycle, termination);
1351
- this.runtimes.delete(record.sessionId);
1352
- this.resolveExitWaiters(record.sessionId, exitCode);
1353
- this.persistNow(record.sessionId);
1354
- this.storage.saveTombstone(record.sessionId, termination);
1355
- this.emitEvent({ type: "session_exit", sessionId: record.sessionId, exitCode, signal, termination });
1356
- const summary = `reason=${termination.reason} exitCode=${termination.exitCode === null ? "unknown" : termination.exitCode} signal=${termination.signal ?? "none"}`;
1357
- this.recordHostLog(
1358
- termination.lifecycle === "stopped" ? "info" : "warn",
1359
- `session terminated: ${summary}`,
1360
- record.sessionId,
1361
- {
1362
- runtimeKey: record.runtimeKey,
1363
- providerType: record.providerType,
1364
- osPid: termination.osPid,
1365
- exitCode: termination.exitCode,
1366
- signal: termination.signal,
1367
- reason: termination.reason,
1368
- previousLifecycle: termination.previousLifecycle,
1369
- lifecycle: termination.lifecycle,
1370
- lastOutputAt: termination.lastOutputAt,
1371
- requestedStop: termination.requestedStop
1372
- }
1373
- );
1374
- this.recordRuntimeTransition(
1375
- record.sessionId,
1376
- "session_exit",
1377
- termination.lifecycle,
1378
- summary,
1379
- termination.lifecycle === "stopped",
1380
- termination.lifecycle === "stopped" ? void 0 : summary
1381
- );
1382
- setTimeout(() => this.storage.remove(record.sessionId), 5e3).unref?.();
1383
- return termination;
1384
- }
1385
1285
  };
1386
1286
 
1387
1287
  // src/index.ts