happy-imou-cloud 2.1.7 → 2.1.8

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.
Files changed (32) hide show
  1. package/bin/happy-cloud.mjs +1 -1
  2. package/dist/{BaseReasoningProcessor-iSuaFeZH.cjs → BaseReasoningProcessor-CbqNgi4p.cjs} +2 -2
  3. package/dist/{BaseReasoningProcessor-C0A6Jr8V.mjs → BaseReasoningProcessor-DJ9zxAdt.mjs} +2 -2
  4. package/dist/{ProviderSelectionHandler-DI9QK1iY.cjs → ProviderSelectionHandler-BZVtGMAn.cjs} +2 -2
  5. package/dist/{ProviderSelectionHandler-WT-tvePy.mjs → ProviderSelectionHandler-BleheBks.mjs} +2 -2
  6. package/dist/{api-CdGT5hsH.cjs → api-CeIpGPqs.cjs} +86 -32
  7. package/dist/{api-BYKV7vX6.mjs → api-DRdn4-dL.mjs} +86 -32
  8. package/dist/{command-uyA8cYmL.cjs → command-CTad-7bA.cjs} +3 -3
  9. package/dist/{command-C1cKqmsa.mjs → command-mDMWVdh5.mjs} +3 -3
  10. package/dist/{index-BAhlFq45.mjs → index-C4S85XB7.mjs} +144 -29
  11. package/dist/{index-D_S_7bqK.cjs → index-D68EOBHW.cjs} +147 -32
  12. package/dist/index.cjs +3 -3
  13. package/dist/index.mjs +3 -3
  14. package/dist/lib.cjs +1 -1
  15. package/dist/lib.d.cts +7 -4
  16. package/dist/lib.d.mts +7 -4
  17. package/dist/lib.mjs +1 -1
  18. package/dist/{persistence-CMvrZ4SA.cjs → persistence-Czyd-Uei.cjs} +1 -1
  19. package/dist/{persistence-B8Wgn6aN.mjs → persistence-DgpGouOO.mjs} +1 -1
  20. package/dist/{registerKillSessionHandler-DjxtkGMv.cjs → registerKillSessionHandler-DECzSYvQ.cjs} +3 -3
  21. package/dist/{registerKillSessionHandler-5DVlZaJx.mjs → registerKillSessionHandler-Dg0DFPae.mjs} +3 -3
  22. package/dist/{runClaude-DNZFsQY0.cjs → runClaude-DtCH-nx-.cjs} +9 -5
  23. package/dist/{runClaude-WB884iOO.mjs → runClaude-OWT6ZYiP.mjs} +9 -5
  24. package/dist/{runCodex-MJar-238.mjs → runCodex-BU3BA1l8.mjs} +96 -21
  25. package/dist/{runCodex-WZ91ZLK7.cjs → runCodex-reARLjN0.cjs} +96 -21
  26. package/dist/{runGemini-B_wCHgPU.cjs → runGemini-BvJUvOvj.cjs} +11 -5
  27. package/dist/{runGemini-BPGpwljp.mjs → runGemini-DeLxSapY.mjs} +11 -5
  28. package/package.json +1 -1
  29. package/scripts/devtools/README.md +9 -9
  30. package/scripts/e2e/fake-codex-acp-agent.mjs +139 -139
  31. package/scripts/e2e/local-server-session-roundtrip.mjs +1063 -1063
  32. package/scripts/ensureAcpSdkCompat.mjs +1 -1
@@ -1,6 +1,6 @@
1
1
  import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
2
- import { l as logger, e as encodeBase64, c as configuration, k as buildAuthenticatedHeaders, S as SigningBootstrapRequiredError, m as SIGNING_BOOTSTRAP_REQUIRED_MESSAGE, n as encodeBase64Url, h as delay, o as buildClientHeaders, p as decodeBase64, q as HAPPY_CLOUD_DAEMON_PORT, r as packageJson, A as ApiClient, t as HeadTailPreviewBuffer, u as getLatestDaemonLog } from './api-BYKV7vX6.mjs';
3
- import { writeCredentialsLegacy, writeCredentialsDataKey, readCredentials, readSettings, updateSettings, readDaemonState, clearDaemonState, acquireDaemonLock, writeDaemonState, releaseDaemonLock, validateProfileForAgent, getProfileEnvironmentVariables, clearCredentials, clearMachineId } from './persistence-B8Wgn6aN.mjs';
2
+ import { l as logger, e as encodeBase64, c as configuration, k as buildAuthenticatedHeaders, S as SigningBootstrapRequiredError, m as SIGNING_BOOTSTRAP_REQUIRED_MESSAGE, n as encodeBase64Url, h as delay, o as buildClientHeaders, p as decodeBase64, q as HAPPY_CLOUD_DAEMON_PORT, r as packageJson, A as ApiClient, t as HeadTailPreviewBuffer, u as getLatestDaemonLog } from './api-DRdn4-dL.mjs';
3
+ import { writeCredentialsLegacy, writeCredentialsDataKey, readCredentials, readSettings, updateSettings, readDaemonState, clearDaemonState, acquireDaemonLock, writeDaemonState, releaseDaemonLock, validateProfileForAgent, getProfileEnvironmentVariables, clearCredentials, clearMachineId } from './persistence-DgpGouOO.mjs';
4
4
  import { z } from 'zod';
5
5
  import fs, { writeFile as writeFile$1, rename, unlink as unlink$1 } from 'fs/promises';
6
6
  import os$1, { homedir } from 'os';
@@ -2447,6 +2447,20 @@ function buildDaemonChildEnv(baseEnv, extraEnv) {
2447
2447
  }
2448
2448
 
2449
2449
  const DIFFERENT_DAEMON_RUNNING_MESSAGE = "A different daemon was started without killing us. We should kill ourselves.";
2450
+ function pruneStaleTrackedSessions({
2451
+ trackedSessionPids,
2452
+ removeTrackedSession,
2453
+ kill = process.kill
2454
+ }) {
2455
+ for (const pid of trackedSessionPids) {
2456
+ try {
2457
+ kill(pid, 0);
2458
+ } catch {
2459
+ logger.debug(`[DAEMON RUN] Removing stale session with PID ${pid} (process no longer exists)`);
2460
+ removeTrackedSession(pid);
2461
+ }
2462
+ }
2463
+ }
2450
2464
  function readProjectCliVersionFromDisk() {
2451
2465
  const packageJsonPath = join(projectPath(), "package.json");
2452
2466
  try {
@@ -2477,14 +2491,10 @@ async function runDaemonHealthCheck({
2477
2491
  requestShutdown,
2478
2492
  writeHeartbeat
2479
2493
  }) {
2480
- for (const pid of trackedSessionPids) {
2481
- try {
2482
- process.kill(pid, 0);
2483
- } catch {
2484
- logger.debug(`[DAEMON RUN] Removing stale session with PID ${pid} (process no longer exists)`);
2485
- removeTrackedSession(pid);
2486
- }
2487
- }
2494
+ pruneStaleTrackedSessions({
2495
+ trackedSessionPids,
2496
+ removeTrackedSession
2497
+ });
2488
2498
  const projectVersion = readProjectCliVersion();
2489
2499
  if (projectVersion && projectVersion !== currentCliVersion) {
2490
2500
  await onDaemonOutdated();
@@ -2956,7 +2966,42 @@ function resolveManagedSessionTag(env = process.env) {
2956
2966
  return readManagedSessionTag(env) ?? randomUUID();
2957
2967
  }
2958
2968
 
2969
+ const DEFAULT_MAX_LINES = 40;
2970
+ const DEFAULT_MAX_LINE_LENGTH = 300;
2971
+ function truncateLine(line, maxLineLength) {
2972
+ if (line.length <= maxLineLength) {
2973
+ return line;
2974
+ }
2975
+ return `${line.slice(0, Math.max(0, maxLineLength - 3))}...`;
2976
+ }
2977
+ function createChildProcessOutputBuffer(options) {
2978
+ const maxLines = Math.max(1, DEFAULT_MAX_LINES);
2979
+ const maxLineLength = Math.max(4, DEFAULT_MAX_LINE_LENGTH);
2980
+ const lines = [];
2981
+ return {
2982
+ push(text) {
2983
+ for (const rawLine of text.split(/\r?\n/)) {
2984
+ const line = rawLine.trim();
2985
+ if (!line) {
2986
+ continue;
2987
+ }
2988
+ lines.push(truncateLine(line, maxLineLength));
2989
+ while (lines.length > maxLines) {
2990
+ lines.shift();
2991
+ }
2992
+ }
2993
+ },
2994
+ snapshot() {
2995
+ return lines.join("\n");
2996
+ },
2997
+ hasContent() {
2998
+ return lines.length > 0;
2999
+ }
3000
+ };
3001
+ }
3002
+
2959
3003
  const DEFAULT_SESSION_WEBHOOK_TIMEOUT_MS = 45e3;
3004
+ const DEFAULT_TRACKED_SESSION_SWEEP_INTERVAL_MS = 5e3;
2960
3005
  function resolveSessionWebhookTimeoutMs() {
2961
3006
  const parsed = Number.parseInt(process.env.HAPPY_DAEMON_SESSION_WEBHOOK_TIMEOUT || "", 10);
2962
3007
  if (Number.isFinite(parsed) && parsed > 0) {
@@ -2964,6 +3009,13 @@ function resolveSessionWebhookTimeoutMs() {
2964
3009
  }
2965
3010
  return DEFAULT_SESSION_WEBHOOK_TIMEOUT_MS;
2966
3011
  }
3012
+ function resolveTrackedSessionSweepIntervalMs() {
3013
+ const parsed = Number.parseInt(process.env.HAPPY_DAEMON_TRACKED_SESSION_SWEEP_INTERVAL || "", 10);
3014
+ if (Number.isFinite(parsed) && parsed > 0) {
3015
+ return parsed;
3016
+ }
3017
+ return DEFAULT_TRACKED_SESSION_SWEEP_INTERVAL_MS;
3018
+ }
2967
3019
  const initialMachineMetadata = {
2968
3020
  host: os$1.hostname(),
2969
3021
  platform: os$1.platform(),
@@ -2994,6 +3046,7 @@ async function getProfileEnvironmentVariablesForAgent(profileId, agentType) {
2994
3046
  }
2995
3047
  async function startDaemon() {
2996
3048
  const sessionWebhookTimeoutMs = resolveSessionWebhookTimeoutMs();
3049
+ const trackedSessionSweepIntervalMs = resolveTrackedSessionSweepIntervalMs();
2997
3050
  const shutdownCoordinator = createShutdownCoordinator(async () => {
2998
3051
  logger.debug("[DAEMON RUN] Startup malfunctioned, forcing exit with code 1");
2999
3052
  await new Promise((resolve) => setTimeout(resolve, 100));
@@ -3328,14 +3381,39 @@ async function startDaemon() {
3328
3381
  // Capture stdout/stderr for debugging
3329
3382
  env: buildDaemonChildEnv(process.env, extraEnv)
3330
3383
  });
3331
- if (process.env.DEBUG) {
3332
- happyProcess.stdout?.on("data", (data) => {
3333
- logger.debug(`[DAEMON RUN] Child stdout: ${data.toString()}`);
3334
- });
3335
- happyProcess.stderr?.on("data", (data) => {
3336
- logger.debug(`[DAEMON RUN] Child stderr: ${data.toString()}`);
3337
- });
3338
- }
3384
+ const stdoutBuffer = createChildProcessOutputBuffer();
3385
+ const stderrBuffer = createChildProcessOutputBuffer();
3386
+ let childOutputSnapshotLogged = false;
3387
+ const logChildOutputSnapshot = (reason) => {
3388
+ if (childOutputSnapshotLogged) {
3389
+ return;
3390
+ }
3391
+ childOutputSnapshotLogged = true;
3392
+ const stdoutSnapshot = stdoutBuffer.snapshot();
3393
+ const stderrSnapshot = stderrBuffer.snapshot();
3394
+ if (stdoutSnapshot) {
3395
+ logger.debug(`[DAEMON RUN] Child PID ${happyProcess.pid} recent stdout before ${reason}:
3396
+ ${stdoutSnapshot}`);
3397
+ }
3398
+ if (stderrSnapshot) {
3399
+ logger.debug(`[DAEMON RUN] Child PID ${happyProcess.pid} recent stderr before ${reason}:
3400
+ ${stderrSnapshot}`);
3401
+ }
3402
+ };
3403
+ happyProcess.stdout?.on("data", (data) => {
3404
+ const text = data.toString();
3405
+ stdoutBuffer.push(text);
3406
+ if (process.env.DEBUG) {
3407
+ logger.debug(`[DAEMON RUN] Child stdout: ${text}`);
3408
+ }
3409
+ });
3410
+ happyProcess.stderr?.on("data", (data) => {
3411
+ const text = data.toString();
3412
+ stderrBuffer.push(text);
3413
+ if (process.env.DEBUG) {
3414
+ logger.debug(`[DAEMON RUN] Child stderr: ${text}`);
3415
+ }
3416
+ });
3339
3417
  if (!happyProcess.pid) {
3340
3418
  logger.debug("[DAEMON RUN] Failed to spawn process - no PID returned");
3341
3419
  if (precreatedCodexSession && api) {
@@ -3366,12 +3444,14 @@ async function startDaemon() {
3366
3444
  };
3367
3445
  pidToTrackedSession.set(happyProcess.pid, trackedSession);
3368
3446
  happyProcess.on("exit", (code, signal) => {
3447
+ logChildOutputSnapshot(`exit (code=${code}, signal=${signal})`);
3369
3448
  logger.debug(`[DAEMON RUN] Child PID ${happyProcess.pid} exited with code ${code}, signal ${signal}`);
3370
3449
  if (happyProcess.pid) {
3371
3450
  onChildExited(happyProcess.pid);
3372
3451
  }
3373
3452
  });
3374
3453
  happyProcess.on("error", (error) => {
3454
+ logChildOutputSnapshot("process error");
3375
3455
  logger.debug(`[DAEMON RUN] Child process error:`, error);
3376
3456
  if (happyProcess.pid) {
3377
3457
  onChildExited(happyProcess.pid);
@@ -3388,6 +3468,7 @@ async function startDaemon() {
3388
3468
  return new Promise((resolve) => {
3389
3469
  const timeout = setTimeout(() => {
3390
3470
  pidToAwaiter.delete(happyProcess.pid);
3471
+ logChildOutputSnapshot("session webhook timeout");
3391
3472
  logger.debug(`[DAEMON RUN] Session webhook timeout for PID ${happyProcess.pid}`);
3392
3473
  const spawnError = createSpawnSessionError(
3393
3474
  SPAWN_SESSION_ERROR_CODES.SESSION_WEBHOOK_TIMEOUT,
@@ -3572,6 +3653,25 @@ async function startDaemon() {
3572
3653
  logger.debug("[DAEMON RUN] Remote session index startup recovery failed", error);
3573
3654
  });
3574
3655
  const heartbeatIntervalMs = parseInt(process.env.HAPPY_DAEMON_HEARTBEAT_INTERVAL || "60000");
3656
+ let trackedSessionSweepRunning = false;
3657
+ const trackedSessionSweepInterval = setInterval(() => {
3658
+ if (trackedSessionSweepRunning) {
3659
+ return;
3660
+ }
3661
+ trackedSessionSweepRunning = true;
3662
+ try {
3663
+ pruneStaleTrackedSessions({
3664
+ trackedSessionPids: pidToTrackedSession.keys(),
3665
+ removeTrackedSession: (pid) => {
3666
+ removeTrackedSession(pid, `fast stale-session sweep removed tracked PID ${pid}`);
3667
+ }
3668
+ });
3669
+ } catch (error) {
3670
+ logger.debug("[DAEMON RUN] Fast tracked-session sweep failed", error);
3671
+ } finally {
3672
+ trackedSessionSweepRunning = false;
3673
+ }
3674
+ }, trackedSessionSweepIntervalMs);
3575
3675
  let heartbeatRunning = false;
3576
3676
  const restartOnStaleVersionAndHeartbeat = setInterval(async () => {
3577
3677
  if (heartbeatRunning) {
@@ -3643,6 +3743,7 @@ async function startDaemon() {
3643
3743
  clearInterval(restartOnStaleVersionAndHeartbeat);
3644
3744
  logger.debug("[DAEMON RUN] Health check interval cleared");
3645
3745
  }
3746
+ clearInterval(trackedSessionSweepInterval);
3646
3747
  if (remoteSessionIndexRefreshTimer) {
3647
3748
  clearTimeout(remoteSessionIndexRefreshTimer);
3648
3749
  remoteSessionIndexRefreshTimer = null;
@@ -7567,7 +7668,14 @@ ${recentStderrExcerpt}`);
7567
7668
  prompt: [contentBlock]
7568
7669
  };
7569
7670
  logger.debug(`[AcpBackend] Prompt request:`, JSON.stringify(promptRequest, null, 2));
7570
- await this.connection.prompt(promptRequest);
7671
+ await raceWithProcessExit(
7672
+ this.process,
7673
+ this.connection.prompt(promptRequest),
7674
+ {
7675
+ agentName: this.transport.agentName,
7676
+ operationName: "prompt"
7677
+ }
7678
+ );
7571
7679
  logger.debug("[AcpBackend] Prompt request sent to ACP connection");
7572
7680
  if (this.waitingForResponse && this.activeToolCalls.size === 0 && this.sawSessionUpdateSincePrompt === false) {
7573
7681
  const noUpdatesTimeoutMs = this.getPostPromptNoUpdatesTimeoutMs();
@@ -9730,11 +9838,11 @@ var launch = /*#__PURE__*/Object.freeze({
9730
9838
 
9731
9839
  const unifiedProviderExecutors = {
9732
9840
  claude: async (opts) => {
9733
- const { runClaude } = await import('./runClaude-WB884iOO.mjs');
9841
+ const { runClaude } = await import('./runClaude-OWT6ZYiP.mjs');
9734
9842
  await runClaude(opts.credentials, opts.claudeOptions ?? {});
9735
9843
  },
9736
9844
  codex: async (opts) => {
9737
- const { runCodex } = await import('./runCodex-MJar-238.mjs');
9845
+ const { runCodex } = await import('./runCodex-BU3BA1l8.mjs');
9738
9846
  await runCodex({
9739
9847
  credentials: opts.credentials,
9740
9848
  startedBy: opts.startedBy,
@@ -9743,7 +9851,7 @@ const unifiedProviderExecutors = {
9743
9851
  });
9744
9852
  },
9745
9853
  gemini: async (opts) => {
9746
- const { runGemini } = await import('./runGemini-BPGpwljp.mjs');
9854
+ const { runGemini } = await import('./runGemini-DeLxSapY.mjs');
9747
9855
  await runGemini({
9748
9856
  credentials: opts.credentials,
9749
9857
  startedBy: opts.startedBy
@@ -9756,13 +9864,17 @@ const unifiedProviderExecutors = {
9756
9864
  });
9757
9865
  }
9758
9866
  };
9759
- async function ensureUnifiedRuntimePrerequisites(credentials) {
9867
+ async function ensureUnifiedRuntimePrerequisites(credentials, opts) {
9760
9868
  if (credentials) {
9761
- await ensureUnifiedDaemonStarted();
9869
+ if (!opts?.skipDaemonBootstrap) {
9870
+ await ensureUnifiedDaemonStarted();
9871
+ }
9762
9872
  return credentials;
9763
9873
  }
9764
9874
  const auth = await authAndSetupMachineIfNeeded();
9765
- await ensureUnifiedDaemonStarted();
9875
+ if (!opts?.skipDaemonBootstrap) {
9876
+ await ensureUnifiedDaemonStarted();
9877
+ }
9766
9878
  return auth.credentials;
9767
9879
  }
9768
9880
  async function ensureUnifiedDaemonStarted() {
@@ -9783,7 +9895,10 @@ async function ensureUnifiedDaemonStarted() {
9783
9895
  throw new Error("Failed to start Happy background service.");
9784
9896
  }
9785
9897
  async function executeUnifiedProvider(opts) {
9786
- const credentials = await ensureUnifiedRuntimePrerequisites(opts.credentials);
9898
+ const skipDaemonBootstrap = "startedBy" in opts && opts.startedBy === "daemon" || opts.provider === "claude" && opts.claudeOptions?.startedBy === "daemon";
9899
+ const credentials = await ensureUnifiedRuntimePrerequisites(opts.credentials, {
9900
+ skipDaemonBootstrap
9901
+ });
9787
9902
  await unifiedProviderExecutors[opts.provider]({
9788
9903
  ...opts,
9789
9904
  credentials
@@ -9819,7 +9934,7 @@ function shouldRunMainClaudeFlow(opts) {
9819
9934
  return;
9820
9935
  } else if (subcommand === "runtime") {
9821
9936
  if (args[1] === "providers") {
9822
- const { renderRuntimeProviders } = await import('./command-C1cKqmsa.mjs');
9937
+ const { renderRuntimeProviders } = await import('./command-mDMWVdh5.mjs');
9823
9938
  console.log(renderRuntimeProviders());
9824
9939
  return;
9825
9940
  }
@@ -9997,8 +10112,8 @@ function shouldRunMainClaudeFlow(opts) {
9997
10112
  const projectId = args[3];
9998
10113
  try {
9999
10114
  const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return config; });
10000
- const { readCredentials: readCredentials2 } = await import('./persistence-B8Wgn6aN.mjs');
10001
- const { ApiClient: ApiClient2 } = await import('./api-BYKV7vX6.mjs').then(function (n) { return n.v; });
10115
+ const { readCredentials: readCredentials2 } = await import('./persistence-DgpGouOO.mjs');
10116
+ const { ApiClient: ApiClient2 } = await import('./api-DRdn4-dL.mjs').then(function (n) { return n.v; });
10002
10117
  let userEmail = void 0;
10003
10118
  try {
10004
10119
  const credentials = await readCredentials2();
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var chalk = require('chalk');
4
- var api = require('./api-CdGT5hsH.cjs');
5
- var persistence = require('./persistence-CMvrZ4SA.cjs');
4
+ var api = require('./api-CeIpGPqs.cjs');
5
+ var persistence = require('./persistence-Czyd-Uei.cjs');
6
6
  var z = require('zod');
7
7
  var fs$2 = require('fs/promises');
8
8
  var os$1 = require('os');
@@ -72,7 +72,7 @@ async function openBrowser(url) {
72
72
  }
73
73
  }
74
74
 
75
- const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-D_S_7bqK.cjs', document.baseURI).href)));
75
+ const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-D68EOBHW.cjs', document.baseURI).href)));
76
76
  const QRCode = require$1("qrcode-terminal/vendor/QRCode");
77
77
  const QRErrorCorrectLevel = require$1("qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel");
78
78
  const pendingTempFiles = /* @__PURE__ */ new Set();
@@ -695,7 +695,7 @@ function setupCleanupHandlers() {
695
695
  });
696
696
  }
697
697
 
698
- const __dirname$2 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-D_S_7bqK.cjs', document.baseURI).href))));
698
+ const __dirname$2 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-D68EOBHW.cjs', document.baseURI).href))));
699
699
  function projectPath() {
700
700
  const path = path$1.resolve(__dirname$2, "..");
701
701
  return path;
@@ -2469,6 +2469,20 @@ function buildDaemonChildEnv(baseEnv, extraEnv) {
2469
2469
  }
2470
2470
 
2471
2471
  const DIFFERENT_DAEMON_RUNNING_MESSAGE = "A different daemon was started without killing us. We should kill ourselves.";
2472
+ function pruneStaleTrackedSessions({
2473
+ trackedSessionPids,
2474
+ removeTrackedSession,
2475
+ kill = process.kill
2476
+ }) {
2477
+ for (const pid of trackedSessionPids) {
2478
+ try {
2479
+ kill(pid, 0);
2480
+ } catch {
2481
+ api.logger.debug(`[DAEMON RUN] Removing stale session with PID ${pid} (process no longer exists)`);
2482
+ removeTrackedSession(pid);
2483
+ }
2484
+ }
2485
+ }
2472
2486
  function readProjectCliVersionFromDisk() {
2473
2487
  const packageJsonPath = path.join(projectPath(), "package.json");
2474
2488
  try {
@@ -2499,14 +2513,10 @@ async function runDaemonHealthCheck({
2499
2513
  requestShutdown,
2500
2514
  writeHeartbeat
2501
2515
  }) {
2502
- for (const pid of trackedSessionPids) {
2503
- try {
2504
- process.kill(pid, 0);
2505
- } catch {
2506
- api.logger.debug(`[DAEMON RUN] Removing stale session with PID ${pid} (process no longer exists)`);
2507
- removeTrackedSession(pid);
2508
- }
2509
- }
2516
+ pruneStaleTrackedSessions({
2517
+ trackedSessionPids,
2518
+ removeTrackedSession
2519
+ });
2510
2520
  const projectVersion = readProjectCliVersion();
2511
2521
  if (projectVersion && projectVersion !== currentCliVersion) {
2512
2522
  await onDaemonOutdated();
@@ -2978,7 +2988,42 @@ function resolveManagedSessionTag(env = process.env) {
2978
2988
  return readManagedSessionTag(env) ?? node_crypto.randomUUID();
2979
2989
  }
2980
2990
 
2991
+ const DEFAULT_MAX_LINES = 40;
2992
+ const DEFAULT_MAX_LINE_LENGTH = 300;
2993
+ function truncateLine(line, maxLineLength) {
2994
+ if (line.length <= maxLineLength) {
2995
+ return line;
2996
+ }
2997
+ return `${line.slice(0, Math.max(0, maxLineLength - 3))}...`;
2998
+ }
2999
+ function createChildProcessOutputBuffer(options) {
3000
+ const maxLines = Math.max(1, DEFAULT_MAX_LINES);
3001
+ const maxLineLength = Math.max(4, DEFAULT_MAX_LINE_LENGTH);
3002
+ const lines = [];
3003
+ return {
3004
+ push(text) {
3005
+ for (const rawLine of text.split(/\r?\n/)) {
3006
+ const line = rawLine.trim();
3007
+ if (!line) {
3008
+ continue;
3009
+ }
3010
+ lines.push(truncateLine(line, maxLineLength));
3011
+ while (lines.length > maxLines) {
3012
+ lines.shift();
3013
+ }
3014
+ }
3015
+ },
3016
+ snapshot() {
3017
+ return lines.join("\n");
3018
+ },
3019
+ hasContent() {
3020
+ return lines.length > 0;
3021
+ }
3022
+ };
3023
+ }
3024
+
2981
3025
  const DEFAULT_SESSION_WEBHOOK_TIMEOUT_MS = 45e3;
3026
+ const DEFAULT_TRACKED_SESSION_SWEEP_INTERVAL_MS = 5e3;
2982
3027
  function resolveSessionWebhookTimeoutMs() {
2983
3028
  const parsed = Number.parseInt(process.env.HAPPY_DAEMON_SESSION_WEBHOOK_TIMEOUT || "", 10);
2984
3029
  if (Number.isFinite(parsed) && parsed > 0) {
@@ -2986,6 +3031,13 @@ function resolveSessionWebhookTimeoutMs() {
2986
3031
  }
2987
3032
  return DEFAULT_SESSION_WEBHOOK_TIMEOUT_MS;
2988
3033
  }
3034
+ function resolveTrackedSessionSweepIntervalMs() {
3035
+ const parsed = Number.parseInt(process.env.HAPPY_DAEMON_TRACKED_SESSION_SWEEP_INTERVAL || "", 10);
3036
+ if (Number.isFinite(parsed) && parsed > 0) {
3037
+ return parsed;
3038
+ }
3039
+ return DEFAULT_TRACKED_SESSION_SWEEP_INTERVAL_MS;
3040
+ }
2989
3041
  const initialMachineMetadata = {
2990
3042
  host: os$1.hostname(),
2991
3043
  platform: os$1.platform(),
@@ -3016,6 +3068,7 @@ async function getProfileEnvironmentVariablesForAgent(profileId, agentType) {
3016
3068
  }
3017
3069
  async function startDaemon() {
3018
3070
  const sessionWebhookTimeoutMs = resolveSessionWebhookTimeoutMs();
3071
+ const trackedSessionSweepIntervalMs = resolveTrackedSessionSweepIntervalMs();
3019
3072
  const shutdownCoordinator = createShutdownCoordinator(async () => {
3020
3073
  api.logger.debug("[DAEMON RUN] Startup malfunctioned, forcing exit with code 1");
3021
3074
  await new Promise((resolve) => setTimeout(resolve, 100));
@@ -3350,14 +3403,39 @@ async function startDaemon() {
3350
3403
  // Capture stdout/stderr for debugging
3351
3404
  env: buildDaemonChildEnv(process.env, extraEnv)
3352
3405
  });
3353
- if (process.env.DEBUG) {
3354
- happyProcess.stdout?.on("data", (data) => {
3355
- api.logger.debug(`[DAEMON RUN] Child stdout: ${data.toString()}`);
3356
- });
3357
- happyProcess.stderr?.on("data", (data) => {
3358
- api.logger.debug(`[DAEMON RUN] Child stderr: ${data.toString()}`);
3359
- });
3360
- }
3406
+ const stdoutBuffer = createChildProcessOutputBuffer();
3407
+ const stderrBuffer = createChildProcessOutputBuffer();
3408
+ let childOutputSnapshotLogged = false;
3409
+ const logChildOutputSnapshot = (reason) => {
3410
+ if (childOutputSnapshotLogged) {
3411
+ return;
3412
+ }
3413
+ childOutputSnapshotLogged = true;
3414
+ const stdoutSnapshot = stdoutBuffer.snapshot();
3415
+ const stderrSnapshot = stderrBuffer.snapshot();
3416
+ if (stdoutSnapshot) {
3417
+ api.logger.debug(`[DAEMON RUN] Child PID ${happyProcess.pid} recent stdout before ${reason}:
3418
+ ${stdoutSnapshot}`);
3419
+ }
3420
+ if (stderrSnapshot) {
3421
+ api.logger.debug(`[DAEMON RUN] Child PID ${happyProcess.pid} recent stderr before ${reason}:
3422
+ ${stderrSnapshot}`);
3423
+ }
3424
+ };
3425
+ happyProcess.stdout?.on("data", (data) => {
3426
+ const text = data.toString();
3427
+ stdoutBuffer.push(text);
3428
+ if (process.env.DEBUG) {
3429
+ api.logger.debug(`[DAEMON RUN] Child stdout: ${text}`);
3430
+ }
3431
+ });
3432
+ happyProcess.stderr?.on("data", (data) => {
3433
+ const text = data.toString();
3434
+ stderrBuffer.push(text);
3435
+ if (process.env.DEBUG) {
3436
+ api.logger.debug(`[DAEMON RUN] Child stderr: ${text}`);
3437
+ }
3438
+ });
3361
3439
  if (!happyProcess.pid) {
3362
3440
  api.logger.debug("[DAEMON RUN] Failed to spawn process - no PID returned");
3363
3441
  if (precreatedCodexSession && api$1) {
@@ -3388,12 +3466,14 @@ async function startDaemon() {
3388
3466
  };
3389
3467
  pidToTrackedSession.set(happyProcess.pid, trackedSession);
3390
3468
  happyProcess.on("exit", (code, signal) => {
3469
+ logChildOutputSnapshot(`exit (code=${code}, signal=${signal})`);
3391
3470
  api.logger.debug(`[DAEMON RUN] Child PID ${happyProcess.pid} exited with code ${code}, signal ${signal}`);
3392
3471
  if (happyProcess.pid) {
3393
3472
  onChildExited(happyProcess.pid);
3394
3473
  }
3395
3474
  });
3396
3475
  happyProcess.on("error", (error) => {
3476
+ logChildOutputSnapshot("process error");
3397
3477
  api.logger.debug(`[DAEMON RUN] Child process error:`, error);
3398
3478
  if (happyProcess.pid) {
3399
3479
  onChildExited(happyProcess.pid);
@@ -3410,6 +3490,7 @@ async function startDaemon() {
3410
3490
  return new Promise((resolve) => {
3411
3491
  const timeout = setTimeout(() => {
3412
3492
  pidToAwaiter.delete(happyProcess.pid);
3493
+ logChildOutputSnapshot("session webhook timeout");
3413
3494
  api.logger.debug(`[DAEMON RUN] Session webhook timeout for PID ${happyProcess.pid}`);
3414
3495
  const spawnError = createSpawnSessionError(
3415
3496
  SPAWN_SESSION_ERROR_CODES.SESSION_WEBHOOK_TIMEOUT,
@@ -3594,6 +3675,25 @@ async function startDaemon() {
3594
3675
  api.logger.debug("[DAEMON RUN] Remote session index startup recovery failed", error);
3595
3676
  });
3596
3677
  const heartbeatIntervalMs = parseInt(process.env.HAPPY_DAEMON_HEARTBEAT_INTERVAL || "60000");
3678
+ let trackedSessionSweepRunning = false;
3679
+ const trackedSessionSweepInterval = setInterval(() => {
3680
+ if (trackedSessionSweepRunning) {
3681
+ return;
3682
+ }
3683
+ trackedSessionSweepRunning = true;
3684
+ try {
3685
+ pruneStaleTrackedSessions({
3686
+ trackedSessionPids: pidToTrackedSession.keys(),
3687
+ removeTrackedSession: (pid) => {
3688
+ removeTrackedSession(pid, `fast stale-session sweep removed tracked PID ${pid}`);
3689
+ }
3690
+ });
3691
+ } catch (error) {
3692
+ api.logger.debug("[DAEMON RUN] Fast tracked-session sweep failed", error);
3693
+ } finally {
3694
+ trackedSessionSweepRunning = false;
3695
+ }
3696
+ }, trackedSessionSweepIntervalMs);
3597
3697
  let heartbeatRunning = false;
3598
3698
  const restartOnStaleVersionAndHeartbeat = setInterval(async () => {
3599
3699
  if (heartbeatRunning) {
@@ -3665,6 +3765,7 @@ async function startDaemon() {
3665
3765
  clearInterval(restartOnStaleVersionAndHeartbeat);
3666
3766
  api.logger.debug("[DAEMON RUN] Health check interval cleared");
3667
3767
  }
3768
+ clearInterval(trackedSessionSweepInterval);
3668
3769
  if (remoteSessionIndexRefreshTimer) {
3669
3770
  clearTimeout(remoteSessionIndexRefreshTimer);
3670
3771
  remoteSessionIndexRefreshTimer = null;
@@ -7589,7 +7690,14 @@ ${recentStderrExcerpt}`);
7589
7690
  prompt: [contentBlock]
7590
7691
  };
7591
7692
  api.logger.debug(`[AcpBackend] Prompt request:`, JSON.stringify(promptRequest, null, 2));
7592
- await this.connection.prompt(promptRequest);
7693
+ await raceWithProcessExit(
7694
+ this.process,
7695
+ this.connection.prompt(promptRequest),
7696
+ {
7697
+ agentName: this.transport.agentName,
7698
+ operationName: "prompt"
7699
+ }
7700
+ );
7593
7701
  api.logger.debug("[AcpBackend] Prompt request sent to ACP connection");
7594
7702
  if (this.waitingForResponse && this.activeToolCalls.size === 0 && this.sawSessionUpdateSincePrompt === false) {
7595
7703
  const noUpdatesTimeoutMs = this.getPostPromptNoUpdatesTimeoutMs();
@@ -8482,7 +8590,7 @@ class AbortError extends Error {
8482
8590
  }
8483
8591
  }
8484
8592
 
8485
- const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-D_S_7bqK.cjs', document.baseURI).href)));
8593
+ const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-D68EOBHW.cjs', document.baseURI).href)));
8486
8594
  const __dirname$1 = path.join(__filename$1, "..");
8487
8595
  function getGlobalClaudeVersion() {
8488
8596
  try {
@@ -9752,11 +9860,11 @@ var launch = /*#__PURE__*/Object.freeze({
9752
9860
 
9753
9861
  const unifiedProviderExecutors = {
9754
9862
  claude: async (opts) => {
9755
- const { runClaude } = await Promise.resolve().then(function () { return require('./runClaude-DNZFsQY0.cjs'); });
9863
+ const { runClaude } = await Promise.resolve().then(function () { return require('./runClaude-DtCH-nx-.cjs'); });
9756
9864
  await runClaude(opts.credentials, opts.claudeOptions ?? {});
9757
9865
  },
9758
9866
  codex: async (opts) => {
9759
- const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-WZ91ZLK7.cjs'); });
9867
+ const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-reARLjN0.cjs'); });
9760
9868
  await runCodex({
9761
9869
  credentials: opts.credentials,
9762
9870
  startedBy: opts.startedBy,
@@ -9765,7 +9873,7 @@ const unifiedProviderExecutors = {
9765
9873
  });
9766
9874
  },
9767
9875
  gemini: async (opts) => {
9768
- const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-B_wCHgPU.cjs'); });
9876
+ const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-BvJUvOvj.cjs'); });
9769
9877
  await runGemini({
9770
9878
  credentials: opts.credentials,
9771
9879
  startedBy: opts.startedBy
@@ -9778,13 +9886,17 @@ const unifiedProviderExecutors = {
9778
9886
  });
9779
9887
  }
9780
9888
  };
9781
- async function ensureUnifiedRuntimePrerequisites(credentials) {
9889
+ async function ensureUnifiedRuntimePrerequisites(credentials, opts) {
9782
9890
  if (credentials) {
9783
- await ensureUnifiedDaemonStarted();
9891
+ if (!opts?.skipDaemonBootstrap) {
9892
+ await ensureUnifiedDaemonStarted();
9893
+ }
9784
9894
  return credentials;
9785
9895
  }
9786
9896
  const auth = await authAndSetupMachineIfNeeded();
9787
- await ensureUnifiedDaemonStarted();
9897
+ if (!opts?.skipDaemonBootstrap) {
9898
+ await ensureUnifiedDaemonStarted();
9899
+ }
9788
9900
  return auth.credentials;
9789
9901
  }
9790
9902
  async function ensureUnifiedDaemonStarted() {
@@ -9805,7 +9917,10 @@ async function ensureUnifiedDaemonStarted() {
9805
9917
  throw new Error("Failed to start Happy background service.");
9806
9918
  }
9807
9919
  async function executeUnifiedProvider(opts) {
9808
- const credentials = await ensureUnifiedRuntimePrerequisites(opts.credentials);
9920
+ const skipDaemonBootstrap = "startedBy" in opts && opts.startedBy === "daemon" || opts.provider === "claude" && opts.claudeOptions?.startedBy === "daemon";
9921
+ const credentials = await ensureUnifiedRuntimePrerequisites(opts.credentials, {
9922
+ skipDaemonBootstrap
9923
+ });
9809
9924
  await unifiedProviderExecutors[opts.provider]({
9810
9925
  ...opts,
9811
9926
  credentials
@@ -9841,7 +9956,7 @@ function shouldRunMainClaudeFlow(opts) {
9841
9956
  return;
9842
9957
  } else if (subcommand === "runtime") {
9843
9958
  if (args[1] === "providers") {
9844
- const { renderRuntimeProviders } = await Promise.resolve().then(function () { return require('./command-uyA8cYmL.cjs'); });
9959
+ const { renderRuntimeProviders } = await Promise.resolve().then(function () { return require('./command-CTad-7bA.cjs'); });
9845
9960
  console.log(renderRuntimeProviders());
9846
9961
  return;
9847
9962
  }
@@ -10019,8 +10134,8 @@ function shouldRunMainClaudeFlow(opts) {
10019
10134
  const projectId = args[3];
10020
10135
  try {
10021
10136
  const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return config; });
10022
- const { readCredentials: readCredentials2 } = await Promise.resolve().then(function () { return require('./persistence-CMvrZ4SA.cjs'); });
10023
- const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./api-CdGT5hsH.cjs'); }).then(function (n) { return n.api; });
10137
+ const { readCredentials: readCredentials2 } = await Promise.resolve().then(function () { return require('./persistence-Czyd-Uei.cjs'); });
10138
+ const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./api-CeIpGPqs.cjs'); }).then(function (n) { return n.api; });
10024
10139
  let userEmail = void 0;
10025
10140
  try {
10026
10141
  const credentials = await readCredentials2();
package/dist/index.cjs CHANGED
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  require('chalk');
4
- require('./api-CdGT5hsH.cjs');
5
- require('./persistence-CMvrZ4SA.cjs');
4
+ require('./api-CeIpGPqs.cjs');
5
+ require('./persistence-Czyd-Uei.cjs');
6
6
  require('zod');
7
- require('./index-D_S_7bqK.cjs');
7
+ require('./index-D68EOBHW.cjs');
8
8
  require('node:child_process');
9
9
  require('node:fs');
10
10
  require('cross-spawn');
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import 'chalk';
2
- import './api-BYKV7vX6.mjs';
3
- import './persistence-B8Wgn6aN.mjs';
2
+ import './api-DRdn4-dL.mjs';
3
+ import './persistence-DgpGouOO.mjs';
4
4
  import 'zod';
5
- import './index-BAhlFq45.mjs';
5
+ import './index-C4S85XB7.mjs';
6
6
  import 'node:child_process';
7
7
  import 'node:fs';
8
8
  import 'cross-spawn';
package/dist/lib.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var api = require('./api-CdGT5hsH.cjs');
3
+ var api = require('./api-CeIpGPqs.cjs');
4
4
  var types = require('./types-DVk3crez.cjs');
5
5
  require('axios');
6
6
  require('chalk');