@adhdev/daemon-core 0.9.33 → 0.9.34

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
@@ -1688,13 +1688,14 @@ function sliceFromOffset(text, start) {
1688
1688
  function hydrateCliParsedMessages(parsedMessages, options) {
1689
1689
  const { committedMessages, scope, lastOutputAt } = options;
1690
1690
  const referenceMessages = [...committedMessages];
1691
+ const referenceComparables = referenceMessages.map((message) => normalizeComparableMessageContent(message?.content || ""));
1691
1692
  const usedReferenceIndexes = /* @__PURE__ */ new Set();
1692
1693
  const now = options.now ?? Date.now();
1693
1694
  const findReferenceTimestamp = (role, content, parsedIndex) => {
1694
1695
  const normalizedContent = normalizeComparableMessageContent(content);
1695
1696
  if (!normalizedContent) return void 0;
1696
1697
  const sameIndex = referenceMessages[parsedIndex];
1697
- if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && normalizeComparableMessageContent(sameIndex.content) === normalizedContent && typeof sameIndex.timestamp === "number" && Number.isFinite(sameIndex.timestamp)) {
1698
+ if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && referenceComparables[parsedIndex] === normalizedContent && typeof sameIndex.timestamp === "number" && Number.isFinite(sameIndex.timestamp)) {
1698
1699
  usedReferenceIndexes.add(parsedIndex);
1699
1700
  return sameIndex.timestamp;
1700
1701
  }
@@ -1702,7 +1703,7 @@ function hydrateCliParsedMessages(parsedMessages, options) {
1702
1703
  if (usedReferenceIndexes.has(i)) continue;
1703
1704
  const candidate = referenceMessages[i];
1704
1705
  if (!candidate || candidate.role !== role) continue;
1705
- const candidateContent = normalizeComparableMessageContent(candidate.content);
1706
+ const candidateContent = referenceComparables[i];
1706
1707
  if (!candidateContent) continue;
1707
1708
  const exactMatch = candidateContent === normalizedContent;
1708
1709
  const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
@@ -2793,7 +2794,7 @@ var init_provider_cli_adapter = __esm({
2793
2794
  return;
2794
2795
  }
2795
2796
  if (this.currentTurnScope && !lastParsedAssistant) {
2796
- LOG.info(
2797
+ LOG.debug(
2797
2798
  "CLI",
2798
2799
  `[${this.cliType}] Settled without assistant: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 220)).slice(0, 260)} screen=${JSON.stringify(summarizeCliTraceText(screenText, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"}`
2799
2800
  );
@@ -3609,9 +3610,43 @@ var init_provider_cli_adapter = __esm({
3609
3610
  }
3610
3611
  armResponseTimeout() {
3611
3612
  if (this.responseTimeout) clearTimeout(this.responseTimeout);
3613
+ const timeoutMs = this.timeouts.maxResponse;
3614
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
3615
+ this.responseTimeout = null;
3616
+ return;
3617
+ }
3612
3618
  this.responseTimeout = setTimeout(() => {
3613
- if (this.isWaitingForResponse) this.finishResponse();
3614
- }, this.timeouts.maxResponse);
3619
+ this.responseTimeout = null;
3620
+ if (!this.isWaitingForResponse) return;
3621
+ const detectedStatusBeforeEval = this.runDetectStatus(this.recentOutputBuffer);
3622
+ this.recordTrace("response_timeout_check", {
3623
+ timeoutMs,
3624
+ detectedStatus: detectedStatusBeforeEval,
3625
+ currentStatus: this.currentStatus,
3626
+ isWaitingForResponse: this.isWaitingForResponse,
3627
+ hasActionableApproval: this.hasActionableApproval(),
3628
+ ...buildCliTraceParseSnapshot({
3629
+ accumulatedBuffer: this.accumulatedBuffer,
3630
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
3631
+ responseBuffer: this.responseBuffer,
3632
+ partialResponse: this.responseBuffer,
3633
+ scope: this.currentTurnScope
3634
+ })
3635
+ });
3636
+ this.settledBuffer = this.recentOutputBuffer;
3637
+ this.evaluateSettled();
3638
+ if (this.isWaitingForResponse && !this.hasActionableApproval()) {
3639
+ const detectedStatusAfterEval = this.runDetectStatus(this.recentOutputBuffer);
3640
+ this.recordTrace("response_timeout_kept_open", {
3641
+ timeoutMs,
3642
+ detectedStatusBeforeEval,
3643
+ detectedStatusAfterEval,
3644
+ currentStatus: this.currentStatus,
3645
+ isWaitingForResponse: this.isWaitingForResponse
3646
+ });
3647
+ this.armResponseTimeout();
3648
+ }
3649
+ }, timeoutMs);
3615
3650
  }
3616
3651
  writeSubmitKeyForRetry(mode) {
3617
3652
  void this.writeToPty(this.sendKey).catch((error) => {
@@ -13250,6 +13285,20 @@ var CliProviderInstance = class {
13250
13285
  getPresentationMode() {
13251
13286
  return this.presentationMode;
13252
13287
  }
13288
+ getHotChatSessionState() {
13289
+ const adapterStatus = this.adapter.getStatus();
13290
+ const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
13291
+ const visibleStatus = autoApproveActive ? "generating" : adapterStatus.status;
13292
+ const runtime = this.adapter.getRuntimeMetadata();
13293
+ return {
13294
+ id: this.instanceId,
13295
+ status: visibleStatus,
13296
+ runtimeLifecycle: runtime?.lifecycle ?? null,
13297
+ runtimeSurfaceKind: runtime?.surfaceKind,
13298
+ runtimeRestoredFromStorage: runtime?.restoredFromStorage === true,
13299
+ runtimeRecoveryState: runtime?.recoveryState ?? null
13300
+ };
13301
+ }
13253
13302
  updateSettings(newSettings) {
13254
13303
  this.settings = { ...newSettings };
13255
13304
  this.adapter.updateRuntimeSettings?.(this.settings);
@@ -13405,6 +13454,15 @@ var CliProviderInstance = class {
13405
13454
  this.completedDebouncePending = { chatTitle, duration, timestamp: now };
13406
13455
  this.completedDebounceTimer = setTimeout(() => {
13407
13456
  if (this.completedDebouncePending) {
13457
+ const latestStatus = this.adapter.getStatus();
13458
+ const latestAutoApproveActive = latestStatus.status === "waiting_approval" && this.shouldAutoApprove();
13459
+ const latestVisibleStatus = latestAutoApproveActive ? "generating" : latestStatus.status;
13460
+ if (latestVisibleStatus !== "idle") {
13461
+ LOG.info("CLI", `[${this.type}] cancelled pending completed (resumed ${latestVisibleStatus})`);
13462
+ this.completedDebouncePending = null;
13463
+ this.completedDebounceTimer = null;
13464
+ return;
13465
+ }
13408
13466
  LOG.info("CLI", `[${this.type}] completed in ${this.completedDebouncePending.duration}s`);
13409
13467
  this.pushEvent({ event: "agent:generating_completed", ...this.completedDebouncePending });
13410
13468
  this.completedDebouncePending = null;
@@ -18416,6 +18474,51 @@ function killPid(pid) {
18416
18474
  return false;
18417
18475
  }
18418
18476
  }
18477
+ function getWindowsProcessCommandLine(pid) {
18478
+ const pidFilter = `ProcessId=${pid}`;
18479
+ try {
18480
+ const psOut = execFileSync2("powershell.exe", [
18481
+ "-NoProfile",
18482
+ "-NonInteractive",
18483
+ "-ExecutionPolicy",
18484
+ "Bypass",
18485
+ "-Command",
18486
+ `(Get-CimInstance Win32_Process -Filter "${pidFilter}").CommandLine`
18487
+ ], { encoding: "utf8", timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).trim();
18488
+ if (psOut) return psOut;
18489
+ } catch {
18490
+ }
18491
+ try {
18492
+ const wmicOut = execFileSync2("wmic", [
18493
+ "process",
18494
+ "where",
18495
+ pidFilter,
18496
+ "get",
18497
+ "CommandLine"
18498
+ ], { encoding: "utf8", timeout: 3e3, stdio: ["ignore", "pipe", "ignore"] }).trim();
18499
+ if (wmicOut) return wmicOut;
18500
+ } catch {
18501
+ }
18502
+ return null;
18503
+ }
18504
+ function getProcessCommandLine(pid) {
18505
+ if (!Number.isFinite(pid) || pid <= 0) return null;
18506
+ if (process.platform === "win32") return getWindowsProcessCommandLine(pid);
18507
+ try {
18508
+ const text = execFileSync2("ps", ["-o", "command=", "-p", String(pid)], {
18509
+ encoding: "utf8",
18510
+ timeout: 3e3,
18511
+ stdio: ["ignore", "pipe", "ignore"]
18512
+ }).trim();
18513
+ return text || null;
18514
+ } catch {
18515
+ return null;
18516
+ }
18517
+ }
18518
+ function isManagedSessionHostPid(pid) {
18519
+ const commandLine = getProcessCommandLine(pid);
18520
+ return !!commandLine && /session-host-daemon/i.test(commandLine);
18521
+ }
18419
18522
  async function waitForPidExit(pid, timeoutMs) {
18420
18523
  const start = Date.now();
18421
18524
  while (Date.now() - start < timeoutMs) {
@@ -18432,7 +18535,7 @@ function stopSessionHostProcesses(appName) {
18432
18535
  try {
18433
18536
  if (fs8.existsSync(pidFile)) {
18434
18537
  const pid = Number.parseInt(fs8.readFileSync(pidFile, "utf8").trim(), 10);
18435
- if (Number.isFinite(pid)) {
18538
+ if (Number.isFinite(pid) && pid !== process.pid && isManagedSessionHostPid(pid)) {
18436
18539
  killPid(pid);
18437
18540
  }
18438
18541
  }
@@ -18443,18 +18546,6 @@ function stopSessionHostProcesses(appName) {
18443
18546
  } catch {
18444
18547
  }
18445
18548
  }
18446
- if (process.platform !== "win32") {
18447
- try {
18448
- const raw = execFileSync2("pgrep", ["-f", "session-host-daemon"], { encoding: "utf8" }).trim();
18449
- for (const line of raw.split("\n")) {
18450
- const pid = Number.parseInt(line.trim(), 10);
18451
- if (Number.isFinite(pid)) {
18452
- killPid(pid);
18453
- }
18454
- }
18455
- } catch {
18456
- }
18457
- }
18458
18549
  }
18459
18550
  function removeDaemonPidFile() {
18460
18551
  const pidFile = path16.join(os17.homedir(), ".adhdev", "daemon.pid");
@@ -20689,6 +20780,20 @@ function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
20689
20780
 
20690
20781
  // src/providers/provider-instance-manager.ts
20691
20782
  init_logger();
20783
+ function projectHotChatSessionStatesFromProviderState(state) {
20784
+ const project = (item) => ({
20785
+ id: item.instanceId,
20786
+ status: item.activeChat?.status || item.status,
20787
+ runtimeLifecycle: item.runtime?.lifecycle ?? null,
20788
+ runtimeSurfaceKind: item.runtime?.surfaceKind,
20789
+ runtimeRestoredFromStorage: item.runtime?.restoredFromStorage === true,
20790
+ runtimeRecoveryState: item.runtime?.recoveryState ?? null
20791
+ });
20792
+ if (state.category === "ide") {
20793
+ return [project(state), ...state.extensions.map(project)];
20794
+ }
20795
+ return [project(state)];
20796
+ }
20692
20797
  var ProviderInstanceManager = class {
20693
20798
  instances = /* @__PURE__ */ new Map();
20694
20799
  tickTimer = null;
@@ -20784,6 +20889,27 @@ var ProviderInstanceManager = class {
20784
20889
  }
20785
20890
  return states;
20786
20891
  }
20892
+ collectHotChatSessionStates() {
20893
+ const sessions = [];
20894
+ for (const [id, instance] of this.instances) {
20895
+ try {
20896
+ const projected = instance.getHotChatSessionState?.();
20897
+ if (Array.isArray(projected)) {
20898
+ sessions.push(...projected.filter((session) => !!session?.id));
20899
+ continue;
20900
+ }
20901
+ if (projected?.id) {
20902
+ sessions.push(projected);
20903
+ continue;
20904
+ }
20905
+ const state = instance.getState();
20906
+ sessions.push(...projectHotChatSessionStatesFromProviderState(state));
20907
+ } catch (e) {
20908
+ LOG.warn("InstanceMgr", `[InstanceManager] Failed to collect hot chat metadata from ${id}: ${e.message}`);
20909
+ }
20910
+ }
20911
+ return sessions;
20912
+ }
20787
20913
  /**
20788
20914
  * Per-category status collect
20789
20915
  */