very-happy-cli 0.2.78 → 0.2.80

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 (31) hide show
  1. package/dist/{AcpBackend-CDngyx5G.mjs → AcpBackend-DBJGqMwR.mjs} +1 -1
  2. package/dist/{AcpBackend-BxZ-KvBy.cjs → AcpBackend-_662AILI.cjs} +1 -1
  3. package/dist/{AcpSessionManager-Dcq8dl4l.mjs → AcpSessionManager-DcWebwii.mjs} +1 -1
  4. package/dist/{AcpSessionManager-BWFM_8f9.cjs → AcpSessionManager-ENIrbDWT.cjs} +1 -1
  5. package/dist/{config-Co1Tpb5e.mjs → config-DHUFJkEr.mjs} +2 -2
  6. package/dist/{config-Byay91xM.cjs → config-Dn4CC1I_.cjs} +2 -2
  7. package/dist/{index-CkjEzh-Y.cjs → index-C9JZ3wyP.cjs} +4 -4
  8. package/dist/{index-CuvhWx_d.cjs → index-CdmSlaUU.cjs} +252 -73
  9. package/dist/{index-DdOYA0qe.mjs → index-D9OFwx0T.mjs} +5 -5
  10. package/dist/{index-w0zkr6EM.mjs → index-DoLyKWEW.mjs} +249 -70
  11. package/dist/index.cjs +2 -2
  12. package/dist/index.mjs +2 -2
  13. package/dist/{installTerminalHooks-DFmjn6EQ.mjs → installTerminalHooks-D48YflmS.mjs} +2 -2
  14. package/dist/{installTerminalHooks-nXjKPP3D.cjs → installTerminalHooks-RgJOM2ds.cjs} +2 -2
  15. package/dist/lib.cjs +1 -1
  16. package/dist/lib.d.cts +8 -2
  17. package/dist/lib.d.mts +8 -2
  18. package/dist/lib.mjs +1 -1
  19. package/dist/{mcp-BreMIH5r.cjs → mcp-CIJ6lM8-.cjs} +2 -2
  20. package/dist/{mcp-nlZLEkmO.mjs → mcp-DnO0vHep.mjs} +2 -2
  21. package/dist/{runGemini-by29Tp8r.cjs → runGemini-CDko3vdP.cjs} +4 -4
  22. package/dist/{runGemini-DEZ0neEl.mjs → runGemini-Cnvz6a6J.mjs} +4 -4
  23. package/dist/{runOpenClaw-DyJQFzoX.mjs → runOpenClaw-Cpxdqf9Z.mjs} +3 -3
  24. package/dist/{runOpenClaw-DENpTXhw.cjs → runOpenClaw-Dk_FfroQ.cjs} +3 -3
  25. package/dist/{send-e6BSMl0m.cjs → send-BavRmzTl.cjs} +2 -2
  26. package/dist/{send-pX36Sd4p.mjs → send-DJWwqdS_.mjs} +2 -2
  27. package/dist/{spawn-C87d_KDj.cjs → spawn-Bqrneceh.cjs} +2 -2
  28. package/dist/{spawn-Da-94Ejo.mjs → spawn-DWf78N7k.mjs} +2 -2
  29. package/dist/{types-Clmu74iY.mjs → types-B2DG32ua.mjs} +46 -16
  30. package/dist/{types-Dua2iF5S.cjs → types-DL98ZceN.cjs} +46 -16
  31. package/package.json +7 -7
@@ -1,10 +1,10 @@
1
- import { D as DefaultTransport, A as AcpBackend } from './AcpBackend-CDngyx5G.mjs';
2
- export { a as DEFAULT_IDLE_TIMEOUT_MS, b as DEFAULT_TOOL_CALL_TIMEOUT_MS, e as extractErrorDetail, f as formatDuration, c as formatDurationMinutes, h as handleAgentMessageChunk, d as handleAgentThoughtChunk, g as handleLegacyMessageChunk, i as handlePlanUpdate, j as handleThinkingUpdate, k as handleToolCall, l as handleToolCallUpdate, p as parseArgsFromContent } from './AcpBackend-CDngyx5G.mjs';
3
- import { h as connectionState, A as ApiClient, i as readSettings, j as encodeBase64, l as logger, p as projectPath } from './types-Clmu74iY.mjs';
4
- import { A as AcpSessionManager } from './AcpSessionManager-Dcq8dl4l.mjs';
1
+ import { D as DefaultTransport, A as AcpBackend } from './AcpBackend-DBJGqMwR.mjs';
2
+ export { a as DEFAULT_IDLE_TIMEOUT_MS, b as DEFAULT_TOOL_CALL_TIMEOUT_MS, e as extractErrorDetail, f as formatDuration, c as formatDurationMinutes, h as handleAgentMessageChunk, d as handleAgentThoughtChunk, g as handleLegacyMessageChunk, i as handlePlanUpdate, j as handleThinkingUpdate, k as handleToolCall, l as handleToolCallUpdate, p as parseArgsFromContent } from './AcpBackend-DBJGqMwR.mjs';
3
+ import { h as connectionState, A as ApiClient, i as readSettings, j as encodeBase64, l as logger, p as projectPath } from './types-B2DG32ua.mjs';
4
+ import { A as AcpSessionManager } from './AcpSessionManager-DcWebwii.mjs';
5
5
  import { randomUUID } from 'node:crypto';
6
6
  import { join } from 'node:path';
7
- import { i as initialMachineMetadata, d as createSessionMetadata, e as setupOfflineReconnection, n as notifyDaemonSessionStarted, M as MessageQueue2, h as hashObject, f as startHappyServer, r as registerKillSessionHandler, B as BasePermissionHandler } from './index-w0zkr6EM.mjs';
7
+ import { i as initialMachineMetadata, d as createSessionMetadata, e as setupOfflineReconnection, n as notifyDaemonSessionStarted, M as MessageQueue2, h as hashObject, f as startHappyServer, r as registerKillSessionHandler, B as BasePermissionHandler } from './index-DoLyKWEW.mjs';
8
8
  import 'node:child_process';
9
9
  import '@agentclientprotocol/sdk';
10
10
  import 'axios';
@@ -1,7 +1,7 @@
1
1
  import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
2
2
  import os, { homedir } from 'node:os';
3
3
  import { randomUUID, randomBytes, createHash as createHash$1, timingSafeEqual } from 'node:crypto';
4
- import { n as readDaemonState, l as logger, c as configuration, o as clearDaemonState, q as getProjectPath, p as projectPath, s as initializeSandbox, t as wrapCommand, d as contentLogMetadata, I as InvalidateSync, R as RawJSONLinesSchema, g as delay, u as AsyncLock, f as packageJson, i as readSettings, v as readCredentials, x as credentialRelayProblem, y as deriveLocalCliUpdateSummary, j as encodeBase64, z as updateSettings, B as encodeBase64Url, C as decodeBase64, D as writeCredentialsLegacy, E as writeCredentialsDataKey, F as readCredentialsForConfiguredRelay, G as encrypt, r as readPersistedSessions, H as getLocalHappyAgentCredentialPath, J as readLocalHappyAgentCredentials, K as decryptWithDataKey, L as decryptLegacy, M as extractCompleteLines, N as decideBackfill, O as parseTerminalHookPayload, P as decideMirrorBinding, Q as persistSession, S as MIRROR_BACKFILL_LINES_DEFAULT, T as mirrorLineKey, U as mirrorLocalId, V as detectResumeSupport, W as detectCLIAvailability, X as acquireDaemonLock, Y as summarizeSpawnSessionForLog, Z as deletePersistedSessions, _ as decrypt, $ as writeDaemonState, A as ApiClient, a0 as fetchCliUpdateState, a1 as resolveCliUpdateCheckInterval, a2 as DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS, a3 as releaseDaemonLock, a4 as isValidSessionId, a5 as listVhTerminals, a6 as isValidTerminalId, a7 as readVhTerminal, a8 as sendToVhTerminal, h as connectionState, a9 as startOfflineReconnection, aa as clearCredentials, ab as clearMachineId, k as ensurePrivateDirectorySync, w as writePrivateFileSync, ac as SandboxConfigSchema, b as createEnvelope, ad as CodexAppServerClient, ae as getLatestDaemonLog } from './types-Clmu74iY.mjs';
4
+ import { n as readDaemonState, l as logger, c as configuration, o as clearDaemonState, q as getProjectPath, p as projectPath, s as initializeSandbox, t as wrapCommand, d as contentLogMetadata, I as InvalidateSync, R as RawJSONLinesSchema, g as delay, u as AsyncLock, f as packageJson, i as readSettings, v as readCredentials, x as credentialRelayProblem, y as deriveLocalCliUpdateSummary, j as encodeBase64, z as updateSettings, B as encodeBase64Url, C as decodeBase64, D as writeCredentialsLegacy, E as writeCredentialsDataKey, F as readCredentialsForConfiguredRelay, G as encrypt, r as readPersistedSessions, H as getLocalHappyAgentCredentialPath, J as readLocalHappyAgentCredentials, K as decryptWithDataKey, L as decryptLegacy, M as extractCompleteLines, N as decideBackfill, O as parseTerminalHookPayload, P as decideMirrorBinding, Q as persistSession, S as MIRROR_BACKFILL_LINES_DEFAULT, T as mirrorLineKey, U as mirrorLocalId, V as detectResumeSupport, W as detectCLIAvailability, X as acquireDaemonLock, Y as summarizeSpawnSessionForLog, Z as deletePersistedSessions, _ as decrypt, $ as writeDaemonState, A as ApiClient, a0 as fetchCliUpdateState, a1 as resolveCliUpdateCheckInterval, a2 as DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS, a3 as releaseDaemonLock, a4 as isValidSessionId, a5 as listVhTerminals, a6 as isValidTerminalId, a7 as readVhTerminal, a8 as sendToVhTerminal, h as connectionState, a9 as startOfflineReconnection, aa as clearCredentials, ab as clearMachineId, k as ensurePrivateDirectorySync, w as writePrivateFileSync, ac as SandboxConfigSchema, b as createEnvelope, ad as CodexAppServerClient, ae as getLatestDaemonLog } from './types-B2DG32ua.mjs';
5
5
  import spawn$1, { spawn } from 'cross-spawn';
6
6
  import path, { join, resolve, isAbsolute, normalize, sep, dirname } from 'node:path';
7
7
  import { createInterface } from 'node:readline';
@@ -1489,6 +1489,7 @@ function query(params) {
1489
1489
  fallbackModel: opts?.fallbackModel,
1490
1490
  maxTurns: opts?.maxTurns,
1491
1491
  permissionMode: opts?.permissionMode,
1492
+ allowDangerouslySkipPermissions: opts?.permissionMode === "bypassPermissions",
1492
1493
  allowedTools: opts?.allowedTools,
1493
1494
  disallowedTools: opts?.disallowedTools,
1494
1495
  mcpServers: opts?.mcpServers,
@@ -1507,11 +1508,18 @@ function query(params) {
1507
1508
  settingSources: ["user", "project", "local"],
1508
1509
  strictMcpConfig: opts?.strictMcpConfig,
1509
1510
  sessionId: void 0,
1510
- effort: opts?.effort
1511
+ effort: opts?.effort,
1512
+ onElicitation: opts?.onElicitation,
1513
+ onUserDialog: opts?.onUserDialog,
1514
+ supportedDialogKinds: opts?.onUserDialog ? opts.supportedDialogKinds : void 0
1511
1515
  };
1512
1516
  if (opts?.abort) {
1513
1517
  const controller = new AbortController();
1514
- opts.abort.addEventListener("abort", () => controller.abort(), { once: true });
1518
+ if (opts.abort.aborted) {
1519
+ controller.abort(opts.abort.reason);
1520
+ } else {
1521
+ opts.abort.addEventListener("abort", () => controller.abort(opts.abort?.reason), { once: true });
1522
+ }
1515
1523
  sdkOptions.abortController = controller;
1516
1524
  }
1517
1525
  const env = {};
@@ -1864,6 +1872,9 @@ async function claudeRemote(opts) {
1864
1872
  disallowedTools: initial.mode.disallowedTools,
1865
1873
  effort: initial.mode.effort,
1866
1874
  canCallTool: (toolName, input, options) => opts.canCallTool(toolName, input, mode, options),
1875
+ onElicitation: opts.onElicitation,
1876
+ onUserDialog: opts.onUserDialog,
1877
+ supportedDialogKinds: opts.onUserDialog ? ["refusal_fallback_prompt"] : void 0,
1867
1878
  abort: opts.signal,
1868
1879
  settingsPath: opts.hookSettingsPath
1869
1880
  };
@@ -1929,13 +1940,14 @@ async function claudeRemote(opts) {
1929
1940
  updateThinking(false);
1930
1941
  logger.debug("[claudeRemote] Result received");
1931
1942
  if (isCompactCommand) {
1932
- logger.debug("[claudeRemote] Compaction completed");
1943
+ const compactSucceeded = message.subtype === "success";
1944
+ logger.debug(`[claudeRemote] Compaction ${compactSucceeded ? "completed" : "failed"}`);
1933
1945
  if (opts.onCompletionEvent) {
1934
- opts.onCompletionEvent("Compaction completed");
1946
+ opts.onCompletionEvent(message.subtype === "success" ? "Compaction completed" : `Compaction failed: ${message.errors?.join("\n") || message.subtype}`);
1935
1947
  }
1936
1948
  isCompactCommand = false;
1937
1949
  }
1938
- opts.onReady();
1950
+ opts.onReady(message);
1939
1951
  opts.nextMessage().then((next) => {
1940
1952
  if (!next) {
1941
1953
  messages.end();
@@ -1983,6 +1995,16 @@ function getToolDescriptor(toolName) {
1983
1995
  return { edit: false, exitPlan: false, dangerous: false };
1984
1996
  }
1985
1997
 
1998
+ function elicitationContent(input) {
1999
+ if (!input) return void 0;
2000
+ const content = {};
2001
+ for (const [key, value] of Object.entries(input)) {
2002
+ if (typeof value === "string" || typeof value === "number" && Number.isFinite(value) || typeof value === "boolean" || Array.isArray(value) && value.every((item) => typeof item === "string")) {
2003
+ content[key] = value;
2004
+ }
2005
+ }
2006
+ return content;
2007
+ }
1986
2008
  class PermissionHandler {
1987
2009
  responses = /* @__PURE__ */ new Map();
1988
2010
  pendingRequests = /* @__PURE__ */ new Map();
@@ -2017,19 +2039,7 @@ class PermissionHandler {
2017
2039
  /**
2018
2040
  * Handler response
2019
2041
  */
2020
- handlePermissionResponse(response, pending) {
2021
- if (response.allowTools && response.allowTools.length > 0) {
2022
- response.allowTools.forEach((tool) => {
2023
- if (tool.startsWith("Bash(") || tool === "Bash") {
2024
- this.parseBashPermission(tool);
2025
- } else {
2026
- this.allowedTools.add(tool);
2027
- }
2028
- });
2029
- }
2030
- if (response.mode) {
2031
- this.permissionMode = response.mode;
2032
- }
2042
+ async handlePermissionResponse(response, pending) {
2033
2043
  if (pending.toolName === "exit_plan_mode" || pending.toolName === "ExitPlanMode") {
2034
2044
  logger.debug("Plan mode result received", {
2035
2045
  approved: response.approved,
@@ -2041,10 +2051,14 @@ class PermissionHandler {
2041
2051
  if (response.approved) {
2042
2052
  const newMode = response.mode && ["default", "acceptEdits", "bypassPermissions"].includes(response.mode) ? response.mode : "default";
2043
2053
  logger.debug(`Plan approved - switching to ${newMode} mode and allowing ExitPlanMode`);
2044
- if (this.setPermissionModeCallback) {
2045
- this.setPermissionModeCallback(newMode).catch((err) => {
2046
- logger.debug("Failed to set permission mode via SDK:", err);
2047
- });
2054
+ try {
2055
+ if (!this.setPermissionModeCallback) throw new Error("permission mode updater unavailable");
2056
+ await this.setPermissionModeCallback(newMode);
2057
+ } catch (err) {
2058
+ const reason = `Failed to switch permission mode: ${err instanceof Error ? err.message : String(err)}`;
2059
+ logger.debug(reason);
2060
+ pending.resolve({ behavior: "deny", message: reason });
2061
+ return { ...response, approved: false, reason };
2048
2062
  }
2049
2063
  this.permissionMode = newMode;
2050
2064
  pending.resolve({ behavior: "allow", updatedInput: pending.input || {} });
@@ -2052,11 +2066,36 @@ class PermissionHandler {
2052
2066
  pending.resolve({ behavior: "deny", message: response.reason || "Plan rejected" });
2053
2067
  }
2054
2068
  } else {
2069
+ if (response.approved && response.mode) {
2070
+ try {
2071
+ if (!this.setPermissionModeCallback) throw new Error("permission mode updater unavailable");
2072
+ await this.setPermissionModeCallback(response.mode);
2073
+ this.permissionMode = response.mode;
2074
+ } catch (err) {
2075
+ const reason = `Failed to switch permission mode: ${err instanceof Error ? err.message : String(err)}`;
2076
+ pending.resolve({ behavior: "deny", message: reason });
2077
+ return { ...response, approved: false, reason };
2078
+ }
2079
+ }
2080
+ if (response.approved && !pending.suggestions?.length && response.allowTools?.length) {
2081
+ response.allowTools.forEach((tool) => {
2082
+ if (tool.startsWith("Bash(") || tool === "Bash") {
2083
+ this.parseBashPermission(tool);
2084
+ } else {
2085
+ this.allowedTools.add(tool);
2086
+ }
2087
+ });
2088
+ }
2055
2089
  const originalInput = pending.input || {};
2056
2090
  const updatedInput = response.updatedInput ? { ...originalInput, ...response.updatedInput } : originalInput;
2057
- const result = response.approved ? { behavior: "allow", updatedInput } : { behavior: "deny", message: response.reason || `The user doesn't want to proceed with this tool use. The tool use was rejected (eg. if it was a file edit, the new_string was NOT written to the file). STOP what you are doing and wait for the user to tell you how to proceed.` };
2091
+ const result = response.approved ? {
2092
+ behavior: "allow",
2093
+ updatedInput,
2094
+ ...response.decision === "approved_for_session" && pending.suggestions?.length ? { updatedPermissions: pending.suggestions } : {}
2095
+ } : { behavior: "deny", message: response.reason || `The user doesn't want to proceed with this tool use. The tool use was rejected (eg. if it was a file edit, the new_string was NOT written to the file). STOP what you are doing and wait for the user to tell you how to proceed.` };
2058
2096
  pending.resolve(result);
2059
2097
  }
2098
+ return response;
2060
2099
  }
2061
2100
  /**
2062
2101
  * Creates the canCallTool callback for the SDK.
@@ -2065,7 +2104,7 @@ class PermissionHandler {
2065
2104
  handleToolCall = async (toolName, input, mode, options) => {
2066
2105
  const toolCallId = options.toolUseID;
2067
2106
  if (toolName === "AskUserQuestion") {
2068
- return this.handlePermissionRequest(toolCallId, toolName, input, options.signal);
2107
+ return this.handlePermissionRequest(toolCallId, toolName, input, options.signal, options.suggestions);
2069
2108
  }
2070
2109
  if (toolName === "Bash") {
2071
2110
  const inputObj = input;
@@ -2084,7 +2123,7 @@ class PermissionHandler {
2084
2123
  }
2085
2124
  const descriptor = getToolDescriptor(toolName);
2086
2125
  if (descriptor.exitPlan) {
2087
- return this.handlePermissionRequest(toolCallId, toolName, input, options.signal);
2126
+ return this.handlePermissionRequest(toolCallId, toolName, input, options.signal, options.suggestions);
2088
2127
  }
2089
2128
  if (this.permissionMode === "bypassPermissions") {
2090
2129
  return { behavior: "allow", updatedInput: input };
@@ -2095,19 +2134,25 @@ class PermissionHandler {
2095
2134
  if (this.permissionMode === "plan" && !descriptor.dangerous) {
2096
2135
  return { behavior: "allow", updatedInput: input };
2097
2136
  }
2098
- return this.handlePermissionRequest(toolCallId, toolName, input, options.signal);
2137
+ return this.handlePermissionRequest(toolCallId, toolName, input, options.signal, options.suggestions);
2099
2138
  };
2100
2139
  /**
2101
2140
  * Handles individual permission requests
2102
2141
  */
2103
- async handlePermissionRequest(id, toolName, input, signal) {
2142
+ async handlePermissionRequest(id, toolName, input, signal, suggestions) {
2104
2143
  return new Promise((resolve, reject) => {
2144
+ if (signal.aborted) {
2145
+ reject(new Error("Permission request aborted", { cause: signal.reason }));
2146
+ return;
2147
+ }
2105
2148
  const abortHandler = () => {
2106
2149
  this.pendingRequests.delete(id);
2150
+ this.cancelRequestInAgentState(id, "Permission request aborted");
2107
2151
  reject(new Error("Permission request aborted"));
2108
2152
  };
2109
2153
  signal.addEventListener("abort", abortHandler, { once: true });
2110
2154
  this.pendingRequests.set(id, {
2155
+ kind: "tool",
2111
2156
  resolve: (result) => {
2112
2157
  signal.removeEventListener("abort", abortHandler);
2113
2158
  resolve(result);
@@ -2117,7 +2162,8 @@ class PermissionHandler {
2117
2162
  reject(error);
2118
2163
  },
2119
2164
  toolName,
2120
- input
2165
+ input,
2166
+ suggestions
2121
2167
  });
2122
2168
  if (this.onPermissionRequestCallback) {
2123
2169
  this.onPermissionRequestCallback(id);
@@ -2140,7 +2186,9 @@ class PermissionHandler {
2140
2186
  [id]: {
2141
2187
  tool: toolName,
2142
2188
  arguments: input,
2143
- createdAt: Date.now()
2189
+ createdAt: Date.now(),
2190
+ kind: "tool",
2191
+ ...suggestions?.length ? { permissionSuggestions: suggestions } : {}
2144
2192
  }
2145
2193
  }
2146
2194
  }));
@@ -2149,6 +2197,98 @@ class PermissionHandler {
2149
2197
  logger.debug(`Permission request sent for tool call ${id}: ${toolName}`);
2150
2198
  });
2151
2199
  }
2200
+ handleElicitation = async (request, options) => {
2201
+ return this.handleInteractionRequest(options.requestId, "elicitation", request, options.signal);
2202
+ };
2203
+ handleUserDialog = async (request, options) => {
2204
+ if (request.dialogKind !== "refusal_fallback_prompt") {
2205
+ return { behavior: "cancelled" };
2206
+ }
2207
+ return this.handleInteractionRequest(options.requestId, "user_dialog", request, options.signal);
2208
+ };
2209
+ handleInteractionRequest(id, kind, request, signal) {
2210
+ return new Promise((resolve, reject) => {
2211
+ if (signal.aborted) {
2212
+ reject(new Error("Interaction request aborted", { cause: signal.reason }));
2213
+ return;
2214
+ }
2215
+ const abortHandler = () => {
2216
+ this.pendingRequests.delete(id);
2217
+ this.cancelRequestInAgentState(id, "Interaction request aborted");
2218
+ reject(new Error("Interaction request aborted", { cause: signal.reason }));
2219
+ };
2220
+ signal.addEventListener("abort", abortHandler, { once: true });
2221
+ const finishResolve = (value) => {
2222
+ signal.removeEventListener("abort", abortHandler);
2223
+ resolve(value);
2224
+ };
2225
+ const finishReject = (error) => {
2226
+ signal.removeEventListener("abort", abortHandler);
2227
+ reject(error);
2228
+ };
2229
+ if (kind === "elicitation") {
2230
+ this.pendingRequests.set(id, {
2231
+ kind,
2232
+ request,
2233
+ resolve: finishResolve,
2234
+ reject: finishReject
2235
+ });
2236
+ } else {
2237
+ this.pendingRequests.set(id, {
2238
+ kind,
2239
+ request,
2240
+ resolve: finishResolve,
2241
+ reject: finishReject
2242
+ });
2243
+ }
2244
+ const tool = "AskUserQuestion";
2245
+ this.publishRequest(id, tool, request, kind);
2246
+ });
2247
+ }
2248
+ publishRequest(id, tool, args, kind) {
2249
+ this.session.api.push().sendSessionNotification({
2250
+ kind: "permission",
2251
+ metadata: this.session.client.getMetadata(),
2252
+ data: {
2253
+ sessionId: this.session.client.sessionId,
2254
+ requestId: id,
2255
+ tool,
2256
+ type: "permission_request",
2257
+ provider: "claude"
2258
+ }
2259
+ });
2260
+ this.session.client.updateAgentState((currentState) => ({
2261
+ ...currentState,
2262
+ requests: {
2263
+ ...currentState.requests,
2264
+ [id]: { tool, arguments: args, createdAt: Date.now(), kind }
2265
+ }
2266
+ }));
2267
+ this.session.notificationProducer?.permissionRequest(tool);
2268
+ this.session.reportEventToDaemon("needs_input");
2269
+ logger.debug(`${kind} request sent: ${id}`);
2270
+ }
2271
+ cancelRequestInAgentState(id, reason) {
2272
+ this.session.client.updateAgentState((currentState) => {
2273
+ const request = currentState.requests?.[id];
2274
+ if (!request) return currentState;
2275
+ const requests = { ...currentState.requests };
2276
+ delete requests[id];
2277
+ return {
2278
+ ...currentState,
2279
+ requests,
2280
+ completedRequests: {
2281
+ ...currentState.completedRequests,
2282
+ [id]: {
2283
+ ...request,
2284
+ completedAt: Date.now(),
2285
+ status: "canceled",
2286
+ reason
2287
+ }
2288
+ }
2289
+ };
2290
+ });
2291
+ }
2152
2292
  /**
2153
2293
  * Parses Bash permission strings into literal and prefix sets
2154
2294
  */
@@ -2229,9 +2369,16 @@ class PermissionHandler {
2229
2369
  logger.debug("Permission request not found or already resolved");
2230
2370
  return;
2231
2371
  }
2232
- this.responses.set(id, { ...message, receivedAt: Date.now() });
2233
2372
  this.pendingRequests.delete(id);
2234
- this.handlePermissionResponse(message, pending);
2373
+ let effectiveResponse = message;
2374
+ if (pending.kind === "tool") {
2375
+ effectiveResponse = await this.handlePermissionResponse(message, pending);
2376
+ this.responses.set(id, { ...effectiveResponse, receivedAt: Date.now() });
2377
+ } else if (pending.kind === "elicitation") {
2378
+ pending.resolve(message.approved ? { action: "accept", content: elicitationContent(message.updatedInput) } : { action: message.decision === "abort" ? "cancel" : "decline" });
2379
+ } else {
2380
+ pending.resolve(message.approved ? { behavior: "completed", result: message.updatedInput?.result ?? "retry_fallback" } : { behavior: "cancelled" });
2381
+ }
2235
2382
  this.session.client.updateAgentState((currentState) => {
2236
2383
  const request = currentState.requests?.[id];
2237
2384
  if (!request) return currentState;
@@ -2245,10 +2392,11 @@ class PermissionHandler {
2245
2392
  [id]: {
2246
2393
  ...request,
2247
2394
  completedAt: Date.now(),
2248
- status: message.approved ? "approved" : "denied",
2249
- reason: message.reason,
2250
- mode: message.mode,
2251
- allowTools: message.allowTools
2395
+ status: effectiveResponse.approved ? "approved" : "denied",
2396
+ reason: effectiveResponse.reason,
2397
+ mode: effectiveResponse.mode,
2398
+ decision: effectiveResponse.decision,
2399
+ allowedTools: effectiveResponse.allowTools
2252
2400
  }
2253
2401
  }
2254
2402
  };
@@ -2469,7 +2617,8 @@ class SDKToLogConverter {
2469
2617
  // Assistant messages often have additional fields
2470
2618
  requestId: assistantMsg.requestId,
2471
2619
  ...assistantMsg.isCompactSummary ? { isCompactSummary: true } : {},
2472
- ...assistantMsg.parent_tool_use_id ? { parent_tool_use_id: assistantMsg.parent_tool_use_id } : {}
2620
+ ...assistantMsg.parent_tool_use_id ? { parent_tool_use_id: assistantMsg.parent_tool_use_id } : {},
2621
+ ...assistantMsg.error ? { error: assistantMsg.error } : {}
2473
2622
  };
2474
2623
  break;
2475
2624
  }
@@ -2500,17 +2649,28 @@ class SDKToLogConverter {
2500
2649
  total_cost_usd: resultMsg.total_cost_usd,
2501
2650
  duration_ms: resultMsg.duration_ms,
2502
2651
  num_turns: resultMsg.num_turns,
2503
- usage: resultMsg.usage
2652
+ usage: resultMsg.usage,
2653
+ ..."errors" in resultMsg ? { errors: resultMsg.errors } : {},
2654
+ ..."terminal_reason" in resultMsg && resultMsg.terminal_reason ? { terminal_reason: resultMsg.terminal_reason } : {}
2504
2655
  };
2505
2656
  break;
2506
2657
  }
2507
- default:
2508
- logMessage = {
2509
- ...baseFields,
2510
- ...sdkMessage,
2511
- type: sdkMessage.type
2512
- // Override type last to ensure it's set
2513
- };
2658
+ // These SDK lifecycle/advisory frames are intentionally not part
2659
+ // of the persisted Claude transcript. Enumerating them keeps SDK
2660
+ // upgrades type-visible instead of silently passing new frames
2661
+ // through as conversation messages.
2662
+ case "stream_event":
2663
+ case "tool_progress":
2664
+ case "auth_status":
2665
+ case "tool_use_summary":
2666
+ case "rate_limit_event":
2667
+ case "prompt_suggestion":
2668
+ case "conversation_reset":
2669
+ return null;
2670
+ default: {
2671
+ const exhaustive = sdkMessage;
2672
+ return exhaustive;
2673
+ }
2514
2674
  }
2515
2675
  if (logMessage && logMessage.type !== "summary" && logMessage.type !== "result") {
2516
2676
  this.lastUuid = uuid;
@@ -2806,6 +2966,17 @@ async function cleanupStdinAfterInk(opts) {
2806
2966
  }
2807
2967
  }
2808
2968
 
2969
+ function applyClaudeResultLifecycle(result, callbacks) {
2970
+ if (result && result.subtype !== "success") {
2971
+ const error = result.errors?.filter(Boolean).join("\n").trim() || result.subtype;
2972
+ callbacks.closeFailed(error);
2973
+ callbacks.onFailed(error);
2974
+ return;
2975
+ }
2976
+ callbacks.closeCompleted();
2977
+ callbacks.onCompleted();
2978
+ }
2979
+
2809
2980
  async function claudeRemoteLauncher(session) {
2810
2981
  logger.debug("[claudeRemoteLauncher] Starting remote launcher");
2811
2982
  const hasTTY = process.stdout.isTTY && process.stdin.isTTY;
@@ -3018,6 +3189,8 @@ async function claudeRemoteLauncher(session) {
3018
3189
  hookSettingsPath: session.hookSettingsPath,
3019
3190
  jsRuntime: session.jsRuntime,
3020
3191
  canCallTool: permissionHandler.handleToolCall,
3192
+ onElicitation: permissionHandler.handleElicitation,
3193
+ onUserDialog: permissionHandler.handleUserDialog,
3021
3194
  isAborted: (toolCallId) => {
3022
3195
  return permissionHandler.isAborted(toolCallId);
3023
3196
  },
@@ -3106,21 +3279,27 @@ async function claudeRemoteLauncher(session) {
3106
3279
  logger.debug("[remote]: Session reset");
3107
3280
  session.clearSessionId();
3108
3281
  },
3109
- onReady: () => {
3110
- session.client.closeClaudeSessionTurn("completed");
3111
- const idle = !pending && session.queue.size() === 0;
3112
- session.onTurnEnd(idle);
3113
- if (idle) {
3114
- session.api.push().sendSessionNotification({
3115
- kind: "done",
3116
- metadata: session.client.getMetadata(),
3117
- data: {
3118
- sessionId: session.client.sessionId,
3119
- type: "ready",
3120
- provider: "claude"
3282
+ onReady: (result) => {
3283
+ applyClaudeResultLifecycle(result, {
3284
+ closeCompleted: () => session.client.closeClaudeSessionTurn("completed"),
3285
+ closeFailed: (error) => session.client.closeClaudeSessionTurn("failed", { error }),
3286
+ onFailed: (error) => session.onSessionError(error),
3287
+ onCompleted: () => {
3288
+ const idle = !pending && session.queue.size() === 0;
3289
+ session.onTurnEnd(idle);
3290
+ if (idle) {
3291
+ session.api.push().sendSessionNotification({
3292
+ kind: "done",
3293
+ metadata: session.client.getMetadata(),
3294
+ data: {
3295
+ sessionId: session.client.sessionId,
3296
+ type: "ready",
3297
+ provider: "claude"
3298
+ }
3299
+ });
3121
3300
  }
3122
- });
3123
- }
3301
+ }
3302
+ });
3124
3303
  },
3125
3304
  signal: abortController.signal
3126
3305
  });
@@ -12983,7 +13162,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
12983
13162
  process.exit(0);
12984
13163
  } else if (subcommand === "install-terminal-hooks") {
12985
13164
  try {
12986
- const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await import('./installTerminalHooks-DFmjn6EQ.mjs');
13165
+ const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await import('./installTerminalHooks-D48YflmS.mjs');
12987
13166
  const command = parseTerminalHooksArgs(args.slice(1));
12988
13167
  if (command.action === "help") {
12989
13168
  console.log(TERMINAL_HOOKS_HELP);
@@ -13000,7 +13179,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13000
13179
  }
13001
13180
  } else if (subcommand === "spawn") {
13002
13181
  try {
13003
- const { handleSpawnCommand } = await import('./spawn-Da-94Ejo.mjs');
13182
+ const { handleSpawnCommand } = await import('./spawn-DWf78N7k.mjs');
13004
13183
  await handleSpawnCommand(args.slice(1));
13005
13184
  } catch (error) {
13006
13185
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -13012,7 +13191,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13012
13191
  return;
13013
13192
  } else if (subcommand === "send") {
13014
13193
  try {
13015
- const { handleSendCommand } = await import('./send-pX36Sd4p.mjs');
13194
+ const { handleSendCommand } = await import('./send-DJWwqdS_.mjs');
13016
13195
  await handleSendCommand(args.slice(1));
13017
13196
  } catch (error) {
13018
13197
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -13118,9 +13297,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13118
13297
  if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
13119
13298
  const projectId = args[3];
13120
13299
  try {
13121
- const { saveGoogleCloudProjectToConfig } = await import('./config-Co1Tpb5e.mjs');
13122
- const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await import('./types-Clmu74iY.mjs').then(function (n) { return n.af; });
13123
- const { ApiClient: ApiClient2 } = await import('./types-Clmu74iY.mjs').then(function (n) { return n.ag; });
13300
+ const { saveGoogleCloudProjectToConfig } = await import('./config-DHUFJkEr.mjs');
13301
+ const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await import('./types-B2DG32ua.mjs').then(function (n) { return n.af; });
13302
+ const { ApiClient: ApiClient2 } = await import('./types-B2DG32ua.mjs').then(function (n) { return n.ag; });
13124
13303
  let userEmail = void 0;
13125
13304
  try {
13126
13305
  const credentials = await readCredentialsForConfiguredRelay2();
@@ -13151,7 +13330,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13151
13330
  }
13152
13331
  if (geminiSubcommand === "project" && args[2] === "get") {
13153
13332
  try {
13154
- const { readGeminiLocalConfig } = await import('./config-Co1Tpb5e.mjs');
13333
+ const { readGeminiLocalConfig } = await import('./config-DHUFJkEr.mjs');
13155
13334
  const config = readGeminiLocalConfig();
13156
13335
  if (config.googleCloudProject) {
13157
13336
  console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
@@ -13191,7 +13370,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13191
13370
  process.exit(0);
13192
13371
  }
13193
13372
  try {
13194
- const { runGemini } = await import('./runGemini-DEZ0neEl.mjs');
13373
+ const { runGemini } = await import('./runGemini-Cnvz6a6J.mjs');
13195
13374
  let startedBy = void 0;
13196
13375
  for (let i = 1; i < args.length; i++) {
13197
13376
  if (args[i] === "--started-by") {
@@ -13213,7 +13392,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13213
13392
  return;
13214
13393
  } else if (subcommand === "acp") {
13215
13394
  try {
13216
- const { runAcp, resolveAcpAgentConfig } = await import('./index-DdOYA0qe.mjs');
13395
+ const { runAcp, resolveAcpAgentConfig } = await import('./index-D9OFwx0T.mjs');
13217
13396
  let startedBy = void 0;
13218
13397
  let verbose = false;
13219
13398
  const acpArgs = [];
@@ -13253,7 +13432,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13253
13432
  return;
13254
13433
  } else if (subcommand === "openclaw") {
13255
13434
  try {
13256
- const { runOpenClaw } = await import('./runOpenClaw-DyJQFzoX.mjs');
13435
+ const { runOpenClaw } = await import('./runOpenClaw-Cpxdqf9Z.mjs');
13257
13436
  let startedBy = void 0;
13258
13437
  let verbose = false;
13259
13438
  let gatewayUrl;
@@ -13304,7 +13483,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13304
13483
  return;
13305
13484
  } else if (subcommand === "mcp" && args.length === 1) {
13306
13485
  try {
13307
- const { handleMcpCommand } = await import('./mcp-nlZLEkmO.mjs');
13486
+ const { handleMcpCommand } = await import('./mcp-DnO0vHep.mjs');
13308
13487
  await handleMcpCommand();
13309
13488
  } catch (error) {
13310
13489
  process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  require('chalk');
4
- require('./index-CuvhWx_d.cjs');
5
- require('./types-Dua2iF5S.cjs');
4
+ require('./index-CdmSlaUU.cjs');
5
+ require('./types-DL98ZceN.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-w0zkr6EM.mjs';
3
- import './types-Clmu74iY.mjs';
2
+ import './index-DoLyKWEW.mjs';
3
+ import './types-B2DG32ua.mjs';
4
4
  import 'zod';
5
5
  import 'node:child_process';
6
6
  import 'node:os';
@@ -3,8 +3,8 @@ import { join, resolve } from 'node:path';
3
3
  import { homedir } from 'node:os';
4
4
  import { spawnSync } from 'node:child_process';
5
5
  import chalk from 'chalk';
6
- import { p as projectPath } from './types-Clmu74iY.mjs';
7
- import { t as tmuxSupportsSessionEnv } from './index-w0zkr6EM.mjs';
6
+ import { p as projectPath } from './types-B2DG32ua.mjs';
7
+ import { t as tmuxSupportsSessionEnv } from './index-DoLyKWEW.mjs';
8
8
  import 'axios';
9
9
  import 'node:util';
10
10
  import 'node:fs/promises';
@@ -5,8 +5,8 @@ var path = require('node:path');
5
5
  var os = require('node:os');
6
6
  var node_child_process = require('node:child_process');
7
7
  var chalk = require('chalk');
8
- var persistence = require('./types-Dua2iF5S.cjs');
9
- var index = require('./index-CuvhWx_d.cjs');
8
+ var persistence = require('./types-DL98ZceN.cjs');
9
+ var index = require('./index-CdmSlaUU.cjs');
10
10
  require('axios');
11
11
  require('node:util');
12
12
  require('node:fs/promises');
package/dist/lib.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var persistence = require('./types-Dua2iF5S.cjs');
3
+ var persistence = require('./types-DL98ZceN.cjs');
4
4
  require('axios');
5
5
  require('chalk');
6
6
  require('node:util');