@zhigang1992/happy-cli 0.13.4 → 0.13.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import chalk from 'chalk';
2
2
  import os$1, { homedir } from 'node:os';
3
3
  import { randomUUID, randomBytes, createHmac } from 'node:crypto';
4
- import { l as logger, p as projectPath, j as backoff, k as delay, R as RawJSONLinesSchema, m as AsyncLock, c as configuration, n as readDaemonState, o as clearDaemonState, i as packageJson, r as readSettings, q as readCredentials, g as encodeBase64, u as updateSettings, s as encodeBase64Url, d as decodeBase64, w as writeCredentialsLegacy, t as writeCredentialsDataKey, v as acquireDaemonLock, x as writeDaemonState, A as ApiClient, y as releaseDaemonLock, z as authChallenge, B as clearCredentials, C as clearMachineId, D as getLatestDaemonLog } from './types-BUeYxLoB.mjs';
4
+ import { l as logger, p as projectPath, j as backoff, k as delay, R as RawJSONLinesSchema, m as AsyncLock, c as configuration, n as readDaemonState, o as clearDaemonState, i as packageJson, r as readSettings, q as readCredentials, g as encodeBase64, u as updateSettings, s as encodeBase64Url, d as decodeBase64, w as writeCredentialsLegacy, t as writeCredentialsDataKey, v as acquireDaemonLock, x as writeDaemonState, A as ApiClient, y as releaseDaemonLock, z as authChallenge, B as clearCredentials, C as clearMachineId, D as getLatestDaemonLog } from './types-DiRuiHcP.mjs';
5
5
  import { spawn, execSync, exec as exec$1, execFileSync } from 'node:child_process';
6
6
  import { resolve, join, extname, basename as basename$1 } from 'node:path';
7
7
  import { createInterface } from 'node:readline';
@@ -1497,6 +1497,7 @@ function query(config) {
1497
1497
  }
1498
1498
  if (continueConversation) args.push("--continue");
1499
1499
  if (resume) args.push("--resume", resume);
1500
+ if (config.options?.forkSession) args.push("--fork-session");
1500
1501
  if (allowedTools.length > 0) args.push("--allowedTools", allowedTools.join(","));
1501
1502
  if (disallowedTools.length > 0) args.push("--disallowedTools", disallowedTools.join(","));
1502
1503
  if (mcpServers && Object.keys(mcpServers).length > 0) {
@@ -1816,22 +1817,24 @@ async function claudeRemote(opts) {
1816
1817
  if (opts.sessionId && !claudeCheckSession(opts.sessionId, opts.path)) {
1817
1818
  startFrom = null;
1818
1819
  }
1819
- if (!startFrom && opts.claudeArgs) {
1820
+ let forkSession = false;
1821
+ if (opts.claudeArgs) {
1820
1822
  for (let i = 0; i < opts.claudeArgs.length; i++) {
1821
- if (opts.claudeArgs[i] === "--resume") {
1823
+ if (opts.claudeArgs[i] === "--fork-session") {
1824
+ forkSession = true;
1825
+ logger.debug("[claudeRemote] Found --fork-session flag");
1826
+ }
1827
+ if (!startFrom && opts.claudeArgs[i] === "--resume") {
1822
1828
  if (i + 1 < opts.claudeArgs.length) {
1823
1829
  const nextArg = opts.claudeArgs[i + 1];
1824
1830
  if (!nextArg.startsWith("-") && nextArg.includes("-")) {
1825
1831
  startFrom = nextArg;
1826
1832
  logger.debug(`[claudeRemote] Found --resume with session ID: ${startFrom}`);
1827
- break;
1828
1833
  } else {
1829
1834
  logger.debug("[claudeRemote] Found --resume without session ID - not supported in remote mode");
1830
- break;
1831
1835
  }
1832
1836
  } else {
1833
1837
  logger.debug("[claudeRemote] Found --resume without session ID - not supported in remote mode");
1834
- break;
1835
1838
  }
1836
1839
  }
1837
1840
  }
@@ -2013,6 +2016,7 @@ Echo message: ${echoMessage}` : "");
2013
2016
  const sdkOptions = {
2014
2017
  cwd: opts.path,
2015
2018
  resume: startFrom ?? void 0,
2019
+ forkSession,
2016
2020
  mcpServers: opts.mcpServers,
2017
2021
  permissionMode: initial.mode.permissionMode === "plan" ? "plan" : "default",
2018
2022
  model: initial.mode.model,
@@ -3109,6 +3113,38 @@ async function claudeRemoteLauncher(session) {
3109
3113
  cwd: session.path,
3110
3114
  version: process.env.npm_package_version
3111
3115
  }, permissionHandler.getResponses());
3116
+ const sentMessageUuids = /* @__PURE__ */ new Set();
3117
+ function getMessageDedupeKey(msg) {
3118
+ if (msg.type === "summary") {
3119
+ return `summary:${msg.leafUuid}:${msg.summary}`;
3120
+ }
3121
+ if (msg.type === "system") {
3122
+ return `system:${msg.uuid}`;
3123
+ }
3124
+ try {
3125
+ const content = JSON.stringify(msg.message?.content ?? "");
3126
+ const contentKey = content.slice(0, 100) + ":" + content.length;
3127
+ return `${msg.type}:${contentKey}`;
3128
+ } catch {
3129
+ return msg.uuid ?? null;
3130
+ }
3131
+ }
3132
+ const sessionScanner = await createSessionScanner({
3133
+ sessionId: session.sessionId,
3134
+ workingDirectory: session.path,
3135
+ onMessage: (logMessage) => {
3136
+ const dedupeKey = getMessageDedupeKey(logMessage);
3137
+ if (dedupeKey && sentMessageUuids.has(dedupeKey)) {
3138
+ logger.debug(`[remote]: Scanner skipping (already sent): ${logMessage.type}`);
3139
+ return;
3140
+ }
3141
+ if (dedupeKey) {
3142
+ sentMessageUuids.add(dedupeKey);
3143
+ }
3144
+ logger.debug(`[remote]: Scanner forwarding message: ${logMessage.type}`);
3145
+ messageQueue.enqueue(logMessage);
3146
+ }
3147
+ });
3112
3148
  let ongoingToolCalls = /* @__PURE__ */ new Map();
3113
3149
  function onMessage(message) {
3114
3150
  formatClaudeMessageForInk(message, messageBuffer);
@@ -3137,6 +3173,10 @@ async function claudeRemoteLauncher(session) {
3137
3173
  }
3138
3174
  const logMessage = sdkToLogConverter.convert(message);
3139
3175
  if (logMessage) {
3176
+ const dedupeKey = getMessageDedupeKey(logMessage);
3177
+ if (dedupeKey) {
3178
+ sentMessageUuids.add(dedupeKey);
3179
+ }
3140
3180
  if (logMessage.type === "user" && logMessage.message?.content) {
3141
3181
  const content = Array.isArray(logMessage.message.content) ? logMessage.message.content : [];
3142
3182
  for (let i = 0; i < content.length; i++) {
@@ -3184,6 +3224,14 @@ async function claudeRemoteLauncher(session) {
3184
3224
  }
3185
3225
  }
3186
3226
  }
3227
+ if (logMessage.type === "user") {
3228
+ const content = logMessage.message?.content;
3229
+ const hasToolResult = Array.isArray(content) && content.some((c) => c.type === "tool_result");
3230
+ if (!hasToolResult) {
3231
+ logger.debug("[remote]: Skipping user text message (scanner will handle)");
3232
+ return;
3233
+ }
3234
+ }
3187
3235
  messageQueue.enqueue(logMessage);
3188
3236
  }
3189
3237
  if (message.type === "assistant") {
@@ -3193,6 +3241,10 @@ async function claudeRemoteLauncher(session) {
3193
3241
  if (c.type === "tool_use" && c.name === "Task" && c.input && typeof c.input.prompt === "string") {
3194
3242
  const logMessage2 = sdkToLogConverter.convertSidechainUserMessage(c.id, c.input.prompt);
3195
3243
  if (logMessage2) {
3244
+ const dedupeKey2 = getMessageDedupeKey(logMessage2);
3245
+ if (dedupeKey2) {
3246
+ sentMessageUuids.add(dedupeKey2);
3247
+ }
3196
3248
  messageQueue.enqueue(logMessage2);
3197
3249
  }
3198
3250
  }
@@ -3272,6 +3324,7 @@ async function claudeRemoteLauncher(session) {
3272
3324
  onSessionFound: (sessionId) => {
3273
3325
  sdkToLogConverter.updateSessionId(sessionId);
3274
3326
  session.onSessionFound(sessionId);
3327
+ sessionScanner.onNewSession(sessionId);
3275
3328
  },
3276
3329
  onThinkingChange: session.onThinkingChange,
3277
3330
  claudeEnvVars: session.claudeEnvVars,
@@ -3367,6 +3420,7 @@ async function claudeRemoteLauncher(session) {
3367
3420
  }
3368
3421
  }
3369
3422
  } finally {
3423
+ await sessionScanner.cleanup();
3370
3424
  permissionHandler.reset();
3371
3425
  process.stdin.off("data", abort);
3372
3426
  if (process.stdin.isTTY) {
@@ -7021,7 +7075,7 @@ async function handleConnectVendor(vendor, displayName) {
7021
7075
  return;
7022
7076
  } else if (subcommand === "codex") {
7023
7077
  try {
7024
- const { runCodex } = await import('./runCodex-BJaAstnJ.mjs');
7078
+ const { runCodex } = await import('./runCodex-D0U-q5eD.mjs');
7025
7079
  let startedBy = void 0;
7026
7080
  for (let i = 1; i < args.length; i++) {
7027
7081
  if (args[i] === "--started-by") {
@@ -7066,7 +7120,7 @@ async function handleConnectVendor(vendor, displayName) {
7066
7120
  } else if (subcommand === "list") {
7067
7121
  try {
7068
7122
  const { credentials } = await authAndSetupMachineIfNeeded();
7069
- const { listSessions } = await import('./list-DF7IVJD4.mjs');
7123
+ const { listSessions } = await import('./list-CJIFYb6N.mjs');
7070
7124
  let sessionId;
7071
7125
  let titleFilter;
7072
7126
  let recentMsgs;
@@ -7168,7 +7222,7 @@ Examples:
7168
7222
  process.exit(1);
7169
7223
  }
7170
7224
  const { credentials } = await authAndSetupMachineIfNeeded();
7171
- const { promptSession } = await import('./prompt-D2BswByO.mjs');
7225
+ const { promptSession } = await import('./prompt-CsSxmvT_.mjs');
7172
7226
  await promptSession(credentials, sessionId, promptText, timeoutMinutes ?? void 0);
7173
7227
  } catch (error) {
7174
7228
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -3,7 +3,7 @@
3
3
  var chalk = require('chalk');
4
4
  var os = require('node:os');
5
5
  var node_crypto = require('node:crypto');
6
- var types = require('./types-CSnGRdLP.cjs');
6
+ var types = require('./types-PYoidcSb.cjs');
7
7
  var node_child_process = require('node:child_process');
8
8
  var node_path = require('node:path');
9
9
  var node_readline = require('node:readline');
@@ -1184,7 +1184,7 @@ class AbortError extends Error {
1184
1184
  }
1185
1185
  }
1186
1186
 
1187
- const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-BdNIt5w7.cjs', document.baseURI).href)));
1187
+ const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-g2JPIqmn.cjs', document.baseURI).href)));
1188
1188
  const __dirname$1 = node_path.join(__filename$1, "..");
1189
1189
  function getGlobalClaudeVersion() {
1190
1190
  try {
@@ -1520,6 +1520,7 @@ function query(config) {
1520
1520
  }
1521
1521
  if (continueConversation) args.push("--continue");
1522
1522
  if (resume) args.push("--resume", resume);
1523
+ if (config.options?.forkSession) args.push("--fork-session");
1523
1524
  if (allowedTools.length > 0) args.push("--allowedTools", allowedTools.join(","));
1524
1525
  if (disallowedTools.length > 0) args.push("--disallowedTools", disallowedTools.join(","));
1525
1526
  if (mcpServers && Object.keys(mcpServers).length > 0) {
@@ -1839,22 +1840,24 @@ async function claudeRemote(opts) {
1839
1840
  if (opts.sessionId && !claudeCheckSession(opts.sessionId, opts.path)) {
1840
1841
  startFrom = null;
1841
1842
  }
1842
- if (!startFrom && opts.claudeArgs) {
1843
+ let forkSession = false;
1844
+ if (opts.claudeArgs) {
1843
1845
  for (let i = 0; i < opts.claudeArgs.length; i++) {
1844
- if (opts.claudeArgs[i] === "--resume") {
1846
+ if (opts.claudeArgs[i] === "--fork-session") {
1847
+ forkSession = true;
1848
+ types.logger.debug("[claudeRemote] Found --fork-session flag");
1849
+ }
1850
+ if (!startFrom && opts.claudeArgs[i] === "--resume") {
1845
1851
  if (i + 1 < opts.claudeArgs.length) {
1846
1852
  const nextArg = opts.claudeArgs[i + 1];
1847
1853
  if (!nextArg.startsWith("-") && nextArg.includes("-")) {
1848
1854
  startFrom = nextArg;
1849
1855
  types.logger.debug(`[claudeRemote] Found --resume with session ID: ${startFrom}`);
1850
- break;
1851
1856
  } else {
1852
1857
  types.logger.debug("[claudeRemote] Found --resume without session ID - not supported in remote mode");
1853
- break;
1854
1858
  }
1855
1859
  } else {
1856
1860
  types.logger.debug("[claudeRemote] Found --resume without session ID - not supported in remote mode");
1857
- break;
1858
1861
  }
1859
1862
  }
1860
1863
  }
@@ -2036,6 +2039,7 @@ Echo message: ${echoMessage}` : "");
2036
2039
  const sdkOptions = {
2037
2040
  cwd: opts.path,
2038
2041
  resume: startFrom ?? void 0,
2042
+ forkSession,
2039
2043
  mcpServers: opts.mcpServers,
2040
2044
  permissionMode: initial.mode.permissionMode === "plan" ? "plan" : "default",
2041
2045
  model: initial.mode.model,
@@ -3132,6 +3136,38 @@ async function claudeRemoteLauncher(session) {
3132
3136
  cwd: session.path,
3133
3137
  version: process.env.npm_package_version
3134
3138
  }, permissionHandler.getResponses());
3139
+ const sentMessageUuids = /* @__PURE__ */ new Set();
3140
+ function getMessageDedupeKey(msg) {
3141
+ if (msg.type === "summary") {
3142
+ return `summary:${msg.leafUuid}:${msg.summary}`;
3143
+ }
3144
+ if (msg.type === "system") {
3145
+ return `system:${msg.uuid}`;
3146
+ }
3147
+ try {
3148
+ const content = JSON.stringify(msg.message?.content ?? "");
3149
+ const contentKey = content.slice(0, 100) + ":" + content.length;
3150
+ return `${msg.type}:${contentKey}`;
3151
+ } catch {
3152
+ return msg.uuid ?? null;
3153
+ }
3154
+ }
3155
+ const sessionScanner = await createSessionScanner({
3156
+ sessionId: session.sessionId,
3157
+ workingDirectory: session.path,
3158
+ onMessage: (logMessage) => {
3159
+ const dedupeKey = getMessageDedupeKey(logMessage);
3160
+ if (dedupeKey && sentMessageUuids.has(dedupeKey)) {
3161
+ types.logger.debug(`[remote]: Scanner skipping (already sent): ${logMessage.type}`);
3162
+ return;
3163
+ }
3164
+ if (dedupeKey) {
3165
+ sentMessageUuids.add(dedupeKey);
3166
+ }
3167
+ types.logger.debug(`[remote]: Scanner forwarding message: ${logMessage.type}`);
3168
+ messageQueue.enqueue(logMessage);
3169
+ }
3170
+ });
3135
3171
  let ongoingToolCalls = /* @__PURE__ */ new Map();
3136
3172
  function onMessage(message) {
3137
3173
  formatClaudeMessageForInk(message, messageBuffer);
@@ -3160,6 +3196,10 @@ async function claudeRemoteLauncher(session) {
3160
3196
  }
3161
3197
  const logMessage = sdkToLogConverter.convert(message);
3162
3198
  if (logMessage) {
3199
+ const dedupeKey = getMessageDedupeKey(logMessage);
3200
+ if (dedupeKey) {
3201
+ sentMessageUuids.add(dedupeKey);
3202
+ }
3163
3203
  if (logMessage.type === "user" && logMessage.message?.content) {
3164
3204
  const content = Array.isArray(logMessage.message.content) ? logMessage.message.content : [];
3165
3205
  for (let i = 0; i < content.length; i++) {
@@ -3207,6 +3247,14 @@ async function claudeRemoteLauncher(session) {
3207
3247
  }
3208
3248
  }
3209
3249
  }
3250
+ if (logMessage.type === "user") {
3251
+ const content = logMessage.message?.content;
3252
+ const hasToolResult = Array.isArray(content) && content.some((c) => c.type === "tool_result");
3253
+ if (!hasToolResult) {
3254
+ types.logger.debug("[remote]: Skipping user text message (scanner will handle)");
3255
+ return;
3256
+ }
3257
+ }
3210
3258
  messageQueue.enqueue(logMessage);
3211
3259
  }
3212
3260
  if (message.type === "assistant") {
@@ -3216,6 +3264,10 @@ async function claudeRemoteLauncher(session) {
3216
3264
  if (c.type === "tool_use" && c.name === "Task" && c.input && typeof c.input.prompt === "string") {
3217
3265
  const logMessage2 = sdkToLogConverter.convertSidechainUserMessage(c.id, c.input.prompt);
3218
3266
  if (logMessage2) {
3267
+ const dedupeKey2 = getMessageDedupeKey(logMessage2);
3268
+ if (dedupeKey2) {
3269
+ sentMessageUuids.add(dedupeKey2);
3270
+ }
3219
3271
  messageQueue.enqueue(logMessage2);
3220
3272
  }
3221
3273
  }
@@ -3295,6 +3347,7 @@ async function claudeRemoteLauncher(session) {
3295
3347
  onSessionFound: (sessionId) => {
3296
3348
  sdkToLogConverter.updateSessionId(sessionId);
3297
3349
  session.onSessionFound(sessionId);
3350
+ sessionScanner.onNewSession(sessionId);
3298
3351
  },
3299
3352
  onThinkingChange: session.onThinkingChange,
3300
3353
  claudeEnvVars: session.claudeEnvVars,
@@ -3390,6 +3443,7 @@ async function claudeRemoteLauncher(session) {
3390
3443
  }
3391
3444
  }
3392
3445
  } finally {
3446
+ await sessionScanner.cleanup();
3393
3447
  permissionHandler.reset();
3394
3448
  process.stdin.off("data", abort);
3395
3449
  if (process.stdin.isTTY) {
@@ -7044,7 +7098,7 @@ async function handleConnectVendor(vendor, displayName) {
7044
7098
  return;
7045
7099
  } else if (subcommand === "codex") {
7046
7100
  try {
7047
- const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-DKfT8c0k.cjs'); });
7101
+ const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-Cci-tAjU.cjs'); });
7048
7102
  let startedBy = void 0;
7049
7103
  for (let i = 1; i < args.length; i++) {
7050
7104
  if (args[i] === "--started-by") {
@@ -7089,7 +7143,7 @@ async function handleConnectVendor(vendor, displayName) {
7089
7143
  } else if (subcommand === "list") {
7090
7144
  try {
7091
7145
  const { credentials } = await authAndSetupMachineIfNeeded();
7092
- const { listSessions } = await Promise.resolve().then(function () { return require('./list-DQpBq7_O.cjs'); });
7146
+ const { listSessions } = await Promise.resolve().then(function () { return require('./list-oXfJPJTM.cjs'); });
7093
7147
  let sessionId;
7094
7148
  let titleFilter;
7095
7149
  let recentMsgs;
@@ -7191,7 +7245,7 @@ Examples:
7191
7245
  process.exit(1);
7192
7246
  }
7193
7247
  const { credentials } = await authAndSetupMachineIfNeeded();
7194
- const { promptSession } = await Promise.resolve().then(function () { return require('./prompt-Di73cj93.cjs'); });
7248
+ const { promptSession } = await Promise.resolve().then(function () { return require('./prompt-la2aaOYY.cjs'); });
7195
7249
  await promptSession(credentials, sessionId, promptText, timeoutMinutes ?? void 0);
7196
7250
  } catch (error) {
7197
7251
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  require('chalk');
4
- require('./index-BdNIt5w7.cjs');
5
- require('./types-CSnGRdLP.cjs');
4
+ require('./index-g2JPIqmn.cjs');
5
+ require('./types-PYoidcSb.cjs');
6
6
  require('zod');
7
7
  require('node:child_process');
8
8
  require('node:os');
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import 'chalk';
2
- import './index-B2EGBeeU.mjs';
3
- import './types-BUeYxLoB.mjs';
2
+ import './index-CygCJIPr.mjs';
3
+ import './types-DiRuiHcP.mjs';
4
4
  import 'zod';
5
5
  import 'node:child_process';
6
6
  import 'node:os';
package/dist/lib.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var types = require('./types-CSnGRdLP.cjs');
3
+ var types = require('./types-PYoidcSb.cjs');
4
4
  require('axios');
5
5
  require('chalk');
6
6
  require('fs');
package/dist/lib.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-BUeYxLoB.mjs';
1
+ export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-DiRuiHcP.mjs';
2
2
  import 'axios';
3
3
  import 'chalk';
4
4
  import 'fs';
@@ -1,4 +1,4 @@
1
- import { c as configuration, l as logger, d as decodeBase64, b as decrypt, f as formatTimeAgo, e as libsodiumDecryptFromPublicKey } from './types-BUeYxLoB.mjs';
1
+ import { c as configuration, l as logger, d as decodeBase64, b as decrypt, f as formatTimeAgo, e as libsodiumDecryptFromPublicKey } from './types-DiRuiHcP.mjs';
2
2
  import axios from 'axios';
3
3
  import { existsSync, readdirSync, statSync, readFileSync } from 'fs';
4
4
  import { join } from 'path';
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var types = require('./types-CSnGRdLP.cjs');
3
+ var types = require('./types-PYoidcSb.cjs');
4
4
  var axios = require('axios');
5
5
  var fs = require('fs');
6
6
  var path = require('path');
@@ -1,4 +1,4 @@
1
- import { c as configuration, b as decrypt, d as decodeBase64, l as logger, g as encodeBase64, h as encrypt } from './types-BUeYxLoB.mjs';
1
+ import { c as configuration, b as decrypt, d as decodeBase64, l as logger, g as encodeBase64, h as encrypt } from './types-DiRuiHcP.mjs';
2
2
  import axios from 'axios';
3
3
  import { io } from 'socket.io-client';
4
4
  import 'chalk';
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var types = require('./types-CSnGRdLP.cjs');
3
+ var types = require('./types-PYoidcSb.cjs');
4
4
  var axios = require('axios');
5
5
  var socket_ioClient = require('socket.io-client');
6
6
  require('chalk');
@@ -2,14 +2,14 @@
2
2
 
3
3
  var ink = require('ink');
4
4
  var React = require('react');
5
- var types = require('./types-CSnGRdLP.cjs');
5
+ var types = require('./types-PYoidcSb.cjs');
6
6
  var index_js = require('@modelcontextprotocol/sdk/client/index.js');
7
7
  var stdio_js = require('@modelcontextprotocol/sdk/client/stdio.js');
8
8
  var z = require('zod');
9
9
  var types_js = require('@modelcontextprotocol/sdk/types.js');
10
10
  var child_process = require('child_process');
11
11
  var node_crypto = require('node:crypto');
12
- var index = require('./index-BdNIt5w7.cjs');
12
+ var index = require('./index-g2JPIqmn.cjs');
13
13
  var os = require('node:os');
14
14
  var node_path = require('node:path');
15
15
  var fs = require('node:fs');
@@ -1,13 +1,13 @@
1
1
  import { useStdout, useInput, Box, Text, render } from 'ink';
2
2
  import React, { useState, useRef, useEffect, useCallback } from 'react';
3
- import { l as logger, A as ApiClient, r as readSettings, p as projectPath, c as configuration, i as packageJson } from './types-BUeYxLoB.mjs';
3
+ import { l as logger, A as ApiClient, r as readSettings, p as projectPath, c as configuration, i as packageJson } from './types-DiRuiHcP.mjs';
4
4
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
5
5
  import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
6
6
  import { z } from 'zod';
7
7
  import { ElicitRequestSchema } from '@modelcontextprotocol/sdk/types.js';
8
8
  import { execSync } from 'child_process';
9
9
  import { randomUUID } from 'node:crypto';
10
- import { i as initialMachineMetadata, n as notifyDaemonSessionStarted, M as MessageQueue2, h as hashObject, r as registerKillSessionHandler, a as MessageBuffer, s as startHappyServer, t as trimIdent, b as stopCaffeinate } from './index-B2EGBeeU.mjs';
10
+ import { i as initialMachineMetadata, n as notifyDaemonSessionStarted, M as MessageQueue2, h as hashObject, r as registerKillSessionHandler, a as MessageBuffer, s as startHappyServer, t as trimIdent, b as stopCaffeinate } from './index-CygCJIPr.mjs';
11
11
  import os from 'node:os';
12
12
  import { resolve, join } from 'node:path';
13
13
  import fs from 'node:fs';
@@ -20,7 +20,7 @@ import { fileURLToPath } from 'url';
20
20
  import { Expo } from 'expo-server-sdk';
21
21
 
22
22
  var name = "@zhigang1992/happy-cli";
23
- var version = "0.13.4";
23
+ var version = "0.13.6";
24
24
  var description = "Mobile and Web client for Claude Code and Codex";
25
25
  var author = "Kirill Dubovitskiy";
26
26
  var license = "MIT";
@@ -41,7 +41,7 @@ function _interopNamespaceDefault(e) {
41
41
  var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
42
42
 
43
43
  var name = "@zhigang1992/happy-cli";
44
- var version = "0.13.4";
44
+ var version = "0.13.6";
45
45
  var description = "Mobile and Web client for Claude Code and Codex";
46
46
  var author = "Kirill Dubovitskiy";
47
47
  var license = "MIT";
@@ -1150,7 +1150,7 @@ class RpcHandlerManager {
1150
1150
  }
1151
1151
  }
1152
1152
 
1153
- const __dirname$1 = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-CSnGRdLP.cjs', document.baseURI).href))));
1153
+ const __dirname$1 = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-PYoidcSb.cjs', document.baseURI).href))));
1154
1154
  function projectPath() {
1155
1155
  const path$1 = path.resolve(__dirname$1, "..");
1156
1156
  return path$1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhigang1992/happy-cli",
3
- "version": "0.13.4",
3
+ "version": "0.13.6",
4
4
  "description": "Mobile and Web client for Claude Code and Codex",
5
5
  "author": "Kirill Dubovitskiy",
6
6
  "license": "MIT",
@@ -252,13 +252,20 @@ function findLatestVersionBinary(versionsDir, binaryName = null) {
252
252
  /**
253
253
  * Find path to globally installed Claude Code CLI
254
254
  * Checks multiple installation methods in order of preference:
255
- * 1. npm global (highest priority)
255
+ * 0. HAPPY_CLAUDE_PATH env var (highest priority)
256
+ * 1. npm global
256
257
  * 2. Homebrew
257
258
  * 3. Native installer
258
259
  * @returns {{path: string, source: string}|null} Path and source, or null if not found
259
260
  */
260
261
  function findGlobalClaudeCliPath() {
261
- // Check npm global first (highest priority)
262
+ // Environment variable takes highest priority
263
+ const envPath = process.env.HAPPY_CLAUDE_PATH;
264
+ if (envPath && fs.existsSync(envPath)) {
265
+ return { path: envPath, source: 'HAPPY_CLAUDE_PATH env' };
266
+ }
267
+
268
+ // Check npm global
262
269
  const npmPath = findNpmGlobalCliPath();
263
270
  if (npmPath) return { path: npmPath, source: 'npm' };
264
271