@adhdev/daemon-core 0.9.77-rc.49 → 0.9.77-rc.50

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.
@@ -93,6 +93,7 @@ export declare class DaemonCommandRouter {
93
93
  private cleanupLocalWorktreeNode;
94
94
  private getWorktreeForceCleanupConvergence;
95
95
  private isCompletedHostedSession;
96
+ private recordIntentionalMeshSessionStop;
96
97
  private cleanupMeshSessions;
97
98
  private traceSessionHostAction;
98
99
  /**
package/dist/index.js CHANGED
@@ -798,13 +798,20 @@ __export(mesh_ledger_exports, {
798
798
  MAX_LEDGER_SLICE_LIMIT: () => MAX_LEDGER_SLICE_LIMIT,
799
799
  appendLedgerEntry: () => appendLedgerEntry,
800
800
  appendRemoteLedgerEntries: () => appendRemoteLedgerEntries,
801
+ buildTaskCompletionEvidence: () => buildTaskCompletionEvidence,
801
802
  getLedgerDir: () => getLedgerDir,
802
803
  getLedgerSummary: () => getLedgerSummary,
803
804
  getSessionRecoveryContext: () => getSessionRecoveryContext,
805
+ isIntentionalCleanupStopEntry: () => isIntentionalCleanupStopEntry,
804
806
  meshLedgerEvents: () => meshLedgerEvents,
805
807
  readLedgerEntries: () => readLedgerEntries,
806
808
  readLedgerSlice: () => readLedgerSlice
807
809
  });
810
+ function isIntentionalCleanupStopEntry(entry) {
811
+ if (entry.kind !== "session_stopped" && entry.kind !== "task_failed" && entry.kind !== "task_stalled") return false;
812
+ const payload = entry.payload && typeof entry.payload === "object" && !Array.isArray(entry.payload) ? entry.payload : {};
813
+ return payload.intentional === true && (payload.reason === "operator_cleanup" || payload.intentionalStopReason === "operator_cleanup" || payload.source === "mesh_cleanup_sessions" || payload.source === "mesh_remove_node");
814
+ }
808
815
  function getLedgerDir() {
809
816
  const dir = (0, import_path3.join)(getConfigDir(), LEDGER_DIR_NAME);
810
817
  if (!(0, import_fs3.existsSync)(dir)) {
@@ -820,6 +827,37 @@ function getRotatedPath(meshId, index) {
820
827
  const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
821
828
  return (0, import_path3.join)(getLedgerDir(), `${safe}.${index}.jsonl`);
822
829
  }
830
+ function buildTaskCompletionEvidence(opts) {
831
+ const providerSessionId = opts.providerSessionId?.trim() || void 0;
832
+ const providerType = opts.providerType?.trim() || void 0;
833
+ return {
834
+ source: "agent_status_event",
835
+ event: opts.event,
836
+ nodeId: opts.nodeId,
837
+ sessionId: opts.sessionId,
838
+ providerType,
839
+ completedAt: opts.completedAt || (/* @__PURE__ */ new Date()).toISOString(),
840
+ transcriptHandle: {
841
+ kind: providerSessionId ? "provider_session" : "runtime_session",
842
+ sessionId: opts.sessionId,
843
+ providerSessionId,
844
+ finalSummaryAvailable: typeof opts.finalSummary === "string" && opts.finalSummary.trim().length > 0
845
+ },
846
+ git: {
847
+ status: "deferred",
848
+ reason: "ordinary_completion_git_status_not_checked"
849
+ },
850
+ validation: {
851
+ status: "deferred",
852
+ commandsRun: [],
853
+ reason: "ordinary_completion_validation_not_run"
854
+ },
855
+ checkpoint: {
856
+ attempted: false,
857
+ reason: "not_attempted_for_ordinary_completion"
858
+ }
859
+ };
860
+ }
823
861
  function appendLedgerEntry(meshId, partial) {
824
862
  const entry = {
825
863
  id: (0, import_crypto4.randomUUID)(),
@@ -980,15 +1018,17 @@ function getLedgerSummary(meshId) {
980
1018
  summary.taskCompleted++;
981
1019
  break;
982
1020
  case "task_failed": {
1021
+ if (isIntentionalCleanupStopEntry(entry)) break;
983
1022
  summary.taskFailed++;
984
1023
  if (new Date(entry.timestamp).getTime() >= recentFailureCutoff) {
985
1024
  summary.recentFailures++;
986
1025
  }
987
1026
  break;
988
1027
  }
989
- case "task_stalled":
990
- summary.taskStalled++;
1028
+ case "task_stalled": {
1029
+ if (!isIntentionalCleanupStopEntry(entry)) summary.taskStalled++;
991
1030
  break;
1031
+ }
992
1032
  case "session_launched":
993
1033
  summary.sessionLaunched++;
994
1034
  break;
@@ -1027,6 +1067,7 @@ function getSessionRecoveryContext(meshId, opts) {
1027
1067
  if (new Date(e.timestamp).getTime() < recentWindow) break;
1028
1068
  if (opts.nodeId && e.nodeId !== opts.nodeId) continue;
1029
1069
  if (e.kind === "task_failed") {
1070
+ if (isIntentionalCleanupStopEntry(e)) continue;
1030
1071
  consecutiveNodeFailures++;
1031
1072
  } else if (e.kind === "task_completed" || e.kind === "task_dispatched") {
1032
1073
  break;
@@ -1669,6 +1710,28 @@ function getMeshWithCache(components, meshId) {
1669
1710
  if (localMesh) return localMesh;
1670
1711
  return components.router?.getCachedInlineMesh(meshId);
1671
1712
  }
1713
+ function isIntentionalCleanupStopMetadata(event) {
1714
+ return event.intentional === true || event.intentionalStop === true || event.operatorCleanup === true || event.reason === "operator_cleanup" || event.stopReason === "operator_cleanup" || event.cleanupReason === "operator_cleanup" || event.source === "mesh_cleanup_sessions" || event.source === "mesh_remove_node";
1715
+ }
1716
+ function hasRecentIntentionalCleanupStop(meshId, sessionId, nodeId) {
1717
+ if (!sessionId && !nodeId) return false;
1718
+ const cutoff = Date.now() - INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS;
1719
+ const entries = readLedgerEntries(meshId);
1720
+ for (let i = entries.length - 1; i >= 0; i--) {
1721
+ const entry = entries[i];
1722
+ const timestamp = new Date(entry.timestamp).getTime();
1723
+ if (!Number.isNaN(timestamp) && timestamp < cutoff) break;
1724
+ if (!isIntentionalCleanupStopEntry(entry)) continue;
1725
+ if (sessionId && entry.sessionId === sessionId) return true;
1726
+ if (!sessionId && nodeId && entry.nodeId === nodeId) return true;
1727
+ }
1728
+ return false;
1729
+ }
1730
+ function shouldSuppressIntentionalCleanupStop(args) {
1731
+ if (args.event !== "agent:stopped" && args.event !== "monitor:long_generating") return false;
1732
+ if (isIntentionalCleanupStopMetadata(args.metadataEvent)) return true;
1733
+ return hasRecentIntentionalCleanupStop(args.meshId, args.sessionId, args.nodeId);
1734
+ }
1672
1735
  function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
1673
1736
  const task = claimNextTask(meshId, nodeId, sessionId);
1674
1737
  if (!task) {
@@ -2005,6 +2068,22 @@ Do NOT retry on this node. Consider reassigning to a different node or asking th
2005
2068
  return "";
2006
2069
  }
2007
2070
  function injectMeshSystemMessage(components, args) {
2071
+ const eventSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
2072
+ const eventNodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
2073
+ const intentionalCleanupStop = shouldSuppressIntentionalCleanupStop({
2074
+ event: args.event,
2075
+ meshId: args.meshId,
2076
+ metadataEvent: args.metadataEvent,
2077
+ sessionId: eventSessionId || void 0,
2078
+ nodeId: eventNodeId || void 0
2079
+ });
2080
+ if (intentionalCleanupStop) {
2081
+ if (eventSessionId && eventNodeId) {
2082
+ remoteIdleSessions.delete(`${eventNodeId}:${eventSessionId}`);
2083
+ }
2084
+ LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
2085
+ return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
2086
+ }
2008
2087
  let completedTaskForLedger = null;
2009
2088
  if (args.event === "agent:generating_completed") {
2010
2089
  const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
@@ -2038,7 +2117,15 @@ function injectMeshSystemMessage(components, args) {
2038
2117
  taskId: completedTask.id,
2039
2118
  completedViaReady: true,
2040
2119
  providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0,
2041
- finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0
2120
+ finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0,
2121
+ evidence: buildTaskCompletionEvidence({
2122
+ event: "agent:ready",
2123
+ nodeId,
2124
+ sessionId,
2125
+ providerType: providerType || void 0,
2126
+ providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0,
2127
+ finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0
2128
+ })
2042
2129
  }
2043
2130
  });
2044
2131
  } catch (e) {
@@ -2073,17 +2160,29 @@ function injectMeshSystemMessage(components, args) {
2073
2160
  const ledgerKind = EVENT_TO_LEDGER_KIND[args.event];
2074
2161
  if (ledgerKind) {
2075
2162
  try {
2163
+ const ledgerNodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || void 0;
2164
+ const ledgerSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId) || void 0;
2165
+ const ledgerProviderType = readNonEmptyString(args.metadataEvent.providerType) || void 0;
2166
+ const completionEvidence = ledgerKind === "task_completed" && ledgerNodeId && ledgerSessionId ? buildTaskCompletionEvidence({
2167
+ event: "agent:generating_completed",
2168
+ nodeId: ledgerNodeId,
2169
+ sessionId: ledgerSessionId,
2170
+ providerType: ledgerProviderType,
2171
+ providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0,
2172
+ finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0
2173
+ }) : void 0;
2076
2174
  appendLedgerEntry(args.meshId, {
2077
2175
  kind: ledgerKind,
2078
- nodeId: readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || void 0,
2079
- sessionId: resolveEventSessionId(args.metadataEvent, args.sourceInstanceId) || void 0,
2080
- providerType: readNonEmptyString(args.metadataEvent.providerType) || void 0,
2176
+ nodeId: ledgerNodeId,
2177
+ sessionId: ledgerSessionId,
2178
+ providerType: ledgerProviderType,
2081
2179
  payload: {
2082
2180
  event: args.event,
2083
2181
  nodeLabel: args.nodeLabel,
2084
2182
  taskId: completedTaskForLedger?.id || void 0,
2085
2183
  providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0,
2086
- finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0
2184
+ finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0,
2185
+ evidence: completionEvidence
2087
2186
  }
2088
2187
  });
2089
2188
  } catch (e) {
@@ -2199,7 +2298,14 @@ function handleMeshForwardEvent(components, payload) {
2199
2298
  targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId) || readNonEmptyString(payload.instanceId),
2200
2299
  providerType: readNonEmptyString(payload.providerType),
2201
2300
  providerSessionId: readNonEmptyString(payload.providerSessionId),
2202
- finalSummary: readNonEmptyString(payload.finalSummary) || readNonEmptyString(payload.summary)
2301
+ finalSummary: readNonEmptyString(payload.finalSummary) || readNonEmptyString(payload.summary),
2302
+ intentional: payload.intentional === true,
2303
+ intentionalStop: payload.intentionalStop === true,
2304
+ operatorCleanup: payload.operatorCleanup === true,
2305
+ reason: readNonEmptyString(payload.reason),
2306
+ stopReason: readNonEmptyString(payload.stopReason),
2307
+ cleanupReason: readNonEmptyString(payload.cleanupReason),
2308
+ source: readNonEmptyString(payload.source)
2203
2309
  }
2204
2310
  });
2205
2311
  }
@@ -2235,7 +2341,7 @@ function setupMeshEventForwarding(components) {
2235
2341
  });
2236
2342
  });
2237
2343
  }
2238
- var remoteIdleSessions, MAX_PENDING_EVENTS, pendingMeshCoordinatorEvents, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS;
2344
+ var remoteIdleSessions, MAX_PENDING_EVENTS, pendingMeshCoordinatorEvents, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS;
2239
2345
  var init_mesh_events = __esm({
2240
2346
  "src/mesh/mesh-events.ts"() {
2241
2347
  "use strict";
@@ -2262,6 +2368,7 @@ var init_mesh_events = __esm({
2262
2368
  "agent:stopped": "task_failed",
2263
2369
  "monitor:long_generating": "task_stalled"
2264
2370
  };
2371
+ INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS = 30 * 60 * 1e3;
2265
2372
  autoLaunchInProgress = /* @__PURE__ */ new Set();
2266
2373
  autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
2267
2374
  AUTO_LAUNCH_COOLDOWN_MS = 5e3;
@@ -24211,6 +24318,27 @@ var DaemonCommandRouter = class {
24211
24318
  isCompletedHostedSession(record) {
24212
24319
  return record?.lifecycle === "stopped" || record?.lifecycle === "failed" || record?.lifecycle === "interrupted";
24213
24320
  }
24321
+ async recordIntentionalMeshSessionStop(args) {
24322
+ try {
24323
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
24324
+ appendLedgerEntry2(args.meshId, {
24325
+ kind: "session_stopped",
24326
+ nodeId: args.nodeId,
24327
+ sessionId: args.sessionId,
24328
+ payload: {
24329
+ intentional: true,
24330
+ reason: "operator_cleanup",
24331
+ intentionalStopReason: "operator_cleanup",
24332
+ source: args.source,
24333
+ cleanupMode: args.mode,
24334
+ action: args.action,
24335
+ workspace: typeof args.node?.workspace === "string" ? args.node.workspace : void 0
24336
+ }
24337
+ });
24338
+ } catch (e) {
24339
+ LOG.warn("MeshCleanup", `Failed to record intentional cleanup stop for ${args.sessionId}: ${e?.message || e}`);
24340
+ }
24341
+ }
24214
24342
  async cleanupMeshSessions(args) {
24215
24343
  if (args.mode === "preserve") {
24216
24344
  return { success: true, mode: "preserve", matchedCount: 0, stoppedSessionIds: [], deletedSessionIds: [], skippedSessionIds: [] };
@@ -24227,6 +24355,21 @@ var DaemonCommandRouter = class {
24227
24355
  const deleteUnsupportedSessionIds = [];
24228
24356
  const recordsRemainSessionIds = [];
24229
24357
  const errors = [];
24358
+ const cleanupSource = args.source || "mesh_cleanup_sessions";
24359
+ const markedIntentionalStopSessionIds = /* @__PURE__ */ new Set();
24360
+ const markIntentionalStop = async (sessionId, action) => {
24361
+ if (args.dryRun || markedIntentionalStopSessionIds.has(sessionId)) return;
24362
+ markedIntentionalStopSessionIds.add(sessionId);
24363
+ await this.recordIntentionalMeshSessionStop({
24364
+ meshId: args.meshId,
24365
+ nodeId: args.nodeId,
24366
+ node: args.node,
24367
+ sessionId,
24368
+ mode: args.mode,
24369
+ source: cleanupSource,
24370
+ action
24371
+ });
24372
+ };
24230
24373
  const matchedBySurfaceKind = {
24231
24374
  live_runtime: 0,
24232
24375
  recovery_snapshot: 0,
@@ -24249,7 +24392,10 @@ var DaemonCommandRouter = class {
24249
24392
  try {
24250
24393
  if (args.mode === "stop") {
24251
24394
  if (!completed) {
24252
- if (!args.dryRun) await this.deps.sessionHostControl.stopSession(sessionId);
24395
+ if (!args.dryRun) {
24396
+ await markIntentionalStop(sessionId, "stop_session");
24397
+ await this.deps.sessionHostControl.stopSession(sessionId);
24398
+ }
24253
24399
  stoppedSessionIds.push(sessionId);
24254
24400
  } else {
24255
24401
  skippedSessionIds.push(sessionId);
@@ -24266,6 +24412,7 @@ var DaemonCommandRouter = class {
24266
24412
  continue;
24267
24413
  }
24268
24414
  if (args.mode === "stop_and_delete") {
24415
+ if (!completed) await markIntentionalStop(sessionId, "delete_session_force");
24269
24416
  if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: true });
24270
24417
  deletedSessionIds.push(sessionId);
24271
24418
  continue;
@@ -24277,6 +24424,7 @@ var DaemonCommandRouter = class {
24277
24424
  recordsRemainSessionIds.push(sessionId);
24278
24425
  if (args.mode === "stop_and_delete" && !completed) {
24279
24426
  try {
24427
+ await markIntentionalStop(sessionId, "stop_session");
24280
24428
  await this.deps.sessionHostControl.stopSession(sessionId);
24281
24429
  stoppedSessionIds.push(sessionId);
24282
24430
  } catch (stopError) {
@@ -25177,7 +25325,8 @@ var DaemonCommandRouter = class {
25177
25325
  node,
25178
25326
  mode,
25179
25327
  sessionIds,
25180
- dryRun: args?.dryRun === true
25328
+ dryRun: args?.dryRun === true,
25329
+ source: "mesh_cleanup_sessions"
25181
25330
  });
25182
25331
  return result;
25183
25332
  } catch (e) {
@@ -25312,7 +25461,7 @@ var DaemonCommandRouter = class {
25312
25461
  );
25313
25462
  let sessionCleanup;
25314
25463
  if (node && sessionCleanupMode !== "preserve") {
25315
- sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode });
25464
+ sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode, source: "mesh_remove_node" });
25316
25465
  if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
25317
25466
  }
25318
25467
  let worktreeCleanup;