happy-imou-cloud 2.0.0 → 2.0.2

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 (27) hide show
  1. package/dist/{BaseReasoningProcessor-BRCQXCZY.cjs → BaseReasoningProcessor-B6tJ_eL5.cjs} +96 -9
  2. package/dist/{BaseReasoningProcessor-BKLRCKTU.mjs → BaseReasoningProcessor-D8VhEbs2.mjs} +95 -10
  3. package/dist/{api-D7OK-mML.cjs → api-D2Njw9Im.cjs} +124 -6
  4. package/dist/{api-BGXYX0yH.mjs → api-MYhAGPLn.mjs} +122 -7
  5. package/dist/{command-G85giEAF.cjs → command-CVldr51S.cjs} +3 -3
  6. package/dist/{command-CnLtKtP-.mjs → command-nmK6O-ab.mjs} +3 -3
  7. package/dist/{index-C7Y0R-MI.mjs → index-B97L7qLD.mjs} +689 -229
  8. package/dist/{index-B_wlQBy2.cjs → index-Bg-YziG2.cjs} +691 -229
  9. package/dist/index.cjs +4 -4
  10. package/dist/index.mjs +4 -4
  11. package/dist/lib.cjs +1 -1
  12. package/dist/lib.d.cts +7 -0
  13. package/dist/lib.d.mts +7 -0
  14. package/dist/lib.mjs +1 -1
  15. package/dist/{persistence-DHgf1CTG.cjs → persistence-D_2GkJAO.cjs} +28 -6
  16. package/dist/{persistence-BA_unuca.mjs → persistence-Dkm7rm8k.mjs} +29 -7
  17. package/dist/{registerKillSessionHandler-C2-yHm1V.mjs → registerKillSessionHandler-5GbrO0FM.mjs} +6 -4
  18. package/dist/{registerKillSessionHandler-CLREXN11.cjs → registerKillSessionHandler-BAXmJQRt.cjs} +6 -4
  19. package/dist/{runClaude-CwAitpX-.cjs → runClaude-B-GNEkKg.cjs} +237 -45
  20. package/dist/{runClaude-uNC5Eym4.mjs → runClaude-Cii3R2Fv.mjs} +238 -46
  21. package/dist/{runCodex-B-05E-YZ.mjs → runCodex-C--ZwAhl.mjs} +636 -819
  22. package/dist/{runCodex-Cm0VTqw_.cjs → runCodex-CPHyGwj9.cjs} +639 -819
  23. package/dist/{runGemini-_biXvQAH.mjs → runGemini-CQp7Nuzn.mjs} +20 -16
  24. package/dist/{runGemini-CLWjwDYS.cjs → runGemini-DaDz1bzQ.cjs} +20 -16
  25. package/package.json +14 -15
  26. package/scripts/env-wrapper.cjs +11 -11
  27. package/scripts/setup-dev.cjs +4 -4
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var chalk = require('chalk');
4
- var api = require('./api-D7OK-mML.cjs');
5
- var persistence = require('./persistence-DHgf1CTG.cjs');
4
+ var api = require('./api-D2Njw9Im.cjs');
5
+ var persistence = require('./persistence-D_2GkJAO.cjs');
6
6
  var z = require('zod');
7
7
  var fs$2 = require('fs/promises');
8
8
  var os$1 = require('os');
@@ -70,7 +70,7 @@ async function openBrowser(url) {
70
70
  }
71
71
  }
72
72
 
73
- 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-B_wlQBy2.cjs', document.baseURI).href)));
73
+ 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-Bg-YziG2.cjs', document.baseURI).href)));
74
74
  const QRCode = require$1("qrcode-terminal/vendor/QRCode");
75
75
  const QRErrorCorrectLevel = require$1("qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel");
76
76
  const pendingTempFiles = /* @__PURE__ */ new Set();
@@ -241,6 +241,64 @@ const AuthSelector = ({ onSelect, onCancel }) => {
241
241
  })), /* @__PURE__ */ React.createElement(ink.Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(ink.Text, { dimColor: true }, "Use arrows or 1-2 to select, Enter to confirm")));
242
242
  };
243
243
 
244
+ async function ensureSigningCredentials(credentials, opts = {}) {
245
+ if (credentials.signing) {
246
+ return credentials;
247
+ }
248
+ try {
249
+ const response = await axios.post(`${api.configuration.serverUrl}/v1/auth/refresh`, {}, {
250
+ headers: api.buildAuthenticatedHeaders({
251
+ credentials,
252
+ method: "POST",
253
+ url: `${api.configuration.serverUrl}/v1/auth/refresh`,
254
+ body: {},
255
+ headers: {
256
+ "Content-Type": "application/json"
257
+ },
258
+ signRequest: false
259
+ })
260
+ });
261
+ if (!response.data?.success || !response.data?.token || !response.data?.signing) {
262
+ api.logger.debug("[AUTH] Signing bootstrap returned incomplete payload", response.data);
263
+ throw new api.SigningBootstrapRequiredError(api.SIGNING_BOOTSTRAP_REQUIRED_MESSAGE);
264
+ }
265
+ const upgradedCredentials = {
266
+ ...credentials,
267
+ token: response.data.token,
268
+ signing: response.data.signing
269
+ };
270
+ if (upgradedCredentials.encryption.type === "legacy") {
271
+ await persistence.writeCredentialsLegacy({
272
+ secret: upgradedCredentials.encryption.secret,
273
+ token: upgradedCredentials.token,
274
+ signing: upgradedCredentials.signing
275
+ });
276
+ } else {
277
+ await persistence.writeCredentialsDataKey({
278
+ publicKey: upgradedCredentials.encryption.publicKey,
279
+ machineKey: upgradedCredentials.encryption.machineKey,
280
+ token: upgradedCredentials.token,
281
+ signing: upgradedCredentials.signing
282
+ });
283
+ }
284
+ api.logger.debug("[AUTH] Signing credentials bootstrapped successfully");
285
+ return upgradedCredentials;
286
+ } catch (error) {
287
+ if (axios.isAxiosError(error) && error.response?.status === 401) {
288
+ api.logger.debug("[AUTH] Signing bootstrap rejected with 401");
289
+ throw new api.SigningBootstrapRequiredError(api.SIGNING_BOOTSTRAP_REQUIRED_MESSAGE);
290
+ }
291
+ if (error instanceof api.SigningBootstrapRequiredError) {
292
+ throw error;
293
+ }
294
+ api.logger.debug("[AUTH] Failed to bootstrap signing credentials", error);
295
+ if (opts.failFast) {
296
+ throw new api.SigningBootstrapRequiredError(api.SIGNING_BOOTSTRAP_REQUIRED_MESSAGE);
297
+ }
298
+ return credentials;
299
+ }
300
+ }
301
+
244
302
  function isNonInteractive() {
245
303
  return !process.stdin.isTTY || !process.stdout.isTTY;
246
304
  }
@@ -542,7 +600,7 @@ async function authAndSetupMachineIfNeeded() {
542
600
  } else {
543
601
  api.logger.debug("[AUTH] Using existing credentials");
544
602
  }
545
- credentials = await ensureSigningCredentials(credentials);
603
+ credentials = await ensureSigningCredentials(credentials, { failFast: newAuth });
546
604
  const currentSettings = await persistence.readSettings();
547
605
  const settings = newAuth || !currentSettings.machineId ? await persistence.updateSettings(async (s) => ({
548
606
  ...s,
@@ -551,53 +609,6 @@ async function authAndSetupMachineIfNeeded() {
551
609
  api.logger.debug(`[AUTH] Machine ID: ${settings.machineId}`);
552
610
  return { credentials, machineId: settings.machineId };
553
611
  }
554
- async function ensureSigningCredentials(credentials) {
555
- if (credentials.signing) {
556
- return credentials;
557
- }
558
- try {
559
- const response = await axios.post(`${api.configuration.serverUrl}/v1/auth/refresh`, {}, {
560
- headers: api.buildAuthenticatedHeaders({
561
- credentials,
562
- method: "POST",
563
- url: `${api.configuration.serverUrl}/v1/auth/refresh`,
564
- body: {},
565
- headers: {
566
- "Content-Type": "application/json"
567
- },
568
- signRequest: false
569
- })
570
- });
571
- if (!response.data?.success || !response.data?.token || !response.data?.signing) {
572
- api.logger.debug("[AUTH] Signing bootstrap returned incomplete payload");
573
- return credentials;
574
- }
575
- const upgradedCredentials = {
576
- ...credentials,
577
- token: response.data.token,
578
- signing: response.data.signing
579
- };
580
- if (upgradedCredentials.encryption.type === "legacy") {
581
- await persistence.writeCredentialsLegacy({
582
- secret: upgradedCredentials.encryption.secret,
583
- token: upgradedCredentials.token,
584
- signing: upgradedCredentials.signing
585
- });
586
- } else {
587
- await persistence.writeCredentialsDataKey({
588
- publicKey: upgradedCredentials.encryption.publicKey,
589
- machineKey: upgradedCredentials.encryption.machineKey,
590
- token: upgradedCredentials.token,
591
- signing: upgradedCredentials.signing
592
- });
593
- }
594
- api.logger.debug("[AUTH] Signing credentials bootstrapped successfully");
595
- return upgradedCredentials;
596
- } catch (error) {
597
- api.logger.debug("[AUTH] Failed to bootstrap signing credentials", error);
598
- return credentials;
599
- }
600
- }
601
612
 
602
613
  let caffeinateProcess = null;
603
614
  function startCaffeinate() {
@@ -682,7 +693,7 @@ function setupCleanupHandlers() {
682
693
  });
683
694
  }
684
695
 
685
- const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-B_wlQBy2.cjs', document.baseURI).href))));
696
+ const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-Bg-YziG2.cjs', document.baseURI).href))));
686
697
  function projectPath() {
687
698
  const path = path$1.resolve(__dirname$1, "..");
688
699
  return path;
@@ -980,6 +991,32 @@ async function checkIfDaemonRunningAndCleanupStaleState() {
980
991
  return false;
981
992
  }
982
993
  }
994
+ async function isDaemonControlServerResponsive(timeoutMs = 1e3) {
995
+ const state = await persistence.readDaemonState();
996
+ if (!state?.httpPort) {
997
+ api.logger.debug("[DAEMON CONTROL] No daemon state or control port found for readiness check");
998
+ return false;
999
+ }
1000
+ try {
1001
+ process.kill(state.pid, 0);
1002
+ } catch {
1003
+ api.logger.debug("[DAEMON CONTROL] Daemon PID not running during readiness check, cleaning up state");
1004
+ await cleanupDaemonState();
1005
+ return false;
1006
+ }
1007
+ try {
1008
+ const response = await fetch(`http://127.0.0.1:${state.httpPort}/list`, {
1009
+ method: "POST",
1010
+ headers: { "Content-Type": "application/json" },
1011
+ body: JSON.stringify({}),
1012
+ signal: AbortSignal.timeout(timeoutMs)
1013
+ });
1014
+ return response.ok;
1015
+ } catch (error) {
1016
+ api.logger.debug("[DAEMON CONTROL] Daemon control server not ready yet", error);
1017
+ return false;
1018
+ }
1019
+ }
983
1020
  async function isDaemonRunningCurrentlyInstalledHappyVersion() {
984
1021
  api.logger.debug("[DAEMON CONTROL] Checking if daemon is running same version");
985
1022
  const runningDaemon = await checkIfDaemonRunningAndCleanupStaleState();
@@ -997,7 +1034,10 @@ async function isDaemonRunningCurrentlyInstalledHappyVersion() {
997
1034
  const packageJson = JSON.parse(fs$1.readFileSync(packageJsonPath, "utf-8"));
998
1035
  const currentCliVersion = packageJson.version;
999
1036
  api.logger.debug(`[DAEMON CONTROL] Current CLI version: ${currentCliVersion}, Daemon started with version: ${state.startedWithCliVersion}`);
1000
- return currentCliVersion === state.startedWithCliVersion;
1037
+ if (currentCliVersion !== state.startedWithCliVersion) {
1038
+ return false;
1039
+ }
1040
+ return await isDaemonControlServerResponsive();
1001
1041
  } catch (error) {
1002
1042
  api.logger.debug("[DAEMON CONTROL] Error checking daemon version", error);
1003
1043
  return false;
@@ -1214,7 +1254,7 @@ ${typeLabels[type] || type}:`));
1214
1254
  }
1215
1255
  if (filter === "all" && allProcesses.length > 1) {
1216
1256
  console.log(chalk.bold("\n\u{1F4A1} Process Management"));
1217
- console.log(chalk.gray("To clean up runaway processes: happy doctor clean"));
1257
+ console.log(chalk.gray("To clean up runaway processes: hicloud doctor clean"));
1218
1258
  }
1219
1259
  } catch (error) {
1220
1260
  console.log(chalk.red("\u274C Error checking daemon status"));
@@ -1396,7 +1436,8 @@ function startDaemonControlServer({
1396
1436
  schema: {
1397
1437
  body: z.z.object({
1398
1438
  directory: z.z.string(),
1399
- sessionId: z.z.string().optional()
1439
+ sessionId: z.z.string().optional(),
1440
+ agent: z.z.enum(["claude", "codex", "gemini"]).optional()
1400
1441
  }),
1401
1442
  response: {
1402
1443
  200: z.z.object({
@@ -1417,9 +1458,9 @@ function startDaemonControlServer({
1417
1458
  }
1418
1459
  }
1419
1460
  }, async (request, reply) => {
1420
- const { directory, sessionId } = request.body;
1421
- api.logger.debug(`[CONTROL SERVER] Spawn session request: dir=${directory}, sessionId=${sessionId || "new"}`);
1422
- const result = await spawnSession({ directory, sessionId });
1461
+ const { directory, sessionId, agent } = request.body;
1462
+ api.logger.debug(`[CONTROL SERVER] Spawn session request: dir=${directory}, sessionId=${sessionId || "new"}, agent=${agent || "claude"}`);
1463
+ const result = await spawnSession({ directory, sessionId, agent });
1423
1464
  switch (result.type) {
1424
1465
  case "success":
1425
1466
  if (!result.sessionId) {
@@ -2934,13 +2975,13 @@ async function handleAuthCommand(args) {
2934
2975
  }
2935
2976
  function showAuthHelp() {
2936
2977
  console.log(`
2937
- ${chalk.bold("happy-cloud auth")} - Authentication management
2978
+ ${chalk.bold("hicloud auth")} - Authentication management
2938
2979
 
2939
2980
  ${chalk.bold("Usage:")}
2940
- happy-cloud auth login [--force] Authenticate with Happy
2941
- happy-cloud auth logout [--yes] Remove authentication and machine data
2942
- happy-cloud auth status Show authentication status
2943
- happy-cloud auth help Show this help message
2981
+ hicloud auth login [--force] Authenticate with Happy
2982
+ hicloud auth logout [--yes] Remove authentication and machine data
2983
+ hicloud auth status Show authentication status
2984
+ hicloud auth help Show this help message
2944
2985
 
2945
2986
  ${chalk.bold("Options:")}
2946
2987
  --force Clear credentials, machine ID, and stop daemon before re-auth
@@ -2980,7 +3021,7 @@ async function handleAuthLogin(args) {
2980
3021
  console.log(chalk.green("\u2713 Already authenticated"));
2981
3022
  console.log(chalk.gray(` Machine ID: ${settings.machineId}`));
2982
3023
  console.log(chalk.gray(` Host: ${os.hostname()}`));
2983
- console.log(chalk.gray(` Use 'happy-cloud auth login --force' to re-authenticate`));
3024
+ console.log(chalk.gray(` Use 'hicloud auth login --force' to re-authenticate`));
2984
3025
  return;
2985
3026
  } else if (existingCreds && !settings?.machineId) {
2986
3027
  console.log(chalk.yellow("\u26A0\uFE0F Credentials exist but machine ID is missing"));
@@ -3011,7 +3052,7 @@ async function handleAuthLogout(args = []) {
3011
3052
  let confirmed = skipConfirm;
3012
3053
  if (!confirmed) {
3013
3054
  if (isNonInteractive) {
3014
- throw new Error('Non-interactive terminal detected. Use "happy-cloud auth logout --yes" to confirm.');
3055
+ throw new Error('Non-interactive terminal detected. Use "hicloud auth logout --yes" to confirm.');
3015
3056
  }
3016
3057
  const rl = node_readline.createInterface({
3017
3058
  input: process.stdin,
@@ -3034,7 +3075,7 @@ async function handleAuthLogout(args = []) {
3034
3075
  fs.rmSync(happyDir, { recursive: true, force: true });
3035
3076
  }
3036
3077
  console.log(chalk.green("\u2713 Successfully logged out"));
3037
- console.log(chalk.gray(' Run "happy-cloud auth login" to authenticate again'));
3078
+ console.log(chalk.gray(' Run "hicloud auth login" to authenticate again'));
3038
3079
  } catch (error) {
3039
3080
  throw new Error(`Failed to logout: ${error instanceof Error ? error.message : "Unknown error"}`);
3040
3081
  }
@@ -3048,20 +3089,20 @@ async function handleAuthStatus() {
3048
3089
  console.log(chalk.bold("\nAuthentication Status\n"));
3049
3090
  if (!credentials) {
3050
3091
  console.log(chalk.red("\u2717 Not authenticated"));
3051
- console.log(chalk.gray(' Run "happy-cloud auth login" to authenticate'));
3092
+ console.log(chalk.gray(' Run "hicloud auth login" to authenticate'));
3052
3093
  return;
3053
3094
  }
3054
3095
  console.log(chalk.green("\u2713 Authenticated"));
3055
3096
  const tokenPreview = credentials.token.substring(0, 30) + "...";
3056
3097
  console.log(chalk.gray(` Token: ${tokenPreview}`));
3057
- console.log(chalk.gray(` Request signing: ${credentials.signing ? "ready" : "legacy credentials (will auto-upgrade on use)"}`));
3098
+ console.log(chalk.gray(` Request signing: ${describeSigningStatus(credentials)}`));
3058
3099
  if (settings?.machineId) {
3059
3100
  console.log(chalk.green("\u2713 Machine registered"));
3060
3101
  console.log(chalk.gray(` Machine ID: ${settings.machineId}`));
3061
3102
  console.log(chalk.gray(` Host: ${os.hostname()}`));
3062
3103
  } else {
3063
3104
  console.log(chalk.yellow("\u26A0\uFE0F Machine not registered"));
3064
- console.log(chalk.gray(' Run "happy-cloud auth login --force" to fix this'));
3105
+ console.log(chalk.gray(' Run "hicloud auth login --force" to fix this'));
3065
3106
  }
3066
3107
  console.log(chalk.gray(`
3067
3108
  Data directory: ${api.configuration.happyCloudHomeDir}`));
@@ -3076,6 +3117,12 @@ async function handleAuthStatus() {
3076
3117
  console.log(chalk.gray("\u2717 Daemon not running"));
3077
3118
  }
3078
3119
  }
3120
+ function describeSigningStatus(credentials) {
3121
+ if (credentials.signing) {
3122
+ return "ready";
3123
+ }
3124
+ return "not initialized (server write requests may still fail until signing bootstrap succeeds)";
3125
+ }
3079
3126
 
3080
3127
  const CLIENT_ID$2 = "app_EMoamEEZ73f0CkXaXp7hrann";
3081
3128
  const AUTH_BASE_URL = "https://auth.openai.com";
@@ -3592,14 +3639,14 @@ async function handleConnectCommand(args) {
3592
3639
  }
3593
3640
  function showConnectHelp() {
3594
3641
  console.log(`
3595
- ${chalk.bold("happy-cloud connect")} - Connect AI vendor API keys to Happy cloud
3642
+ ${chalk.bold("hicloud connect")} - Connect AI vendor API keys to Happy cloud
3596
3643
 
3597
3644
  ${chalk.bold("Usage:")}
3598
- happy-cloud connect codex Store your Codex API key in Happy cloud
3599
- happy-cloud connect claude Store your Anthropic API key in Happy cloud
3600
- happy-cloud connect gemini Store your Gemini API key in Happy cloud
3601
- happy-cloud connect status Show connection status for all vendors
3602
- happy-cloud connect help Show this help message
3645
+ hicloud connect codex Store your Codex API key in Happy cloud
3646
+ hicloud connect claude Store your Anthropic API key in Happy cloud
3647
+ hicloud connect gemini Store your Gemini API key in Happy cloud
3648
+ hicloud connect status Show connection status for all vendors
3649
+ hicloud connect help Show this help message
3603
3650
 
3604
3651
  ${chalk.bold("Description:")}
3605
3652
  The connect command allows you to securely store your AI vendor API keys
@@ -3607,13 +3654,13 @@ ${chalk.bold("Description:")}
3607
3654
  without exposing your API keys locally.
3608
3655
 
3609
3656
  ${chalk.bold("Examples:")}
3610
- happy-cloud connect codex
3611
- happy-cloud connect claude
3612
- happy-cloud connect gemini
3613
- happy-cloud connect status
3657
+ hicloud connect codex
3658
+ hicloud connect claude
3659
+ hicloud connect gemini
3660
+ hicloud connect status
3614
3661
 
3615
3662
  ${chalk.bold("Notes:")}
3616
- \u2022 You must be authenticated with Happy first (run 'happy-cloud auth login')
3663
+ \u2022 You must be authenticated with Happy first (run 'hicloud auth login')
3617
3664
  \u2022 API keys are encrypted and stored securely in Happy cloud
3618
3665
  \u2022 You can manage your stored keys at https://happycloudcode.imou.com
3619
3666
  `);
@@ -3625,7 +3672,7 @@ async function handleConnectVendor(vendor, displayName) {
3625
3672
  const credentials = await persistence.readCredentials();
3626
3673
  if (!credentials) {
3627
3674
  console.log(chalk.yellow("\u26A0\uFE0F Not authenticated with Happy"));
3628
- console.log(chalk.gray(' Please run "happy-cloud auth login" first'));
3675
+ console.log(chalk.gray(' Please run "hicloud auth login" first'));
3629
3676
  process.exit(1);
3630
3677
  }
3631
3678
  const api$1 = await api.ApiClient.create(credentials);
@@ -3657,7 +3704,7 @@ async function handleConnectStatus() {
3657
3704
  const credentials = await persistence.readCredentials();
3658
3705
  if (!credentials) {
3659
3706
  console.log(chalk.yellow("\u26A0\uFE0F Not authenticated with Happy"));
3660
- console.log(chalk.gray(' Please run "happy-cloud auth login" first'));
3707
+ console.log(chalk.gray(' Please run "hicloud auth login" first'));
3661
3708
  process.exit(1);
3662
3709
  }
3663
3710
  const api$1 = await api.ApiClient.create(credentials);
@@ -3692,8 +3739,8 @@ async function handleConnectStatus() {
3692
3739
  }
3693
3740
  }
3694
3741
  console.log("");
3695
- console.log(chalk.gray("To connect a vendor, run: happy-cloud connect <vendor>"));
3696
- console.log(chalk.gray("Example: happy-cloud connect gemini"));
3742
+ console.log(chalk.gray("To connect a vendor, run: hicloud connect <vendor>"));
3743
+ console.log(chalk.gray("Example: hicloud connect gemini"));
3697
3744
  console.log("");
3698
3745
  }
3699
3746
  function updateLocalGeminiCredentials(tokens) {
@@ -3718,19 +3765,17 @@ function updateLocalGeminiCredentials(tokens) {
3718
3765
  }
3719
3766
  }
3720
3767
 
3721
- function getProjectPath(workingDirectory) {
3722
- let resolved = path.resolve(workingDirectory);
3723
- if (process.platform === "win32" && path.isAbsolute(resolved)) {
3724
- resolved = resolved.replace(/^[A-Z]:/i, "");
3725
- }
3726
- const projectId = resolved.replace(/[\\\/\.: _]/g, "-");
3727
- const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), ".claude");
3768
+ function getProjectPath(workingDirectory, claudeConfigDirOverride) {
3769
+ const projectId = path.resolve(workingDirectory).replace(/[^a-zA-Z0-9-]/g, "-");
3770
+ const claudeConfigDirRaw = process.env.CLAUDE_CONFIG_DIR ?? "";
3771
+ const claudeConfigDirTrimmed = claudeConfigDirRaw.trim();
3772
+ const claudeConfigDir = claudeConfigDirTrimmed ? claudeConfigDirTrimmed : path.join(os.homedir(), ".claude");
3728
3773
  return path.join(claudeConfigDir, "projects", projectId);
3729
3774
  }
3730
3775
 
3731
- function claudeCheckSession(sessionId, path$1) {
3776
+ function claudeCheckSession(sessionId, path$1, transcriptPath) {
3732
3777
  const projectDir = getProjectPath(path$1);
3733
- const sessionFile = path.join(projectDir, `${sessionId}.jsonl`);
3778
+ const sessionFile = transcriptPath ?? path.join(projectDir, `${sessionId}.jsonl`);
3734
3779
  const sessionExists = fs.existsSync(sessionFile);
3735
3780
  if (!sessionExists) {
3736
3781
  api.logger.debug(`[claudeCheckSession] Path ${sessionFile} does not exist`);
@@ -4078,6 +4123,77 @@ class AgentRegistry {
4078
4123
  }
4079
4124
  const agentRegistry = new AgentRegistry();
4080
4125
 
4126
+ const PREFERRED_MESSAGE_FIELDS = ["stderr", "error", "message", "detail", "stdout", "text", "reason"];
4127
+ function safeSerializeDisplayValue(value) {
4128
+ const seen = /* @__PURE__ */ new WeakSet();
4129
+ try {
4130
+ const serialized = JSON.stringify(value, (_key, currentValue) => {
4131
+ if (typeof currentValue === "bigint") {
4132
+ return currentValue.toString();
4133
+ }
4134
+ if (currentValue instanceof Error) {
4135
+ return {
4136
+ name: currentValue.name,
4137
+ message: currentValue.message,
4138
+ stack: currentValue.stack
4139
+ };
4140
+ }
4141
+ if (typeof currentValue === "object" && currentValue !== null) {
4142
+ if (seen.has(currentValue)) {
4143
+ return "[Circular]";
4144
+ }
4145
+ seen.add(currentValue);
4146
+ }
4147
+ return currentValue;
4148
+ });
4149
+ return serialized ?? String(value);
4150
+ } catch {
4151
+ return String(value);
4152
+ }
4153
+ }
4154
+ function formatDisplayMessage(value, seen = /* @__PURE__ */ new WeakSet()) {
4155
+ if (typeof value === "string") {
4156
+ return value;
4157
+ }
4158
+ if (value instanceof Error) {
4159
+ return value.message || String(value);
4160
+ }
4161
+ if (value === null || value === void 0) {
4162
+ return "";
4163
+ }
4164
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer(value)) {
4165
+ return value.toString("utf8");
4166
+ }
4167
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
4168
+ return String(value);
4169
+ }
4170
+ if (typeof value === "object") {
4171
+ if (seen.has(value)) {
4172
+ return "[Circular]";
4173
+ }
4174
+ seen.add(value);
4175
+ const record = value;
4176
+ for (const field of PREFERRED_MESSAGE_FIELDS) {
4177
+ if (!(field in record)) {
4178
+ continue;
4179
+ }
4180
+ const formattedField = formatDisplayMessage(record[field], seen).trim();
4181
+ if (formattedField.length > 0) {
4182
+ return formattedField;
4183
+ }
4184
+ }
4185
+ return safeSerializeDisplayValue(value);
4186
+ }
4187
+ return String(value);
4188
+ }
4189
+ function truncateDisplayMessage(value, maxLength) {
4190
+ const formatted = formatDisplayMessage(value);
4191
+ if (formatted.length <= maxLength) {
4192
+ return formatted;
4193
+ }
4194
+ return `${formatted.substring(0, maxLength)}...`;
4195
+ }
4196
+
4081
4197
  const DEFAULT_TIMEOUTS = {
4082
4198
  /** Default initialization timeout: 60 seconds */
4083
4199
  init: 6e4,
@@ -4372,7 +4488,7 @@ class CodexTransport extends DefaultTransport {
4372
4488
  return 800;
4373
4489
  }
4374
4490
  }
4375
- const codexTransport = new CodexTransport();
4491
+ new CodexTransport();
4376
4492
 
4377
4493
  class ClaudeTransport extends DefaultTransport {
4378
4494
  constructor() {
@@ -4706,6 +4822,70 @@ const RETRY_CONFIG = {
4706
4822
  /** Maximum delay between retries in ms */
4707
4823
  maxDelayMs: 5e3
4708
4824
  };
4825
+ function getSessionUpdates(params) {
4826
+ const notification = params;
4827
+ const updates = Array.isArray(notification.updates) ? notification.updates.filter((update) => Boolean(update && typeof update === "object")) : [];
4828
+ if (updates.length > 0) {
4829
+ return updates;
4830
+ }
4831
+ if (notification.update && typeof notification.update === "object") {
4832
+ return [notification.update];
4833
+ }
4834
+ return [];
4835
+ }
4836
+ function asNonNegativeFiniteNumber(value) {
4837
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
4838
+ }
4839
+ function extractUsageTokens(record) {
4840
+ const used = asNonNegativeFiniteNumber(record.used);
4841
+ const size = asNonNegativeFiniteNumber(record.size);
4842
+ if (used != null || size != null) {
4843
+ const tokens2 = {
4844
+ total: used ?? 0
4845
+ };
4846
+ if (used != null) tokens2.used = used;
4847
+ if (size != null) tokens2.size = size;
4848
+ return tokens2;
4849
+ }
4850
+ const input = asNonNegativeFiniteNumber(record.input_tokens) ?? asNonNegativeFiniteNumber(record.inputTokens) ?? asNonNegativeFiniteNumber(record.prompt_tokens) ?? asNonNegativeFiniteNumber(record.promptTokens);
4851
+ const output = asNonNegativeFiniteNumber(record.output_tokens) ?? asNonNegativeFiniteNumber(record.outputTokens) ?? asNonNegativeFiniteNumber(record.completion_tokens) ?? asNonNegativeFiniteNumber(record.completionTokens);
4852
+ const cacheRead = asNonNegativeFiniteNumber(record.cache_read_input_tokens) ?? asNonNegativeFiniteNumber(record.cacheReadInputTokens) ?? asNonNegativeFiniteNumber(record.cache_read_tokens) ?? asNonNegativeFiniteNumber(record.cacheReadTokens) ?? asNonNegativeFiniteNumber(record.cached_read_tokens) ?? asNonNegativeFiniteNumber(record.cachedReadTokens);
4853
+ const cacheCreation = asNonNegativeFiniteNumber(record.cache_creation_input_tokens) ?? asNonNegativeFiniteNumber(record.cacheCreationInputTokens) ?? asNonNegativeFiniteNumber(record.cache_creation_tokens) ?? asNonNegativeFiniteNumber(record.cacheCreationTokens) ?? asNonNegativeFiniteNumber(record.cached_write_tokens) ?? asNonNegativeFiniteNumber(record.cachedWriteTokens);
4854
+ const thought = asNonNegativeFiniteNumber(record.thought_tokens) ?? asNonNegativeFiniteNumber(record.thoughtTokens);
4855
+ const totalFromPayload = asNonNegativeFiniteNumber(record.total_tokens) ?? asNonNegativeFiniteNumber(record.totalTokens);
4856
+ const anyPresent = totalFromPayload != null || input != null || output != null || cacheRead != null || cacheCreation != null || thought != null;
4857
+ if (!anyPresent) {
4858
+ return null;
4859
+ }
4860
+ const total = totalFromPayload ?? (input ?? 0) + (output ?? 0) + (cacheRead ?? 0) + (cacheCreation ?? 0) + (thought ?? 0);
4861
+ const tokens = { total };
4862
+ if (input != null) tokens.input = input;
4863
+ if (output != null) tokens.output = output;
4864
+ if (cacheRead != null) tokens.cache_read = cacheRead;
4865
+ if (cacheCreation != null) tokens.cache_creation = cacheCreation;
4866
+ if (thought != null) tokens.thought = thought;
4867
+ return tokens;
4868
+ }
4869
+ function isApprovalOption(option) {
4870
+ if (option.optionId === "proceed_once" || option.optionId === "proceed_always" || option.optionId === "cancel") {
4871
+ return true;
4872
+ }
4873
+ const searchable = `${option.name ?? ""} ${option.label ?? ""}`.toLowerCase();
4874
+ return searchable.includes("once") || searchable.includes("always") || searchable.includes("cancel");
4875
+ }
4876
+ function isSelectionPermissionRequest(params) {
4877
+ if (Array.isArray(params.codex_command) && params.codex_command.length > 0) {
4878
+ return false;
4879
+ }
4880
+ if (params.requestedSchema?.properties?.optionId) {
4881
+ return true;
4882
+ }
4883
+ const options = Array.isArray(params.options) ? params.options : [];
4884
+ if (options.length === 0) {
4885
+ return false;
4886
+ }
4887
+ return !options.every((option) => isApprovalOption(option));
4888
+ }
4709
4889
  function nodeToWebStreams(stdin, stdout) {
4710
4890
  const writable = new WritableStream({
4711
4891
  write(chunk) {
@@ -4769,7 +4949,7 @@ async function withRetry(operation, options) {
4769
4949
  try {
4770
4950
  return await operation();
4771
4951
  } catch (error) {
4772
- lastError = error instanceof Error ? error : new Error(String(error));
4952
+ lastError = normalizeAcpError(error);
4773
4953
  if (attempt < options.maxAttempts) {
4774
4954
  const delayMs = Math.min(
4775
4955
  options.baseDelayMs * Math.pow(2, attempt - 1),
@@ -4783,6 +4963,49 @@ async function withRetry(operation, options) {
4783
4963
  }
4784
4964
  throw lastError;
4785
4965
  }
4966
+ function formatAcpErrorMessage(error) {
4967
+ if (error instanceof Error && error.message && error.message !== "[object Object]") {
4968
+ return error.message;
4969
+ }
4970
+ if (typeof error === "object" && error !== null) {
4971
+ const record = error;
4972
+ const message = formatDisplayMessage(error).trim();
4973
+ const code = record.code;
4974
+ const status = record.status;
4975
+ const prefix = [
4976
+ code !== void 0 && code !== null ? `[code=${String(code)}]` : "",
4977
+ status !== void 0 && status !== null ? `[status=${String(status)}]` : ""
4978
+ ].filter(Boolean).join(" ");
4979
+ if (message.length > 0) {
4980
+ return prefix ? `${prefix} ${message}` : message;
4981
+ }
4982
+ }
4983
+ const fallback = formatDisplayMessage(error).trim();
4984
+ return fallback || "Unknown ACP error";
4985
+ }
4986
+ function normalizeAcpError(error) {
4987
+ if (error instanceof Error && error.message && error.message !== "[object Object]") {
4988
+ return error;
4989
+ }
4990
+ const normalized = new Error(formatAcpErrorMessage(error));
4991
+ normalized.name = error instanceof Error ? error.name : "Error";
4992
+ if (error && typeof error === "object") {
4993
+ const { message: _message, ...rest } = error;
4994
+ Object.assign(normalized, rest);
4995
+ }
4996
+ return normalized;
4997
+ }
4998
+ function enrichAcpError(error, stderrExcerpt) {
4999
+ const normalized = normalizeAcpError(error);
5000
+ if (!stderrExcerpt.trim()) {
5001
+ return normalized;
5002
+ }
5003
+ const existingStderr = normalized.stderr;
5004
+ if (typeof existingStderr !== "string" || existingStderr.trim().length === 0) {
5005
+ Object.assign(normalized, { stderr: stderrExcerpt });
5006
+ }
5007
+ return normalized;
5008
+ }
4786
5009
  class AcpBackend {
4787
5010
  constructor(options) {
4788
5011
  this.options = options;
@@ -4810,6 +5033,21 @@ class AcpBackend {
4810
5033
  idleTimeout = null;
4811
5034
  /** Transport handler for agent-specific behavior */
4812
5035
  transport;
5036
+ /** Keep a short rolling stderr buffer so startup failures can surface the real cause. */
5037
+ recentStderrLines = [];
5038
+ recordRecentStderr(text) {
5039
+ const normalized = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
5040
+ if (normalized.length === 0) {
5041
+ return;
5042
+ }
5043
+ this.recentStderrLines.push(...normalized);
5044
+ if (this.recentStderrLines.length > 12) {
5045
+ this.recentStderrLines = this.recentStderrLines.slice(-12);
5046
+ }
5047
+ }
5048
+ getRecentStderrExcerpt() {
5049
+ return this.recentStderrLines.slice(-6).join("\n");
5050
+ }
4813
5051
  onMessage(handler) {
4814
5052
  this.listeners.push(handler);
4815
5053
  }
@@ -4837,6 +5075,7 @@ class AcpBackend {
4837
5075
  this.emit({ type: "status", status: "starting" });
4838
5076
  try {
4839
5077
  api.logger.debug(`[AcpBackend] Starting session: ${sessionId}`);
5078
+ this.recentStderrLines = [];
4840
5079
  const args = this.options.args || [];
4841
5080
  if (process.platform === "win32") {
4842
5081
  const fullCommand = [this.options.command, ...args].join(" ");
@@ -4863,6 +5102,7 @@ class AcpBackend {
4863
5102
  this.process.stderr.on("data", (data) => {
4864
5103
  const text = data.toString();
4865
5104
  if (!text.trim()) return;
5105
+ this.recordRecentStderr(text);
4866
5106
  const hasActiveInvestigation = this.transport.isInvestigationTool ? Array.from(this.activeToolCalls).some((id) => this.transport.isInvestigationTool(id)) : false;
4867
5107
  const context = {
4868
5108
  activeToolCalls: this.activeToolCalls,
@@ -4973,6 +5213,7 @@ class AcpBackend {
4973
5213
  }
4974
5214
  this.toolCallCountSincePrompt++;
4975
5215
  const options = extendedParams.options || [];
5216
+ const isSelectionRequest = isSelectionPermissionRequest(extendedParams);
4976
5217
  api.logger.debug(`[AcpBackend] Permission request: tool=${toolName}, toolCallId=${toolCallId}, input=`, JSON.stringify(input));
4977
5218
  api.logger.debug(`[AcpBackend] Permission request params structure:`, JSON.stringify({
4978
5219
  hasToolCall: !!toolCall,
@@ -4981,6 +5222,42 @@ class AcpBackend {
4981
5222
  paramsKind: extendedParams.kind,
4982
5223
  paramsKeys: Object.keys(params)
4983
5224
  }, null, 2));
5225
+ if (isSelectionRequest) {
5226
+ const selectionOptions = options.reduce((acc, option) => {
5227
+ if (!option.optionId) {
5228
+ return acc;
5229
+ }
5230
+ const displayOption = option;
5231
+ acc.push({
5232
+ optionId: option.optionId,
5233
+ label: displayOption.label || option.name || option.optionId,
5234
+ description: displayOption.description || option.name || option.optionId
5235
+ });
5236
+ return acc;
5237
+ }, []);
5238
+ if (selectionOptions.length === 0) {
5239
+ api.logger.debug("[AcpBackend] Selection request has no valid options, cancelling");
5240
+ return { outcome: { outcome: "selected", optionId: "cancel" } };
5241
+ }
5242
+ if (!this.options.selectionHandler) {
5243
+ api.logger.debug("[AcpBackend] No selection handler configured, cancelling selection request");
5244
+ return { outcome: { outcome: "selected", optionId: "cancel" } };
5245
+ }
5246
+ try {
5247
+ const selectionMessage = typeof extendedParams.message === "string" && extendedParams.message.trim().length > 0 ? extendedParams.message : formatDisplayMessage(input).trim() || toolName;
5248
+ const requestId = extendedParams.codex_event_id || extendedParams.codex_elicitation || toolCallId;
5249
+ const response = await this.options.selectionHandler.handleSelection({
5250
+ id: requestId,
5251
+ message: selectionMessage,
5252
+ options: selectionOptions,
5253
+ defaultOptionId: extendedParams.requestedSchema?.properties?.optionId?.default
5254
+ });
5255
+ return { outcome: { outcome: "selected", optionId: response.optionId } };
5256
+ } catch (error) {
5257
+ api.logger.debug("[AcpBackend] Error in selection handler:", error);
5258
+ return { outcome: { outcome: "selected", optionId: "cancel" } };
5259
+ }
5260
+ }
4984
5261
  this.emit({
4985
5262
  type: "permission-request",
4986
5263
  id: permissionId,
@@ -5154,18 +5431,19 @@ class AcpBackend {
5154
5431
  if (initialPrompt) {
5155
5432
  this.sendPrompt(sessionId, initialPrompt).catch((error) => {
5156
5433
  api.logger.debug("[AcpBackend] Error sending initial prompt:", error);
5157
- this.emit({ type: "status", status: "error", detail: String(error) });
5434
+ this.emit({ type: "status", status: "error", detail: formatAcpErrorMessage(error) });
5158
5435
  });
5159
5436
  }
5160
5437
  return { sessionId };
5161
5438
  } catch (error) {
5162
- api.logger.debug("[AcpBackend] Error starting session:", error);
5439
+ const enrichedError = enrichAcpError(error, this.getRecentStderrExcerpt());
5440
+ api.logger.debug("[AcpBackend] Error starting session:", enrichedError);
5163
5441
  this.emit({
5164
5442
  type: "status",
5165
5443
  status: "error",
5166
- detail: error instanceof Error ? error.message : String(error)
5444
+ detail: formatAcpErrorMessage(enrichedError)
5167
5445
  });
5168
- throw error;
5446
+ throw enrichedError;
5169
5447
  }
5170
5448
  }
5171
5449
  /**
@@ -5196,51 +5474,73 @@ class AcpBackend {
5196
5474
  }
5197
5475
  };
5198
5476
  }
5477
+ emitUsageTelemetry(payload, source) {
5478
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
5479
+ return false;
5480
+ }
5481
+ const tokens = extractUsageTokens(payload);
5482
+ if (!tokens) {
5483
+ return false;
5484
+ }
5485
+ this.emit({
5486
+ type: "token-count",
5487
+ key: source,
5488
+ tokens,
5489
+ source
5490
+ });
5491
+ return true;
5492
+ }
5199
5493
  handleSessionUpdate(params) {
5200
- const notification = params;
5201
- const update = notification.update;
5202
- if (!update) {
5494
+ const updates = getSessionUpdates(params);
5495
+ if (updates.length === 0) {
5203
5496
  api.logger.debug("[AcpBackend] Received session update without update field:", params);
5204
5497
  return;
5205
5498
  }
5206
- const sessionUpdateType = update.sessionUpdate;
5207
- if (sessionUpdateType !== "agent_message_chunk") {
5208
- api.logger.debug(`[AcpBackend] Received session update: ${sessionUpdateType}`, JSON.stringify({
5209
- sessionUpdate: sessionUpdateType,
5210
- toolCallId: update.toolCallId,
5211
- status: update.status,
5212
- kind: update.kind,
5213
- hasContent: !!update.content,
5214
- hasLocations: !!update.locations
5215
- }, null, 2));
5216
- }
5217
- const ctx = this.createHandlerContext();
5218
- if (sessionUpdateType === "agent_message_chunk") {
5219
- handleAgentMessageChunk(update, ctx);
5220
- return;
5221
- }
5222
- if (sessionUpdateType === "tool_call_update") {
5223
- const result = handleToolCallUpdate(update, ctx);
5224
- if (result.toolCallCountSincePrompt !== void 0) {
5225
- this.toolCallCountSincePrompt = result.toolCallCountSincePrompt;
5499
+ for (const update of updates) {
5500
+ const sessionUpdateType = update.sessionUpdate;
5501
+ if (sessionUpdateType !== "agent_message_chunk") {
5502
+ api.logger.debug(`[AcpBackend] Received session update: ${sessionUpdateType}`, JSON.stringify({
5503
+ sessionUpdate: sessionUpdateType,
5504
+ toolCallId: update.toolCallId,
5505
+ status: update.status,
5506
+ kind: update.kind,
5507
+ hasContent: !!update.content,
5508
+ hasLocations: !!update.locations
5509
+ }, null, 2));
5510
+ }
5511
+ const ctx = this.createHandlerContext();
5512
+ if (sessionUpdateType === "agent_message_chunk") {
5513
+ handleAgentMessageChunk(update, ctx);
5514
+ continue;
5515
+ }
5516
+ if (sessionUpdateType === "tool_call_update") {
5517
+ const result = handleToolCallUpdate(update, ctx);
5518
+ if (result.toolCallCountSincePrompt !== void 0) {
5519
+ this.toolCallCountSincePrompt = result.toolCallCountSincePrompt;
5520
+ }
5521
+ continue;
5522
+ }
5523
+ if (sessionUpdateType === "agent_thought_chunk") {
5524
+ handleAgentThoughtChunk(update, ctx);
5525
+ continue;
5526
+ }
5527
+ if (sessionUpdateType === "tool_call") {
5528
+ handleToolCall(update, ctx);
5529
+ continue;
5530
+ }
5531
+ if (sessionUpdateType === "usage_update") {
5532
+ this.emitUsageTelemetry(update, "acp-usage-update");
5533
+ continue;
5534
+ }
5535
+ const handledLegacy = handleLegacyMessageChunk(update, ctx).handled;
5536
+ const handledPlan = handlePlanUpdate(update, ctx).handled;
5537
+ const handledThinking = handleThinkingUpdate(update, ctx).handled;
5538
+ const handledUsage = this.emitUsageTelemetry(update.usage, "acp-session-usage");
5539
+ const updateTypeStr = sessionUpdateType;
5540
+ const handledTypes = ["agent_message_chunk", "tool_call_update", "agent_thought_chunk", "tool_call", "usage_update"];
5541
+ if (updateTypeStr && !handledTypes.includes(updateTypeStr) && !handledLegacy && !handledPlan && !handledThinking && !handledUsage) {
5542
+ api.logger.debug(`[AcpBackend] Unhandled session update type: ${updateTypeStr}`, JSON.stringify(update, null, 2));
5226
5543
  }
5227
- return;
5228
- }
5229
- if (sessionUpdateType === "agent_thought_chunk") {
5230
- handleAgentThoughtChunk(update, ctx);
5231
- return;
5232
- }
5233
- if (sessionUpdateType === "tool_call") {
5234
- handleToolCall(update, ctx);
5235
- return;
5236
- }
5237
- handleLegacyMessageChunk(update, ctx);
5238
- handlePlanUpdate(update, ctx);
5239
- handleThinkingUpdate(update, ctx);
5240
- const updateTypeStr = sessionUpdateType;
5241
- const handledTypes = ["agent_message_chunk", "tool_call_update", "agent_thought_chunk", "tool_call"];
5242
- if (updateTypeStr && !handledTypes.includes(updateTypeStr) && !update.messageChunk && !update.plan && !update.thinking) {
5243
- api.logger.debug(`[AcpBackend] Unhandled session update type: ${updateTypeStr}`, JSON.stringify(update, null, 2));
5244
5544
  }
5245
5545
  }
5246
5546
  // Promise resolver for waitForIdle - set when waiting for response to complete
@@ -5277,17 +5577,9 @@ class AcpBackend {
5277
5577
  if (error instanceof Error) {
5278
5578
  errorDetail = error.message;
5279
5579
  } else if (typeof error === "object" && error !== null) {
5280
- const errObj = error;
5281
- const fallbackMessage = (typeof errObj.message === "string" ? errObj.message : void 0) || String(error);
5282
- if (errObj.code !== void 0) {
5283
- errorDetail = JSON.stringify({ code: errObj.code, message: fallbackMessage });
5284
- } else if (typeof errObj.message === "string") {
5285
- errorDetail = errObj.message;
5286
- } else {
5287
- errorDetail = String(error);
5288
- }
5580
+ errorDetail = formatAcpErrorMessage(error);
5289
5581
  } else {
5290
- errorDetail = String(error);
5582
+ errorDetail = formatAcpErrorMessage(error);
5291
5583
  }
5292
5584
  this.emit({
5293
5585
  type: "status",
@@ -5638,59 +5930,213 @@ function registerGeminiAgent() {
5638
5930
  api.logger.debug("[Gemini] Registered with agent registry");
5639
5931
  }
5640
5932
 
5641
- function firstExistingPath(candidates) {
5642
- for (const candidate of candidates) {
5643
- try {
5933
+ function readFirstEnv(...names) {
5934
+ for (const name of names) {
5935
+ const raw = process.env[name];
5936
+ if (typeof raw === "string" && raw.trim()) {
5937
+ return raw.trim();
5938
+ }
5939
+ }
5940
+ return "";
5941
+ }
5942
+ function normalizeCommandPath(command) {
5943
+ if (path.isAbsolute(command)) {
5944
+ return command;
5945
+ }
5946
+ const resolved = path.resolve(process.cwd(), command);
5947
+ return fs.existsSync(resolved) ? resolved : command;
5948
+ }
5949
+ function resolveCommandOnPath(command) {
5950
+ const pathValue = typeof process.env.PATH === "string" ? process.env.PATH : "";
5951
+ if (!pathValue) {
5952
+ return null;
5953
+ }
5954
+ const extensions = process.platform === "win32" ? (process.env.PATHEXT || ".COM;.EXE;.BAT;.CMD").split(";").map((value) => value.trim().toLowerCase()).filter(Boolean) : [""];
5955
+ for (const dir of pathValue.split(path.delimiter)) {
5956
+ const trimmedDir = dir.trim();
5957
+ if (!trimmedDir) {
5958
+ continue;
5959
+ }
5960
+ const directCandidate = path.join(trimmedDir, command);
5961
+ if (fs.existsSync(directCandidate)) {
5962
+ return directCandidate;
5963
+ }
5964
+ if (process.platform !== "win32") {
5965
+ continue;
5966
+ }
5967
+ const hasExtension = /\.[^\\/]+$/.test(command);
5968
+ if (hasExtension) {
5969
+ continue;
5970
+ }
5971
+ for (const extension of extensions) {
5972
+ const candidate = path.join(trimmedDir, `${command}${extension.toLowerCase()}`);
5644
5973
  if (fs.existsSync(candidate)) {
5645
5974
  return candidate;
5646
5975
  }
5647
- } catch {
5648
5976
  }
5649
5977
  }
5650
5978
  return null;
5651
5979
  }
5652
- function resolveCodexExecutable() {
5653
- if (process.platform === "win32") {
5654
- const appData = process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming");
5655
- const npmGlobalBin = path.join(appData, "npm");
5656
- const resolved = firstExistingPath([
5657
- path.join(npmGlobalBin, "codex.cmd"),
5658
- path.join(npmGlobalBin, "codex.ps1"),
5659
- path.join(npmGlobalBin, "codex")
5660
- ]);
5661
- if (resolved) {
5662
- return resolved;
5663
- }
5980
+ function readCodexAcpNpxMode() {
5981
+ const raw = readFirstEnv("HAPPY_CODEX_ACP_NPX_MODE", "HAPPIER_CODEX_ACP_NPX_MODE").toLowerCase();
5982
+ if (raw === "auto" || raw === "never" || raw === "force") {
5983
+ return raw;
5664
5984
  }
5665
- return "codex";
5985
+ return "auto";
5986
+ }
5987
+ function isBinOnPath(baseName) {
5988
+ return resolveCommandOnPath(baseName) !== null;
5666
5989
  }
5667
- function shouldUseShellForCodex(executable) {
5668
- return process.platform === "win32" && /\.(cmd|bat|ps1)$/i.test(executable);
5990
+ function readCodexAcpConfigOverrides() {
5991
+ const raw = readFirstEnv("HAPPY_CODEX_ACP_CONFIG_OVERRIDES", "HAPPIER_CODEX_ACP_CONFIG_OVERRIDES");
5992
+ return raw.split("\n").map((line) => line.trim()).filter(Boolean);
5993
+ }
5994
+ function buildCodexAcpConfigArgs(options) {
5995
+ const args = [...options.baseArgs ?? []];
5996
+ const overrides = [...readCodexAcpConfigOverrides()];
5997
+ if (options.model) {
5998
+ overrides.push(`model=${JSON.stringify(options.model)}`);
5999
+ }
6000
+ if (options.approvalPolicy) {
6001
+ overrides.push(`approval_policy=${JSON.stringify(options.approvalPolicy)}`);
6002
+ }
6003
+ if (options.sandbox) {
6004
+ overrides.push(`sandbox_mode=${JSON.stringify(options.sandbox)}`);
6005
+ }
6006
+ for (const override of overrides) {
6007
+ args.push("-c", override);
6008
+ }
6009
+ return args;
6010
+ }
6011
+ function resolveNpxCommand() {
6012
+ return resolveCommandOnPath(process.platform === "win32" ? "npx.cmd" : "npx") ?? resolveCommandOnPath("npx") ?? (process.platform === "win32" ? "npx.cmd" : "npx");
6013
+ }
6014
+ function resolveCodexAcpSpawn(options = {}) {
6015
+ if (options.args) {
6016
+ const command = normalizeCommandPath(options.command || readFirstEnv("HAPPY_CODEX_ACP_BIN", "HAPPY_CODEX_ACP_COMMAND", "HAPPIER_CODEX_ACP_BIN") || "codex-acp");
6017
+ return {
6018
+ command,
6019
+ args: [...options.args]
6020
+ };
6021
+ }
6022
+ const directArgs = buildCodexAcpConfigArgs(options);
6023
+ if (options.command) {
6024
+ return {
6025
+ command: normalizeCommandPath(options.command),
6026
+ args: directArgs
6027
+ };
6028
+ }
6029
+ const envOverride = readFirstEnv("HAPPY_CODEX_ACP_BIN", "HAPPY_CODEX_ACP_COMMAND", "HAPPIER_CODEX_ACP_BIN");
6030
+ if (envOverride) {
6031
+ return {
6032
+ command: normalizeCommandPath(envOverride),
6033
+ args: directArgs
6034
+ };
6035
+ }
6036
+ const npxMode = readCodexAcpNpxMode();
6037
+ const codexAcpOnPath = resolveCommandOnPath(process.platform === "win32" ? "codex-acp.cmd" : "codex-acp") ?? resolveCommandOnPath("codex-acp");
6038
+ if (npxMode !== "force" && codexAcpOnPath) {
6039
+ return {
6040
+ command: codexAcpOnPath,
6041
+ args: directArgs
6042
+ };
6043
+ }
6044
+ if (npxMode === "never") {
6045
+ return {
6046
+ command: process.platform === "win32" ? "codex-acp.cmd" : "codex-acp",
6047
+ args: directArgs
6048
+ };
6049
+ }
6050
+ return {
6051
+ command: resolveNpxCommand(),
6052
+ args: ["--prefer-offline", "-y", "@zed-industries/codex-acp", ...directArgs]
6053
+ };
6054
+ }
6055
+ function validateCodexAcpSpawn(options = {}) {
6056
+ let spawn;
6057
+ try {
6058
+ spawn = resolveCodexAcpSpawn(options);
6059
+ } catch (error) {
6060
+ return {
6061
+ ok: false,
6062
+ errorMessage: error instanceof Error ? error.message : "Codex ACP is enabled, but the command could not be resolved."
6063
+ };
6064
+ }
6065
+ const normalizedCommand = spawn.command.trim();
6066
+ const commandLower = normalizedCommand.toLowerCase();
6067
+ const npxMode = readCodexAcpNpxMode();
6068
+ if (path.isAbsolute(normalizedCommand)) {
6069
+ if (!fs.existsSync(normalizedCommand)) {
6070
+ return {
6071
+ ok: false,
6072
+ errorMessage: `Codex ACP is enabled, but the resolved command does not exist: ${normalizedCommand}`
6073
+ };
6074
+ }
6075
+ return { ok: true, spawn };
6076
+ }
6077
+ if (commandLower.endsWith("npx") || commandLower.endsWith("npx.cmd")) {
6078
+ if (isBinOnPath("npx") || isBinOnPath("npx.cmd")) {
6079
+ return { ok: true, spawn };
6080
+ }
6081
+ return {
6082
+ ok: false,
6083
+ errorMessage: "Codex ACP is enabled, but codex-acp is not installed and npx is not available. Install codex-acp, install Node.js/npm so npx is available, or set HAPPY_CODEX_ACP_BIN to a working codex-acp executable."
6084
+ };
6085
+ }
6086
+ if (commandLower === "codex-acp" || commandLower === "codex-acp.cmd") {
6087
+ if (isBinOnPath("codex-acp") || isBinOnPath("codex-acp.cmd")) {
6088
+ return { ok: true, spawn };
6089
+ }
6090
+ return {
6091
+ ok: false,
6092
+ errorMessage: npxMode === "never" ? "Codex ACP is enabled, but codex-acp is not installed and npx fallback is disabled. Install codex-acp, add it to PATH, or set HAPPY_CODEX_ACP_BIN to the executable." : "Codex ACP is enabled, but codex-acp could not be resolved on PATH. Install codex-acp, add it to PATH, or set HAPPY_CODEX_ACP_BIN to the executable."
6093
+ };
6094
+ }
6095
+ return { ok: true, spawn };
5669
6096
  }
5670
6097
 
5671
- function defaultCodexArgs() {
5672
- return ["mcp-server"];
6098
+ class CodexAcpTransport extends CodexTransport {
6099
+ constructor(initTimeoutMs) {
6100
+ super();
6101
+ this.initTimeoutMs = initTimeoutMs;
6102
+ }
6103
+ getInitTimeout() {
6104
+ return this.initTimeoutMs;
6105
+ }
6106
+ }
6107
+ function resolveCodexTransport(command) {
6108
+ if (/npx(?:\.cmd)?$/i.test(command)) {
6109
+ return new CodexAcpTransport(18e4);
6110
+ }
6111
+ return new CodexAcpTransport(6e4);
5673
6112
  }
5674
6113
  function createCodexBackend(options) {
5675
- const command = options.command ?? process.env.HAPPY_CODEX_ACP_COMMAND ?? resolveCodexExecutable();
5676
- const args = options.args ?? defaultCodexArgs();
6114
+ const spawn = resolveCodexAcpSpawn({
6115
+ command: options.command,
6116
+ args: options.args,
6117
+ baseArgs: options.baseArgs,
6118
+ model: options.model,
6119
+ sandbox: options.sandbox,
6120
+ approvalPolicy: options.approvalPolicy
6121
+ });
5677
6122
  const backendOptions = {
5678
6123
  agentName: "codex",
5679
6124
  cwd: options.cwd,
5680
- command,
5681
- args,
6125
+ command: spawn.command,
6126
+ args: spawn.args,
5682
6127
  env: {
5683
6128
  ...options.env,
5684
6129
  NODE_ENV: "production"
5685
6130
  },
5686
6131
  mcpServers: options.mcpServers,
5687
6132
  permissionHandler: options.permissionHandler,
5688
- transportHandler: codexTransport
6133
+ selectionHandler: options.selectionHandler,
6134
+ transportHandler: resolveCodexTransport(spawn.command)
5689
6135
  };
5690
6136
  return {
5691
6137
  backend: new AcpBackend(backendOptions),
5692
- command,
5693
- args
6138
+ command: spawn.command,
6139
+ args: spawn.args
5694
6140
  };
5695
6141
  }
5696
6142
  function registerCodexAgent() {
@@ -5876,17 +6322,26 @@ async function ensureUnifiedDaemonStarted() {
5876
6322
  env: process.env
5877
6323
  });
5878
6324
  daemonProcess.unref();
5879
- await new Promise((resolve) => setTimeout(resolve, 200));
6325
+ for (let i = 0; i < 100; i++) {
6326
+ if (await isDaemonRunningCurrentlyInstalledHappyVersion()) {
6327
+ return;
6328
+ }
6329
+ if (await isDaemonControlServerResponsive(500)) {
6330
+ return;
6331
+ }
6332
+ await new Promise((resolve) => setTimeout(resolve, 100));
6333
+ }
6334
+ throw new Error("Failed to start Happy background service.");
5880
6335
  }
5881
6336
  async function executeUnifiedProvider(opts) {
5882
6337
  const credentials = await ensureUnifiedRuntimePrerequisites(opts.credentials);
5883
6338
  if (opts.provider === "claude") {
5884
- const { runClaude } = await Promise.resolve().then(function () { return require('./runClaude-CwAitpX-.cjs'); });
6339
+ const { runClaude } = await Promise.resolve().then(function () { return require('./runClaude-B-GNEkKg.cjs'); });
5885
6340
  await runClaude(credentials, opts.claudeOptions ?? {});
5886
6341
  return;
5887
6342
  }
5888
6343
  if (opts.provider === "codex") {
5889
- const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-Cm0VTqw_.cjs'); });
6344
+ const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-CPHyGwj9.cjs'); });
5890
6345
  await runCodex({
5891
6346
  credentials,
5892
6347
  startedBy: opts.startedBy,
@@ -5896,7 +6351,7 @@ async function executeUnifiedProvider(opts) {
5896
6351
  return;
5897
6352
  }
5898
6353
  if (opts.provider === "gemini") {
5899
- const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-CLWjwDYS.cjs'); });
6354
+ const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-DaDz1bzQ.cjs'); });
5900
6355
  await runGemini({
5901
6356
  credentials,
5902
6357
  startedBy: opts.startedBy
@@ -5909,6 +6364,10 @@ async function executeUnifiedProvider(opts) {
5909
6364
  });
5910
6365
  }
5911
6366
 
6367
+ function shouldRunMainClaudeFlow(opts) {
6368
+ return !opts.showHelp && !opts.showVersion;
6369
+ }
6370
+
5912
6371
  (async () => {
5913
6372
  const args = process.argv.slice(2);
5914
6373
  const isRemoteMode = args.includes("--happy-starting-mode") && args.includes("remote");
@@ -5917,7 +6376,7 @@ async function executeUnifiedProvider(opts) {
5917
6376
  Object.defineProperty(process.stderr, "isTTY", { value: false });
5918
6377
  }
5919
6378
  if (!args.includes("--version")) {
5920
- api.logger.debug("Starting happy-cloud CLI with args: ", process.argv);
6379
+ api.logger.debug("Starting hicloud CLI with args: ", process.argv);
5921
6380
  }
5922
6381
  const subcommand = args[0];
5923
6382
  if (!args.includes("--version")) ;
@@ -5934,7 +6393,7 @@ async function executeUnifiedProvider(opts) {
5934
6393
  return;
5935
6394
  } else if (subcommand === "runtime") {
5936
6395
  if (args[1] === "providers") {
5937
- const { renderRuntimeProviders } = await Promise.resolve().then(function () { return require('./command-G85giEAF.cjs'); });
6396
+ const { renderRuntimeProviders } = await Promise.resolve().then(function () { return require('./command-CVldr51S.cjs'); });
5938
6397
  console.log(renderRuntimeProviders());
5939
6398
  return;
5940
6399
  }
@@ -5960,8 +6419,8 @@ async function executeUnifiedProvider(opts) {
5960
6419
  }
5961
6420
  return;
5962
6421
  }
5963
- console.log("Usage: happy-cloud runtime providers");
5964
- console.log(" happy-cloud runtime launch <claude|codex|gemini|cursor> [prompt]");
6422
+ console.log("Usage: hicloud runtime providers");
6423
+ console.log(" hicloud runtime launch <claude|codex|gemini|cursor> [prompt]");
5965
6424
  return;
5966
6425
  } else if (subcommand === "auth") {
5967
6426
  try {
@@ -6112,8 +6571,8 @@ async function executeUnifiedProvider(opts) {
6112
6571
  const projectId = args[3];
6113
6572
  try {
6114
6573
  const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return config; });
6115
- const { readCredentials: readCredentials2 } = await Promise.resolve().then(function () { return require('./persistence-DHgf1CTG.cjs'); });
6116
- const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./api-D7OK-mML.cjs'); }).then(function (n) { return n.api; });
6574
+ const { readCredentials: readCredentials2 } = await Promise.resolve().then(function () { return require('./persistence-D_2GkJAO.cjs'); });
6575
+ const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./api-D2Njw9Im.cjs'); }).then(function (n) { return n.api; });
6117
6576
  let userEmail = void 0;
6118
6577
  try {
6119
6578
  const credentials = await readCredentials2();
@@ -6159,7 +6618,7 @@ async function executeUnifiedProvider(opts) {
6159
6618
  console.log("No Google Cloud Project configured.");
6160
6619
  console.log("");
6161
6620
  console.log('If you see "Authentication required" error, you may need to set a project:');
6162
- console.log(" happy-cloud gemini project set <your-project-id>");
6621
+ console.log(" hicloud gemini project set <your-project-id>");
6163
6622
  console.log("");
6164
6623
  console.log("This is required for Google Workspace accounts.");
6165
6624
  console.log("Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca");
@@ -6171,7 +6630,7 @@ async function executeUnifiedProvider(opts) {
6171
6630
  }
6172
6631
  }
6173
6632
  if (geminiSubcommand === "project" && !args[2]) {
6174
- console.log("Usage: happy-cloud gemini project <command>");
6633
+ console.log("Usage: hicloud gemini project <command>");
6175
6634
  console.log("");
6176
6635
  console.log("Commands:");
6177
6636
  console.log(" set <project-id> Set Google Cloud Project ID");
@@ -6203,7 +6662,7 @@ async function executeUnifiedProvider(opts) {
6203
6662
  }
6204
6663
  return;
6205
6664
  } else if (subcommand === "logout") {
6206
- console.log(chalk.yellow('Note: "happy-cloud logout" is deprecated. Use "happy-cloud auth logout" instead.\n'));
6665
+ console.log(chalk.yellow('Note: "hicloud logout" is deprecated. Use "hicloud auth logout" instead.\n'));
6207
6666
  try {
6208
6667
  await handleAuthCommand(["logout"]);
6209
6668
  } catch (error) {
@@ -6262,7 +6721,7 @@ async function executeUnifiedProvider(opts) {
6262
6721
  child.unref();
6263
6722
  let started = false;
6264
6723
  for (let i = 0; i < 100; i++) {
6265
- if (await checkIfDaemonRunningAndCleanupStaleState()) {
6724
+ if (await checkIfDaemonRunningAndCleanupStaleState() && await isDaemonControlServerResponsive(500)) {
6266
6725
  started = true;
6267
6726
  break;
6268
6727
  }
@@ -6319,20 +6778,20 @@ async function executeUnifiedProvider(opts) {
6319
6778
  }
6320
6779
  } else {
6321
6780
  console.log(`
6322
- ${chalk.bold("happy-cloud daemon")} - Daemon management
6781
+ ${chalk.bold("hicloud daemon")} - Daemon management
6323
6782
 
6324
6783
  ${chalk.bold("Usage:")}
6325
- happy-cloud daemon start Start the daemon (detached)
6326
- happy-cloud daemon stop Stop the daemon (sessions stay alive)
6327
- happy-cloud daemon status Show daemon status
6328
- happy-cloud daemon list List active sessions
6784
+ hicloud daemon start Start the daemon (detached)
6785
+ hicloud daemon stop Stop the daemon (sessions stay alive)
6786
+ hicloud daemon status Show daemon status
6787
+ hicloud daemon list List active sessions
6329
6788
 
6330
6789
  If you want to kill all happy related processes run
6331
- ${chalk.cyan("happy-cloud doctor clean")}
6790
+ ${chalk.cyan("hicloud doctor clean")}
6332
6791
 
6333
6792
  ${chalk.bold("Note:")} The daemon runs in the background and manages Claude sessions.
6334
6793
 
6335
- ${chalk.bold("To clean up runaway processes:")} Use ${chalk.cyan("happy-cloud doctor clean")}
6794
+ ${chalk.bold("To clean up runaway processes:")} Use ${chalk.cyan("hicloud doctor clean")}
6336
6795
  `);
6337
6796
  }
6338
6797
  return;
@@ -6407,33 +6866,33 @@ ${chalk.bold("To clean up runaway processes:")} Use ${chalk.cyan("happy-cloud do
6407
6866
  ${chalk.bold(BRAND_CONFIG.name)} - AI \u7F16\u7A0B\u52A9\u624B
6408
6867
 
6409
6868
  ${chalk.bold("Usage:")}
6410
- happy-cloud [options] Start Claude with mobile control
6411
- happy-cloud auth Manage authentication
6412
- happy-cloud codex Start Codex mode
6413
- happy-cloud gemini Start Gemini mode (ACP)
6414
- happy-cloud cursor Start Cursor mode (experimental ACP)
6415
- happy-cloud connect Connect AI vendor API keys
6416
- happy-cloud notify Send push notification
6417
- happy-cloud daemon Manage background service that allows
6869
+ hicloud [options] Start Claude with mobile control
6870
+ hicloud auth Manage authentication
6871
+ hicloud codex Start Codex mode
6872
+ hicloud gemini Start Gemini mode (ACP)
6873
+ hicloud cursor Start Cursor mode (experimental ACP)
6874
+ hicloud connect Connect AI vendor API keys
6875
+ hicloud notify Send push notification
6876
+ hicloud daemon Manage background service that allows
6418
6877
  to spawn new sessions away from your computer
6419
- happy-cloud doctor System diagnostics & troubleshooting
6878
+ hicloud doctor System diagnostics & troubleshooting
6420
6879
 
6421
6880
  ${chalk.bold("Examples:")}
6422
- happy-cloud Start session
6423
- happy-cloud --yolo Start with bypassing permissions
6424
- happy-cloud sugar for --dangerously-skip-permissions
6425
- happy-cloud --chrome Enable Chrome browser access for this session
6426
- happy-cloud --no-chrome Disable Chrome even if default is on
6427
- happy-cloud --js-runtime bun Use bun instead of node to spawn Claude Code
6428
- happy-cloud --claude-env ANTHROPIC_BASE_URL=http://127.0.0.1:3456
6881
+ hicloud Start session
6882
+ hicloud --yolo Start with bypassing permissions
6883
+ hicloud sugar for --dangerously-skip-permissions
6884
+ hicloud --chrome Enable Chrome browser access for this session
6885
+ hicloud --no-chrome Disable Chrome even if default is on
6886
+ hicloud --js-runtime bun Use bun instead of node to spawn Claude Code
6887
+ hicloud --claude-env ANTHROPIC_BASE_URL=http://127.0.0.1:3456
6429
6888
  Use a custom API endpoint (e.g., claude-code-router)
6430
- happy-cloud auth login --force Authenticate
6431
- happy-cloud doctor Run diagnostics
6889
+ hicloud auth login --force Authenticate
6890
+ hicloud doctor Run diagnostics
6432
6891
 
6433
6892
  ${chalk.bold(`${BRAND_CONFIG.name} supports ALL Claude options!`)}
6434
- Use any claude flag with happy-cloud as you would with claude. Our favorite:
6893
+ Use any claude flag with hicloud as you would with claude. Our favorite:
6435
6894
 
6436
- happy-cloud --resume
6895
+ hicloud --resume
6437
6896
 
6438
6897
  ${chalk.gray("\u2500".repeat(60))}
6439
6898
  ${chalk.bold.cyan("Claude Code Options (from `claude --help`):")}
@@ -6448,8 +6907,9 @@ ${chalk.bold.cyan("Claude Code Options (from `claude --help`):")}
6448
6907
  }
6449
6908
  if (showVersion) {
6450
6909
  console.log(getVersionString());
6910
+ return;
6451
6911
  }
6452
- if (!showHelp && !showVersion) {
6912
+ if (shouldRunMainClaudeFlow({ showHelp, showVersion })) {
6453
6913
  printBanner();
6454
6914
  }
6455
6915
  try {
@@ -6485,31 +6945,31 @@ async function handleNotifyCommand(args) {
6485
6945
  }
6486
6946
  if (showHelp) {
6487
6947
  console.log(`
6488
- ${chalk.bold("happy-cloud notify")} - Send notification
6948
+ ${chalk.bold("hicloud notify")} - Send notification
6489
6949
 
6490
6950
  ${chalk.bold("Usage:")}
6491
- happy-cloud notify -p <message> [-t <title>] Send notification with custom message and optional title
6492
- happy-cloud notify -h, --help Show this help
6951
+ hicloud notify -p <message> [-t <title>] Send notification with custom message and optional title
6952
+ hicloud notify -h, --help Show this help
6493
6953
 
6494
6954
  ${chalk.bold("Options:")}
6495
6955
  -p <message> Notification message (required)
6496
6956
  -t <title> Notification title (optional, defaults to "Happy")
6497
6957
 
6498
6958
  ${chalk.bold("Examples:")}
6499
- happy-cloud notify -p "Deployment complete!"
6500
- happy-cloud notify -p "System update complete" -t "Server Status"
6501
- happy-cloud notify -t "Alert" -p "Database connection restored"
6959
+ hicloud notify -p "Deployment complete!"
6960
+ hicloud notify -p "System update complete" -t "Server Status"
6961
+ hicloud notify -t "Alert" -p "Database connection restored"
6502
6962
  `);
6503
6963
  return;
6504
6964
  }
6505
6965
  if (!message) {
6506
6966
  console.error(chalk.red('Error: Message is required. Use -p "your message" to specify the notification text.'));
6507
- console.log(chalk.gray('Run "happy-cloud notify --help" for usage information.'));
6967
+ console.log(chalk.gray('Run "hicloud notify --help" for usage information.'));
6508
6968
  process.exit(1);
6509
6969
  }
6510
6970
  let credentials = await persistence.readCredentials();
6511
6971
  if (!credentials) {
6512
- console.error(chalk.red('Error: Not authenticated. Please run "happy-cloud auth login" first.'));
6972
+ console.error(chalk.red('Error: Not authenticated. Please run "hicloud auth login" first.'));
6513
6973
  process.exit(1);
6514
6974
  }
6515
6975
  console.log(chalk.blue("\u{1F4F1} Sending push notification..."));
@@ -6539,8 +6999,10 @@ exports.ExitCodeError = ExitCodeError;
6539
6999
  exports.GEMINI_MODEL_ENV = GEMINI_MODEL_ENV;
6540
7000
  exports.claudeCheckSession = claudeCheckSession;
6541
7001
  exports.claudeLocal = claudeLocal;
7002
+ exports.createCodexBackend = createCodexBackend;
6542
7003
  exports.createDefaultRuntimeShell = createDefaultRuntimeShell;
6543
7004
  exports.createGeminiBackend = createGeminiBackend;
7005
+ exports.formatDisplayMessage = formatDisplayMessage;
6544
7006
  exports.getEnvironmentInfo = getEnvironmentInfo;
6545
7007
  exports.getInitialGeminiModel = getInitialGeminiModel;
6546
7008
  exports.getProjectPath = getProjectPath;
@@ -6549,9 +7011,9 @@ exports.isBun = isBun;
6549
7011
  exports.notifyDaemonSessionStarted = notifyDaemonSessionStarted;
6550
7012
  exports.projectPath = projectPath;
6551
7013
  exports.readGeminiLocalConfig = readGeminiLocalConfig;
6552
- exports.resolveCodexExecutable = resolveCodexExecutable;
6553
7014
  exports.saveGeminiModelToConfig = saveGeminiModelToConfig;
6554
- exports.shouldUseShellForCodex = shouldUseShellForCodex;
6555
7015
  exports.startCaffeinate = startCaffeinate;
6556
7016
  exports.stopCaffeinate = stopCaffeinate;
6557
7017
  exports.trimIdent = trimIdent;
7018
+ exports.truncateDisplayMessage = truncateDisplayMessage;
7019
+ exports.validateCodexAcpSpawn = validateCodexAcpSpawn;