@adhdev/daemon-core 0.9.32 → 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.
@@ -27,5 +27,6 @@ export declare function buildPinnedGlobalInstallCommand(options: {
27
27
  currentCliPath?: string;
28
28
  nodeExecutable?: string;
29
29
  }): PinnedGlobalInstallCommand;
30
+ export declare function stopSessionHostProcesses(appName: string): void;
30
31
  export declare function spawnDetachedDaemonUpgradeHelper(payload: DaemonUpgradeHelperPayload): void;
31
32
  export declare function maybeRunDaemonUpgradeHelperFromEnv(): Promise<boolean>;
package/dist/index.js CHANGED
@@ -1690,13 +1690,14 @@ function sliceFromOffset(text, start) {
1690
1690
  function hydrateCliParsedMessages(parsedMessages, options) {
1691
1691
  const { committedMessages, scope, lastOutputAt } = options;
1692
1692
  const referenceMessages = [...committedMessages];
1693
+ const referenceComparables = referenceMessages.map((message) => normalizeComparableMessageContent(message?.content || ""));
1693
1694
  const usedReferenceIndexes = /* @__PURE__ */ new Set();
1694
1695
  const now = options.now ?? Date.now();
1695
1696
  const findReferenceTimestamp = (role, content, parsedIndex) => {
1696
1697
  const normalizedContent = normalizeComparableMessageContent(content);
1697
1698
  if (!normalizedContent) return void 0;
1698
1699
  const sameIndex = referenceMessages[parsedIndex];
1699
- if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && normalizeComparableMessageContent(sameIndex.content) === normalizedContent && typeof sameIndex.timestamp === "number" && Number.isFinite(sameIndex.timestamp)) {
1700
+ if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && referenceComparables[parsedIndex] === normalizedContent && typeof sameIndex.timestamp === "number" && Number.isFinite(sameIndex.timestamp)) {
1700
1701
  usedReferenceIndexes.add(parsedIndex);
1701
1702
  return sameIndex.timestamp;
1702
1703
  }
@@ -1704,7 +1705,7 @@ function hydrateCliParsedMessages(parsedMessages, options) {
1704
1705
  if (usedReferenceIndexes.has(i)) continue;
1705
1706
  const candidate = referenceMessages[i];
1706
1707
  if (!candidate || candidate.role !== role) continue;
1707
- const candidateContent = normalizeComparableMessageContent(candidate.content);
1708
+ const candidateContent = referenceComparables[i];
1708
1709
  if (!candidateContent) continue;
1709
1710
  const exactMatch = candidateContent === normalizedContent;
1710
1711
  const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
@@ -2796,7 +2797,7 @@ var init_provider_cli_adapter = __esm({
2796
2797
  return;
2797
2798
  }
2798
2799
  if (this.currentTurnScope && !lastParsedAssistant) {
2799
- LOG.info(
2800
+ LOG.debug(
2800
2801
  "CLI",
2801
2802
  `[${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 || "-"}`
2802
2803
  );
@@ -3612,9 +3613,43 @@ var init_provider_cli_adapter = __esm({
3612
3613
  }
3613
3614
  armResponseTimeout() {
3614
3615
  if (this.responseTimeout) clearTimeout(this.responseTimeout);
3616
+ const timeoutMs = this.timeouts.maxResponse;
3617
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
3618
+ this.responseTimeout = null;
3619
+ return;
3620
+ }
3615
3621
  this.responseTimeout = setTimeout(() => {
3616
- if (this.isWaitingForResponse) this.finishResponse();
3617
- }, this.timeouts.maxResponse);
3622
+ this.responseTimeout = null;
3623
+ if (!this.isWaitingForResponse) return;
3624
+ const detectedStatusBeforeEval = this.runDetectStatus(this.recentOutputBuffer);
3625
+ this.recordTrace("response_timeout_check", {
3626
+ timeoutMs,
3627
+ detectedStatus: detectedStatusBeforeEval,
3628
+ currentStatus: this.currentStatus,
3629
+ isWaitingForResponse: this.isWaitingForResponse,
3630
+ hasActionableApproval: this.hasActionableApproval(),
3631
+ ...buildCliTraceParseSnapshot({
3632
+ accumulatedBuffer: this.accumulatedBuffer,
3633
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
3634
+ responseBuffer: this.responseBuffer,
3635
+ partialResponse: this.responseBuffer,
3636
+ scope: this.currentTurnScope
3637
+ })
3638
+ });
3639
+ this.settledBuffer = this.recentOutputBuffer;
3640
+ this.evaluateSettled();
3641
+ if (this.isWaitingForResponse && !this.hasActionableApproval()) {
3642
+ const detectedStatusAfterEval = this.runDetectStatus(this.recentOutputBuffer);
3643
+ this.recordTrace("response_timeout_kept_open", {
3644
+ timeoutMs,
3645
+ detectedStatusBeforeEval,
3646
+ detectedStatusAfterEval,
3647
+ currentStatus: this.currentStatus,
3648
+ isWaitingForResponse: this.isWaitingForResponse
3649
+ });
3650
+ this.armResponseTimeout();
3651
+ }
3652
+ }, timeoutMs);
3618
3653
  }
3619
3654
  writeSubmitKeyForRetry(mode) {
3620
3655
  void this.writeToPty(this.sendKey).catch((error) => {
@@ -10509,6 +10544,26 @@ function toHistoryPersistedMessages(messages) {
10509
10544
  historyDedupKey: deriveHistoryDedupKey(message)
10510
10545
  }));
10511
10546
  }
10547
+ function findLastMessageIndexBySignature(messages, signature) {
10548
+ if (!signature) return -1;
10549
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
10550
+ if (getChatMessageSignature(messages[index]) === signature) {
10551
+ return index;
10552
+ }
10553
+ }
10554
+ return -1;
10555
+ }
10556
+ function buildBoundedTailSync(messages, cursor) {
10557
+ const totalMessages = messages.length;
10558
+ const tailMessages = cursor.tailLimit > 0 && totalMessages > cursor.tailLimit ? messages.slice(-cursor.tailLimit) : messages;
10559
+ return {
10560
+ syncMode: "full",
10561
+ replaceFrom: 0,
10562
+ messages: tailMessages,
10563
+ totalMessages,
10564
+ lastMessageSignature: getChatMessageSignature(messages[totalMessages - 1])
10565
+ };
10566
+ }
10512
10567
  function computeReadChatSync(messages, cursor) {
10513
10568
  const totalMessages = messages.length;
10514
10569
  const lastMessageSignature = getChatMessageSignature(messages[totalMessages - 1]);
@@ -10540,6 +10595,15 @@ function computeReadChatSync(messages, cursor) {
10540
10595
  lastMessageSignature
10541
10596
  };
10542
10597
  }
10598
+ if (cursor.tailLimit > 0 && knownSignature === lastMessageSignature) {
10599
+ return {
10600
+ syncMode: "noop",
10601
+ replaceFrom: totalMessages,
10602
+ messages: [],
10603
+ totalMessages,
10604
+ lastMessageSignature
10605
+ };
10606
+ }
10543
10607
  if (knownMessageCount < totalMessages) {
10544
10608
  const anchorSignature = getChatMessageSignature(messages[knownMessageCount - 1]);
10545
10609
  if (anchorSignature === knownSignature) {
@@ -10551,6 +10615,19 @@ function computeReadChatSync(messages, cursor) {
10551
10615
  lastMessageSignature
10552
10616
  };
10553
10617
  }
10618
+ if (cursor.tailLimit > 0) {
10619
+ const signatureIndex = findLastMessageIndexBySignature(messages, knownSignature);
10620
+ if (signatureIndex >= 0) {
10621
+ return {
10622
+ syncMode: "append",
10623
+ replaceFrom: knownMessageCount,
10624
+ messages: messages.slice(signatureIndex + 1),
10625
+ totalMessages,
10626
+ lastMessageSignature
10627
+ };
10628
+ }
10629
+ return buildBoundedTailSync(messages, cursor);
10630
+ }
10554
10631
  }
10555
10632
  const replaceFrom = Math.max(0, Math.min(knownMessageCount - 1, totalMessages));
10556
10633
  return {
@@ -13361,6 +13438,20 @@ var CliProviderInstance = class {
13361
13438
  getPresentationMode() {
13362
13439
  return this.presentationMode;
13363
13440
  }
13441
+ getHotChatSessionState() {
13442
+ const adapterStatus = this.adapter.getStatus();
13443
+ const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
13444
+ const visibleStatus = autoApproveActive ? "generating" : adapterStatus.status;
13445
+ const runtime = this.adapter.getRuntimeMetadata();
13446
+ return {
13447
+ id: this.instanceId,
13448
+ status: visibleStatus,
13449
+ runtimeLifecycle: runtime?.lifecycle ?? null,
13450
+ runtimeSurfaceKind: runtime?.surfaceKind,
13451
+ runtimeRestoredFromStorage: runtime?.restoredFromStorage === true,
13452
+ runtimeRecoveryState: runtime?.recoveryState ?? null
13453
+ };
13454
+ }
13364
13455
  updateSettings(newSettings) {
13365
13456
  this.settings = { ...newSettings };
13366
13457
  this.adapter.updateRuntimeSettings?.(this.settings);
@@ -13516,6 +13607,15 @@ var CliProviderInstance = class {
13516
13607
  this.completedDebouncePending = { chatTitle, duration, timestamp: now };
13517
13608
  this.completedDebounceTimer = setTimeout(() => {
13518
13609
  if (this.completedDebouncePending) {
13610
+ const latestStatus = this.adapter.getStatus();
13611
+ const latestAutoApproveActive = latestStatus.status === "waiting_approval" && this.shouldAutoApprove();
13612
+ const latestVisibleStatus = latestAutoApproveActive ? "generating" : latestStatus.status;
13613
+ if (latestVisibleStatus !== "idle") {
13614
+ LOG.info("CLI", `[${this.type}] cancelled pending completed (resumed ${latestVisibleStatus})`);
13615
+ this.completedDebouncePending = null;
13616
+ this.completedDebounceTimer = null;
13617
+ return;
13618
+ }
13519
13619
  LOG.info("CLI", `[${this.type}] completed in ${this.completedDebouncePending.duration}s`);
13520
13620
  this.pushEvent({ event: "agent:generating_completed", ...this.completedDebouncePending });
13521
13621
  this.completedDebouncePending = null;
@@ -16551,10 +16651,22 @@ var ProviderLoader = class _ProviderLoader {
16551
16651
  setMachineProviderEnabled(type, enabled) {
16552
16652
  return this.setMachineProviderConfig(type, { enabled });
16553
16653
  }
16654
+ getEffectiveProviderAvailability(type) {
16655
+ const providerType = this.resolveAlias(type);
16656
+ const availability = this.providerAvailability.get(providerType);
16657
+ if (availability) return availability;
16658
+ const machineConfig = this.getMachineProviderConfig(providerType);
16659
+ const lastDetection = machineConfig.lastDetection;
16660
+ if (!lastDetection) return void 0;
16661
+ return {
16662
+ installed: lastDetection.ok === true,
16663
+ detectedPath: typeof lastDetection.path === "string" && lastDetection.path.trim() ? lastDetection.path.trim() : null
16664
+ };
16665
+ }
16554
16666
  getMachineProviderStatus(type) {
16555
16667
  const providerType = this.resolveAlias(type);
16556
16668
  if (!this.isMachineProviderEnabled(providerType)) return "disabled";
16557
- const availability = this.providerAvailability.get(providerType);
16669
+ const availability = this.getEffectiveProviderAvailability(providerType);
16558
16670
  if (!availability) return "enabled_unchecked";
16559
16671
  return availability.installed ? "detected" : "not_detected";
16560
16672
  }
@@ -16682,7 +16794,7 @@ var ProviderLoader = class _ProviderLoader {
16682
16794
  }
16683
16795
  getAvailableProviderInfos() {
16684
16796
  return this.getAll().map((provider) => {
16685
- const availability = this.providerAvailability.get(provider.type);
16797
+ const availability = this.getEffectiveProviderAvailability(provider.type);
16686
16798
  const enabled = this.isMachineProviderEnabled(provider.type);
16687
16799
  const machineConfig = this.getMachineProviderConfig(provider.type);
16688
16800
  return {
@@ -18510,6 +18622,51 @@ function killPid(pid) {
18510
18622
  return false;
18511
18623
  }
18512
18624
  }
18625
+ function getWindowsProcessCommandLine(pid) {
18626
+ const pidFilter = `ProcessId=${pid}`;
18627
+ try {
18628
+ const psOut = (0, import_child_process8.execFileSync)("powershell.exe", [
18629
+ "-NoProfile",
18630
+ "-NonInteractive",
18631
+ "-ExecutionPolicy",
18632
+ "Bypass",
18633
+ "-Command",
18634
+ `(Get-CimInstance Win32_Process -Filter "${pidFilter}").CommandLine`
18635
+ ], { encoding: "utf8", timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).trim();
18636
+ if (psOut) return psOut;
18637
+ } catch {
18638
+ }
18639
+ try {
18640
+ const wmicOut = (0, import_child_process8.execFileSync)("wmic", [
18641
+ "process",
18642
+ "where",
18643
+ pidFilter,
18644
+ "get",
18645
+ "CommandLine"
18646
+ ], { encoding: "utf8", timeout: 3e3, stdio: ["ignore", "pipe", "ignore"] }).trim();
18647
+ if (wmicOut) return wmicOut;
18648
+ } catch {
18649
+ }
18650
+ return null;
18651
+ }
18652
+ function getProcessCommandLine(pid) {
18653
+ if (!Number.isFinite(pid) || pid <= 0) return null;
18654
+ if (process.platform === "win32") return getWindowsProcessCommandLine(pid);
18655
+ try {
18656
+ const text = (0, import_child_process8.execFileSync)("ps", ["-o", "command=", "-p", String(pid)], {
18657
+ encoding: "utf8",
18658
+ timeout: 3e3,
18659
+ stdio: ["ignore", "pipe", "ignore"]
18660
+ }).trim();
18661
+ return text || null;
18662
+ } catch {
18663
+ return null;
18664
+ }
18665
+ }
18666
+ function isManagedSessionHostPid(pid) {
18667
+ const commandLine = getProcessCommandLine(pid);
18668
+ return !!commandLine && /session-host-daemon/i.test(commandLine);
18669
+ }
18513
18670
  async function waitForPidExit(pid, timeoutMs) {
18514
18671
  const start = Date.now();
18515
18672
  while (Date.now() - start < timeoutMs) {
@@ -18526,7 +18683,7 @@ function stopSessionHostProcesses(appName) {
18526
18683
  try {
18527
18684
  if (fs8.existsSync(pidFile)) {
18528
18685
  const pid = Number.parseInt(fs8.readFileSync(pidFile, "utf8").trim(), 10);
18529
- if (Number.isFinite(pid)) {
18686
+ if (Number.isFinite(pid) && pid !== process.pid && isManagedSessionHostPid(pid)) {
18530
18687
  killPid(pid);
18531
18688
  }
18532
18689
  }
@@ -18537,18 +18694,6 @@ function stopSessionHostProcesses(appName) {
18537
18694
  } catch {
18538
18695
  }
18539
18696
  }
18540
- if (process.platform !== "win32") {
18541
- try {
18542
- const raw = (0, import_child_process8.execFileSync)("pgrep", ["-f", "session-host-daemon"], { encoding: "utf8" }).trim();
18543
- for (const line of raw.split("\n")) {
18544
- const pid = Number.parseInt(line.trim(), 10);
18545
- if (Number.isFinite(pid)) {
18546
- killPid(pid);
18547
- }
18548
- }
18549
- } catch {
18550
- }
18551
- }
18552
18697
  }
18553
18698
  function removeDaemonPidFile() {
18554
18699
  const pidFile = path16.join(os17.homedir(), ".adhdev", "daemon.pid");
@@ -20783,6 +20928,20 @@ function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
20783
20928
 
20784
20929
  // src/providers/provider-instance-manager.ts
20785
20930
  init_logger();
20931
+ function projectHotChatSessionStatesFromProviderState(state) {
20932
+ const project = (item) => ({
20933
+ id: item.instanceId,
20934
+ status: item.activeChat?.status || item.status,
20935
+ runtimeLifecycle: item.runtime?.lifecycle ?? null,
20936
+ runtimeSurfaceKind: item.runtime?.surfaceKind,
20937
+ runtimeRestoredFromStorage: item.runtime?.restoredFromStorage === true,
20938
+ runtimeRecoveryState: item.runtime?.recoveryState ?? null
20939
+ });
20940
+ if (state.category === "ide") {
20941
+ return [project(state), ...state.extensions.map(project)];
20942
+ }
20943
+ return [project(state)];
20944
+ }
20786
20945
  var ProviderInstanceManager = class {
20787
20946
  instances = /* @__PURE__ */ new Map();
20788
20947
  tickTimer = null;
@@ -20878,6 +21037,27 @@ var ProviderInstanceManager = class {
20878
21037
  }
20879
21038
  return states;
20880
21039
  }
21040
+ collectHotChatSessionStates() {
21041
+ const sessions = [];
21042
+ for (const [id, instance] of this.instances) {
21043
+ try {
21044
+ const projected = instance.getHotChatSessionState?.();
21045
+ if (Array.isArray(projected)) {
21046
+ sessions.push(...projected.filter((session) => !!session?.id));
21047
+ continue;
21048
+ }
21049
+ if (projected?.id) {
21050
+ sessions.push(projected);
21051
+ continue;
21052
+ }
21053
+ const state = instance.getState();
21054
+ sessions.push(...projectHotChatSessionStatesFromProviderState(state));
21055
+ } catch (e) {
21056
+ LOG.warn("InstanceMgr", `[InstanceManager] Failed to collect hot chat metadata from ${id}: ${e.message}`);
21057
+ }
21058
+ }
21059
+ return sessions;
21060
+ }
20881
21061
  /**
20882
21062
  * Per-category status collect
20883
21063
  */