happy-imou-cloud 2.1.47 → 2.1.48

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 (25) hide show
  1. package/dist/{BaseReasoningProcessor-CBbzF7oj.cjs → BaseReasoningProcessor-CKtDfihV.cjs} +2 -2
  2. package/dist/{BaseReasoningProcessor-KXIi0QF_.mjs → BaseReasoningProcessor-CM3JbXUC.mjs} +2 -2
  3. package/dist/{ProviderSelectionHandler-CJLlwlAu.cjs → ProviderSelectionHandler-BHKIBw4t.cjs} +2 -2
  4. package/dist/{ProviderSelectionHandler-DzYObYrV.mjs → ProviderSelectionHandler-vgZ2egD_.mjs} +2 -2
  5. package/dist/{api-D3vYIva3.mjs → api-CSjP-Z3Y.mjs} +3 -3
  6. package/dist/{api-CVuTajTL.cjs → api-eaGKJjMt.cjs} +3 -3
  7. package/dist/{command-fcJ-4Yq3.mjs → command-BzPI4N1n.mjs} +2 -2
  8. package/dist/{command-BZRQuZsh.cjs → command-DDoz1Eky.cjs} +2 -2
  9. package/dist/{index-Cp1I5I3U.mjs → index-BzsBo3_Z.mjs} +290 -20
  10. package/dist/{index-CyW9A7hx.cjs → index-C8X1VlHZ.cjs} +289 -19
  11. package/dist/index.cjs +2 -2
  12. package/dist/index.mjs +2 -2
  13. package/dist/lib.cjs +1 -1
  14. package/dist/lib.d.cts +2 -0
  15. package/dist/lib.d.mts +2 -0
  16. package/dist/lib.mjs +1 -1
  17. package/dist/{registerKillSessionHandler-OhhMUuCQ.mjs → registerKillSessionHandler-BHu-3hZQ.mjs} +2 -2
  18. package/dist/{registerKillSessionHandler-8C_Wrgor.cjs → registerKillSessionHandler-CLCYBgZX.cjs} +2 -2
  19. package/dist/{runClaude-CfdT_ccS.cjs → runClaude-BkUbXE2F.cjs} +4 -4
  20. package/dist/{runClaude-BviM1Wl5.mjs → runClaude-D3CBLW5o.mjs} +4 -4
  21. package/dist/{runCodex-B-t0yy4k.cjs → runCodex-CdgrZK7P.cjs} +29 -8
  22. package/dist/{runCodex-Dx3osc7U.mjs → runCodex-DqzdgDwZ.mjs} +29 -8
  23. package/dist/{runGemini-DZ5-uzB9.cjs → runGemini-BE05R24D.cjs} +4 -4
  24. package/dist/{runGemini-CnJ75Q--.mjs → runGemini-UZuiKe59.mjs} +4 -4
  25. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-CyW9A7hx.cjs');
4
- var persistence = require('./api-CVuTajTL.cjs');
3
+ var index = require('./index-C8X1VlHZ.cjs');
4
+ var persistence = require('./api-eaGKJjMt.cjs');
5
5
  var node_events = require('node:events');
6
6
  var node_crypto = require('node:crypto');
7
7
 
@@ -1,5 +1,5 @@
1
- import { a as createSessionMetadata, p as publishSessionRegistration } from './index-Cp1I5I3U.mjs';
2
- import { s as startOfflineReconnection, c as configuration, i as isAuthenticationRequiredError, l as logger } from './api-D3vYIva3.mjs';
1
+ import { a as createSessionMetadata, p as publishSessionRegistration } from './index-BzsBo3_Z.mjs';
2
+ import { s as startOfflineReconnection, c as configuration, i as isAuthenticationRequiredError, l as logger } from './api-CSjP-Z3Y.mjs';
3
3
  import { EventEmitter } from 'node:events';
4
4
  import { randomUUID } from 'node:crypto';
5
5
 
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var persistence = require('./api-CVuTajTL.cjs');
4
- var registerKillSessionHandler = require('./registerKillSessionHandler-8C_Wrgor.cjs');
3
+ var persistence = require('./api-eaGKJjMt.cjs');
4
+ var registerKillSessionHandler = require('./registerKillSessionHandler-CLCYBgZX.cjs');
5
5
 
6
6
  async function runModeLoop(opts) {
7
7
  let currentMode = opts.startingMode;
@@ -1,5 +1,5 @@
1
- import { l as logger } from './api-D3vYIva3.mjs';
2
- import { g as getPendingInteractionTimeoutMs, I as INTERACTION_SUPERSEDED_ERROR, a as INTERACTION_TIMED_OUT_ERROR } from './registerKillSessionHandler-OhhMUuCQ.mjs';
1
+ import { l as logger } from './api-CSjP-Z3Y.mjs';
2
+ import { g as getPendingInteractionTimeoutMs, I as INTERACTION_SUPERSEDED_ERROR, a as INTERACTION_TIMED_OUT_ERROR } from './registerKillSessionHandler-BHu-3hZQ.mjs';
3
3
 
4
4
  async function runModeLoop(opts) {
5
5
  let currentMode = opts.startingMode;
@@ -18,7 +18,7 @@ import { spawn } from 'node:child_process';
18
18
  import { Expo } from 'expo-server-sdk';
19
19
 
20
20
  var name = "happy-imou-cloud";
21
- var version = "2.1.47";
21
+ var version = "2.1.48";
22
22
  var description = "hicloud - Imou 企业定制版。关键是 happy!移动端远程 AI 编程工具,支持 Claude Code、Codex 和 Gemini CLI";
23
23
  var author = "long.zhu";
24
24
  var license = "MIT";
@@ -6198,12 +6198,12 @@ class ApiMachineClient {
6198
6198
  requestShutdown
6199
6199
  }) {
6200
6200
  this.rpcHandlerManager.registerHandler("spawn-happy-session", async (params) => {
6201
- const { directory, sessionId, machineId, managedSessionTag, approvedNewDirectoryCreation, agent, token, resume, environmentVariables } = params || {};
6201
+ const { directory, sessionId, machineId, managedSessionTag, approvedNewDirectoryCreation, agent, token, resume, launchMode, environmentVariables } = params || {};
6202
6202
  logger.debug(`[API MACHINE] Spawning session with params: ${JSON.stringify(params)}`);
6203
6203
  if (!directory) {
6204
6204
  throw new Error("Directory is required");
6205
6205
  }
6206
- const result = await spawnSession({ directory, sessionId, machineId, managedSessionTag, approvedNewDirectoryCreation, agent, token, resume, environmentVariables });
6206
+ const result = await spawnSession({ directory, sessionId, machineId, managedSessionTag, approvedNewDirectoryCreation, agent, token, resume, launchMode, environmentVariables });
6207
6207
  switch (result.type) {
6208
6208
  case "success":
6209
6209
  logger.debug(`[API MACHINE] Spawned session ${result.sessionId}`);
@@ -38,7 +38,7 @@ function _interopNamespaceDefault(e) {
38
38
  var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
39
39
 
40
40
  var name = "happy-imou-cloud";
41
- var version = "2.1.47";
41
+ var version = "2.1.48";
42
42
  var description = "hicloud - Imou 企业定制版。关键是 happy!移动端远程 AI 编程工具,支持 Claude Code、Codex 和 Gemini CLI";
43
43
  var author = "long.zhu";
44
44
  var license = "MIT";
@@ -6218,12 +6218,12 @@ class ApiMachineClient {
6218
6218
  requestShutdown
6219
6219
  }) {
6220
6220
  this.rpcHandlerManager.registerHandler("spawn-happy-session", async (params) => {
6221
- const { directory, sessionId, machineId, managedSessionTag, approvedNewDirectoryCreation, agent, token, resume, environmentVariables } = params || {};
6221
+ const { directory, sessionId, machineId, managedSessionTag, approvedNewDirectoryCreation, agent, token, resume, launchMode, environmentVariables } = params || {};
6222
6222
  logger.debug(`[API MACHINE] Spawning session with params: ${JSON.stringify(params)}`);
6223
6223
  if (!directory) {
6224
6224
  throw new Error("Directory is required");
6225
6225
  }
6226
- const result = await spawnSession({ directory, sessionId, machineId, managedSessionTag, approvedNewDirectoryCreation, agent, token, resume, environmentVariables });
6226
+ const result = await spawnSession({ directory, sessionId, machineId, managedSessionTag, approvedNewDirectoryCreation, agent, token, resume, launchMode, environmentVariables });
6227
6227
  switch (result.type) {
6228
6228
  case "success":
6229
6229
  logger.debug(`[API MACHINE] Spawned session ${result.sessionId}`);
@@ -1,6 +1,6 @@
1
- import { c as createDefaultRuntimeShell } from './index-Cp1I5I3U.mjs';
1
+ import { c as createDefaultRuntimeShell } from './index-BzsBo3_Z.mjs';
2
2
  import 'chalk';
3
- import './api-D3vYIva3.mjs';
3
+ import './api-CSjP-Z3Y.mjs';
4
4
  import 'axios';
5
5
  import 'fs';
6
6
  import 'node:fs';
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-CyW9A7hx.cjs');
3
+ var index = require('./index-C8X1VlHZ.cjs');
4
4
  require('chalk');
5
- require('./api-CVuTajTL.cjs');
5
+ require('./api-eaGKJjMt.cjs');
6
6
  require('axios');
7
7
  require('fs');
8
8
  require('node:fs');
@@ -1,5 +1,5 @@
1
1
  import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
2
- import { l as logger, q as encodeBase64, c as configuration, t as readCredentials, u as ensureSigningCredentials, r as readSettings, v as updateSettings, w as encodeBase64Url, m as delay, x as buildClientHeaders, y as decodeBase64, z as writeCredentialsLegacy, B as writeCredentialsDataKey, C as readDaemonState, D as HAPPY_CLOUD_DAEMON_PORT, E as clearDaemonState, F as packageJson, i as isAuthenticationRequiredError, G as buildSessionRuntimeIndex, I as acquireDaemonLock, J as writeDaemonState, A as ApiClient, K as releaseDaemonLock, L as validateProfileForAgent, M as getProfileEnvironmentVariables, N as clearCredentials, O as clearMachineId, P as readHappyOrgDispatchTruthSnapshot, Q as processHappyOrgRepoRequests, R as readHappyOrgRepoTaskBoard, S as HappyOrgTurnReportSchema, T as recordHappyOrgTurnReport, U as MessageContentSchema, V as buildSocketAuth, W as encrypt, H as HeadTailPreviewBuffer, X as getLatestDaemonLog } from './api-D3vYIva3.mjs';
2
+ import { l as logger, q as encodeBase64, c as configuration, t as readCredentials, u as ensureSigningCredentials, r as readSettings, v as updateSettings, w as encodeBase64Url, m as delay, x as buildClientHeaders, y as decodeBase64, z as writeCredentialsLegacy, B as writeCredentialsDataKey, C as readDaemonState, D as HAPPY_CLOUD_DAEMON_PORT, E as clearDaemonState, F as packageJson, i as isAuthenticationRequiredError, G as buildSessionRuntimeIndex, I as acquireDaemonLock, J as writeDaemonState, A as ApiClient, K as releaseDaemonLock, L as validateProfileForAgent, M as getProfileEnvironmentVariables, N as clearCredentials, O as clearMachineId, P as readHappyOrgDispatchTruthSnapshot, Q as processHappyOrgRepoRequests, R as readHappyOrgRepoTaskBoard, S as HappyOrgTurnReportSchema, T as recordHappyOrgTurnReport, U as MessageContentSchema, V as buildSocketAuth, W as encrypt, H as HeadTailPreviewBuffer, X as getLatestDaemonLog } from './api-CSjP-Z3Y.mjs';
3
3
  import { z } from 'zod';
4
4
  import fs, { writeFile as writeFile$1, rename, unlink as unlink$1 } from 'fs/promises';
5
5
  import os$1, { homedir as homedir$1 } from 'os';
@@ -10,18 +10,18 @@ import qrcode from 'qrcode-terminal';
10
10
  import { writeFile, unlink, readdir, readFile, mkdir } from 'node:fs/promises';
11
11
  import { createRequire } from 'node:module';
12
12
  import os, { tmpdir, homedir } from 'node:os';
13
- import path, { join, resolve as resolve$1, dirname as dirname$1, normalize, isAbsolute, delimiter, relative, basename } from 'node:path';
13
+ import path, { join, delimiter, resolve as resolve$1, dirname as dirname$1, normalize, isAbsolute, relative, basename } from 'node:path';
14
14
  import open from 'open';
15
15
  import React, { useState } from 'react';
16
16
  import { useInput, Box, Text, render } from 'ink';
17
17
  import { spawn, execSync, exec } from 'child_process';
18
18
  import { dirname, resolve, join as join$1 } from 'path';
19
19
  import { fileURLToPath } from 'url';
20
- import { readFileSync as readFileSync$1, existsSync as existsSync$1, writeFileSync as writeFileSync$1, chmodSync, unlinkSync as unlinkSync$1, mkdirSync as mkdirSync$1 } from 'fs';
20
+ import { readFileSync as readFileSync$1, existsSync as existsSync$1, writeFileSync as writeFileSync$1, chmodSync as chmodSync$1, unlinkSync as unlinkSync$1, mkdirSync as mkdirSync$1 } from 'fs';
21
21
  import { execFileSync, spawn as spawn$2, execSync as execSync$1 } from 'node:child_process';
22
22
  import psList from 'ps-list';
23
23
  import spawn$1 from 'cross-spawn';
24
- import fs$1, { existsSync, readFileSync, readdirSync, statSync, unlinkSync, mkdirSync, writeFileSync, cpSync, rmSync, mkdtempSync, realpathSync } from 'node:fs';
24
+ import fs$1, { existsSync, readFileSync, readdirSync, statSync, mkdtempSync, writeFileSync, chmodSync, unlinkSync, mkdirSync, cpSync, rmSync, realpathSync } from 'node:fs';
25
25
  import fastify from 'fastify';
26
26
  import { validatorCompiler, serializerCompiler } from 'fastify-type-provider-zod';
27
27
  import { randomUUID as randomUUID$1, randomBytes as randomBytes$1, createHash } from 'crypto';
@@ -1566,7 +1566,8 @@ function startDaemonControlServer({
1566
1566
  body: z.object({
1567
1567
  directory: z.string(),
1568
1568
  sessionId: z.string().optional(),
1569
- agent: z.enum(["claude", "codex", "gemini"]).optional()
1569
+ agent: z.enum(["claude", "codex", "gemini"]).optional(),
1570
+ launchMode: z.enum(["background", "terminalWindow", "localTerminal"]).optional()
1570
1571
  }),
1571
1572
  response: {
1572
1573
  200: z.object({
@@ -1587,9 +1588,9 @@ function startDaemonControlServer({
1587
1588
  }
1588
1589
  }
1589
1590
  }, async (request, reply) => {
1590
- const { directory, sessionId, agent } = request.body;
1591
- logger.debug(`[CONTROL SERVER] Spawn session request: dir=${directory}, sessionId=${sessionId || "new"}, agent=${agent || "claude"}`);
1592
- const result = await spawnSession({ directory, sessionId, agent });
1591
+ const { directory, sessionId, agent, launchMode } = request.body;
1592
+ logger.debug(`[CONTROL SERVER] Spawn session request: dir=${directory}, sessionId=${sessionId || "new"}, agent=${agent || "claude"}, launchMode=${launchMode || "background"}`);
1593
+ const result = await spawnSession({ directory, sessionId, agent, launchMode });
1593
1594
  switch (result.type) {
1594
1595
  case "success":
1595
1596
  if (!result.sessionId) {
@@ -2333,20 +2334,33 @@ function resolveDaemonSpawnAgent(agent) {
2333
2334
  throw new Error(`Unsupported agent type: '${agent}'. Please update your CLI to the latest version.`);
2334
2335
  }
2335
2336
  }
2336
- function buildDaemonSpawnArgs(agent, resume) {
2337
+ function buildDaemonSpawnArgs(agent, optionsOrResume) {
2338
+ const options = isLegacyResumeOptions(optionsOrResume) ? { resume: optionsOrResume } : optionsOrResume ?? {};
2339
+ const startingMode = options.startingMode ?? "remote";
2340
+ const startedBy = options.startedBy ?? "daemon";
2337
2341
  const args = [
2338
2342
  resolveDaemonSpawnAgent(agent),
2339
2343
  "--happy-starting-mode",
2340
- "remote",
2344
+ startingMode,
2341
2345
  "--started-by",
2342
- "daemon"
2346
+ startedBy
2343
2347
  ];
2344
- const providerSessionId = typeof resume?.providerSessionId === "string" ? resume.providerSessionId.trim() : "";
2348
+ const providerSessionId = typeof options.resume?.providerSessionId === "string" ? options.resume.providerSessionId.trim() : "";
2345
2349
  if (providerSessionId.length > 0) {
2346
2350
  args.push("--resume", providerSessionId);
2347
2351
  }
2348
2352
  return args;
2349
2353
  }
2354
+ function buildTerminalWindowSpawnArgs(agent, resume) {
2355
+ return buildDaemonSpawnArgs(agent, {
2356
+ resume,
2357
+ startingMode: "local",
2358
+ startedBy: "terminal"
2359
+ });
2360
+ }
2361
+ function isLegacyResumeOptions(value) {
2362
+ return Boolean(value && "providerSessionId" in value);
2363
+ }
2350
2364
 
2351
2365
  const SPAWN_SESSION_ERROR_CODES = {
2352
2366
  INVALID_REQUEST: "INVALID_REQUEST",
@@ -2409,6 +2423,157 @@ function buildDaemonChildEnv(baseEnv, extraEnv) {
2409
2423
  return childEnv;
2410
2424
  }
2411
2425
 
2426
+ function quotePosix(value) {
2427
+ return `'${value.replace(/'/g, `'"'"'`)}'`;
2428
+ }
2429
+ function quoteAppleScriptString(value) {
2430
+ return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
2431
+ }
2432
+ function quoteWindowsCmd(value) {
2433
+ return `"${value.replace(/(["^&|<>()%])/g, "^$1")}"`;
2434
+ }
2435
+ function buildRuntimeInvocation(args, platform, entrypointOverride) {
2436
+ const projectRoot = projectPath();
2437
+ const entrypoint = entrypointOverride || join(projectRoot, "dist", "index.mjs");
2438
+ const runtime = isBun() ? "bun" : "node";
2439
+ const runtimeArgs = ["--no-warnings", "--no-deprecation", entrypoint, ...args];
2440
+ const commandParts = [runtime, ...runtimeArgs];
2441
+ if (platform === "win32") {
2442
+ return commandParts.map(quoteWindowsCmd).join(" ");
2443
+ }
2444
+ return commandParts.map(quotePosix).join(" ");
2445
+ }
2446
+ function buildUserFacingPreview(args) {
2447
+ const agent = args[0];
2448
+ if (agent === "claude" || agent === "codex" || agent === "gemini") {
2449
+ return `hicloud ${agent}`;
2450
+ }
2451
+ return `hicloud ${args.join(" ")}`.trim();
2452
+ }
2453
+ function buildPathWithProjectBin(env, platform) {
2454
+ const binPath = join(projectPath(), "node_modules", ".bin");
2455
+ const pathDelimiter = platform === "win32" ? ";" : delimiter;
2456
+ const currentPath = env?.PATH || env?.Path || process.env.PATH || "";
2457
+ return currentPath ? `${binPath}${pathDelimiter}${currentPath}` : binPath;
2458
+ }
2459
+ function isValidEnvironmentVariableName(name) {
2460
+ return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name);
2461
+ }
2462
+ function escapeWindowsBatchSetValue(value) {
2463
+ return value.replace(/\r?\n/g, "").replace(/%/g, "%%");
2464
+ }
2465
+ function collectLaunchEnv(env, platform) {
2466
+ const result = {};
2467
+ for (const [key, value] of Object.entries(env || {})) {
2468
+ if (typeof value === "string" && isValidEnvironmentVariableName(key)) {
2469
+ result[key] = value;
2470
+ }
2471
+ }
2472
+ result.PATH = buildPathWithProjectBin(env, platform);
2473
+ return result;
2474
+ }
2475
+ function buildTerminalLaunchScriptContent(options) {
2476
+ const platform = options.platform || process.platform;
2477
+ const launchEnv = collectLaunchEnv(options.env, platform);
2478
+ const preview = buildUserFacingPreview(options.args);
2479
+ const runtimeInvocation = buildRuntimeInvocation(options.args, platform, options.entrypoint);
2480
+ if (platform === "win32") {
2481
+ const envLines2 = Object.entries(launchEnv).map(([key, value]) => `set "${key}=${escapeWindowsBatchSetValue(value)}"`).join("\r\n");
2482
+ return [
2483
+ "@echo off",
2484
+ "setlocal",
2485
+ envLines2,
2486
+ `cd /d ${quoteWindowsCmd(options.cwd)}`,
2487
+ `echo $ ${preview}`,
2488
+ runtimeInvocation,
2489
+ "echo.",
2490
+ "echo Happy session command exited. You can close this window.",
2491
+ 'del "%~f0" >nul 2>nul',
2492
+ "endlocal",
2493
+ ""
2494
+ ].join("\r\n");
2495
+ }
2496
+ const envLines = Object.entries(launchEnv).map(([key, value]) => `export ${key}=${quotePosix(value)}`).join("\n");
2497
+ return [
2498
+ "#!/usr/bin/env bash",
2499
+ "set +e",
2500
+ 'rm -f "$0" >/dev/null 2>&1 || true',
2501
+ envLines,
2502
+ `cd ${quotePosix(options.cwd)} || exit $?`,
2503
+ `echo ${quotePosix(`$ ${preview}`)}`,
2504
+ runtimeInvocation,
2505
+ "status=$?",
2506
+ "echo",
2507
+ 'echo "Happy session command exited with status ${status}. You can close this window."',
2508
+ 'exec "${SHELL:-bash}" -l',
2509
+ ""
2510
+ ].join("\n");
2511
+ }
2512
+ function createTerminalLaunchScript(options) {
2513
+ if (options.scriptPath) {
2514
+ return options.scriptPath;
2515
+ }
2516
+ const platform = options.platform || process.platform;
2517
+ const scriptDirectory = mkdtempSync(join(tmpdir(), "happy-terminal-launch-"));
2518
+ const scriptPath = join(scriptDirectory, platform === "win32" ? "launch.cmd" : "launch.sh");
2519
+ writeFileSync(scriptPath, buildTerminalLaunchScriptContent({ ...options, platform }), { encoding: "utf8", mode: 448 });
2520
+ if (platform !== "win32") {
2521
+ chmodSync(scriptPath, 448);
2522
+ }
2523
+ return scriptPath;
2524
+ }
2525
+ function buildTerminalWindowLaunchCommand(options) {
2526
+ const platform = options.platform || process.platform;
2527
+ const scriptPath = createTerminalLaunchScript({ ...options, platform });
2528
+ const preview = buildUserFacingPreview(options.args);
2529
+ if (platform === "win32") {
2530
+ return {
2531
+ command: "cmd.exe",
2532
+ args: ["/d", "/s", "/c", `start "" cmd.exe /d /s /k ${quoteWindowsCmd(scriptPath)}`],
2533
+ options: {
2534
+ cwd: options.cwd,
2535
+ detached: true,
2536
+ stdio: "ignore",
2537
+ env: options.env,
2538
+ windowsHide: false
2539
+ },
2540
+ preview,
2541
+ scriptPath
2542
+ };
2543
+ }
2544
+ if (platform === "darwin") {
2545
+ const appleScript = `tell application "Terminal" to do script ${quoteAppleScriptString(`bash ${quotePosix(scriptPath)}`)}`;
2546
+ return {
2547
+ command: "osascript",
2548
+ args: ["-e", appleScript],
2549
+ options: {
2550
+ cwd: options.cwd,
2551
+ detached: true,
2552
+ stdio: "ignore",
2553
+ env: options.env
2554
+ },
2555
+ preview,
2556
+ scriptPath
2557
+ };
2558
+ }
2559
+ return {
2560
+ command: "x-terminal-emulator",
2561
+ args: ["-e", "bash", scriptPath],
2562
+ options: {
2563
+ cwd: options.cwd,
2564
+ detached: true,
2565
+ stdio: "ignore",
2566
+ env: options.env
2567
+ },
2568
+ preview,
2569
+ scriptPath
2570
+ };
2571
+ }
2572
+ function spawnHappyCLIInTerminalWindow(options) {
2573
+ const launchCommand = buildTerminalWindowLaunchCommand(options);
2574
+ return spawn$2(launchCommand.command, launchCommand.args, launchCommand.options);
2575
+ }
2576
+
2412
2577
  const DIFFERENT_DAEMON_RUNNING_MESSAGE = "A different daemon was started without killing us. We should kill ourselves.";
2413
2578
  function pruneStaleTrackedSessions({
2414
2579
  trackedSessionPids,
@@ -3566,6 +3731,28 @@ async function startDaemon() {
3566
3731
  let api = null;
3567
3732
  const pidToTrackedSession = /* @__PURE__ */ new Map();
3568
3733
  const pidToAwaiter = /* @__PURE__ */ new Map();
3734
+ const terminalLaunchAwaiters = /* @__PURE__ */ new Map();
3735
+ const normalizePathForSessionMatch = (value) => (value || "").trim().replace(/[\\/]+$/, "");
3736
+ const resolveTerminalLaunchAwaiter = (sessionId, sessionMetadata) => {
3737
+ const reportedDirectory = normalizePathForSessionMatch(sessionMetadata.path);
3738
+ const reportedFlavor = resolveRecoverySpawnAgent(sessionMetadata.flavor);
3739
+ const now = Date.now();
3740
+ for (const [awaiterId, awaiter] of terminalLaunchAwaiters.entries()) {
3741
+ if (awaiter.startedAt - 5e3 > now) {
3742
+ continue;
3743
+ }
3744
+ const directoryMatches = normalizePathForSessionMatch(awaiter.directory) === reportedDirectory;
3745
+ const agentMatches = !awaiter.agent || !reportedFlavor || awaiter.agent === reportedFlavor;
3746
+ if (!directoryMatches || !agentMatches) {
3747
+ continue;
3748
+ }
3749
+ terminalLaunchAwaiters.delete(awaiterId);
3750
+ awaiter.resolve({ type: "success", sessionId });
3751
+ logger.debug(`[DAEMON RUN] Resolved terminal window session awaiter ${awaiterId} for session ${sessionId}`);
3752
+ return true;
3753
+ }
3754
+ return false;
3755
+ };
3569
3756
  const getCurrentChildren = () => Array.from(pidToTrackedSession.values());
3570
3757
  let userScopedObserver = null;
3571
3758
  const removeTrackedSession = (pid, archiveReason) => {
@@ -3614,6 +3801,7 @@ async function startDaemon() {
3614
3801
  };
3615
3802
  pidToTrackedSession.set(pid, trackedSession);
3616
3803
  logger.debug(`[DAEMON RUN] Registered externally-started session ${sessionId}`);
3804
+ resolveTerminalLaunchAwaiter(sessionId, sessionMetadata);
3617
3805
  }
3618
3806
  };
3619
3807
  const spawnSession = async (options) => {
@@ -3723,6 +3911,84 @@ async function startDaemon() {
3723
3911
  errorMessage: spawnError.errorMessage
3724
3912
  };
3725
3913
  }
3914
+ if (options.launchMode === "terminalWindow" || options.launchMode === "localTerminal") {
3915
+ logger.debug(`[DAEMON RUN] Using visible terminal window spawning`);
3916
+ let args;
3917
+ try {
3918
+ args = buildTerminalWindowSpawnArgs(options.agent, options.resume);
3919
+ } catch (error) {
3920
+ const spawnError = createSpawnSessionError(
3921
+ SPAWN_SESSION_ERROR_CODES.INVALID_REQUEST,
3922
+ error instanceof Error ? error.message : String(error)
3923
+ );
3924
+ return {
3925
+ type: spawnError.type,
3926
+ errorMessage: spawnError.errorMessage
3927
+ };
3928
+ }
3929
+ const terminalEnv = buildDaemonChildEnv(process.env, extraEnv);
3930
+ const terminalProcess = spawnHappyCLIInTerminalWindow({
3931
+ cwd: directory,
3932
+ args,
3933
+ env: terminalEnv
3934
+ });
3935
+ if (!terminalProcess.pid) {
3936
+ logger.debug("[DAEMON RUN] Failed to spawn terminal window - no PID returned");
3937
+ const spawnError = createSpawnSessionError(
3938
+ SPAWN_SESSION_ERROR_CODES.SPAWN_NO_PID,
3939
+ "Failed to spawn terminal window - no PID returned"
3940
+ );
3941
+ return {
3942
+ type: spawnError.type,
3943
+ errorMessage: spawnError.errorMessage
3944
+ };
3945
+ }
3946
+ logger.debug(`[DAEMON RUN] Spawned terminal window process with PID ${terminalProcess.pid}`);
3947
+ const trackedSession = {
3948
+ startedBy: "daemon terminal window",
3949
+ happySessionId: options.sessionId,
3950
+ sessionIndex: null,
3951
+ skipDetachedManagedSessionArchive: true,
3952
+ pid: terminalProcess.pid,
3953
+ childProcess: terminalProcess,
3954
+ directoryCreated,
3955
+ message: directoryCreated ? `The path '${directory}' did not exist. We created a new folder and opened a terminal window there.` : `Opened a terminal window in '${directory}' to start the session.`
3956
+ };
3957
+ pidToTrackedSession.set(terminalProcess.pid, trackedSession);
3958
+ terminalProcess.on("exit", (code, signal) => {
3959
+ logger.debug(`[DAEMON RUN] Terminal launcher PID ${terminalProcess.pid} exited with code ${code}, signal ${signal}`);
3960
+ });
3961
+ terminalProcess.on("error", (error) => {
3962
+ logger.debug(`[DAEMON RUN] Terminal launcher process error:`, error);
3963
+ });
3964
+ terminalProcess.unref();
3965
+ const terminalAwaiterId = randomUUID();
3966
+ const launchStartedAt = Date.now();
3967
+ logger.debug(`[DAEMON RUN] Waiting for terminal window session webhook ${terminalAwaiterId}`);
3968
+ return new Promise((resolve) => {
3969
+ const timeout = setTimeout(() => {
3970
+ terminalLaunchAwaiters.delete(terminalAwaiterId);
3971
+ logger.debug(`[DAEMON RUN] Terminal window session webhook timeout for PID ${terminalProcess.pid}`);
3972
+ const spawnError = createSpawnSessionError(
3973
+ SPAWN_SESSION_ERROR_CODES.SESSION_WEBHOOK_TIMEOUT,
3974
+ `Terminal window session webhook timeout for PID ${terminalProcess.pid}`
3975
+ );
3976
+ resolve({
3977
+ type: spawnError.type,
3978
+ errorMessage: spawnError.errorMessage
3979
+ });
3980
+ }, sessionWebhookTimeoutMs);
3981
+ terminalLaunchAwaiters.set(terminalAwaiterId, {
3982
+ directory,
3983
+ agent: options.agent,
3984
+ startedAt: launchStartedAt,
3985
+ resolve: (result) => {
3986
+ clearTimeout(timeout);
3987
+ resolve(result);
3988
+ }
3989
+ });
3990
+ });
3991
+ }
3726
3992
  let tmuxSessionName = extraEnv.TMUX_SESSION_NAME;
3727
3993
  const tmuxRequested = tmuxSessionName !== void 0;
3728
3994
  const tmuxAvailable = tmuxRequested ? await isTmuxAvailable() : false;
@@ -4383,7 +4649,7 @@ async function install$1() {
4383
4649
  </plist>
4384
4650
  `);
4385
4651
  writeFileSync$1(PLIST_FILE$1, plistContent);
4386
- chmodSync(PLIST_FILE$1, 420);
4652
+ chmodSync$1(PLIST_FILE$1, 420);
4387
4653
  logger.info(`Created daemon plist at ${PLIST_FILE$1}`);
4388
4654
  execSync(`launchctl load ${PLIST_FILE$1}`, { stdio: "inherit" });
4389
4655
  logger.info("Daemon installed and started successfully");
@@ -9397,10 +9663,14 @@ Recent stderr: ${recentStderrSummaryLine}` : `Signal: ${signal}`;
9397
9663
  async () => {
9398
9664
  let timeoutHandle = null;
9399
9665
  try {
9666
+ const resumeSession = this.connection.resumeSession ?? this.connection.unstable_resumeSession;
9400
9667
  const result = await raceWithProcessExit(
9401
9668
  this.process,
9402
9669
  () => Promise.race([
9403
- (sessionOperation === "resume" ? this.connection.resumeSession(sessionRequest) : sessionOperation === "load" ? this.connection.loadSession(sessionRequest) : this.connection.newSession(sessionRequest)).then((res) => {
9670
+ (sessionOperation === "resume" ? resumeSession ? resumeSession(sessionRequest).then((response) => ({
9671
+ ...response,
9672
+ sessionId: requestedResumeSessionId
9673
+ })) : Promise.reject(new Error("ACP agent advertised session resume, but this SDK connection does not expose resumeSession.")) : sessionOperation === "load" ? this.connection.loadSession(sessionRequest) : this.connection.newSession(sessionRequest)).then((res) => {
9404
9674
  if (timeoutHandle) {
9405
9675
  clearTimeout(timeoutHandle);
9406
9676
  timeoutHandle = null;
@@ -12221,14 +12491,14 @@ var launch = /*#__PURE__*/Object.freeze({
12221
12491
  const unifiedProviderExecutors = {
12222
12492
  claude: async (opts) => {
12223
12493
  const claudeOptions = opts.claudeOptions ?? {};
12224
- const { runClaude } = await import('./runClaude-BviM1Wl5.mjs');
12494
+ const { runClaude } = await import('./runClaude-D3CBLW5o.mjs');
12225
12495
  await runClaude(opts.credentials, {
12226
12496
  ...claudeOptions,
12227
12497
  startingMode: claudeOptions.startingMode ?? (claudeOptions.startedBy === "daemon" ? "remote" : void 0)
12228
12498
  });
12229
12499
  },
12230
12500
  codex: async (opts) => {
12231
- const { runCodex } = await import('./runCodex-Dx3osc7U.mjs');
12501
+ const { runCodex } = await import('./runCodex-DqzdgDwZ.mjs');
12232
12502
  await runCodex({
12233
12503
  credentials: opts.credentials,
12234
12504
  startedBy: opts.startedBy,
@@ -12237,7 +12507,7 @@ const unifiedProviderExecutors = {
12237
12507
  });
12238
12508
  },
12239
12509
  gemini: async (opts) => {
12240
- const { runGemini } = await import('./runGemini-CnJ75Q--.mjs');
12510
+ const { runGemini } = await import('./runGemini-UZuiKe59.mjs');
12241
12511
  await runGemini({
12242
12512
  credentials: opts.credentials,
12243
12513
  startedBy: opts.startedBy
@@ -12320,7 +12590,7 @@ function shouldRunMainClaudeFlow(opts) {
12320
12590
  return;
12321
12591
  } else if (subcommand === "runtime") {
12322
12592
  if (args[1] === "providers") {
12323
- const { renderRuntimeProviders } = await import('./command-fcJ-4Yq3.mjs');
12593
+ const { renderRuntimeProviders } = await import('./command-BzPI4N1n.mjs');
12324
12594
  console.log(renderRuntimeProviders());
12325
12595
  return;
12326
12596
  }
@@ -12526,8 +12796,8 @@ function shouldRunMainClaudeFlow(opts) {
12526
12796
  const projectId = args[3];
12527
12797
  try {
12528
12798
  const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return config; });
12529
- const { readCredentials: readCredentials2 } = await import('./api-D3vYIva3.mjs').then(function (n) { return n.Y; });
12530
- const { ApiClient: ApiClient2 } = await import('./api-D3vYIva3.mjs').then(function (n) { return n.Z; });
12799
+ const { readCredentials: readCredentials2 } = await import('./api-CSjP-Z3Y.mjs').then(function (n) { return n.Y; });
12800
+ const { ApiClient: ApiClient2 } = await import('./api-CSjP-Z3Y.mjs').then(function (n) { return n.Z; });
12531
12801
  let userEmail = void 0;
12532
12802
  try {
12533
12803
  const credentials = await readCredentials2();