@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.
package/dist/index.mjs CHANGED
@@ -793,9 +793,11 @@ __export(mesh_ledger_exports, {
793
793
  MAX_LEDGER_SLICE_LIMIT: () => MAX_LEDGER_SLICE_LIMIT,
794
794
  appendLedgerEntry: () => appendLedgerEntry,
795
795
  appendRemoteLedgerEntries: () => appendRemoteLedgerEntries,
796
+ buildTaskCompletionEvidence: () => buildTaskCompletionEvidence,
796
797
  getLedgerDir: () => getLedgerDir,
797
798
  getLedgerSummary: () => getLedgerSummary,
798
799
  getSessionRecoveryContext: () => getSessionRecoveryContext,
800
+ isIntentionalCleanupStopEntry: () => isIntentionalCleanupStopEntry,
799
801
  meshLedgerEvents: () => meshLedgerEvents,
800
802
  readLedgerEntries: () => readLedgerEntries,
801
803
  readLedgerSlice: () => readLedgerSlice
@@ -804,6 +806,11 @@ import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as rea
804
806
  import { join as join5 } from "path";
805
807
  import { randomUUID as randomUUID4 } from "crypto";
806
808
  import { EventEmitter } from "events";
809
+ function isIntentionalCleanupStopEntry(entry) {
810
+ if (entry.kind !== "session_stopped" && entry.kind !== "task_failed" && entry.kind !== "task_stalled") return false;
811
+ const payload = entry.payload && typeof entry.payload === "object" && !Array.isArray(entry.payload) ? entry.payload : {};
812
+ return payload.intentional === true && (payload.reason === "operator_cleanup" || payload.intentionalStopReason === "operator_cleanup" || payload.source === "mesh_cleanup_sessions" || payload.source === "mesh_remove_node");
813
+ }
807
814
  function getLedgerDir() {
808
815
  const dir = join5(getConfigDir(), LEDGER_DIR_NAME);
809
816
  if (!existsSync5(dir)) {
@@ -819,6 +826,37 @@ function getRotatedPath(meshId, index) {
819
826
  const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
820
827
  return join5(getLedgerDir(), `${safe}.${index}.jsonl`);
821
828
  }
829
+ function buildTaskCompletionEvidence(opts) {
830
+ const providerSessionId = opts.providerSessionId?.trim() || void 0;
831
+ const providerType = opts.providerType?.trim() || void 0;
832
+ return {
833
+ source: "agent_status_event",
834
+ event: opts.event,
835
+ nodeId: opts.nodeId,
836
+ sessionId: opts.sessionId,
837
+ providerType,
838
+ completedAt: opts.completedAt || (/* @__PURE__ */ new Date()).toISOString(),
839
+ transcriptHandle: {
840
+ kind: providerSessionId ? "provider_session" : "runtime_session",
841
+ sessionId: opts.sessionId,
842
+ providerSessionId,
843
+ finalSummaryAvailable: typeof opts.finalSummary === "string" && opts.finalSummary.trim().length > 0
844
+ },
845
+ git: {
846
+ status: "deferred",
847
+ reason: "ordinary_completion_git_status_not_checked"
848
+ },
849
+ validation: {
850
+ status: "deferred",
851
+ commandsRun: [],
852
+ reason: "ordinary_completion_validation_not_run"
853
+ },
854
+ checkpoint: {
855
+ attempted: false,
856
+ reason: "not_attempted_for_ordinary_completion"
857
+ }
858
+ };
859
+ }
822
860
  function appendLedgerEntry(meshId, partial) {
823
861
  const entry = {
824
862
  id: randomUUID4(),
@@ -979,15 +1017,17 @@ function getLedgerSummary(meshId) {
979
1017
  summary.taskCompleted++;
980
1018
  break;
981
1019
  case "task_failed": {
1020
+ if (isIntentionalCleanupStopEntry(entry)) break;
982
1021
  summary.taskFailed++;
983
1022
  if (new Date(entry.timestamp).getTime() >= recentFailureCutoff) {
984
1023
  summary.recentFailures++;
985
1024
  }
986
1025
  break;
987
1026
  }
988
- case "task_stalled":
989
- summary.taskStalled++;
1027
+ case "task_stalled": {
1028
+ if (!isIntentionalCleanupStopEntry(entry)) summary.taskStalled++;
990
1029
  break;
1030
+ }
991
1031
  case "session_launched":
992
1032
  summary.sessionLaunched++;
993
1033
  break;
@@ -1026,6 +1066,7 @@ function getSessionRecoveryContext(meshId, opts) {
1026
1066
  if (new Date(e.timestamp).getTime() < recentWindow) break;
1027
1067
  if (opts.nodeId && e.nodeId !== opts.nodeId) continue;
1028
1068
  if (e.kind === "task_failed") {
1069
+ if (isIntentionalCleanupStopEntry(e)) continue;
1029
1070
  consecutiveNodeFailures++;
1030
1071
  } else if (e.kind === "task_completed" || e.kind === "task_dispatched") {
1031
1072
  break;
@@ -1663,6 +1704,28 @@ function getMeshWithCache(components, meshId) {
1663
1704
  if (localMesh) return localMesh;
1664
1705
  return components.router?.getCachedInlineMesh(meshId);
1665
1706
  }
1707
+ function isIntentionalCleanupStopMetadata(event) {
1708
+ 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";
1709
+ }
1710
+ function hasRecentIntentionalCleanupStop(meshId, sessionId, nodeId) {
1711
+ if (!sessionId && !nodeId) return false;
1712
+ const cutoff = Date.now() - INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS;
1713
+ const entries = readLedgerEntries(meshId);
1714
+ for (let i = entries.length - 1; i >= 0; i--) {
1715
+ const entry = entries[i];
1716
+ const timestamp = new Date(entry.timestamp).getTime();
1717
+ if (!Number.isNaN(timestamp) && timestamp < cutoff) break;
1718
+ if (!isIntentionalCleanupStopEntry(entry)) continue;
1719
+ if (sessionId && entry.sessionId === sessionId) return true;
1720
+ if (!sessionId && nodeId && entry.nodeId === nodeId) return true;
1721
+ }
1722
+ return false;
1723
+ }
1724
+ function shouldSuppressIntentionalCleanupStop(args) {
1725
+ if (args.event !== "agent:stopped" && args.event !== "monitor:long_generating") return false;
1726
+ if (isIntentionalCleanupStopMetadata(args.metadataEvent)) return true;
1727
+ return hasRecentIntentionalCleanupStop(args.meshId, args.sessionId, args.nodeId);
1728
+ }
1666
1729
  function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
1667
1730
  const task = claimNextTask(meshId, nodeId, sessionId);
1668
1731
  if (!task) {
@@ -1999,6 +2062,22 @@ Do NOT retry on this node. Consider reassigning to a different node or asking th
1999
2062
  return "";
2000
2063
  }
2001
2064
  function injectMeshSystemMessage(components, args) {
2065
+ const eventSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
2066
+ const eventNodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
2067
+ const intentionalCleanupStop = shouldSuppressIntentionalCleanupStop({
2068
+ event: args.event,
2069
+ meshId: args.meshId,
2070
+ metadataEvent: args.metadataEvent,
2071
+ sessionId: eventSessionId || void 0,
2072
+ nodeId: eventNodeId || void 0
2073
+ });
2074
+ if (intentionalCleanupStop) {
2075
+ if (eventSessionId && eventNodeId) {
2076
+ remoteIdleSessions.delete(`${eventNodeId}:${eventSessionId}`);
2077
+ }
2078
+ LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
2079
+ return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
2080
+ }
2002
2081
  let completedTaskForLedger = null;
2003
2082
  if (args.event === "agent:generating_completed") {
2004
2083
  const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
@@ -2032,7 +2111,15 @@ function injectMeshSystemMessage(components, args) {
2032
2111
  taskId: completedTask.id,
2033
2112
  completedViaReady: true,
2034
2113
  providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0,
2035
- finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0
2114
+ finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0,
2115
+ evidence: buildTaskCompletionEvidence({
2116
+ event: "agent:ready",
2117
+ nodeId,
2118
+ sessionId,
2119
+ providerType: providerType || void 0,
2120
+ providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0,
2121
+ finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0
2122
+ })
2036
2123
  }
2037
2124
  });
2038
2125
  } catch (e) {
@@ -2067,17 +2154,29 @@ function injectMeshSystemMessage(components, args) {
2067
2154
  const ledgerKind = EVENT_TO_LEDGER_KIND[args.event];
2068
2155
  if (ledgerKind) {
2069
2156
  try {
2157
+ const ledgerNodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || void 0;
2158
+ const ledgerSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId) || void 0;
2159
+ const ledgerProviderType = readNonEmptyString(args.metadataEvent.providerType) || void 0;
2160
+ const completionEvidence = ledgerKind === "task_completed" && ledgerNodeId && ledgerSessionId ? buildTaskCompletionEvidence({
2161
+ event: "agent:generating_completed",
2162
+ nodeId: ledgerNodeId,
2163
+ sessionId: ledgerSessionId,
2164
+ providerType: ledgerProviderType,
2165
+ providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0,
2166
+ finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0
2167
+ }) : void 0;
2070
2168
  appendLedgerEntry(args.meshId, {
2071
2169
  kind: ledgerKind,
2072
- nodeId: readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || void 0,
2073
- sessionId: resolveEventSessionId(args.metadataEvent, args.sourceInstanceId) || void 0,
2074
- providerType: readNonEmptyString(args.metadataEvent.providerType) || void 0,
2170
+ nodeId: ledgerNodeId,
2171
+ sessionId: ledgerSessionId,
2172
+ providerType: ledgerProviderType,
2075
2173
  payload: {
2076
2174
  event: args.event,
2077
2175
  nodeLabel: args.nodeLabel,
2078
2176
  taskId: completedTaskForLedger?.id || void 0,
2079
2177
  providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0,
2080
- finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0
2178
+ finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0,
2179
+ evidence: completionEvidence
2081
2180
  }
2082
2181
  });
2083
2182
  } catch (e) {
@@ -2193,7 +2292,14 @@ function handleMeshForwardEvent(components, payload) {
2193
2292
  targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId) || readNonEmptyString(payload.instanceId),
2194
2293
  providerType: readNonEmptyString(payload.providerType),
2195
2294
  providerSessionId: readNonEmptyString(payload.providerSessionId),
2196
- finalSummary: readNonEmptyString(payload.finalSummary) || readNonEmptyString(payload.summary)
2295
+ finalSummary: readNonEmptyString(payload.finalSummary) || readNonEmptyString(payload.summary),
2296
+ intentional: payload.intentional === true,
2297
+ intentionalStop: payload.intentionalStop === true,
2298
+ operatorCleanup: payload.operatorCleanup === true,
2299
+ reason: readNonEmptyString(payload.reason),
2300
+ stopReason: readNonEmptyString(payload.stopReason),
2301
+ cleanupReason: readNonEmptyString(payload.cleanupReason),
2302
+ source: readNonEmptyString(payload.source)
2197
2303
  }
2198
2304
  });
2199
2305
  }
@@ -2229,7 +2335,7 @@ function setupMeshEventForwarding(components) {
2229
2335
  });
2230
2336
  });
2231
2337
  }
2232
- var remoteIdleSessions, MAX_PENDING_EVENTS, pendingMeshCoordinatorEvents, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS;
2338
+ var remoteIdleSessions, MAX_PENDING_EVENTS, pendingMeshCoordinatorEvents, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS;
2233
2339
  var init_mesh_events = __esm({
2234
2340
  "src/mesh/mesh-events.ts"() {
2235
2341
  "use strict";
@@ -2256,6 +2362,7 @@ var init_mesh_events = __esm({
2256
2362
  "agent:stopped": "task_failed",
2257
2363
  "monitor:long_generating": "task_stalled"
2258
2364
  };
2365
+ INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS = 30 * 60 * 1e3;
2259
2366
  autoLaunchInProgress = /* @__PURE__ */ new Set();
2260
2367
  autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
2261
2368
  AUTO_LAUNCH_COOLDOWN_MS = 5e3;
@@ -23982,6 +24089,27 @@ var DaemonCommandRouter = class {
23982
24089
  isCompletedHostedSession(record) {
23983
24090
  return record?.lifecycle === "stopped" || record?.lifecycle === "failed" || record?.lifecycle === "interrupted";
23984
24091
  }
24092
+ async recordIntentionalMeshSessionStop(args) {
24093
+ try {
24094
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
24095
+ appendLedgerEntry2(args.meshId, {
24096
+ kind: "session_stopped",
24097
+ nodeId: args.nodeId,
24098
+ sessionId: args.sessionId,
24099
+ payload: {
24100
+ intentional: true,
24101
+ reason: "operator_cleanup",
24102
+ intentionalStopReason: "operator_cleanup",
24103
+ source: args.source,
24104
+ cleanupMode: args.mode,
24105
+ action: args.action,
24106
+ workspace: typeof args.node?.workspace === "string" ? args.node.workspace : void 0
24107
+ }
24108
+ });
24109
+ } catch (e) {
24110
+ LOG.warn("MeshCleanup", `Failed to record intentional cleanup stop for ${args.sessionId}: ${e?.message || e}`);
24111
+ }
24112
+ }
23985
24113
  async cleanupMeshSessions(args) {
23986
24114
  if (args.mode === "preserve") {
23987
24115
  return { success: true, mode: "preserve", matchedCount: 0, stoppedSessionIds: [], deletedSessionIds: [], skippedSessionIds: [] };
@@ -23998,6 +24126,21 @@ var DaemonCommandRouter = class {
23998
24126
  const deleteUnsupportedSessionIds = [];
23999
24127
  const recordsRemainSessionIds = [];
24000
24128
  const errors = [];
24129
+ const cleanupSource = args.source || "mesh_cleanup_sessions";
24130
+ const markedIntentionalStopSessionIds = /* @__PURE__ */ new Set();
24131
+ const markIntentionalStop = async (sessionId, action) => {
24132
+ if (args.dryRun || markedIntentionalStopSessionIds.has(sessionId)) return;
24133
+ markedIntentionalStopSessionIds.add(sessionId);
24134
+ await this.recordIntentionalMeshSessionStop({
24135
+ meshId: args.meshId,
24136
+ nodeId: args.nodeId,
24137
+ node: args.node,
24138
+ sessionId,
24139
+ mode: args.mode,
24140
+ source: cleanupSource,
24141
+ action
24142
+ });
24143
+ };
24001
24144
  const matchedBySurfaceKind = {
24002
24145
  live_runtime: 0,
24003
24146
  recovery_snapshot: 0,
@@ -24020,7 +24163,10 @@ var DaemonCommandRouter = class {
24020
24163
  try {
24021
24164
  if (args.mode === "stop") {
24022
24165
  if (!completed) {
24023
- if (!args.dryRun) await this.deps.sessionHostControl.stopSession(sessionId);
24166
+ if (!args.dryRun) {
24167
+ await markIntentionalStop(sessionId, "stop_session");
24168
+ await this.deps.sessionHostControl.stopSession(sessionId);
24169
+ }
24024
24170
  stoppedSessionIds.push(sessionId);
24025
24171
  } else {
24026
24172
  skippedSessionIds.push(sessionId);
@@ -24037,6 +24183,7 @@ var DaemonCommandRouter = class {
24037
24183
  continue;
24038
24184
  }
24039
24185
  if (args.mode === "stop_and_delete") {
24186
+ if (!completed) await markIntentionalStop(sessionId, "delete_session_force");
24040
24187
  if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: true });
24041
24188
  deletedSessionIds.push(sessionId);
24042
24189
  continue;
@@ -24048,6 +24195,7 @@ var DaemonCommandRouter = class {
24048
24195
  recordsRemainSessionIds.push(sessionId);
24049
24196
  if (args.mode === "stop_and_delete" && !completed) {
24050
24197
  try {
24198
+ await markIntentionalStop(sessionId, "stop_session");
24051
24199
  await this.deps.sessionHostControl.stopSession(sessionId);
24052
24200
  stoppedSessionIds.push(sessionId);
24053
24201
  } catch (stopError) {
@@ -24948,7 +25096,8 @@ var DaemonCommandRouter = class {
24948
25096
  node,
24949
25097
  mode,
24950
25098
  sessionIds,
24951
- dryRun: args?.dryRun === true
25099
+ dryRun: args?.dryRun === true,
25100
+ source: "mesh_cleanup_sessions"
24952
25101
  });
24953
25102
  return result;
24954
25103
  } catch (e) {
@@ -25083,7 +25232,7 @@ var DaemonCommandRouter = class {
25083
25232
  );
25084
25233
  let sessionCleanup;
25085
25234
  if (node && sessionCleanupMode !== "preserve") {
25086
- sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode });
25235
+ sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode, source: "mesh_remove_node" });
25087
25236
  if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
25088
25237
  }
25089
25238
  let worktreeCleanup;