very-happy-cli 0.2.88 → 0.2.90

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-C_simUP7.mjs → AcpBackend-BV4wSnJ3.mjs} +1 -1
  2. package/dist/{AcpBackend-CBZNjcYO.cjs → AcpBackend-CnYZFdd0.cjs} +1 -1
  3. package/dist/{AcpSessionManager-B9mJWEzL.cjs → AcpSessionManager-BPBdrrME.cjs} +1 -1
  4. package/dist/{AcpSessionManager-G8w8Q6tt.mjs → AcpSessionManager-Cyne6Rmg.mjs} +1 -1
  5. package/dist/{config-CFSdirvc.mjs → config-BEdyyciP.mjs} +2 -2
  6. package/dist/{config-BPPY98U1.cjs → config-CgXitj0f.cjs} +2 -2
  7. package/dist/{index-FxD6Abgx.cjs → index-4YmVbx7j.cjs} +199 -46
  8. package/dist/{index-Bp5ZSCRm.cjs → index-B1wTVXjt.cjs} +4 -4
  9. package/dist/{index-Cn3VqAah.mjs → index-Dfu5uvjk.mjs} +5 -5
  10. package/dist/{index-j2LYx2KW.mjs → index-an09rejO.mjs} +196 -43
  11. package/dist/index.cjs +2 -2
  12. package/dist/index.mjs +2 -2
  13. package/dist/{installTerminalHooks-DsqU3Dxc.mjs → installTerminalHooks-C-OgZr5k.mjs} +2 -2
  14. package/dist/{installTerminalHooks-BL25f9BN.cjs → installTerminalHooks-DDpVxk8-.cjs} +2 -2
  15. package/dist/lib.cjs +1 -1
  16. package/dist/lib.d.cts +8 -0
  17. package/dist/lib.d.mts +8 -0
  18. package/dist/lib.mjs +1 -1
  19. package/dist/{mcp-BVoo0PQS.cjs → mcp-B6Nq-RUL.cjs} +2 -2
  20. package/dist/{mcp-DV49L5g2.mjs → mcp-Du-N0qlK.mjs} +2 -2
  21. package/dist/{runGemini-t_Oikq3z.cjs → runGemini-ChG7cGMC.cjs} +4 -4
  22. package/dist/{runGemini-cm1mKuxv.mjs → runGemini-DBr_TiTL.mjs} +4 -4
  23. package/dist/{runOpenClaw-CCwYAKyZ.mjs → runOpenClaw-Cbde8t92.mjs} +3 -3
  24. package/dist/{runOpenClaw-CCGywWGD.cjs → runOpenClaw-D2jtVgpC.cjs} +3 -3
  25. package/dist/{send-ifKBw-7j.mjs → send-BHliX59m.mjs} +2 -2
  26. package/dist/{send-CqPpRb7v.cjs → send-Bjen1TUE.cjs} +2 -2
  27. package/dist/{spawn-28RbN4P6.cjs → spawn-CH1Rq-LW.cjs} +2 -2
  28. package/dist/{spawn-DkG_GIXM.mjs → spawn-JxaPHAoP.mjs} +2 -2
  29. package/dist/{types-DE03map-.cjs → types-BNGeiP1C.cjs} +62 -44
  30. package/dist/{types-AO-TVSTa.mjs → types-DS3i_5LV.mjs} +60 -44
  31. package/package.json +7 -7
@@ -1,7 +1,7 @@
1
1
  import { spawn } from 'node:child_process';
2
2
  import { ndJsonStream, ClientSideConnection } from '@agentclientprotocol/sdk';
3
3
  import { randomUUID } from 'node:crypto';
4
- import { l as logger, d as contentLogMetadata, e as errorLogMetadata, f as packageJson, g as delay } from './types-AO-TVSTa.mjs';
4
+ import { l as logger, d as contentLogMetadata, e as errorLogMetadata, f as packageJson, g as delay } from './types-DS3i_5LV.mjs';
5
5
 
6
6
  const DEFAULT_TIMEOUTS = {
7
7
  /** Default initialization timeout: 60 seconds */
@@ -3,7 +3,7 @@
3
3
  var node_child_process = require('node:child_process');
4
4
  var sdk = require('@agentclientprotocol/sdk');
5
5
  var node_crypto = require('node:crypto');
6
- var persistence = require('./types-DE03map-.cjs');
6
+ var persistence = require('./types-BNGeiP1C.cjs');
7
7
 
8
8
  const DEFAULT_TIMEOUTS = {
9
9
  /** Default initialization timeout: 60 seconds */
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var cuid2 = require('@paralleldrive/cuid2');
4
- var persistence = require('./types-DE03map-.cjs');
4
+ var persistence = require('./types-BNGeiP1C.cjs');
5
5
 
6
6
  function turnOptions(turnId, time) {
7
7
  return turnId ? { turn: turnId, time } : { time };
@@ -1,5 +1,5 @@
1
1
  import { createId } from '@paralleldrive/cuid2';
2
- import { b as createEnvelope } from './types-AO-TVSTa.mjs';
2
+ import { b as createEnvelope } from './types-DS3i_5LV.mjs';
3
3
 
4
4
  function turnOptions(turnId, time) {
5
5
  return turnId ? { turn: turnId, time } : { time };
@@ -2,8 +2,8 @@ import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import { homedir } from 'os';
4
4
  import { execSync } from 'child_process';
5
- import { l as logger } from './types-AO-TVSTa.mjs';
6
- import { D as DEFAULT_GEMINI_MODEL, G as GEMINI_MODEL_ENV } from './index-j2LYx2KW.mjs';
5
+ import { l as logger } from './types-DS3i_5LV.mjs';
6
+ import { D as DEFAULT_GEMINI_MODEL, G as GEMINI_MODEL_ENV } from './index-an09rejO.mjs';
7
7
  import 'axios';
8
8
  import 'chalk';
9
9
  import 'node:util';
@@ -4,8 +4,8 @@ var fs = require('fs');
4
4
  var path = require('path');
5
5
  var os = require('os');
6
6
  var child_process = require('child_process');
7
- var persistence = require('./types-DE03map-.cjs');
8
- var index = require('./index-FxD6Abgx.cjs');
7
+ var persistence = require('./types-BNGeiP1C.cjs');
8
+ var index = require('./index-4YmVbx7j.cjs');
9
9
  require('axios');
10
10
  require('chalk');
11
11
  require('node:util');
@@ -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 persistence = require('./types-DE03map-.cjs');
6
+ var persistence = require('./types-BNGeiP1C.cjs');
7
7
  var spawn = require('cross-spawn');
8
8
  var path = require('node:path');
9
9
  var node_readline = require('node:readline');
@@ -1528,7 +1528,7 @@ function query(params) {
1528
1528
  fallbackModel: opts?.fallbackModel,
1529
1529
  maxTurns: opts?.maxTurns,
1530
1530
  permissionMode: opts?.permissionMode,
1531
- allowDangerouslySkipPermissions: opts?.permissionMode === "bypassPermissions",
1531
+ allowDangerouslySkipPermissions: opts?.allowDangerouslySkipPermissions ?? opts?.permissionMode === "bypassPermissions",
1532
1532
  allowedTools: opts?.allowedTools,
1533
1533
  disallowedTools: opts?.disallowedTools,
1534
1534
  mcpServers: opts?.mcpServers,
@@ -1603,6 +1603,9 @@ const VALID_PERMISSION_MODES = [
1603
1603
  function isPermissionMode(value) {
1604
1604
  return !!value && VALID_PERMISSION_MODES.includes(value);
1605
1605
  }
1606
+ function parseClaudePermissionMode(value) {
1607
+ return typeof value === "string" && isPermissionMode(value) ? mapToClaudeMode(value) : null;
1608
+ }
1606
1609
  function extractPermissionModeFromClaudeArgs(claudeArgs) {
1607
1610
  if (!claudeArgs || claudeArgs.length === 0) {
1608
1611
  return void 0;
@@ -1903,6 +1906,10 @@ async function claudeRemote(opts) {
1903
1906
  resume: startFrom ?? void 0,
1904
1907
  mcpServers: opts.mcpServers,
1905
1908
  permissionMode: mapToClaudeMode(initial.mode.permissionMode),
1909
+ // This is only the SDK safety opt-in; permissionMode/canUseTool still
1910
+ // enforce the selected policy. It must be enabled at Query creation so
1911
+ // a later explicit live switch to bypassPermissions can succeed.
1912
+ allowDangerouslySkipPermissions: true,
1906
1913
  model: initial.mode.model,
1907
1914
  fallbackModel: initial.mode.fallbackModel,
1908
1915
  customSystemPrompt: initial.mode.customSystemPrompt ? initial.mode.customSystemPrompt + "\n\n" + systemPrompt : void 0,
@@ -2078,6 +2085,10 @@ class PermissionHandler {
2078
2085
  onPermissionRequestCallback;
2079
2086
  /** Callback to change permission mode on the active query (set by claudeRemote) */
2080
2087
  setPermissionModeCallback;
2088
+ modeChangeQueue = Promise.resolve();
2089
+ deferredPermissionMode;
2090
+ /** Fired when an approval response (plan approval / approve-with-mode) moved the mode. */
2091
+ onModeChangedCallback;
2081
2092
  constructor(session) {
2082
2093
  this.session = session;
2083
2094
  this.setupClientHandler();
@@ -2089,7 +2100,19 @@ class PermissionHandler {
2089
2100
  this.onPermissionRequestCallback = callback;
2090
2101
  }
2091
2102
  handleModeChange(mode) {
2092
- this.permissionMode = mode;
2103
+ this.permissionMode = mapToClaudeMode(mode);
2104
+ }
2105
+ /** Current locally enforced mode (what canUseTool applies right now). */
2106
+ getPermissionMode() {
2107
+ return this.permissionMode;
2108
+ }
2109
+ /**
2110
+ * Observe mode transitions that originate inside the approval flow
2111
+ * (ExitPlanMode approval, approve-with-mode). Live/idle RPC changes and
2112
+ * queue-driven changes are owned by the launcher and do not fire this.
2113
+ */
2114
+ setOnModeChanged(callback) {
2115
+ this.onModeChangedCallback = callback;
2093
2116
  }
2094
2117
  /**
2095
2118
  * Set callback to dynamically change permission mode on the active query.
@@ -2098,6 +2121,74 @@ class PermissionHandler {
2098
2121
  setPermissionModeUpdater(callback) {
2099
2122
  this.setPermissionModeCallback = callback;
2100
2123
  }
2124
+ /**
2125
+ * Apply a user-requested mode to the active SDK Query. Mode changes are
2126
+ * serialized so rapid menu selections cannot finish out of order.
2127
+ *
2128
+ * A live Query can be blocked inside canUseTool. When the requested mode
2129
+ * would have auto-allowed that ordinary tool, finish the callback first;
2130
+ * interactive prompts and ExitPlanMode deliberately remain pending.
2131
+ */
2132
+ setLivePermissionMode(mode) {
2133
+ const task = this.modeChangeQueue.then(() => this.applyLivePermissionMode(mode));
2134
+ this.modeChangeQueue = task.catch(() => void 0);
2135
+ return task;
2136
+ }
2137
+ async applyLivePermissionMode(mode) {
2138
+ if (!this.setPermissionModeCallback) {
2139
+ throw new Error("active Claude query is not ready");
2140
+ }
2141
+ const previousMode = this.permissionMode;
2142
+ this.permissionMode = mode;
2143
+ this.deferredPermissionMode = void 0;
2144
+ try {
2145
+ const autoApproved = [...this.pendingRequests.entries()].filter(([, pending]) => pending.kind === "tool" && this.modeAutoAllowsTool(mode, pending.toolName));
2146
+ for (const [id, pending] of autoApproved) {
2147
+ if (pending.kind !== "tool" || !this.pendingRequests.delete(id)) continue;
2148
+ const response = {
2149
+ id,
2150
+ approved: true,
2151
+ decision: "approved",
2152
+ reason: `Approved by live permission mode ${mode}`
2153
+ };
2154
+ const effectiveResponse = await this.handlePermissionResponse(response, pending);
2155
+ this.responses.set(id, { ...effectiveResponse, receivedAt: Date.now() });
2156
+ this.recordCompletedRequest(id, effectiveResponse);
2157
+ }
2158
+ if (this.pendingRequests.size > 0) {
2159
+ this.deferredPermissionMode = mode;
2160
+ return;
2161
+ }
2162
+ await new Promise((resolve) => setImmediate(resolve));
2163
+ await this.setPermissionModeCallback(mode);
2164
+ } catch (error) {
2165
+ this.permissionMode = previousMode;
2166
+ if (this.deferredPermissionMode === mode) this.deferredPermissionMode = void 0;
2167
+ throw error;
2168
+ }
2169
+ }
2170
+ scheduleDeferredPermissionModeUpdate() {
2171
+ const mode = this.deferredPermissionMode;
2172
+ if (!mode || this.pendingRequests.size > 0) return;
2173
+ this.deferredPermissionMode = void 0;
2174
+ setImmediate(() => {
2175
+ const task = this.modeChangeQueue.then(async () => {
2176
+ if (!this.setPermissionModeCallback || this.permissionMode !== mode) return;
2177
+ await this.setPermissionModeCallback(mode);
2178
+ });
2179
+ this.modeChangeQueue = task.catch((error) => {
2180
+ persistence.logger.debug("[PermissionHandler] Deferred SDK permission mode update failed", error);
2181
+ });
2182
+ });
2183
+ }
2184
+ modeAutoAllowsTool(mode, toolName) {
2185
+ if (toolName === "AskUserQuestion") return false;
2186
+ const descriptor = getToolDescriptor(toolName);
2187
+ if (descriptor.exitPlan) return false;
2188
+ if (mode === "bypassPermissions") return true;
2189
+ if (mode === "acceptEdits") return descriptor.edit;
2190
+ return mode === "plan" && !descriptor.dangerous;
2191
+ }
2101
2192
  /**
2102
2193
  * Handler response
2103
2194
  */
@@ -2111,9 +2202,10 @@ class PermissionHandler {
2111
2202
  updatedInput: persistence.contentLogMetadata(response.updatedInput)
2112
2203
  });
2113
2204
  if (response.approved) {
2114
- const newMode = response.mode && ["default", "acceptEdits", "bypassPermissions"].includes(response.mode) ? response.mode : "default";
2205
+ const newMode = response.mode && ["default", "acceptEdits", "bypassPermissions"].includes(response.mode) ? response.mode : "bypassPermissions";
2115
2206
  persistence.logger.debug(`Plan approved - allowing ExitPlanMode with ${newMode} as the local follow-up mode`);
2116
2207
  this.permissionMode = newMode;
2208
+ this.onModeChangedCallback?.(newMode);
2117
2209
  pending.resolve({ behavior: "allow", updatedInput: pending.input || {} });
2118
2210
  } else {
2119
2211
  pending.resolve({ behavior: "deny", message: response.reason || "Plan rejected" });
@@ -2124,6 +2216,7 @@ class PermissionHandler {
2124
2216
  if (!this.setPermissionModeCallback) throw new Error("permission mode updater unavailable");
2125
2217
  await this.setPermissionModeCallback(response.mode);
2126
2218
  this.permissionMode = response.mode;
2219
+ this.onModeChangedCallback?.(response.mode);
2127
2220
  } catch (err) {
2128
2221
  const reason = `Failed to switch permission mode: ${err instanceof Error ? err.message : String(err)}`;
2129
2222
  pending.resolve({ behavior: "deny", message: reason });
@@ -2342,6 +2435,30 @@ class PermissionHandler {
2342
2435
  };
2343
2436
  });
2344
2437
  }
2438
+ recordCompletedRequest(id, response) {
2439
+ this.session.client.updateAgentState((currentState) => {
2440
+ const request = currentState.requests?.[id];
2441
+ if (!request) return currentState;
2442
+ const requests = { ...currentState.requests };
2443
+ delete requests[id];
2444
+ return {
2445
+ ...currentState,
2446
+ requests,
2447
+ completedRequests: {
2448
+ ...currentState.completedRequests,
2449
+ [id]: {
2450
+ ...request,
2451
+ completedAt: Date.now(),
2452
+ status: response.approved ? "approved" : "denied",
2453
+ reason: response.reason,
2454
+ mode: response.mode,
2455
+ decision: response.decision,
2456
+ allowedTools: response.allowTools
2457
+ }
2458
+ }
2459
+ };
2460
+ });
2461
+ }
2345
2462
  /**
2346
2463
  * Parses Bash permission strings into literal and prefix sets
2347
2464
  */
@@ -2380,6 +2497,7 @@ class PermissionHandler {
2380
2497
  this.allowedBashLiterals.clear();
2381
2498
  this.allowedBashPrefixes.clear();
2382
2499
  this.permissionMode = "default";
2500
+ this.deferredPermissionMode = void 0;
2383
2501
  for (const [, pending] of this.pendingRequests.entries()) {
2384
2502
  pending.reject(new Error("Session reset"));
2385
2503
  }
@@ -2432,28 +2550,8 @@ class PermissionHandler {
2432
2550
  } else {
2433
2551
  pending.resolve(message.approved ? { behavior: "completed", result: message.updatedInput?.result ?? "retry_fallback" } : { behavior: "cancelled" });
2434
2552
  }
2435
- this.session.client.updateAgentState((currentState) => {
2436
- const request = currentState.requests?.[id];
2437
- if (!request) return currentState;
2438
- let r = { ...currentState.requests };
2439
- delete r[id];
2440
- return {
2441
- ...currentState,
2442
- requests: r,
2443
- completedRequests: {
2444
- ...currentState.completedRequests,
2445
- [id]: {
2446
- ...request,
2447
- completedAt: Date.now(),
2448
- status: effectiveResponse.approved ? "approved" : "denied",
2449
- reason: effectiveResponse.reason,
2450
- mode: effectiveResponse.mode,
2451
- decision: effectiveResponse.decision,
2452
- allowedTools: effectiveResponse.allowTools
2453
- }
2454
- }
2455
- };
2456
- });
2553
+ this.recordCompletedRequest(id, effectiveResponse);
2554
+ this.scheduleDeferredPermissionModeUpdate();
2457
2555
  });
2458
2556
  }
2459
2557
  /**
@@ -3229,7 +3327,7 @@ function createTurnSteeringController() {
3229
3327
  };
3230
3328
  }
3231
3329
 
3232
- async function claudeRemoteLauncher(session) {
3330
+ async function claudeRemoteLauncher(session, onPermissionModeChange) {
3233
3331
  persistence.logger.debug("[claudeRemoteLauncher] Starting remote launcher");
3234
3332
  const hasTTY = process.stdout.isTTY && process.stdin.isTTY;
3235
3333
  persistence.logger.debug(`[claudeRemoteLauncher] TTY available: ${hasTTY}`);
@@ -3290,7 +3388,24 @@ async function claudeRemoteLauncher(session) {
3290
3388
  await turnSteering.steer();
3291
3389
  });
3292
3390
  session.client.rpcHandlerManager.registerHandler("switch", doSwitch);
3391
+ let livePermissionModeHandler = null;
3392
+ let idlePermissionModeHandler = null;
3393
+ session.client.rpcHandlerManager.registerHandler(
3394
+ "set-permission-mode",
3395
+ async (request) => {
3396
+ const requestedMode = parseClaudePermissionMode(request?.mode);
3397
+ if (!requestedMode) throw new Error("Invalid Claude permission mode");
3398
+ if (livePermissionModeHandler) return { mode: await livePermissionModeHandler(requestedMode) };
3399
+ if (idlePermissionModeHandler) return { mode: idlePermissionModeHandler(requestedMode) };
3400
+ throw new Error("No active Claude query");
3401
+ }
3402
+ );
3293
3403
  const permissionHandler = new PermissionHandler(session);
3404
+ idlePermissionModeHandler = (nextMode) => {
3405
+ permissionHandler.handleModeChange(nextMode);
3406
+ onPermissionModeChange?.(nextMode);
3407
+ return nextMode;
3408
+ };
3294
3409
  permissionHandler.reset("Previous CLI process exited before responding");
3295
3410
  const messageQueue = new OutgoingMessageQueue(
3296
3411
  (logMessage) => session.client.sendClaudeSessionMessage(logMessage)
@@ -3440,6 +3555,19 @@ async function claudeRemoteLauncher(session) {
3440
3555
  abortFuture = new Future();
3441
3556
  let modeHash = null;
3442
3557
  let mode = null;
3558
+ const commitPermissionMode = (nextMode) => {
3559
+ permissionHandler.handleModeChange(nextMode);
3560
+ if (mode) {
3561
+ mode = { ...mode, permissionMode: nextMode };
3562
+ modeHash = session.queue.modeHasher(mode);
3563
+ }
3564
+ onPermissionModeChange?.(nextMode);
3565
+ return nextMode;
3566
+ };
3567
+ idlePermissionModeHandler = commitPermissionMode;
3568
+ permissionHandler.setOnModeChanged((nextMode) => {
3569
+ commitPermissionMode(nextMode);
3570
+ });
3443
3571
  try {
3444
3572
  const attachmentDirectory = chatAttachmentDirectory(persistence.configuration.happyHomeDir, session.client.sessionId);
3445
3573
  await persistence.ensurePrivateDirectory(attachmentDirectory);
@@ -3526,6 +3654,15 @@ async function claudeRemoteLauncher(session) {
3526
3654
  permissionHandler.setPermissionModeUpdater(async (mode2) => {
3527
3655
  await q.setPermissionMode(mode2);
3528
3656
  });
3657
+ livePermissionModeHandler = async (nextMode) => {
3658
+ await permissionHandler.setLivePermissionMode(nextMode);
3659
+ if (mode) {
3660
+ mode = { ...mode, permissionMode: nextMode };
3661
+ modeHash = session.queue.modeHasher(mode);
3662
+ }
3663
+ onPermissionModeChange?.(nextMode);
3664
+ return nextMode;
3665
+ };
3529
3666
  },
3530
3667
  onThinkingChange: session.onThinkingChange,
3531
3668
  claudeEnvVars: session.claudeEnvVars,
@@ -3587,6 +3724,8 @@ async function claudeRemoteLauncher(session) {
3587
3724
  } finally {
3588
3725
  turnSteering.reset();
3589
3726
  session.setSteerHandler(null);
3727
+ livePermissionModeHandler = null;
3728
+ permissionHandler.setPermissionModeUpdater(void 0);
3590
3729
  sdkToLogConverter.resetTransientState();
3591
3730
  persistence.logger.debug("[remote]: launch finally");
3592
3731
  for (let [toolCallId, { parentToolCallId }] of ongoingToolCalls) {
@@ -3671,7 +3810,7 @@ async function loop(opts) {
3671
3810
  break;
3672
3811
  }
3673
3812
  case "remote": {
3674
- const reason = await claudeRemoteLauncher(session);
3813
+ const reason = await claudeRemoteLauncher(session, opts.onPermissionModeChange);
3675
3814
  switch (reason) {
3676
3815
  case "exit":
3677
3816
  return 0;
@@ -6533,7 +6672,7 @@ function createMirrorManager(deps) {
6533
6672
  let chain = Promise.resolve();
6534
6673
  const isTerminalAlive = deps.isTerminalAlive ?? ((terminalId) => {
6535
6674
  try {
6536
- return node_child_process.spawnSync("tmux", ["has-session", "-t", `=vh-${terminalId}:`], { stdio: "ignore", timeout: 3e3 }).status === 0;
6675
+ return node_child_process.spawnSync("tmux", persistence.tmuxArgs(["has-session", "-t", `=vh-${terminalId}:`]), { stdio: "ignore", timeout: 3e3, env: persistence.scrubTmuxClientEnv({ ...process.env }) }).status === 0;
6537
6676
  } catch {
6538
6677
  return false;
6539
6678
  }
@@ -8704,7 +8843,7 @@ const MAX_TITLE_CHARS = 60;
8704
8843
  const GENERATION_TIMEOUT_MS = 3e4;
8705
8844
  function resolveClaudeBinary() {
8706
8845
  try {
8707
- const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-FxD6Abgx.cjs', document.baseURI).href)));
8846
+ const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-4YmVbx7j.cjs', document.baseURI).href)));
8708
8847
  const utilsPath = path.resolve(path.join(persistence.projectPath(), "scripts", "claude_version_utils.cjs"));
8709
8848
  const { getClaudeCliPath } = require$1(utilsPath);
8710
8849
  const path$1 = getClaudeCliPath();
@@ -9161,7 +9300,10 @@ async function runClaude(credentials, options = {}) {
9161
9300
  // a brand-new session cannot pick a PDF until after sending once.
9162
9301
  attachmentKinds: [...CLAUDE_ATTACHMENT_KINDS],
9163
9302
  queueCancellation: true,
9164
- capabilities: ["claude-steer-v1"],
9303
+ capabilities: ["claude-steer-v1", "claude-live-permission-v1", "claude-live-permission-v2"],
9304
+ // Effective mode this process enforces. Kept current by
9305
+ // publishPermissionMode below; the web renders it instead of guessing.
9306
+ permissionMode: mapToClaudeMode(initialPermissionMode ?? "default"),
9165
9307
  sandbox: sandboxConfig?.enabled ? sandboxConfig : null,
9166
9308
  dangerouslySkipPermissions,
9167
9309
  ...forkedFromSessionId ? { parentSessionId: forkedFromSessionId } : {},
@@ -9398,6 +9540,14 @@ async function runClaude(credentials, options = {}) {
9398
9540
  )
9399
9541
  }));
9400
9542
  let currentPermissionMode = initialPermissionMode;
9543
+ let publishedPermissionMode = mapToClaudeMode(initialPermissionMode ?? "default");
9544
+ const publishPermissionMode = (mode) => {
9545
+ currentPermissionMode = mode;
9546
+ const published = mapToClaudeMode(mode ?? "default");
9547
+ if (published === publishedPermissionMode) return;
9548
+ publishedPermissionMode = published;
9549
+ session.updateMetadata((meta) => ({ ...meta, permissionMode: published }));
9550
+ };
9401
9551
  let currentModel = options.model ?? DEFAULT_CLAUDE_MODEL;
9402
9552
  let currentFallbackModel = void 0;
9403
9553
  let currentCustomSystemPrompt = void 0;
@@ -9406,7 +9556,6 @@ async function runClaude(credentials, options = {}) {
9406
9556
  let currentDisallowedTools = withAssistantDenylist(void 0, isAssistantVariant);
9407
9557
  let currentEffort = DEFAULT_CLAUDE_EFFORT;
9408
9558
  const resetCurrentModeDefaults = () => {
9409
- currentPermissionMode = initialPermissionMode;
9410
9559
  currentModel = options.model ?? DEFAULT_CLAUDE_MODEL;
9411
9560
  currentFallbackModel = void 0;
9412
9561
  currentCustomSystemPrompt = void 0;
@@ -9450,7 +9599,7 @@ async function runClaude(credentials, options = {}) {
9450
9599
  message.meta.permissionMode,
9451
9600
  sandboxEnabled
9452
9601
  );
9453
- currentPermissionMode = messagePermissionMode;
9602
+ publishPermissionMode(messagePermissionMode);
9454
9603
  const ignoredDefaultDowngrade = (previousPermissionMode === "bypassPermissions" || previousPermissionMode === "yolo") && message.meta.permissionMode === "default" && currentPermissionMode === previousPermissionMode;
9455
9604
  if (ignoredDefaultDowngrade) {
9456
9605
  persistence.logger.debug(`[loop] Ignoring permission mode downgrade from ${previousPermissionMode} to default`);
@@ -9706,6 +9855,10 @@ async function runClaude(credentials, options = {}) {
9706
9855
  currentSession = sessionInstance;
9707
9856
  },
9708
9857
  onAbort: resetCurrentModeDefaults,
9858
+ onPermissionModeChange: (mode) => {
9859
+ publishPermissionMode(mode);
9860
+ persistence.logger.debug(`[loop] Permission mode updated from session RPC / approval to: ${mode}`);
9861
+ },
9709
9862
  mcpServers: {
9710
9863
  "happy": {
9711
9864
  type: "http",
@@ -10848,9 +11001,9 @@ function resolveLocalSignupBootstrap(configuredMode, configuredInviteCodes, gene
10848
11001
  };
10849
11002
  }
10850
11003
 
10851
- 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-FxD6Abgx.cjs', document.baseURI).href)));
11004
+ 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-4YmVbx7j.cjs', document.baseURI).href)));
10852
11005
  const __dirname$1 = path.dirname(__filename$1);
10853
- const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-FxD6Abgx.cjs', document.baseURI).href)));
11006
+ const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-4YmVbx7j.cjs', document.baseURI).href)));
10854
11007
  const PRISMA_QUERY_ENGINE_FILES = {
10855
11008
  "arm64-darwin": "libquery_engine-darwin-arm64.dylib.node",
10856
11009
  "x64-darwin": "libquery_engine-darwin.dylib.node",
@@ -13462,7 +13615,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13462
13615
  process.exit(0);
13463
13616
  } else if (subcommand === "install-terminal-hooks") {
13464
13617
  try {
13465
- const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-BL25f9BN.cjs'); });
13618
+ const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-DDpVxk8-.cjs'); });
13466
13619
  const command = parseTerminalHooksArgs(args.slice(1));
13467
13620
  if (command.action === "help") {
13468
13621
  console.log(TERMINAL_HOOKS_HELP);
@@ -13479,7 +13632,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13479
13632
  }
13480
13633
  } else if (subcommand === "spawn") {
13481
13634
  try {
13482
- const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-28RbN4P6.cjs'); });
13635
+ const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-CH1Rq-LW.cjs'); });
13483
13636
  await handleSpawnCommand(args.slice(1));
13484
13637
  } catch (error) {
13485
13638
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -13491,7 +13644,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13491
13644
  return;
13492
13645
  } else if (subcommand === "send") {
13493
13646
  try {
13494
- const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-CqPpRb7v.cjs'); });
13647
+ const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-Bjen1TUE.cjs'); });
13495
13648
  await handleSendCommand(args.slice(1));
13496
13649
  } catch (error) {
13497
13650
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -13597,9 +13750,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13597
13750
  if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
13598
13751
  const projectId = args[3];
13599
13752
  try {
13600
- const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-BPPY98U1.cjs'); });
13601
- const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./types-DE03map-.cjs'); }).then(function (n) { return n.persistence; });
13602
- const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-DE03map-.cjs'); }).then(function (n) { return n.api; });
13753
+ const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-CgXitj0f.cjs'); });
13754
+ const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./types-BNGeiP1C.cjs'); }).then(function (n) { return n.persistence; });
13755
+ const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-BNGeiP1C.cjs'); }).then(function (n) { return n.api; });
13603
13756
  let userEmail = void 0;
13604
13757
  try {
13605
13758
  const credentials = await readCredentialsForConfiguredRelay2();
@@ -13630,7 +13783,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13630
13783
  }
13631
13784
  if (geminiSubcommand === "project" && args[2] === "get") {
13632
13785
  try {
13633
- const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-BPPY98U1.cjs'); });
13786
+ const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-CgXitj0f.cjs'); });
13634
13787
  const config = readGeminiLocalConfig();
13635
13788
  if (config.googleCloudProject) {
13636
13789
  console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
@@ -13670,7 +13823,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13670
13823
  process.exit(0);
13671
13824
  }
13672
13825
  try {
13673
- const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-t_Oikq3z.cjs'); });
13826
+ const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-ChG7cGMC.cjs'); });
13674
13827
  let startedBy = void 0;
13675
13828
  for (let i = 1; i < args.length; i++) {
13676
13829
  if (args[i] === "--started-by") {
@@ -13692,7 +13845,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13692
13845
  return;
13693
13846
  } else if (subcommand === "acp") {
13694
13847
  try {
13695
- const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-Bp5ZSCRm.cjs'); });
13848
+ const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-B1wTVXjt.cjs'); });
13696
13849
  let startedBy = void 0;
13697
13850
  let verbose = false;
13698
13851
  const acpArgs = [];
@@ -13732,7 +13885,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13732
13885
  return;
13733
13886
  } else if (subcommand === "openclaw") {
13734
13887
  try {
13735
- const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-CCGywWGD.cjs'); });
13888
+ const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-D2jtVgpC.cjs'); });
13736
13889
  let startedBy = void 0;
13737
13890
  let verbose = false;
13738
13891
  let gatewayUrl;
@@ -13783,7 +13936,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
13783
13936
  return;
13784
13937
  } else if (subcommand === "mcp" && args.length === 1) {
13785
13938
  try {
13786
- const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-BVoo0PQS.cjs'); });
13939
+ const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-B6Nq-RUL.cjs'); });
13787
13940
  await handleMcpCommand();
13788
13941
  } catch (error) {
13789
13942
  process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var AcpBackend = require('./AcpBackend-CBZNjcYO.cjs');
4
- var persistence = require('./types-DE03map-.cjs');
5
- var AcpSessionManager = require('./AcpSessionManager-B9mJWEzL.cjs');
3
+ var AcpBackend = require('./AcpBackend-CnYZFdd0.cjs');
4
+ var persistence = require('./types-BNGeiP1C.cjs');
5
+ var AcpSessionManager = require('./AcpSessionManager-BPBdrrME.cjs');
6
6
  var node_crypto = require('node:crypto');
7
7
  var path = require('node:path');
8
- var index = require('./index-FxD6Abgx.cjs');
8
+ var index = require('./index-4YmVbx7j.cjs');
9
9
  require('node:child_process');
10
10
  require('@agentclientprotocol/sdk');
11
11
  require('axios');
@@ -1,10 +1,10 @@
1
- import { D as DefaultTransport, A as AcpBackend } from './AcpBackend-C_simUP7.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-C_simUP7.mjs';
3
- import { h as connectionState, A as ApiClient, i as readSettings, j as encodeBase64, l as logger, p as projectPath } from './types-AO-TVSTa.mjs';
4
- import { A as AcpSessionManager } from './AcpSessionManager-G8w8Q6tt.mjs';
1
+ import { D as DefaultTransport, A as AcpBackend } from './AcpBackend-BV4wSnJ3.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-BV4wSnJ3.mjs';
3
+ import { h as connectionState, A as ApiClient, i as readSettings, j as encodeBase64, l as logger, p as projectPath } from './types-DS3i_5LV.mjs';
4
+ import { A as AcpSessionManager } from './AcpSessionManager-Cyne6Rmg.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-j2LYx2KW.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-an09rejO.mjs';
8
8
  import 'node:child_process';
9
9
  import '@agentclientprotocol/sdk';
10
10
  import 'axios';