@zhigang1992/happy-cli 0.12.13 → 0.12.15

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.
@@ -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-DwjUGi0J.cjs');
6
+ var types = require('./types-CYn1BLoj.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');
@@ -782,20 +782,27 @@ async function claudeLocalLauncher(session) {
782
782
  };
783
783
  session.addSessionFoundCallback(scannerSessionCallback);
784
784
  let exitReason = null;
785
- const processAbortController = new AbortController();
785
+ let abortRequested = false;
786
+ let processAbortController = new AbortController();
786
787
  let exutFuture = new Future();
787
788
  try {
789
+ let getAbortController2 = function() {
790
+ return processAbortController;
791
+ }, getExitFuture2 = function() {
792
+ return exutFuture;
793
+ };
794
+ var getAbortController = getAbortController2, getExitFuture = getExitFuture2;
788
795
  async function abort() {
789
- if (!processAbortController.signal.aborted) {
790
- processAbortController.abort();
796
+ const controller = getAbortController2();
797
+ const exitFuture = getExitFuture2();
798
+ if (!controller.signal.aborted) {
799
+ controller.abort();
791
800
  }
792
- await exutFuture.promise;
801
+ await exitFuture.promise;
793
802
  }
794
803
  async function doAbort() {
795
804
  types.logger.debug("[local]: doAbort");
796
- if (!exitReason) {
797
- exitReason = "switch";
798
- }
805
+ abortRequested = true;
799
806
  session.queue.reset();
800
807
  await abort();
801
808
  }
@@ -837,6 +844,13 @@ async function claudeLocalLauncher(session) {
837
844
  hookSettingsPath: session.hookSettingsPath
838
845
  });
839
846
  session.consumeOneTimeFlags();
847
+ if (abortRequested) {
848
+ types.logger.debug("[local]: Aborting current operation, continuing local mode");
849
+ abortRequested = false;
850
+ processAbortController = new AbortController();
851
+ exutFuture = new Future();
852
+ continue;
853
+ }
840
854
  if (!exitReason) {
841
855
  exitReason = "exit";
842
856
  break;
@@ -844,6 +858,13 @@ async function claudeLocalLauncher(session) {
844
858
  } catch (e) {
845
859
  const errorMessage = e instanceof Error ? e.message : String(e);
846
860
  types.logger.debug("[local]: launch error", e);
861
+ if (abortRequested) {
862
+ types.logger.debug("[local]: Aborting after error, continuing local mode");
863
+ abortRequested = false;
864
+ processAbortController = new AbortController();
865
+ exutFuture = new Future();
866
+ continue;
867
+ }
847
868
  const reason = exitReason;
848
869
  if (reason === "switch") {
849
870
  session.client.sendSessionEvent({ type: "message", message: `Error during mode switch: ${errorMessage}` });
@@ -1163,7 +1184,7 @@ class AbortError extends Error {
1163
1184
  }
1164
1185
  }
1165
1186
 
1166
- 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-VlluCzOw.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-BXhnIvhV.cjs', document.baseURI).href)));
1167
1188
  const __dirname$1 = node_path.join(__filename$1, "..");
1168
1189
  function getGlobalClaudeVersion() {
1169
1190
  try {
@@ -1479,6 +1500,7 @@ function query(config) {
1479
1500
  fallbackModel,
1480
1501
  strictMcpConfig,
1481
1502
  canCallTool,
1503
+ settingsPath,
1482
1504
  onStderr
1483
1505
  } = {}
1484
1506
  } = config;
@@ -1505,6 +1527,7 @@ function query(config) {
1505
1527
  }
1506
1528
  if (strictMcpConfig) args.push("--strict-mcp-config");
1507
1529
  if (permissionMode) args.push("--permission-mode", permissionMode);
1530
+ if (settingsPath) args.push("--settings", settingsPath);
1508
1531
  if (fallbackModel) {
1509
1532
  if (model && fallbackModel === model) {
1510
1533
  throw new Error("Fallback model cannot be the same as the main model. Please specify a different model for fallbackModel option.");
@@ -2027,6 +2050,7 @@ Echo message: ${echoMessage}` : "");
2027
2050
  pathToClaudeCodeExecutable: (() => {
2028
2051
  return node_path.resolve(node_path.join(types.projectPath(), "scripts", "claude_remote_launcher.cjs"));
2029
2052
  })(),
2053
+ settingsPath: opts.hookSettingsPath,
2030
2054
  onStderr: opts.onStderr
2031
2055
  };
2032
2056
  let thinking = false;
@@ -2062,6 +2086,8 @@ Echo message: ${echoMessage}` : "");
2062
2086
  const initialContent = await buildMessageContent(initial.message, initial.mode.imageRefs);
2063
2087
  messages.push({
2064
2088
  type: "user",
2089
+ uuid: node_crypto.randomUUID(),
2090
+ // UUID is required for Claude CLI streaming mode
2065
2091
  message: {
2066
2092
  role: "user",
2067
2093
  content: initialContent
@@ -2106,7 +2132,12 @@ Echo message: ${echoMessage}` : "");
2106
2132
  }
2107
2133
  mode = next.mode;
2108
2134
  const nextContent = await buildMessageContent(next.message, next.mode.imageRefs);
2109
- messages.push({ type: "user", message: { role: "user", content: nextContent } });
2135
+ messages.push({
2136
+ type: "user",
2137
+ uuid: node_crypto.randomUUID(),
2138
+ // UUID is required for Claude CLI streaming mode
2139
+ message: { role: "user", content: nextContent }
2140
+ });
2110
2141
  }
2111
2142
  if (message.type === "user") {
2112
2143
  const msg = message;
@@ -3027,6 +3058,7 @@ async function claudeRemoteLauncher(session) {
3027
3058
  let exitReason = null;
3028
3059
  let abortController = null;
3029
3060
  let abortFuture = null;
3061
+ let abortRequested = false;
3030
3062
  async function abort() {
3031
3063
  if (abortController && !abortController.signal.aborted) {
3032
3064
  abortController.abort();
@@ -3035,6 +3067,7 @@ async function claudeRemoteLauncher(session) {
3035
3067
  }
3036
3068
  async function doAbort() {
3037
3069
  types.logger.debug("[remote]: doAbort");
3070
+ abortRequested = true;
3038
3071
  await abort();
3039
3072
  }
3040
3073
  async function doSwitch() {
@@ -3220,6 +3253,7 @@ async function claudeRemoteLauncher(session) {
3220
3253
  path: session.path,
3221
3254
  allowedTools: session.allowedTools ?? [],
3222
3255
  mcpServers: session.mcpServers,
3256
+ hookSettingsPath: session.hookSettingsPath,
3223
3257
  canCallTool: permissionHandler.handleToolCall,
3224
3258
  isAborted: (toolCallId) => {
3225
3259
  return permissionHandler.isAborted(toolCallId);
@@ -3299,16 +3333,30 @@ async function claudeRemoteLauncher(session) {
3299
3333
  signal: abortController.signal
3300
3334
  });
3301
3335
  session.consumeOneTimeFlags();
3336
+ if (abortRequested && abortController.signal.aborted) {
3337
+ types.logger.debug("[remote]: Operation aborted by user, continuing remote mode");
3338
+ session.client.sendSessionEvent({ type: "message", message: "Aborted" });
3339
+ abortRequested = false;
3340
+ continue;
3341
+ }
3302
3342
  if (!exitReason && abortController.signal.aborted) {
3303
3343
  session.client.sendSessionEvent({ type: "message", message: "Aborted by user" });
3304
3344
  }
3305
3345
  } catch (e) {
3306
3346
  const errorMessage = e instanceof Error ? e.message : String(e);
3307
3347
  types.logger.debug("[remote]: launch error", e);
3348
+ if (abortRequested) {
3349
+ types.logger.debug("[remote]: Aborting after error, continuing remote mode");
3350
+ session.client.sendSessionEvent({ type: "message", message: "Aborted" });
3351
+ abortRequested = false;
3352
+ continue;
3353
+ }
3308
3354
  if (exitReason === "switch") {
3309
3355
  session.client.sendSessionEvent({ type: "message", message: `Error during mode switch: ${errorMessage}` });
3356
+ break;
3310
3357
  } else if (exitReason === "exit") {
3311
3358
  session.client.sendSessionEvent({ type: "message", message: `Error during exit: ${errorMessage}` });
3359
+ break;
3312
3360
  } else {
3313
3361
  session.client.sendSessionEvent({ type: "message", message: `Process error: ${errorMessage}` });
3314
3362
  continue;
@@ -3874,6 +3922,139 @@ function extractSDKMetadataAsync(onComplete) {
3874
3922
  });
3875
3923
  }
3876
3924
 
3925
+ function parseFrontmatter(content) {
3926
+ const trimmed = content.trim();
3927
+ if (!trimmed.startsWith("---")) {
3928
+ return { frontmatter: null, body: content };
3929
+ }
3930
+ const endIndex = trimmed.indexOf("---", 3);
3931
+ if (endIndex === -1) {
3932
+ return { frontmatter: null, body: content };
3933
+ }
3934
+ const frontmatterStr = trimmed.substring(3, endIndex).trim();
3935
+ const body = trimmed.substring(endIndex + 3).trim();
3936
+ const frontmatter = {};
3937
+ const lines = frontmatterStr.split("\n");
3938
+ for (const line of lines) {
3939
+ const colonIndex = line.indexOf(":");
3940
+ if (colonIndex === -1) continue;
3941
+ const key = line.substring(0, colonIndex).trim();
3942
+ let value = line.substring(colonIndex + 1).trim();
3943
+ if (key === "allowed-tools" && value) {
3944
+ frontmatter["allowed-tools"] = value.split(",").map((s) => s.trim());
3945
+ } else if (key === "description") {
3946
+ frontmatter.description = value;
3947
+ } else if (key === "argument-hint") {
3948
+ frontmatter["argument-hint"] = value;
3949
+ } else if (key === "model") {
3950
+ frontmatter.model = value;
3951
+ }
3952
+ }
3953
+ return { frontmatter, body };
3954
+ }
3955
+ function extractDescriptionFromContent(content) {
3956
+ const lines = content.split("\n");
3957
+ for (const line of lines) {
3958
+ const trimmed = line.trim();
3959
+ if (trimmed && !trimmed.startsWith("#") && !trimmed.startsWith("!")) {
3960
+ return trimmed.length > 100 ? trimmed.substring(0, 100) + "..." : trimmed;
3961
+ }
3962
+ }
3963
+ return void 0;
3964
+ }
3965
+ function findMarkdownFiles(dir, baseDir = dir) {
3966
+ const results = [];
3967
+ if (!fs.existsSync(dir)) {
3968
+ return results;
3969
+ }
3970
+ try {
3971
+ const entries = fs.readdirSync(dir);
3972
+ for (const entry of entries) {
3973
+ const fullPath = node_path.join(dir, entry);
3974
+ const stat = fs.statSync(fullPath);
3975
+ if (stat.isDirectory()) {
3976
+ const subResults = findMarkdownFiles(fullPath, baseDir);
3977
+ results.push(...subResults);
3978
+ } else if (stat.isFile() && node_path.extname(entry).toLowerCase() === ".md") {
3979
+ const relativePath = fullPath.substring(baseDir.length + 1);
3980
+ const namespace = relativePath.includes("/") ? relativePath.substring(0, relativePath.lastIndexOf("/")) : void 0;
3981
+ results.push({ filePath: fullPath, namespace });
3982
+ }
3983
+ }
3984
+ } catch (error) {
3985
+ types.logger.debug("[customCommands] Error reading directory:", dir, error);
3986
+ }
3987
+ return results;
3988
+ }
3989
+ function parseCommandFile(filePath, namespace, scope) {
3990
+ try {
3991
+ const content = fs.readFileSync(filePath, "utf-8");
3992
+ const { frontmatter, body } = parseFrontmatter(content);
3993
+ const name = node_path.basename(filePath, ".md");
3994
+ const description = frontmatter?.description || extractDescriptionFromContent(body);
3995
+ let allowedTools;
3996
+ if (frontmatter?.["allowed-tools"]) {
3997
+ const at = frontmatter["allowed-tools"];
3998
+ allowedTools = Array.isArray(at) ? at : [at];
3999
+ }
4000
+ return {
4001
+ name,
4002
+ description,
4003
+ argumentHint: frontmatter?.["argument-hint"],
4004
+ allowedTools,
4005
+ model: frontmatter?.model,
4006
+ scope,
4007
+ namespace,
4008
+ filePath,
4009
+ content: body
4010
+ };
4011
+ } catch (error) {
4012
+ types.logger.debug("[customCommands] Error parsing command file:", filePath, error);
4013
+ return null;
4014
+ }
4015
+ }
4016
+ function discoverCustomCommands(projectDir) {
4017
+ const commands = [];
4018
+ const projectCommandsDir = node_path.join(projectDir, ".claude", "commands");
4019
+ if (fs.existsSync(projectCommandsDir)) {
4020
+ types.logger.debug("[customCommands] Scanning project commands:", projectCommandsDir);
4021
+ const files = findMarkdownFiles(projectCommandsDir);
4022
+ for (const { filePath, namespace } of files) {
4023
+ const command = parseCommandFile(filePath, namespace, "project");
4024
+ if (command) {
4025
+ commands.push(command);
4026
+ }
4027
+ }
4028
+ }
4029
+ const personalCommandsDir = node_path.join(os.homedir(), ".claude", "commands");
4030
+ if (fs.existsSync(personalCommandsDir)) {
4031
+ types.logger.debug("[customCommands] Scanning personal commands:", personalCommandsDir);
4032
+ const files = findMarkdownFiles(personalCommandsDir);
4033
+ for (const { filePath, namespace } of files) {
4034
+ const command = parseCommandFile(filePath, namespace, "personal");
4035
+ if (command) {
4036
+ const existingIndex = commands.findIndex((c) => c.name === command.name);
4037
+ if (existingIndex === -1) {
4038
+ commands.push(command);
4039
+ } else {
4040
+ types.logger.debug(`[customCommands] Skipping personal command "${command.name}" - project command takes precedence`);
4041
+ }
4042
+ }
4043
+ }
4044
+ }
4045
+ types.logger.debug(`[customCommands] Discovered ${commands.length} custom commands`);
4046
+ return commands;
4047
+ }
4048
+ function commandsToMetadata(commands) {
4049
+ return commands.map((cmd) => ({
4050
+ name: cmd.name,
4051
+ description: cmd.description,
4052
+ argumentHint: cmd.argumentHint,
4053
+ scope: cmd.scope,
4054
+ namespace: cmd.namespace
4055
+ }));
4056
+ }
4057
+
3877
4058
  async function daemonPost(path, body) {
3878
4059
  const state = await types.readDaemonState();
3879
4060
  if (!state?.httpPort) {
@@ -4964,7 +5145,9 @@ async function startDaemon() {
4964
5145
  "--happy-starting-mode",
4965
5146
  "remote",
4966
5147
  "--started-by",
4967
- "daemon"
5148
+ "daemon",
5149
+ // Add --resume flag if resuming from a previous Claude session
5150
+ ...options.resumeClaudeSessionId ? ["--resume", options.resumeClaudeSessionId] : []
4968
5151
  ];
4969
5152
  const happyProcess = spawnHappyCLI(args, {
4970
5153
  cwd: directory,
@@ -5469,6 +5652,20 @@ async function runClaude(credentials, options = {}) {
5469
5652
  } catch (error) {
5470
5653
  types.logger.debug("[START] Failed to report to daemon (may not be running):", error);
5471
5654
  }
5655
+ const customCommands = discoverCustomCommands(workingDirectory);
5656
+ const customCommandsMetadata = commandsToMetadata(customCommands);
5657
+ types.logger.debug(`[start] Discovered ${customCommands.length} custom commands`);
5658
+ if (customCommandsMetadata.length > 0) {
5659
+ try {
5660
+ api.sessionSyncClient(response).updateMetadata((currentMetadata) => ({
5661
+ ...currentMetadata,
5662
+ customCommands: customCommandsMetadata
5663
+ }));
5664
+ types.logger.debug("[start] Session metadata updated with custom commands");
5665
+ } catch (error) {
5666
+ types.logger.debug("[start] Failed to update session metadata with custom commands:", error);
5667
+ }
5668
+ }
5472
5669
  extractSDKMetadataAsync(async (sdkMetadata) => {
5473
5670
  types.logger.debug("[start] SDK metadata extracted, updating session:", sdkMetadata);
5474
5671
  try {
@@ -6833,7 +7030,7 @@ async function handleConnectVendor(vendor, displayName) {
6833
7030
  return;
6834
7031
  } else if (subcommand === "codex") {
6835
7032
  try {
6836
- const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-3jsfzjVM.cjs'); });
7033
+ const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-CDA2a_3g.cjs'); });
6837
7034
  let startedBy = void 0;
6838
7035
  for (let i = 1; i < args.length; i++) {
6839
7036
  if (args[i] === "--started-by") {
@@ -6878,7 +7075,7 @@ async function handleConnectVendor(vendor, displayName) {
6878
7075
  } else if (subcommand === "list") {
6879
7076
  try {
6880
7077
  const { credentials } = await authAndSetupMachineIfNeeded();
6881
- const { listSessions } = await Promise.resolve().then(function () { return require('./list-DXxyuwT9.cjs'); });
7078
+ const { listSessions } = await Promise.resolve().then(function () { return require('./list-DnyoGVs0.cjs'); });
6882
7079
  let sessionId;
6883
7080
  let titleFilter;
6884
7081
  let recentMsgs;
@@ -6980,7 +7177,7 @@ Examples:
6980
7177
  process.exit(1);
6981
7178
  }
6982
7179
  const { credentials } = await authAndSetupMachineIfNeeded();
6983
- const { promptSession } = await Promise.resolve().then(function () { return require('./prompt-LEVV0Hst.cjs'); });
7180
+ const { promptSession } = await Promise.resolve().then(function () { return require('./prompt-1J3xTRvg.cjs'); });
6984
7181
  await promptSession(credentials, sessionId, promptText, timeoutMinutes ?? void 0);
6985
7182
  } catch (error) {
6986
7183
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -1,9 +1,9 @@
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-C1SMg54t.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-Do0vU1JP.mjs';
5
5
  import { spawn, execSync, exec as exec$1, execFileSync } from 'node:child_process';
6
- import { resolve, join } from 'node:path';
6
+ import { resolve, join, extname, basename as basename$1 } from 'node:path';
7
7
  import { createInterface } from 'node:readline';
8
8
  import { existsSync, readFileSync, mkdirSync, readdirSync, statSync, writeFileSync, unlinkSync, rmSync } from 'node:fs';
9
9
  import { exec, spawn as spawn$1, execSync as execSync$1 } from 'child_process';
@@ -759,20 +759,27 @@ async function claudeLocalLauncher(session) {
759
759
  };
760
760
  session.addSessionFoundCallback(scannerSessionCallback);
761
761
  let exitReason = null;
762
- const processAbortController = new AbortController();
762
+ let abortRequested = false;
763
+ let processAbortController = new AbortController();
763
764
  let exutFuture = new Future();
764
765
  try {
766
+ let getAbortController2 = function() {
767
+ return processAbortController;
768
+ }, getExitFuture2 = function() {
769
+ return exutFuture;
770
+ };
771
+ var getAbortController = getAbortController2, getExitFuture = getExitFuture2;
765
772
  async function abort() {
766
- if (!processAbortController.signal.aborted) {
767
- processAbortController.abort();
773
+ const controller = getAbortController2();
774
+ const exitFuture = getExitFuture2();
775
+ if (!controller.signal.aborted) {
776
+ controller.abort();
768
777
  }
769
- await exutFuture.promise;
778
+ await exitFuture.promise;
770
779
  }
771
780
  async function doAbort() {
772
781
  logger.debug("[local]: doAbort");
773
- if (!exitReason) {
774
- exitReason = "switch";
775
- }
782
+ abortRequested = true;
776
783
  session.queue.reset();
777
784
  await abort();
778
785
  }
@@ -814,6 +821,13 @@ async function claudeLocalLauncher(session) {
814
821
  hookSettingsPath: session.hookSettingsPath
815
822
  });
816
823
  session.consumeOneTimeFlags();
824
+ if (abortRequested) {
825
+ logger.debug("[local]: Aborting current operation, continuing local mode");
826
+ abortRequested = false;
827
+ processAbortController = new AbortController();
828
+ exutFuture = new Future();
829
+ continue;
830
+ }
817
831
  if (!exitReason) {
818
832
  exitReason = "exit";
819
833
  break;
@@ -821,6 +835,13 @@ async function claudeLocalLauncher(session) {
821
835
  } catch (e) {
822
836
  const errorMessage = e instanceof Error ? e.message : String(e);
823
837
  logger.debug("[local]: launch error", e);
838
+ if (abortRequested) {
839
+ logger.debug("[local]: Aborting after error, continuing local mode");
840
+ abortRequested = false;
841
+ processAbortController = new AbortController();
842
+ exutFuture = new Future();
843
+ continue;
844
+ }
824
845
  const reason = exitReason;
825
846
  if (reason === "switch") {
826
847
  session.client.sendSessionEvent({ type: "message", message: `Error during mode switch: ${errorMessage}` });
@@ -1456,6 +1477,7 @@ function query(config) {
1456
1477
  fallbackModel,
1457
1478
  strictMcpConfig,
1458
1479
  canCallTool,
1480
+ settingsPath,
1459
1481
  onStderr
1460
1482
  } = {}
1461
1483
  } = config;
@@ -1482,6 +1504,7 @@ function query(config) {
1482
1504
  }
1483
1505
  if (strictMcpConfig) args.push("--strict-mcp-config");
1484
1506
  if (permissionMode) args.push("--permission-mode", permissionMode);
1507
+ if (settingsPath) args.push("--settings", settingsPath);
1485
1508
  if (fallbackModel) {
1486
1509
  if (model && fallbackModel === model) {
1487
1510
  throw new Error("Fallback model cannot be the same as the main model. Please specify a different model for fallbackModel option.");
@@ -2004,6 +2027,7 @@ Echo message: ${echoMessage}` : "");
2004
2027
  pathToClaudeCodeExecutable: (() => {
2005
2028
  return resolve(join(projectPath(), "scripts", "claude_remote_launcher.cjs"));
2006
2029
  })(),
2030
+ settingsPath: opts.hookSettingsPath,
2007
2031
  onStderr: opts.onStderr
2008
2032
  };
2009
2033
  let thinking = false;
@@ -2039,6 +2063,8 @@ Echo message: ${echoMessage}` : "");
2039
2063
  const initialContent = await buildMessageContent(initial.message, initial.mode.imageRefs);
2040
2064
  messages.push({
2041
2065
  type: "user",
2066
+ uuid: randomUUID(),
2067
+ // UUID is required for Claude CLI streaming mode
2042
2068
  message: {
2043
2069
  role: "user",
2044
2070
  content: initialContent
@@ -2083,7 +2109,12 @@ Echo message: ${echoMessage}` : "");
2083
2109
  }
2084
2110
  mode = next.mode;
2085
2111
  const nextContent = await buildMessageContent(next.message, next.mode.imageRefs);
2086
- messages.push({ type: "user", message: { role: "user", content: nextContent } });
2112
+ messages.push({
2113
+ type: "user",
2114
+ uuid: randomUUID(),
2115
+ // UUID is required for Claude CLI streaming mode
2116
+ message: { role: "user", content: nextContent }
2117
+ });
2087
2118
  }
2088
2119
  if (message.type === "user") {
2089
2120
  const msg = message;
@@ -3004,6 +3035,7 @@ async function claudeRemoteLauncher(session) {
3004
3035
  let exitReason = null;
3005
3036
  let abortController = null;
3006
3037
  let abortFuture = null;
3038
+ let abortRequested = false;
3007
3039
  async function abort() {
3008
3040
  if (abortController && !abortController.signal.aborted) {
3009
3041
  abortController.abort();
@@ -3012,6 +3044,7 @@ async function claudeRemoteLauncher(session) {
3012
3044
  }
3013
3045
  async function doAbort() {
3014
3046
  logger.debug("[remote]: doAbort");
3047
+ abortRequested = true;
3015
3048
  await abort();
3016
3049
  }
3017
3050
  async function doSwitch() {
@@ -3197,6 +3230,7 @@ async function claudeRemoteLauncher(session) {
3197
3230
  path: session.path,
3198
3231
  allowedTools: session.allowedTools ?? [],
3199
3232
  mcpServers: session.mcpServers,
3233
+ hookSettingsPath: session.hookSettingsPath,
3200
3234
  canCallTool: permissionHandler.handleToolCall,
3201
3235
  isAborted: (toolCallId) => {
3202
3236
  return permissionHandler.isAborted(toolCallId);
@@ -3276,16 +3310,30 @@ async function claudeRemoteLauncher(session) {
3276
3310
  signal: abortController.signal
3277
3311
  });
3278
3312
  session.consumeOneTimeFlags();
3313
+ if (abortRequested && abortController.signal.aborted) {
3314
+ logger.debug("[remote]: Operation aborted by user, continuing remote mode");
3315
+ session.client.sendSessionEvent({ type: "message", message: "Aborted" });
3316
+ abortRequested = false;
3317
+ continue;
3318
+ }
3279
3319
  if (!exitReason && abortController.signal.aborted) {
3280
3320
  session.client.sendSessionEvent({ type: "message", message: "Aborted by user" });
3281
3321
  }
3282
3322
  } catch (e) {
3283
3323
  const errorMessage = e instanceof Error ? e.message : String(e);
3284
3324
  logger.debug("[remote]: launch error", e);
3325
+ if (abortRequested) {
3326
+ logger.debug("[remote]: Aborting after error, continuing remote mode");
3327
+ session.client.sendSessionEvent({ type: "message", message: "Aborted" });
3328
+ abortRequested = false;
3329
+ continue;
3330
+ }
3285
3331
  if (exitReason === "switch") {
3286
3332
  session.client.sendSessionEvent({ type: "message", message: `Error during mode switch: ${errorMessage}` });
3333
+ break;
3287
3334
  } else if (exitReason === "exit") {
3288
3335
  session.client.sendSessionEvent({ type: "message", message: `Error during exit: ${errorMessage}` });
3336
+ break;
3289
3337
  } else {
3290
3338
  session.client.sendSessionEvent({ type: "message", message: `Process error: ${errorMessage}` });
3291
3339
  continue;
@@ -3851,6 +3899,139 @@ function extractSDKMetadataAsync(onComplete) {
3851
3899
  });
3852
3900
  }
3853
3901
 
3902
+ function parseFrontmatter(content) {
3903
+ const trimmed = content.trim();
3904
+ if (!trimmed.startsWith("---")) {
3905
+ return { frontmatter: null, body: content };
3906
+ }
3907
+ const endIndex = trimmed.indexOf("---", 3);
3908
+ if (endIndex === -1) {
3909
+ return { frontmatter: null, body: content };
3910
+ }
3911
+ const frontmatterStr = trimmed.substring(3, endIndex).trim();
3912
+ const body = trimmed.substring(endIndex + 3).trim();
3913
+ const frontmatter = {};
3914
+ const lines = frontmatterStr.split("\n");
3915
+ for (const line of lines) {
3916
+ const colonIndex = line.indexOf(":");
3917
+ if (colonIndex === -1) continue;
3918
+ const key = line.substring(0, colonIndex).trim();
3919
+ let value = line.substring(colonIndex + 1).trim();
3920
+ if (key === "allowed-tools" && value) {
3921
+ frontmatter["allowed-tools"] = value.split(",").map((s) => s.trim());
3922
+ } else if (key === "description") {
3923
+ frontmatter.description = value;
3924
+ } else if (key === "argument-hint") {
3925
+ frontmatter["argument-hint"] = value;
3926
+ } else if (key === "model") {
3927
+ frontmatter.model = value;
3928
+ }
3929
+ }
3930
+ return { frontmatter, body };
3931
+ }
3932
+ function extractDescriptionFromContent(content) {
3933
+ const lines = content.split("\n");
3934
+ for (const line of lines) {
3935
+ const trimmed = line.trim();
3936
+ if (trimmed && !trimmed.startsWith("#") && !trimmed.startsWith("!")) {
3937
+ return trimmed.length > 100 ? trimmed.substring(0, 100) + "..." : trimmed;
3938
+ }
3939
+ }
3940
+ return void 0;
3941
+ }
3942
+ function findMarkdownFiles(dir, baseDir = dir) {
3943
+ const results = [];
3944
+ if (!existsSync(dir)) {
3945
+ return results;
3946
+ }
3947
+ try {
3948
+ const entries = readdirSync(dir);
3949
+ for (const entry of entries) {
3950
+ const fullPath = join(dir, entry);
3951
+ const stat = statSync(fullPath);
3952
+ if (stat.isDirectory()) {
3953
+ const subResults = findMarkdownFiles(fullPath, baseDir);
3954
+ results.push(...subResults);
3955
+ } else if (stat.isFile() && extname(entry).toLowerCase() === ".md") {
3956
+ const relativePath = fullPath.substring(baseDir.length + 1);
3957
+ const namespace = relativePath.includes("/") ? relativePath.substring(0, relativePath.lastIndexOf("/")) : void 0;
3958
+ results.push({ filePath: fullPath, namespace });
3959
+ }
3960
+ }
3961
+ } catch (error) {
3962
+ logger.debug("[customCommands] Error reading directory:", dir, error);
3963
+ }
3964
+ return results;
3965
+ }
3966
+ function parseCommandFile(filePath, namespace, scope) {
3967
+ try {
3968
+ const content = readFileSync(filePath, "utf-8");
3969
+ const { frontmatter, body } = parseFrontmatter(content);
3970
+ const name = basename$1(filePath, ".md");
3971
+ const description = frontmatter?.description || extractDescriptionFromContent(body);
3972
+ let allowedTools;
3973
+ if (frontmatter?.["allowed-tools"]) {
3974
+ const at = frontmatter["allowed-tools"];
3975
+ allowedTools = Array.isArray(at) ? at : [at];
3976
+ }
3977
+ return {
3978
+ name,
3979
+ description,
3980
+ argumentHint: frontmatter?.["argument-hint"],
3981
+ allowedTools,
3982
+ model: frontmatter?.model,
3983
+ scope,
3984
+ namespace,
3985
+ filePath,
3986
+ content: body
3987
+ };
3988
+ } catch (error) {
3989
+ logger.debug("[customCommands] Error parsing command file:", filePath, error);
3990
+ return null;
3991
+ }
3992
+ }
3993
+ function discoverCustomCommands(projectDir) {
3994
+ const commands = [];
3995
+ const projectCommandsDir = join(projectDir, ".claude", "commands");
3996
+ if (existsSync(projectCommandsDir)) {
3997
+ logger.debug("[customCommands] Scanning project commands:", projectCommandsDir);
3998
+ const files = findMarkdownFiles(projectCommandsDir);
3999
+ for (const { filePath, namespace } of files) {
4000
+ const command = parseCommandFile(filePath, namespace, "project");
4001
+ if (command) {
4002
+ commands.push(command);
4003
+ }
4004
+ }
4005
+ }
4006
+ const personalCommandsDir = join(homedir(), ".claude", "commands");
4007
+ if (existsSync(personalCommandsDir)) {
4008
+ logger.debug("[customCommands] Scanning personal commands:", personalCommandsDir);
4009
+ const files = findMarkdownFiles(personalCommandsDir);
4010
+ for (const { filePath, namespace } of files) {
4011
+ const command = parseCommandFile(filePath, namespace, "personal");
4012
+ if (command) {
4013
+ const existingIndex = commands.findIndex((c) => c.name === command.name);
4014
+ if (existingIndex === -1) {
4015
+ commands.push(command);
4016
+ } else {
4017
+ logger.debug(`[customCommands] Skipping personal command "${command.name}" - project command takes precedence`);
4018
+ }
4019
+ }
4020
+ }
4021
+ }
4022
+ logger.debug(`[customCommands] Discovered ${commands.length} custom commands`);
4023
+ return commands;
4024
+ }
4025
+ function commandsToMetadata(commands) {
4026
+ return commands.map((cmd) => ({
4027
+ name: cmd.name,
4028
+ description: cmd.description,
4029
+ argumentHint: cmd.argumentHint,
4030
+ scope: cmd.scope,
4031
+ namespace: cmd.namespace
4032
+ }));
4033
+ }
4034
+
3854
4035
  async function daemonPost(path, body) {
3855
4036
  const state = await readDaemonState();
3856
4037
  if (!state?.httpPort) {
@@ -4941,7 +5122,9 @@ async function startDaemon() {
4941
5122
  "--happy-starting-mode",
4942
5123
  "remote",
4943
5124
  "--started-by",
4944
- "daemon"
5125
+ "daemon",
5126
+ // Add --resume flag if resuming from a previous Claude session
5127
+ ...options.resumeClaudeSessionId ? ["--resume", options.resumeClaudeSessionId] : []
4945
5128
  ];
4946
5129
  const happyProcess = spawnHappyCLI(args, {
4947
5130
  cwd: directory,
@@ -5446,6 +5629,20 @@ async function runClaude(credentials, options = {}) {
5446
5629
  } catch (error) {
5447
5630
  logger.debug("[START] Failed to report to daemon (may not be running):", error);
5448
5631
  }
5632
+ const customCommands = discoverCustomCommands(workingDirectory);
5633
+ const customCommandsMetadata = commandsToMetadata(customCommands);
5634
+ logger.debug(`[start] Discovered ${customCommands.length} custom commands`);
5635
+ if (customCommandsMetadata.length > 0) {
5636
+ try {
5637
+ api.sessionSyncClient(response).updateMetadata((currentMetadata) => ({
5638
+ ...currentMetadata,
5639
+ customCommands: customCommandsMetadata
5640
+ }));
5641
+ logger.debug("[start] Session metadata updated with custom commands");
5642
+ } catch (error) {
5643
+ logger.debug("[start] Failed to update session metadata with custom commands:", error);
5644
+ }
5645
+ }
5449
5646
  extractSDKMetadataAsync(async (sdkMetadata) => {
5450
5647
  logger.debug("[start] SDK metadata extracted, updating session:", sdkMetadata);
5451
5648
  try {
@@ -6810,7 +7007,7 @@ async function handleConnectVendor(vendor, displayName) {
6810
7007
  return;
6811
7008
  } else if (subcommand === "codex") {
6812
7009
  try {
6813
- const { runCodex } = await import('./runCodex-DO1tAsMY.mjs');
7010
+ const { runCodex } = await import('./runCodex-CWaOl3u2.mjs');
6814
7011
  let startedBy = void 0;
6815
7012
  for (let i = 1; i < args.length; i++) {
6816
7013
  if (args[i] === "--started-by") {
@@ -6855,7 +7052,7 @@ async function handleConnectVendor(vendor, displayName) {
6855
7052
  } else if (subcommand === "list") {
6856
7053
  try {
6857
7054
  const { credentials } = await authAndSetupMachineIfNeeded();
6858
- const { listSessions } = await import('./list-C0F4TAPa.mjs');
7055
+ const { listSessions } = await import('./list-CXZgsrb3.mjs');
6859
7056
  let sessionId;
6860
7057
  let titleFilter;
6861
7058
  let recentMsgs;
@@ -6957,7 +7154,7 @@ Examples:
6957
7154
  process.exit(1);
6958
7155
  }
6959
7156
  const { credentials } = await authAndSetupMachineIfNeeded();
6960
- const { promptSession } = await import('./prompt-Br-GiaVj.mjs');
7157
+ const { promptSession } = await import('./prompt-CvpPWx4v.mjs');
6961
7158
  await promptSession(credentials, sessionId, promptText, timeoutMinutes ?? void 0);
6962
7159
  } catch (error) {
6963
7160
  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-VlluCzOw.cjs');
5
- require('./types-DwjUGi0J.cjs');
4
+ require('./index-BXhnIvhV.cjs');
5
+ require('./types-CYn1BLoj.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-Bzl-ixRP.mjs';
3
- import './types-C1SMg54t.mjs';
2
+ import './index-C1S8W6hS.mjs';
3
+ import './types-Do0vU1JP.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-DwjUGi0J.cjs');
3
+ var types = require('./types-CYn1BLoj.cjs');
4
4
  require('axios');
5
5
  require('chalk');
6
6
  require('fs');
package/dist/lib.d.cts CHANGED
@@ -715,6 +715,13 @@ type Metadata = {
715
715
  claudeSessionId?: string;
716
716
  tools?: string[];
717
717
  slashCommands?: string[];
718
+ customCommands?: Array<{
719
+ name: string;
720
+ description?: string;
721
+ argumentHint?: string;
722
+ scope: 'project' | 'personal';
723
+ namespace?: string;
724
+ }>;
718
725
  homeDir: string;
719
726
  happyHomeDir: string;
720
727
  happyLibDir: string;
@@ -760,6 +767,7 @@ interface SpawnSessionOptions {
760
767
  approvedNewDirectoryCreation?: boolean;
761
768
  agent?: 'claude' | 'codex';
762
769
  token?: string;
770
+ resumeClaudeSessionId?: string;
763
771
  }
764
772
  type SpawnSessionResult = {
765
773
  type: 'success';
package/dist/lib.d.mts CHANGED
@@ -715,6 +715,13 @@ type Metadata = {
715
715
  claudeSessionId?: string;
716
716
  tools?: string[];
717
717
  slashCommands?: string[];
718
+ customCommands?: Array<{
719
+ name: string;
720
+ description?: string;
721
+ argumentHint?: string;
722
+ scope: 'project' | 'personal';
723
+ namespace?: string;
724
+ }>;
718
725
  homeDir: string;
719
726
  happyHomeDir: string;
720
727
  happyLibDir: string;
@@ -760,6 +767,7 @@ interface SpawnSessionOptions {
760
767
  approvedNewDirectoryCreation?: boolean;
761
768
  agent?: 'claude' | 'codex';
762
769
  token?: string;
770
+ resumeClaudeSessionId?: string;
763
771
  }
764
772
  type SpawnSessionResult = {
765
773
  type: 'success';
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-C1SMg54t.mjs';
1
+ export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-Do0vU1JP.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-C1SMg54t.mjs';
1
+ import { c as configuration, l as logger, d as decodeBase64, b as decrypt, f as formatTimeAgo, e as libsodiumDecryptFromPublicKey } from './types-Do0vU1JP.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-DwjUGi0J.cjs');
3
+ var types = require('./types-CYn1BLoj.cjs');
4
4
  var axios = require('axios');
5
5
  var fs = require('fs');
6
6
  var path = require('path');
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var types = require('./types-DwjUGi0J.cjs');
3
+ var types = require('./types-CYn1BLoj.cjs');
4
4
  var axios = require('axios');
5
5
  var socket_ioClient = require('socket.io-client');
6
6
  require('chalk');
@@ -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-C1SMg54t.mjs';
1
+ import { c as configuration, b as decrypt, d as decodeBase64, l as logger, g as encodeBase64, h as encrypt } from './types-Do0vU1JP.mjs';
2
2
  import axios from 'axios';
3
3
  import { io } from 'socket.io-client';
4
4
  import 'chalk';
@@ -2,14 +2,14 @@
2
2
 
3
3
  var ink = require('ink');
4
4
  var React = require('react');
5
- var types = require('./types-DwjUGi0J.cjs');
5
+ var types = require('./types-CYn1BLoj.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-VlluCzOw.cjs');
12
+ var index = require('./index-BXhnIvhV.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-C1SMg54t.mjs';
3
+ import { l as logger, A as ApiClient, r as readSettings, p as projectPath, c as configuration, i as packageJson } from './types-Do0vU1JP.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-Bzl-ixRP.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-C1S8W6hS.mjs';
11
11
  import os from 'node:os';
12
12
  import { resolve, join } from 'node:path';
13
13
  import fs from 'node:fs';
@@ -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.12.13";
44
+ var version = "0.12.15";
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-DwjUGi0J.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-CYn1BLoj.cjs', document.baseURI).href))));
1154
1154
  function projectPath() {
1155
1155
  const path$1 = path.resolve(__dirname$1, "..");
1156
1156
  return path$1;
@@ -1914,12 +1914,12 @@ class ApiMachineClient {
1914
1914
  requestShutdown
1915
1915
  }) {
1916
1916
  this.rpcHandlerManager.registerHandler("spawn-happy-session", async (params) => {
1917
- const { directory, sessionId, machineId, approvedNewDirectoryCreation, agent, token } = params || {};
1917
+ const { directory, sessionId, machineId, approvedNewDirectoryCreation, agent, token, resumeClaudeSessionId } = params || {};
1918
1918
  logger.debug(`[API MACHINE] Spawning session with params: ${JSON.stringify(params)}`);
1919
1919
  if (!directory) {
1920
1920
  throw new Error("Directory is required");
1921
1921
  }
1922
- const result = await spawnSession({ directory, sessionId, machineId, approvedNewDirectoryCreation, agent, token });
1922
+ const result = await spawnSession({ directory, sessionId, machineId, approvedNewDirectoryCreation, agent, token, resumeClaudeSessionId });
1923
1923
  switch (result.type) {
1924
1924
  case "success":
1925
1925
  logger.debug(`[API MACHINE] Spawned session ${result.sessionId}`);
@@ -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.12.13";
23
+ var version = "0.12.15";
24
24
  var description = "Mobile and Web client for Claude Code and Codex";
25
25
  var author = "Kirill Dubovitskiy";
26
26
  var license = "MIT";
@@ -1893,12 +1893,12 @@ class ApiMachineClient {
1893
1893
  requestShutdown
1894
1894
  }) {
1895
1895
  this.rpcHandlerManager.registerHandler("spawn-happy-session", async (params) => {
1896
- const { directory, sessionId, machineId, approvedNewDirectoryCreation, agent, token } = params || {};
1896
+ const { directory, sessionId, machineId, approvedNewDirectoryCreation, agent, token, resumeClaudeSessionId } = params || {};
1897
1897
  logger.debug(`[API MACHINE] Spawning session with params: ${JSON.stringify(params)}`);
1898
1898
  if (!directory) {
1899
1899
  throw new Error("Directory is required");
1900
1900
  }
1901
- const result = await spawnSession({ directory, sessionId, machineId, approvedNewDirectoryCreation, agent, token });
1901
+ const result = await spawnSession({ directory, sessionId, machineId, approvedNewDirectoryCreation, agent, token, resumeClaudeSessionId });
1902
1902
  switch (result.type) {
1903
1903
  case "success":
1904
1904
  logger.debug(`[API MACHINE] Spawned session ${result.sessionId}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhigang1992/happy-cli",
3
- "version": "0.12.13",
3
+ "version": "0.12.15",
4
4
  "description": "Mobile and Web client for Claude Code and Codex",
5
5
  "author": "Kirill Dubovitskiy",
6
6
  "license": "MIT",
@@ -330,7 +330,7 @@ function getClaudeCliPath() {
330
330
 
331
331
  const version = getVersion(result.path);
332
332
  const versionStr = version ? ` v${version}` : '';
333
- console.error(`\x1b[90mUsing Claude Code${versionStr} from ${result.source}\x1b[0m`);
333
+ console.error(`Using Claude Code${versionStr} from ${result.source}`);
334
334
 
335
335
  return result.path;
336
336
  }