happy-imou-cloud 2.1.4 → 2.1.6

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 (28) hide show
  1. package/bin/happy-cloud.mjs +38 -38
  2. package/dist/{BaseReasoningProcessor-DgdsExMH.cjs → BaseReasoningProcessor-C3oDrA4i.cjs} +17 -4
  3. package/dist/{BaseReasoningProcessor-lTsZVuAU.mjs → BaseReasoningProcessor-CRXr7Axk.mjs} +16 -3
  4. package/dist/{ProviderSelectionHandler-CGTnB7ba.mjs → ProviderSelectionHandler-C3kHFqeq.mjs} +2 -2
  5. package/dist/{ProviderSelectionHandler-Bavm9TDG.cjs → ProviderSelectionHandler-Drg2Pp1-.cjs} +2 -2
  6. package/dist/{api-B6ESNpGB.cjs → api-CvtU4DI-.cjs} +2 -2
  7. package/dist/{api-l8X03rs-.mjs → api-DF9A136-.mjs} +3 -3
  8. package/dist/{command-DPLKOzMr.cjs → command-UZr1nodh.cjs} +3 -3
  9. package/dist/{command-BVCkEMtp.mjs → command-hO52qTzQ.mjs} +3 -3
  10. package/dist/{index-D72RMo5Z.mjs → index-B5e-MA1d.mjs} +268 -32
  11. package/dist/{index-D1BP-fEm.cjs → index-DA-K28E3.cjs} +264 -24
  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 +36 -36
  16. package/dist/lib.d.mts +36 -36
  17. package/dist/lib.mjs +1 -1
  18. package/dist/{persistence-CyFjFOlN.mjs → persistence-BsWBBi7E.mjs} +1 -1
  19. package/dist/{persistence-EDmI-c8T.cjs → persistence-CKgPuZRR.cjs} +1 -1
  20. package/dist/{registerKillSessionHandler-71xCO8e_.cjs → registerKillSessionHandler-3ytO-yBI.cjs} +72 -79
  21. package/dist/{registerKillSessionHandler-DAVhkb-l.mjs → registerKillSessionHandler-DmG1p8l7.mjs} +73 -78
  22. package/dist/{runClaude-BRhQLKjh.mjs → runClaude-MF34EsCp.mjs} +103 -40
  23. package/dist/{runClaude-DjnTGJGC.cjs → runClaude-bAlUdUGw.cjs} +106 -43
  24. package/dist/{runCodex-DUs_jBE-.mjs → runCodex-B31D_imZ.mjs} +10 -8
  25. package/dist/{runCodex-BHq7Rnq7.cjs → runCodex-CiIbJ1wa.cjs} +12 -10
  26. package/dist/{runGemini-pmvBZ6qU.mjs → runGemini-BJ7PxLyl.mjs} +5 -5
  27. package/dist/{runGemini-hkZeOnA_.cjs → runGemini-BZJR84o-.cjs} +7 -7
  28. package/package.json +2 -2
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var chalk = require('chalk');
4
- var api = require('./api-B6ESNpGB.cjs');
5
- var persistence = require('./persistence-EDmI-c8T.cjs');
4
+ var api = require('./api-CvtU4DI-.cjs');
5
+ var persistence = require('./persistence-CKgPuZRR.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-D1BP-fEm.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-DA-K28E3.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-D1BP-fEm.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-DA-K28E3.cjs', document.baseURI).href))));
699
699
  function projectPath() {
700
700
  const path = path$1.resolve(__dirname$2, "..");
701
701
  return path;
@@ -2521,6 +2521,128 @@ async function runDaemonHealthCheck({
2521
2521
  await writeHeartbeat();
2522
2522
  }
2523
2523
 
2524
+ async function closeProviderSession(session, opts = {}) {
2525
+ let firstError;
2526
+ const captureError = (error) => {
2527
+ if (firstError === void 0) {
2528
+ firstError = error;
2529
+ }
2530
+ };
2531
+ if (opts.archiveOnClose || opts.archiveReason) {
2532
+ try {
2533
+ session.updateMetadata((currentMetadata) => {
2534
+ const { archiveReason: _existingArchiveReason, ...metadataWithoutArchiveReason } = currentMetadata;
2535
+ return {
2536
+ ...metadataWithoutArchiveReason,
2537
+ lifecycleState: "archived",
2538
+ lifecycleStateSince: Date.now(),
2539
+ archivedBy: opts.archivedBy ?? "cli",
2540
+ ...opts.archiveReason ? { archiveReason: opts.archiveReason } : {}
2541
+ };
2542
+ });
2543
+ } catch (error) {
2544
+ captureError(error);
2545
+ }
2546
+ }
2547
+ try {
2548
+ session.sendSessionDeath();
2549
+ } catch (error) {
2550
+ captureError(error);
2551
+ }
2552
+ try {
2553
+ await session.flush();
2554
+ } catch (error) {
2555
+ captureError(error);
2556
+ }
2557
+ try {
2558
+ await session.close();
2559
+ } catch (error) {
2560
+ captureError(error);
2561
+ }
2562
+ if (firstError !== void 0) {
2563
+ throw firstError;
2564
+ }
2565
+ }
2566
+
2567
+ function createSessionMetadata(opts) {
2568
+ const state = {
2569
+ controlledByUser: false
2570
+ };
2571
+ const metadataPath = opts.path ?? process.cwd();
2572
+ const metadataHostPid = opts.hostPid === void 0 ? process.pid : opts.hostPid;
2573
+ const metadata = {
2574
+ path: metadataPath,
2575
+ host: os.hostname(),
2576
+ version: api.packageJson.version,
2577
+ os: os.platform(),
2578
+ machineId: opts.machineId,
2579
+ homeDir: os.homedir(),
2580
+ happyHomeDir: api.configuration.happyCloudHomeDir,
2581
+ happyLibDir: projectPath(),
2582
+ happyToolsDir: path.resolve(projectPath(), "tools", "unpacked"),
2583
+ startedFromDaemon: opts.startedBy === "daemon",
2584
+ startedBy: opts.startedBy || "terminal",
2585
+ lifecycleState: "running",
2586
+ lifecycleStateSince: Date.now(),
2587
+ flavor: opts.flavor,
2588
+ ...metadataHostPid == null ? {} : { hostPid: metadataHostPid }
2589
+ };
2590
+ return { state, metadata };
2591
+ }
2592
+
2593
+ async function archiveManagedSessionById(opts) {
2594
+ try {
2595
+ const sessionClient = opts.api.sessionSyncClient({ id: opts.sessionId });
2596
+ await closeProviderSession(sessionClient, {
2597
+ archiveReason: opts.archiveReason,
2598
+ archivedBy: "daemon"
2599
+ });
2600
+ } catch (error) {
2601
+ api.logger.debug(
2602
+ `[DAEMON RUN] Failed to archive managed session ${opts.sessionId}: ${opts.archiveReason}`,
2603
+ error
2604
+ );
2605
+ }
2606
+ }
2607
+ async function precreateDaemonManagedSession(opts) {
2608
+ const { state, metadata } = createSessionMetadata({
2609
+ flavor: opts.flavor,
2610
+ machineId: opts.machineId,
2611
+ startedBy: "daemon",
2612
+ path: opts.directory,
2613
+ hostPid: null
2614
+ });
2615
+ try {
2616
+ return await opts.api.getOrCreateSession({
2617
+ tag: opts.sessionTag,
2618
+ metadata,
2619
+ state
2620
+ });
2621
+ } catch (error) {
2622
+ api.logger.debug(`[DAEMON RUN] Failed to precreate ${opts.flavor} session for tag ${opts.sessionTag}`, error);
2623
+ return null;
2624
+ }
2625
+ }
2626
+ async function archivePrecreatedManagedSession(opts) {
2627
+ await archiveManagedSessionById({
2628
+ api: opts.api,
2629
+ sessionId: opts.session.id,
2630
+ archiveReason: opts.archiveReason
2631
+ });
2632
+ }
2633
+ async function archiveDetachedManagedSessionIfNeeded(opts) {
2634
+ const { trackedSession } = opts;
2635
+ if (trackedSession.startedBy !== "daemon" || !trackedSession.happySessionId || trackedSession.happySessionMetadataFromLocalWebhook) {
2636
+ return false;
2637
+ }
2638
+ await archiveManagedSessionById({
2639
+ api: opts.api,
2640
+ sessionId: trackedSession.happySessionId,
2641
+ archiveReason: opts.archiveReason
2642
+ });
2643
+ return true;
2644
+ }
2645
+
2524
2646
  const NON_SESSION_PROCESS_TYPES$1 = /* @__PURE__ */ new Set([
2525
2647
  "current",
2526
2648
  "daemon",
@@ -2843,6 +2965,19 @@ async function recoverTrackedSessionsFromLocalRegistry({
2843
2965
  return { recoveredCount, removedStaleCount };
2844
2966
  }
2845
2967
 
2968
+ const HAPPY_MANAGED_SESSION_TAG_ENV = "HAPPY_MANAGED_SESSION_TAG";
2969
+ function readManagedSessionTag(env = process.env) {
2970
+ const raw = env[HAPPY_MANAGED_SESSION_TAG_ENV];
2971
+ if (typeof raw !== "string") {
2972
+ return null;
2973
+ }
2974
+ const trimmed = raw.trim();
2975
+ return trimmed.length > 0 ? trimmed : null;
2976
+ }
2977
+ function resolveManagedSessionTag(env = process.env) {
2978
+ return readManagedSessionTag(env) ?? node_crypto.randomUUID();
2979
+ }
2980
+
2846
2981
  const DEFAULT_SESSION_WEBHOOK_TIMEOUT_MS = 45e3;
2847
2982
  function resolveSessionWebhookTimeoutMs() {
2848
2983
  const parsed = Number.parseInt(process.env.HAPPY_DAEMON_SESSION_WEBHOOK_TIMEOUT || "", 10);
@@ -2939,9 +3074,21 @@ async function startDaemon() {
2939
3074
  }
2940
3075
  const { credentials, machineId } = await authAndSetupMachineIfNeeded();
2941
3076
  api.logger.debug("[DAEMON RUN] Auth and machine setup complete");
3077
+ let api$1 = null;
2942
3078
  const pidToTrackedSession = /* @__PURE__ */ new Map();
2943
3079
  const pidToAwaiter = /* @__PURE__ */ new Map();
2944
3080
  const getCurrentChildren = () => Array.from(pidToTrackedSession.values());
3081
+ const removeTrackedSession = (pid, archiveReason) => {
3082
+ const trackedSession = pidToTrackedSession.get(pid);
3083
+ if (trackedSession && api$1) {
3084
+ void archiveDetachedManagedSessionIfNeeded({
3085
+ api: api$1,
3086
+ trackedSession,
3087
+ archiveReason
3088
+ });
3089
+ }
3090
+ pidToTrackedSession.delete(pid);
3091
+ };
2945
3092
  const onHappySessionWebhook = (sessionId, sessionMetadata) => {
2946
3093
  api.logger.debugLargeJson(`[DAEMON RUN] Session reported`, sessionMetadata);
2947
3094
  const pid = sessionMetadata.hostPid;
@@ -2978,8 +3125,9 @@ async function startDaemon() {
2978
3125
  };
2979
3126
  const spawnSession = async (options) => {
2980
3127
  api.logger.debugLargeJson("[DAEMON RUN] Spawning session", options);
2981
- const { directory, sessionId, machineId: machineId2, approvedNewDirectoryCreation = true } = options;
3128
+ const { directory, sessionId, machineId: _requestedMachineId, approvedNewDirectoryCreation = true } = options;
2982
3129
  let directoryCreated = false;
3130
+ let precreatedCodexSession = null;
2983
3131
  try {
2984
3132
  await fs$2.access(directory);
2985
3133
  api.logger.debug(`[DAEMON RUN] Directory exists: ${directory}`);
@@ -3053,6 +3201,11 @@ async function startDaemon() {
3053
3201
  }
3054
3202
  let extraEnv = { ...profileEnv, ...authEnv };
3055
3203
  api.logger.debug(`[DAEMON RUN] Final environment variable keys (before expansion) (${Object.keys(extraEnv).length}): ${Object.keys(extraEnv).join(", ")}`);
3204
+ const managedSessionTag = options.agent === "codex" ? node_crypto.randomUUID() : null;
3205
+ if (managedSessionTag) {
3206
+ extraEnv[HAPPY_MANAGED_SESSION_TAG_ENV] = managedSessionTag;
3207
+ api.logger.debug(`[DAEMON RUN] Reserved managed Codex session tag ${managedSessionTag}`);
3208
+ }
3056
3209
  extraEnv = expandEnvironmentVariables(extraEnv, process.env);
3057
3210
  api.logger.debug(`[DAEMON RUN] After variable expansion: ${Object.keys(extraEnv).join(", ")}`);
3058
3211
  const potentialAuthVars = ["ANTHROPIC_AUTH_TOKEN", "CLAUDE_CODE_OAUTH_TOKEN", "OPENAI_API_KEY", "CODEX_HOME", "AZURE_OPENAI_API_KEY", "TOGETHER_API_KEY"];
@@ -3091,6 +3244,18 @@ async function startDaemon() {
3091
3244
  const fullCommand = `node --no-warnings --no-deprecation ${cliPath} ${buildDaemonSpawnArgs(agent).join(" ")}`;
3092
3245
  const windowName = `happy-${Date.now()}-${agent}`;
3093
3246
  const tmuxEnv = buildDaemonChildEnv(process.env, extraEnv);
3247
+ if (managedSessionTag && api$1) {
3248
+ precreatedCodexSession = await precreateDaemonManagedSession({
3249
+ api: api$1,
3250
+ sessionTag: managedSessionTag,
3251
+ machineId,
3252
+ directory,
3253
+ flavor: "codex"
3254
+ });
3255
+ if (precreatedCodexSession) {
3256
+ api.logger.debug(`[DAEMON RUN] Precreated Codex session ${precreatedCodexSession.id} before tmux spawn`);
3257
+ }
3258
+ }
3094
3259
  const tmuxResult = await tmux.spawnInTmux([fullCommand], {
3095
3260
  sessionName: tmuxSessionName,
3096
3261
  windowName,
@@ -3103,6 +3268,7 @@ async function startDaemon() {
3103
3268
  }
3104
3269
  const trackedSession = {
3105
3270
  startedBy: "daemon",
3271
+ happySessionId: precreatedCodexSession?.id,
3106
3272
  pid: tmuxResult.pid,
3107
3273
  // Real PID from tmux -P flag
3108
3274
  tmuxSessionId: tmuxResult.sessionId,
@@ -3110,6 +3276,13 @@ async function startDaemon() {
3110
3276
  message: directoryCreated ? `The path '${directory}' did not exist. We created a new folder and spawned a new session in tmux session '${tmuxSessionName}'. Use 'tmux attach -t ${tmuxSessionName}' to view the session.` : `Spawned new session in tmux session '${tmuxSessionName}'. Use 'tmux attach -t ${tmuxSessionName}' to view the session.`
3111
3277
  };
3112
3278
  pidToTrackedSession.set(tmuxResult.pid, trackedSession);
3279
+ if (precreatedCodexSession) {
3280
+ api.logger.debug(`[DAEMON RUN] Returning precreated Codex session ${precreatedCodexSession.id} without waiting for webhook`);
3281
+ return {
3282
+ type: "success",
3283
+ sessionId: precreatedCodexSession.id
3284
+ };
3285
+ }
3113
3286
  api.logger.debug(`[DAEMON RUN] Waiting for session webhook for PID ${tmuxResult.pid} (tmux)`);
3114
3287
  return new Promise((resolve) => {
3115
3288
  const timeout = setTimeout(() => {
@@ -3130,6 +3303,14 @@ async function startDaemon() {
3130
3303
  });
3131
3304
  });
3132
3305
  } else {
3306
+ if (precreatedCodexSession && api$1) {
3307
+ await archivePrecreatedManagedSession({
3308
+ api: api$1,
3309
+ session: precreatedCodexSession,
3310
+ archiveReason: `tmux spawn failed before Codex session ${precreatedCodexSession.id} attached`
3311
+ });
3312
+ precreatedCodexSession = null;
3313
+ }
3133
3314
  api.logger.debug(`[DAEMON RUN] Failed to spawn in tmux: ${tmuxResult.error}, falling back to regular spawning`);
3134
3315
  useTmux = false;
3135
3316
  }
@@ -3149,6 +3330,18 @@ async function startDaemon() {
3149
3330
  errorMessage: spawnError.errorMessage
3150
3331
  };
3151
3332
  }
3333
+ if (managedSessionTag && api$1) {
3334
+ precreatedCodexSession = await precreateDaemonManagedSession({
3335
+ api: api$1,
3336
+ sessionTag: managedSessionTag,
3337
+ machineId,
3338
+ directory,
3339
+ flavor: "codex"
3340
+ });
3341
+ if (precreatedCodexSession) {
3342
+ api.logger.debug(`[DAEMON RUN] Precreated Codex session ${precreatedCodexSession.id} before process spawn`);
3343
+ }
3344
+ }
3152
3345
  const happyProcess = spawnHappyCLI(args, {
3153
3346
  cwd: directory,
3154
3347
  detached: true,
@@ -3167,6 +3360,14 @@ async function startDaemon() {
3167
3360
  }
3168
3361
  if (!happyProcess.pid) {
3169
3362
  api.logger.debug("[DAEMON RUN] Failed to spawn process - no PID returned");
3363
+ if (precreatedCodexSession && api$1) {
3364
+ await archivePrecreatedManagedSession({
3365
+ api: api$1,
3366
+ session: precreatedCodexSession,
3367
+ archiveReason: `spawn produced no PID for precreated Codex session ${precreatedCodexSession.id}`
3368
+ });
3369
+ precreatedCodexSession = null;
3370
+ }
3170
3371
  const spawnError = createSpawnSessionError(
3171
3372
  SPAWN_SESSION_ERROR_CODES.SPAWN_NO_PID,
3172
3373
  "Failed to spawn Happy process - no PID returned"
@@ -3179,6 +3380,7 @@ async function startDaemon() {
3179
3380
  api.logger.debug(`[DAEMON RUN] Spawned process with PID ${happyProcess.pid}`);
3180
3381
  const trackedSession = {
3181
3382
  startedBy: "daemon",
3383
+ happySessionId: precreatedCodexSession?.id,
3182
3384
  pid: happyProcess.pid,
3183
3385
  childProcess: happyProcess,
3184
3386
  directoryCreated,
@@ -3197,6 +3399,13 @@ async function startDaemon() {
3197
3399
  onChildExited(happyProcess.pid);
3198
3400
  }
3199
3401
  });
3402
+ if (precreatedCodexSession) {
3403
+ api.logger.debug(`[DAEMON RUN] Returning precreated Codex session ${precreatedCodexSession.id} without waiting for webhook`);
3404
+ return {
3405
+ type: "success",
3406
+ sessionId: precreatedCodexSession.id
3407
+ };
3408
+ }
3200
3409
  api.logger.debug(`[DAEMON RUN] Waiting for session webhook for PID ${happyProcess.pid}`);
3201
3410
  return new Promise((resolve) => {
3202
3411
  const timeout = setTimeout(() => {
@@ -3224,6 +3433,13 @@ async function startDaemon() {
3224
3433
  } catch (error) {
3225
3434
  const errorMessage = error instanceof Error ? error.message : String(error);
3226
3435
  api.logger.debug("[DAEMON RUN] Failed to spawn session:", error);
3436
+ if (precreatedCodexSession && api$1) {
3437
+ await archivePrecreatedManagedSession({
3438
+ api: api$1,
3439
+ session: precreatedCodexSession,
3440
+ archiveReason: `spawn failed before precreated Codex session ${precreatedCodexSession.id} attached: ${errorMessage}`
3441
+ });
3442
+ }
3227
3443
  const spawnError = createSpawnSessionError(
3228
3444
  SPAWN_SESSION_ERROR_CODES.SPAWN_FAILED,
3229
3445
  `Failed to spawn session: ${errorMessage}`
@@ -3253,7 +3469,7 @@ async function startDaemon() {
3253
3469
  api.logger.debug(`[DAEMON RUN] Failed to kill external session PID ${pid}:`, error);
3254
3470
  }
3255
3471
  }
3256
- pidToTrackedSession.delete(pid);
3472
+ removeTrackedSession(pid, `session ${sessionId} was stopped from daemon control before local attachment completed`);
3257
3473
  api.logger.debug(`[DAEMON RUN] Removed session ${sessionId} from tracking`);
3258
3474
  return true;
3259
3475
  }
@@ -3275,7 +3491,7 @@ async function startDaemon() {
3275
3491
  errorMessage: spawnError.errorMessage
3276
3492
  });
3277
3493
  }
3278
- pidToTrackedSession.delete(pid);
3494
+ removeTrackedSession(pid, `process ${pid} exited before the managed session fully attached`);
3279
3495
  };
3280
3496
  const { port: controlPort, stop: stopControlServer } = await startDaemonControlServer({
3281
3497
  getChildren: getCurrentChildren,
@@ -3313,22 +3529,23 @@ async function startDaemon() {
3313
3529
  httpPort: controlPort,
3314
3530
  startedAt: Date.now()
3315
3531
  };
3316
- const api$1 = await api.ApiClient.create(credentials);
3532
+ api$1 = await api.ApiClient.create(credentials);
3533
+ const activeApi = api$1;
3317
3534
  let userScopedObserver = null;
3318
3535
  if (credentials.signing) {
3319
3536
  try {
3320
- userScopedObserver = api$1.userScopedObserverClient?.() ?? null;
3537
+ userScopedObserver = activeApi.userScopedObserverClient?.() ?? null;
3321
3538
  } catch (error) {
3322
3539
  api.logger.debug("[DAEMON RUN] Failed to start user-scoped observer, continuing without it", error);
3323
3540
  }
3324
3541
  }
3325
- const machine = await api$1.getOrCreateMachine({
3542
+ const machine = await activeApi.getOrCreateMachine({
3326
3543
  machineId,
3327
3544
  metadata: initialMachineMetadata,
3328
3545
  daemonState: initialDaemonState
3329
3546
  });
3330
3547
  api.logger.debug(`[DAEMON RUN] Machine registered: ${machine.id}`);
3331
- const apiMachine = api$1.machineSyncClient(machine);
3548
+ const apiMachine = activeApi.machineSyncClient(machine);
3332
3549
  apiMachine.setRPCHandlers({
3333
3550
  spawnSession,
3334
3551
  stopSession,
@@ -3336,7 +3553,7 @@ async function startDaemon() {
3336
3553
  });
3337
3554
  const runRemoteSessionIndexRecovery = async (label) => {
3338
3555
  const recoveryResult = await recoverTrackedSessionsFromRemoteIndex({
3339
- api: api$1,
3556
+ api: activeApi,
3340
3557
  machineId,
3341
3558
  trackedSessionPids: pidToTrackedSession.keys(),
3342
3559
  trackSession: (pid, trackedSession) => {
@@ -3392,7 +3609,7 @@ async function startDaemon() {
3392
3609
  await runDaemonHealthCheck({
3393
3610
  trackedSessionPids: pidToTrackedSession.keys(),
3394
3611
  removeTrackedSession: (pid) => {
3395
- pidToTrackedSession.delete(pid);
3612
+ removeTrackedSession(pid, `health check removed stale tracked PID ${pid} before local attachment completed`);
3396
3613
  },
3397
3614
  currentCliVersion: api.configuration.currentCliVersion,
3398
3615
  onDaemonOutdated: async () => {
@@ -8265,7 +8482,7 @@ class AbortError extends Error {
8265
8482
  }
8266
8483
  }
8267
8484
 
8268
- 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-D1BP-fEm.cjs', document.baseURI).href)));
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-DA-K28E3.cjs', document.baseURI).href)));
8269
8486
  const __dirname$1 = path.join(__filename$1, "..");
8270
8487
  function getGlobalClaudeVersion() {
8271
8488
  try {
@@ -8387,6 +8604,7 @@ class Query {
8387
8604
  }
8388
8605
  pendingControlResponses = /* @__PURE__ */ new Map();
8389
8606
  cancelControllers = /* @__PURE__ */ new Map();
8607
+ controlTasks = /* @__PURE__ */ new Set();
8390
8608
  sdkMessages;
8391
8609
  inputStream = new Stream();
8392
8610
  canCallTool;
@@ -8435,7 +8653,12 @@ class Query {
8435
8653
  }
8436
8654
  continue;
8437
8655
  } else if (message.type === "control_request") {
8438
- await this.handleControlRequest(message);
8656
+ const controlTask = this.handleControlRequest(message).catch((error) => {
8657
+ api.logger.debug("[ClaudeSDK] Failed to handle control request:", error);
8658
+ }).finally(() => {
8659
+ this.controlTasks.delete(controlTask);
8660
+ });
8661
+ this.controlTasks.add(controlTask);
8439
8662
  continue;
8440
8663
  } else if (message.type === "control_cancel_request") {
8441
8664
  this.handleControlCancelRequest(message);
@@ -8451,8 +8674,11 @@ class Query {
8451
8674
  } catch (error) {
8452
8675
  this.inputStream.error(error);
8453
8676
  } finally {
8454
- this.inputStream.done();
8455
8677
  this.cleanupControllers();
8678
+ if (this.controlTasks.size > 0) {
8679
+ await Promise.allSettled(Array.from(this.controlTasks));
8680
+ }
8681
+ this.inputStream.done();
8456
8682
  rl.close();
8457
8683
  }
8458
8684
  }
@@ -8517,7 +8743,7 @@ class Query {
8517
8743
  response
8518
8744
  }
8519
8745
  };
8520
- this.childStdin.write(JSON.stringify(controlResponse) + "\n");
8746
+ this.writeControlResponse(controlResponse);
8521
8747
  } catch (error) {
8522
8748
  const controlErrorResponse = {
8523
8749
  type: "control_response",
@@ -8527,11 +8753,21 @@ class Query {
8527
8753
  error: error instanceof Error ? error.message : String(error)
8528
8754
  }
8529
8755
  };
8530
- this.childStdin.write(JSON.stringify(controlErrorResponse) + "\n");
8756
+ this.writeControlResponse(controlErrorResponse);
8531
8757
  } finally {
8532
8758
  this.cancelControllers.delete(request.request_id);
8533
8759
  }
8534
8760
  }
8761
+ writeControlResponse(response) {
8762
+ if (!this.childStdin || this.childStdin.destroyed || !this.childStdin.writable) {
8763
+ return;
8764
+ }
8765
+ try {
8766
+ this.childStdin.write(JSON.stringify(response) + "\n");
8767
+ } catch (error) {
8768
+ api.logger.debug("[ClaudeSDK] Failed to write control response:", error);
8769
+ }
8770
+ }
8535
8771
  /**
8536
8772
  * Handle control cancel requests
8537
8773
  * Replicates the exact logic from the SDK's handleControlCancelRequest method
@@ -9516,11 +9752,11 @@ var launch = /*#__PURE__*/Object.freeze({
9516
9752
 
9517
9753
  const unifiedProviderExecutors = {
9518
9754
  claude: async (opts) => {
9519
- const { runClaude } = await Promise.resolve().then(function () { return require('./runClaude-DjnTGJGC.cjs'); });
9755
+ const { runClaude } = await Promise.resolve().then(function () { return require('./runClaude-bAlUdUGw.cjs'); });
9520
9756
  await runClaude(opts.credentials, opts.claudeOptions ?? {});
9521
9757
  },
9522
9758
  codex: async (opts) => {
9523
- const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-BHq7Rnq7.cjs'); });
9759
+ const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-CiIbJ1wa.cjs'); });
9524
9760
  await runCodex({
9525
9761
  credentials: opts.credentials,
9526
9762
  startedBy: opts.startedBy,
@@ -9529,7 +9765,7 @@ const unifiedProviderExecutors = {
9529
9765
  });
9530
9766
  },
9531
9767
  gemini: async (opts) => {
9532
- const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-hkZeOnA_.cjs'); });
9768
+ const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-BZJR84o-.cjs'); });
9533
9769
  await runGemini({
9534
9770
  credentials: opts.credentials,
9535
9771
  startedBy: opts.startedBy
@@ -9605,7 +9841,7 @@ function shouldRunMainClaudeFlow(opts) {
9605
9841
  return;
9606
9842
  } else if (subcommand === "runtime") {
9607
9843
  if (args[1] === "providers") {
9608
- const { renderRuntimeProviders } = await Promise.resolve().then(function () { return require('./command-DPLKOzMr.cjs'); });
9844
+ const { renderRuntimeProviders } = await Promise.resolve().then(function () { return require('./command-UZr1nodh.cjs'); });
9609
9845
  console.log(renderRuntimeProviders());
9610
9846
  return;
9611
9847
  }
@@ -9783,8 +10019,8 @@ function shouldRunMainClaudeFlow(opts) {
9783
10019
  const projectId = args[3];
9784
10020
  try {
9785
10021
  const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return config; });
9786
- const { readCredentials: readCredentials2 } = await Promise.resolve().then(function () { return require('./persistence-EDmI-c8T.cjs'); });
9787
- const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./api-B6ESNpGB.cjs'); }).then(function (n) { return n.api; });
10022
+ const { readCredentials: readCredentials2 } = await Promise.resolve().then(function () { return require('./persistence-CKgPuZRR.cjs'); });
10023
+ const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./api-CvtU4DI-.cjs'); }).then(function (n) { return n.api; });
9788
10024
  let userEmail = void 0;
9789
10025
  try {
9790
10026
  const credentials = await readCredentials2();
@@ -10208,10 +10444,12 @@ exports.PushableAsyncIterable = PushableAsyncIterable;
10208
10444
  exports.RuntimeShell = RuntimeShell;
10209
10445
  exports.claudeCheckSession = claudeCheckSession;
10210
10446
  exports.claudeLocal = claudeLocal;
10447
+ exports.closeProviderSession = closeProviderSession;
10211
10448
  exports.createClaudeBackend = createClaudeBackend;
10212
10449
  exports.createCodexBackend = createCodexBackend;
10213
10450
  exports.createDefaultRuntimeShell = createDefaultRuntimeShell;
10214
10451
  exports.createGeminiBackend = createGeminiBackend;
10452
+ exports.createSessionMetadata = createSessionMetadata;
10215
10453
  exports.formatDisplayMessage = formatDisplayMessage;
10216
10454
  exports.getEnvironmentInfo = getEnvironmentInfo;
10217
10455
  exports.getInitialGeminiModel = getInitialGeminiModel;
@@ -10222,7 +10460,9 @@ exports.projectPath = projectPath;
10222
10460
  exports.publishSessionRegistration = publishSessionRegistration;
10223
10461
  exports.query = query;
10224
10462
  exports.readGeminiLocalConfig = readGeminiLocalConfig;
10463
+ exports.readManagedSessionTag = readManagedSessionTag;
10225
10464
  exports.resolveCanonicalToolNameV2 = resolveCanonicalToolNameV2;
10465
+ exports.resolveManagedSessionTag = resolveManagedSessionTag;
10226
10466
  exports.saveGeminiModelToConfig = saveGeminiModelToConfig;
10227
10467
  exports.startCaffeinate = startCaffeinate;
10228
10468
  exports.stopCaffeinate = stopCaffeinate;
package/dist/index.cjs CHANGED
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  require('chalk');
4
- require('./api-B6ESNpGB.cjs');
5
- require('./persistence-EDmI-c8T.cjs');
4
+ require('./api-CvtU4DI-.cjs');
5
+ require('./persistence-CKgPuZRR.cjs');
6
6
  require('zod');
7
- require('./index-D1BP-fEm.cjs');
7
+ require('./index-DA-K28E3.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-l8X03rs-.mjs';
3
- import './persistence-CyFjFOlN.mjs';
2
+ import './api-DF9A136-.mjs';
3
+ import './persistence-BsWBBi7E.mjs';
4
4
  import 'zod';
5
- import './index-D72RMo5Z.mjs';
5
+ import './index-B5e-MA1d.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-B6ESNpGB.cjs');
3
+ var api = require('./api-CvtU4DI-.cjs');
4
4
  var types = require('./types-DVk3crez.cjs');
5
5
  require('axios');
6
6
  require('chalk');