very-happy-cli 0.2.128 → 0.2.130

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 (45) hide show
  1. package/dist/{AcpBackend-BYU6J2n0.cjs → AcpBackend-5slez7vM.cjs} +16 -4
  2. package/dist/{AcpBackend-D7987ody.mjs → AcpBackend-Co3atHW2.mjs} +16 -4
  3. package/dist/{AcpSessionManager-BwrjVZyn.mjs → AcpSessionManager-B0sD6Zi7.mjs} +1 -1
  4. package/dist/{AcpSessionManager-artXJgqb.cjs → AcpSessionManager-CxvVg8ec.cjs} +1 -1
  5. package/dist/{agentGuidance-BPGPaNlo.mjs → agentGuidance-7pJxf_3b.mjs} +1 -1
  6. package/dist/{agentGuidance-B1xYgHx6.cjs → agentGuidance-TjPzDO7d.cjs} +1 -1
  7. package/dist/codex/happyMcpStdioBridge.cjs +2 -2
  8. package/dist/codex/happyMcpStdioBridge.mjs +2 -2
  9. package/dist/{config-Dmkzs3o4.cjs → config-B4Md4FvK.cjs} +4 -4
  10. package/dist/{config-DSBE0Az0.mjs → config-BWu8j7bO.mjs} +4 -4
  11. package/dist/{index-CfM6ewd8.mjs → index-BUhcXX8R.mjs} +187 -83
  12. package/dist/{index-35FahgEU.mjs → index-C13U8MkT.mjs} +4 -4
  13. package/dist/{index-D_YVlpsW.cjs → index-C7TA3haC.cjs} +194 -86
  14. package/dist/{index-m0Dnccc_.mjs → index-CdOVizh_.mjs} +115 -32
  15. package/dist/{index-vyTJsT_R.cjs → index-DksoP9b2.cjs} +114 -31
  16. package/dist/{index-CJmXLSQc.cjs → index-Ds0aHXiU.cjs} +4 -4
  17. package/dist/index.cjs +4 -4
  18. package/dist/index.mjs +4 -4
  19. package/dist/{installTerminalHooks-C1zwiJJ2.cjs → installTerminalHooks-cNXov61F.cjs} +4 -4
  20. package/dist/{installTerminalHooks-ClrFe2fA.mjs → installTerminalHooks-kUC6I6Rn.mjs} +4 -4
  21. package/dist/lib.cjs +2 -2
  22. package/dist/lib.d.cts +7 -0
  23. package/dist/lib.d.mts +7 -0
  24. package/dist/lib.mjs +2 -2
  25. package/dist/{limits-CrwtFbi8.cjs → limits-BhK6ovLz.cjs} +7 -7
  26. package/dist/{limits-BNTLh2lw.mjs → limits-CIcZA0Bn.mjs} +7 -7
  27. package/dist/{mcp-Bc_mmJt8.cjs → mcp-CNX1qErQ.cjs} +4 -4
  28. package/dist/{mcp-BsohER5A.mjs → mcp-D5uyhbfB.mjs} +4 -4
  29. package/dist/{runGemini-B9S85Vms.mjs → runGemini-BQd3qlVY.mjs} +6 -6
  30. package/dist/{runGemini-B2GesRWm.cjs → runGemini-DvV6X_GE.cjs} +6 -6
  31. package/dist/{runOpenClaw-Byhq-B1y.mjs → runOpenClaw-BgtE2jKF.mjs} +5 -5
  32. package/dist/{runOpenClaw-DCK-R8qe.cjs → runOpenClaw-jxvPz3bo.cjs} +5 -5
  33. package/dist/{send-DQS1zNWp.mjs → send-BdhUFGTm.mjs} +4 -4
  34. package/dist/{send-CPdT1nOg.cjs → send-Di8Q32Ds.cjs} +4 -4
  35. package/dist/{sessions-DIOdWnPe.mjs → sessions-Bo2THj4y.mjs} +4 -4
  36. package/dist/{sessions-DC0IKaD9.cjs → sessions-eaAew6IP.cjs} +4 -4
  37. package/dist/{spawn-DrnCW2QK.cjs → spawn-6GfCYB5i.cjs} +4 -4
  38. package/dist/{spawn-DV4pIAHZ.mjs → spawn-CJxg1JUO.mjs} +4 -4
  39. package/dist/{teams-DlTHOiCk.mjs → teams-CHGj90rR.mjs} +4 -4
  40. package/dist/{teams-CwXEJs9I.cjs → teams-WdwFtptw.cjs} +4 -4
  41. package/dist/{todo-DrME15xq.cjs → todo-C-wktj2K.cjs} +3 -3
  42. package/dist/{todo-BwXURAbQ.mjs → todo-C8hDSNBP.mjs} +3 -3
  43. package/dist/{types-CFs8FmiY.mjs → types-B-ySoSY9.mjs} +21 -5
  44. package/dist/{types-DfatCoQL.cjs → types-QB33ckXt.cjs} +21 -5
  45. package/package.json +7 -7
@@ -3,13 +3,13 @@
3
3
  var chalk = require('chalk');
4
4
  var os = require('node:os');
5
5
  var node_crypto = require('node:crypto');
6
- var api = require('./types-DfatCoQL.cjs');
7
- var persistence = require('./limits-CrwtFbi8.cjs');
6
+ var api = require('./types-QB33ckXt.cjs');
7
+ var persistence = require('./limits-BhK6ovLz.cjs');
8
8
  var spawn = require('cross-spawn');
9
9
  var path = require('node:path');
10
10
  var node_readline = require('node:readline');
11
11
  var node_fs = require('node:fs');
12
- var agentGuidance = require('./agentGuidance-B1xYgHx6.cjs');
12
+ var agentGuidance = require('./agentGuidance-TjPzDO7d.cjs');
13
13
  var promises = require('node:fs/promises');
14
14
  var fs = require('fs/promises');
15
15
  var ink = require('ink');
@@ -2068,6 +2068,20 @@ async function claudeRemote(opts) {
2068
2068
  prompt: messages,
2069
2069
  options: sdkOptions
2070
2070
  });
2071
+ let models;
2072
+ if (typeof response.supportedModels === "function") {
2073
+ try {
2074
+ models = (await response.supportedModels()).map((model) => ({
2075
+ code: model.value,
2076
+ value: model.displayName,
2077
+ description: model.description,
2078
+ resolvedModel: model.resolvedModel,
2079
+ ...model.supportsEffort === false ? { reasoningEfforts: [] } : model.supportedEffortLevels ? { reasoningEfforts: model.supportedEffortLevels } : {}
2080
+ }));
2081
+ } catch (error) {
2082
+ persistence.logger.debug("[claudeRemote] Model capability discovery unavailable");
2083
+ }
2084
+ }
2071
2085
  if (opts.onQueryReady) {
2072
2086
  opts.onQueryReady({
2073
2087
  setPermissionMode: (mode2) => response.setPermissionMode(mode2),
@@ -2119,6 +2133,7 @@ async function claudeRemote(opts) {
2119
2133
  const systemInit = message;
2120
2134
  if (opts.onSDKMetadata) {
2121
2135
  opts.onSDKMetadata({
2136
+ models,
2122
2137
  tools: systemInit.tools,
2123
2138
  slashCommands: systemInit.slash_commands,
2124
2139
  mcpServers: systemInit.mcp_servers?.map((s) => ({ name: s.name, status: s.status })),
@@ -3402,6 +3417,16 @@ class StreamRelay {
3402
3417
  this.flushPending();
3403
3418
  this.closeOpenBlocks();
3404
3419
  this.currentMid = typeof mid === "string" && mid.length > 0 ? mid : null;
3420
+ const usage = e.message?.usage;
3421
+ if (usage || ["inputTokens", "cacheTokens", "outputTokens", "thinkingTokens"].some((key) => key in this.progress)) {
3422
+ const count = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : 0;
3423
+ this.setProgress({
3424
+ inputTokens: count(usage?.input_tokens),
3425
+ cacheTokens: count(usage?.cache_creation_input_tokens) + count(usage?.cache_read_input_tokens),
3426
+ outputTokens: count(usage?.output_tokens),
3427
+ thinkingTokens: 0
3428
+ });
3429
+ }
3405
3430
  return;
3406
3431
  }
3407
3432
  if (e.type === "content_block_start") {
@@ -3692,6 +3717,7 @@ function stripAttachmentManifest(text) {
3692
3717
  function applyClaudeSdkMetadata(current, update) {
3693
3718
  return {
3694
3719
  ...current,
3720
+ ...update.models ? { models: update.models } : {},
3695
3721
  tools: update.tools,
3696
3722
  slashCommands: update.slashCommands,
3697
3723
  mcpServers: update.mcpServers,
@@ -5293,6 +5319,11 @@ ${typeLabels[type] || type}:`));
5293
5319
  console.log(chalk.green("\n\u2705 Doctor diagnosis complete!\n"));
5294
5320
  }
5295
5321
 
5322
+ function sanitizeSpawnModel(value) {
5323
+ if (typeof value !== "string") return null;
5324
+ return /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}(\[1m\])?$/i.test(value) ? value : null;
5325
+ }
5326
+
5296
5327
  const SPAWN_AGENTS = ["claude", "codex", "gemini", "openclaw", "pi"];
5297
5328
  function isSpawnAgent(value) {
5298
5329
  return typeof value === "string" && SPAWN_AGENTS.includes(value);
@@ -7055,6 +7086,12 @@ function parsePiRunnerArgs(args) {
7055
7086
  parsed.verbose = true;
7056
7087
  continue;
7057
7088
  }
7089
+ if (arg === "--model") {
7090
+ const model = sanitizeSpawnModel(args[++i]);
7091
+ if (!model) throw new Error("Invalid --model identifier");
7092
+ parsed.model = model;
7093
+ continue;
7094
+ }
7058
7095
  if (arg === "--permission-mode") {
7059
7096
  const mode = normalizeAcpPermissionMode(args[++i]);
7060
7097
  if (mode) parsed.permissionMode = mode;
@@ -7677,7 +7714,7 @@ function parseJsonObject(text) {
7677
7714
  return null;
7678
7715
  }
7679
7716
  }
7680
- function resolveSdkClaudeBinary(platform = process.platform, arch = process.arch, resolver = (s) => node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-D_YVlpsW.cjs', document.baseURI).href))).resolve(s)) {
7717
+ function resolveSdkClaudeBinary(platform = process.platform, arch = process.arch, resolver = (s) => node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-C7TA3haC.cjs', document.baseURI).href))).resolve(s)) {
7681
7718
  const platformArch = `${platform}-${arch}`;
7682
7719
  const candidates = [
7683
7720
  `@anthropic-ai/claude-agent-sdk-${platformArch}/claude`,
@@ -9945,6 +9982,7 @@ async function startDaemon() {
9945
9982
  const currentCliAvailability = () => apiMachineRef?.getCLIAvailability() ?? startupCliAvailability;
9946
9983
  const spawnSessionImpl = async (options) => {
9947
9984
  persistence.logger.debugLargeJson("[DAEMON RUN] Spawning session", api.summarizeSpawnSessionForLog(options));
9985
+ const spawnModel = options.agent === "pi" ? sanitizeSpawnModel(options.model) : null;
9948
9986
  const spawnPermissionMode = sanitizeSpawnPermissionMode(options.permissionMode);
9949
9987
  if (options.permissionMode !== void 0 && spawnPermissionMode === null) {
9950
9988
  persistence.logger.warn("[DAEMON RUN] Ignoring invalid permissionMode in spawn request");
@@ -10169,7 +10207,8 @@ async function startDaemon() {
10169
10207
  const resumeId = agent === "claude" ? options.resumeClaudeSessionId : agent === "codex" ? options.resumeCodexThreadId : void 0;
10170
10208
  const resumeFragment = resumeId ? ` --resume ${api.shellescape(resumeId)}` : "";
10171
10209
  const permissionModeFragment = spawnPermissionMode ? ` --permission-mode ${api.shellescape(spawnPermissionMode)}` : "";
10172
- const fullCommand = `node --no-warnings --no-deprecation ${cliPath} ${agent} --happy-starting-mode remote --started-by daemon${resumeFragment}${permissionModeFragment}`;
10210
+ const modelFragment = spawnModel ? ` --model ${api.shellescape(spawnModel)}` : "";
10211
+ const fullCommand = `node --no-warnings --no-deprecation ${cliPath} ${agent} --happy-starting-mode remote --started-by daemon${resumeFragment}${permissionModeFragment}${modelFragment}`;
10173
10212
  const windowName = `happy-${Date.now()}-${agent}`;
10174
10213
  const tmuxEnv = {};
10175
10214
  for (const [key, value] of Object.entries(process.env)) {
@@ -10262,6 +10301,7 @@ async function startDaemon() {
10262
10301
  if (options.resumeCodexThreadId && agentCommand === "codex") {
10263
10302
  args.push("--resume", options.resumeCodexThreadId);
10264
10303
  }
10304
+ if (spawnModel) args.push("--model", spawnModel);
10265
10305
  if (spawnPermissionMode) {
10266
10306
  args.push("--permission-mode", spawnPermissionMode);
10267
10307
  }
@@ -12045,7 +12085,7 @@ function registerSideQuestionHandler(rpc, deps) {
12045
12085
  const retainMs = deps.retainMs ?? SIDE_QUESTION_RETAIN_MS;
12046
12086
  const maxRunMs = deps.maxRunMs ?? SIDE_QUESTION_MAX_RUN_MS;
12047
12087
  const run = deps.run ?? (async (input) => {
12048
- const { query } = await Promise.resolve().then(function () { return require('./index-CJmXLSQc.cjs'); });
12088
+ const { query } = await Promise.resolve().then(function () { return require('./index-Ds0aHXiU.cjs'); });
12049
12089
  return runSideQuestion(query, input);
12050
12090
  });
12051
12091
  const slots = /* @__PURE__ */ new Map();
@@ -12147,7 +12187,7 @@ const MAX_TITLE_CHARS = 60;
12147
12187
  const GENERATION_TIMEOUT_MS = 3e4;
12148
12188
  function resolveClaudeBinary() {
12149
12189
  try {
12150
- 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-D_YVlpsW.cjs', document.baseURI).href)));
12190
+ 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-C7TA3haC.cjs', document.baseURI).href)));
12151
12191
  const utilsPath = path.resolve(path.join(api.projectPath(), "scripts", "claude_version_utils.cjs"));
12152
12192
  const { getClaudeCliPath } = require$1(utilsPath);
12153
12193
  const path$1 = getClaudeCliPath();
@@ -14365,9 +14405,9 @@ function resolveLocalSignupBootstrap(configuredMode, configuredInviteCodes, gene
14365
14405
  };
14366
14406
  }
14367
14407
 
14368
- 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-D_YVlpsW.cjs', document.baseURI).href)));
14408
+ 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-C7TA3haC.cjs', document.baseURI).href)));
14369
14409
  const __dirname$1 = path.dirname(__filename$1);
14370
- const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-D_YVlpsW.cjs', document.baseURI).href)));
14410
+ const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-C7TA3haC.cjs', document.baseURI).href)));
14371
14411
  const PRISMA_QUERY_ENGINE_FILES = {
14372
14412
  "arm64-darwin": "libquery_engine-darwin-arm64.dylib.node",
14373
14413
  "x64-darwin": "libquery_engine-darwin.dylib.node",
@@ -14789,6 +14829,23 @@ async function ensureDaemonRunning() {
14789
14829
  persistence.logger.debug(`Happy background service did not become ready within ${DAEMON_READY_TIMEOUT_MS}ms; continuing anyway`);
14790
14830
  }
14791
14831
 
14832
+ function registerAgentAttachmentDownloads(session) {
14833
+ session.onFileEvent((fileEvent) => {
14834
+ const attachment = fileEvent.content.data.ev;
14835
+ const download = (async () => {
14836
+ try {
14837
+ const data = await session.downloadAndDecryptAttachment(attachment.ref);
14838
+ if (!data) throw new Error("Attachment decryption failed");
14839
+ return { data, mimeType: attachment.mimeType ?? "image/jpeg", name: attachment.name };
14840
+ } catch {
14841
+ session.sendSessionEvent({ type: "message", message: `Could not download attachment: ${attachment.name}. Please attach it again.` });
14842
+ return null;
14843
+ }
14844
+ })();
14845
+ session.trackAttachmentDownload(download);
14846
+ });
14847
+ }
14848
+
14792
14849
  class BasePermissionHandler {
14793
14850
  pendingRequests = /* @__PURE__ */ new Map();
14794
14851
  session;
@@ -15428,6 +15485,11 @@ function createOfflineSessionStub(sessionTag) {
15428
15485
  },
15429
15486
  onUserMessage: () => {
15430
15487
  },
15488
+ onFileEvent: () => {
15489
+ },
15490
+ trackAttachmentDownload: () => {
15491
+ },
15492
+ drainAttachmentsForUserMessage: async () => [],
15431
15493
  rpcHandlerManager: {
15432
15494
  registerHandler: () => {
15433
15495
  }
@@ -15478,8 +15540,8 @@ function resolveCodexExecutionPolicy(permissionMode, sandboxManagedByHappy) {
15478
15540
  return "never";
15479
15541
  // Never ask, read-only enforced by sandbox
15480
15542
  case "safe-yolo":
15481
- return "on-failure";
15482
- // Auto-run, ask only on failure
15543
+ return "on-request";
15544
+ // Workspace auto-run; request approval for escalation (0.153 removed on-failure)
15483
15545
  case "yolo":
15484
15546
  return "never";
15485
15547
  // Full YOLO: never interrupt for approvals
@@ -16075,10 +16137,10 @@ function isCodexClearText(text) {
16075
16137
  }
16076
16138
  function enqueueCodexUserText(opts) {
16077
16139
  if (isCodexClearText(opts.text)) {
16078
- opts.queue.pushIsolateAndClear(opts.text, opts.mode, void 0, opts.sourceId);
16140
+ opts.queue.pushIsolateAndClear(opts.text, opts.mode, opts.attachments, opts.sourceId);
16079
16141
  return "clear";
16080
16142
  }
16081
- opts.queue.push(opts.text, opts.mode, void 0, opts.sourceId);
16143
+ opts.queue.push(opts.text, opts.mode, opts.attachments, opts.sourceId);
16082
16144
  return "queued";
16083
16145
  }
16084
16146
 
@@ -16202,6 +16264,7 @@ async function runCodex(opts) {
16202
16264
  ...forkedFromSessionId ? { parentSessionId: forkedFromSessionId } : {},
16203
16265
  ...forkedFromMessageId ? { forkedFromMessageId } : {}
16204
16266
  });
16267
+ metadata.attachmentKinds = [...CLAUDE_ATTACHMENT_KINDS];
16205
16268
  const reconnectSessionId = process.env.HAPPY_RECONNECT_SESSION_ID;
16206
16269
  const reconnectKeyBase64 = process.env.HAPPY_RECONNECT_ENCRYPTION_KEY;
16207
16270
  const reconnectVariant = process.env.HAPPY_RECONNECT_ENCRYPTION_VARIANT;
@@ -16309,76 +16372,88 @@ async function runCodex(opts) {
16309
16372
  "safe-yolo",
16310
16373
  "yolo"
16311
16374
  ];
16375
+ let discoveredModels = [];
16312
16376
  const VALID_REMOTE_EFFORTS = [
16313
16377
  "none",
16314
16378
  "minimal",
16315
16379
  "low",
16316
16380
  "medium",
16317
16381
  "high",
16318
- "xhigh"
16382
+ "xhigh",
16383
+ "max"
16319
16384
  ];
16385
+ registerAgentAttachmentDownloads(session);
16386
+ let userMessageDelivery = Promise.resolve();
16320
16387
  session.onUserMessage((message) => {
16321
- let messagePermissionMode = currentPermissionMode;
16322
- if (message.meta?.permissionMode) {
16323
- const incoming = message.meta.permissionMode;
16324
- if (VALID_REMOTE_PERMISSION_MODES.includes(incoming)) {
16325
- messagePermissionMode = incoming;
16326
- currentPermissionMode = messagePermissionMode;
16327
- persistence.logger.debug("[Codex] Valid permission mode override applied");
16388
+ const downloads = session.drainAttachmentsForUserMessage();
16389
+ userMessageDelivery = userMessageDelivery.then(async () => {
16390
+ const attachments = await downloads;
16391
+ let messagePermissionMode = currentPermissionMode;
16392
+ if (message.meta?.permissionMode) {
16393
+ const incoming = message.meta.permissionMode;
16394
+ if (VALID_REMOTE_PERMISSION_MODES.includes(incoming)) {
16395
+ messagePermissionMode = incoming;
16396
+ currentPermissionMode = messagePermissionMode;
16397
+ persistence.logger.debug("[Codex] Valid permission mode override applied");
16398
+ } else {
16399
+ persistence.logger.debug("[Codex] Ignoring invalid permission mode override", logValueMetadata(message.meta.permissionMode));
16400
+ }
16328
16401
  } else {
16329
- persistence.logger.debug("[Codex] Ignoring invalid permission mode override", logValueMetadata(message.meta.permissionMode));
16402
+ persistence.logger.debug("[Codex] User message received without a permission mode override");
16330
16403
  }
16331
- } else {
16332
- persistence.logger.debug("[Codex] User message received without a permission mode override");
16333
- }
16334
- let messageModel = currentModel;
16335
- if (message.meta?.hasOwnProperty("model")) {
16336
- messageModel = message.meta.model || void 0;
16337
- currentModel = messageModel;
16338
- persistence.logger.debug("[Codex] Model override updated", logValueMetadata(message.meta.model));
16339
- } else {
16340
- persistence.logger.debug("[Codex] User message received without a model override");
16341
- }
16342
- let messageEffort = currentEffort;
16343
- if (message.meta?.hasOwnProperty("effort")) {
16344
- const incoming = message.meta.effort;
16345
- if (incoming === null || incoming === void 0) {
16346
- messageEffort = void 0;
16347
- currentEffort = void 0;
16348
- persistence.logger.debug(`[Codex] Effort reset to default`);
16349
- } else if (typeof incoming === "string" && VALID_REMOTE_EFFORTS.includes(incoming)) {
16350
- messageEffort = incoming;
16351
- currentEffort = messageEffort;
16352
- persistence.logger.debug("[Codex] Valid effort override applied");
16404
+ let messageModel = currentModel;
16405
+ if (message.meta?.hasOwnProperty("model")) {
16406
+ messageModel = message.meta.model || void 0;
16407
+ currentModel = messageModel;
16408
+ persistence.logger.debug("[Codex] Model override updated", logValueMetadata(message.meta.model));
16409
+ } else {
16410
+ persistence.logger.debug("[Codex] User message received without a model override");
16411
+ }
16412
+ let messageEffort = currentEffort;
16413
+ if (message.meta?.hasOwnProperty("effort")) {
16414
+ const incoming = message.meta.effort;
16415
+ if (incoming === null || incoming === void 0) {
16416
+ messageEffort = void 0;
16417
+ currentEffort = void 0;
16418
+ persistence.logger.debug(`[Codex] Effort reset to default`);
16419
+ } else if (typeof incoming === "string") {
16420
+ messageEffort = incoming;
16421
+ currentEffort = messageEffort;
16422
+ persistence.logger.debug("[Codex] Valid effort override applied");
16423
+ } else {
16424
+ persistence.logger.debug("[Codex] Ignoring invalid effort override", logValueMetadata(incoming));
16425
+ }
16353
16426
  } else {
16354
- persistence.logger.debug("[Codex] Ignoring invalid effort override", logValueMetadata(incoming));
16427
+ persistence.logger.debug("[Codex] User message received without an effort override");
16355
16428
  }
16356
- } else {
16357
- persistence.logger.debug("[Codex] User message received without an effort override");
16358
- }
16359
- let messageAppendSystemPrompt = currentAppendSystemPrompt;
16360
- if (message.meta?.hasOwnProperty("appendSystemPrompt")) {
16361
- messageAppendSystemPrompt = message.meta.appendSystemPrompt || void 0;
16362
- currentAppendSystemPrompt = messageAppendSystemPrompt;
16363
- persistence.logger.debug("[Codex] Append system prompt override updated", logValueMetadata(message.meta.appendSystemPrompt));
16364
- } else {
16365
- persistence.logger.debug("[Codex] User message received without an append system prompt override");
16366
- }
16367
- const enhancedMode = {
16368
- permissionMode: messagePermissionMode || "default",
16369
- model: messageModel,
16370
- appendSystemPrompt: messageAppendSystemPrompt,
16371
- effort: messageEffort
16372
- };
16373
- const enqueueResult = enqueueCodexUserText({
16374
- text: message.content.text,
16375
- mode: enhancedMode,
16376
- queue: messageQueue,
16377
- sourceId: message.localKey
16429
+ let messageAppendSystemPrompt = currentAppendSystemPrompt;
16430
+ if (message.meta?.hasOwnProperty("appendSystemPrompt")) {
16431
+ messageAppendSystemPrompt = message.meta.appendSystemPrompt || void 0;
16432
+ currentAppendSystemPrompt = messageAppendSystemPrompt;
16433
+ persistence.logger.debug("[Codex] Append system prompt override updated", logValueMetadata(message.meta.appendSystemPrompt));
16434
+ } else {
16435
+ persistence.logger.debug("[Codex] User message received without an append system prompt override");
16436
+ }
16437
+ const enhancedMode = {
16438
+ permissionMode: messagePermissionMode || "default",
16439
+ model: messageModel,
16440
+ appendSystemPrompt: messageAppendSystemPrompt,
16441
+ effort: messageEffort
16442
+ };
16443
+ const enqueueResult = enqueueCodexUserText({
16444
+ text: message.content.text,
16445
+ mode: enhancedMode,
16446
+ queue: messageQueue,
16447
+ attachments,
16448
+ sourceId: message.localKey
16449
+ });
16450
+ if (enqueueResult === "clear") {
16451
+ persistence.logger.debug("[Codex] /clear command pushed to isolated queue");
16452
+ }
16453
+ }).catch((error) => {
16454
+ persistence.logger.warn("[Codex] Failed to prepare user attachments", safeCodexErrorMetadata(error));
16455
+ session.sendSessionEvent({ type: "message", message: "Could not prepare this message. Please send it again." });
16378
16456
  });
16379
- if (enqueueResult === "clear") {
16380
- persistence.logger.debug("[Codex] /clear command pushed to isolated queue");
16381
- }
16382
16457
  });
16383
16458
  let thinking = false;
16384
16459
  let currentTurnId = null;
@@ -16654,6 +16729,24 @@ async function runCodex(opts) {
16654
16729
  persistence.logger.debug("[codex]: client.connect begin");
16655
16730
  await client.connect();
16656
16731
  persistence.logger.debug("[codex]: client.connect done");
16732
+ try {
16733
+ discoveredModels = await client.listModels();
16734
+ if (discoveredModels.length > 0) {
16735
+ session.updateMetadata((metadata2) => ({
16736
+ ...metadata2,
16737
+ models: discoveredModels.map((model) => ({
16738
+ code: model.model,
16739
+ value: model.displayName,
16740
+ description: model.description,
16741
+ reasoningEfforts: model.supportedReasoningEfforts.map((option) => option.reasoningEffort),
16742
+ defaultReasoningEffort: model.defaultReasoningEffort
16743
+ })),
16744
+ defaultModelCode: discoveredModels.find((model) => model.isDefault)?.model
16745
+ }));
16746
+ }
16747
+ } catch (error) {
16748
+ persistence.logger.debug("[Codex] Model discovery unavailable; using compatibility fallback", safeCodexErrorMetadata(error));
16749
+ }
16657
16750
  if (opts.resumeThreadId) {
16658
16751
  await resumeExistingThread({
16659
16752
  client,
@@ -16742,6 +16835,11 @@ async function runCodex(opts) {
16742
16835
  message.mode.permissionMode,
16743
16836
  sandboxManagedByHappy
16744
16837
  );
16838
+ const selectedModel = discoveredModels.find((model) => message.mode.model ? model.model === message.mode.model : model.isDefault);
16839
+ const supportedEfforts = selectedModel?.supportedReasoningEfforts.map((option) => option.reasoningEffort) ?? VALID_REMOTE_EFFORTS;
16840
+ if (message.mode.effort && !supportedEfforts.includes(message.mode.effort)) {
16841
+ throw new Error(`Reasoning effort "${message.mode.effort}" is not supported by ${message.mode.model ?? "the default model"}. Choose a supported level.`);
16842
+ }
16745
16843
  if (!client.hasActiveThread()) {
16746
16844
  const startedThread = await client.startThread({
16747
16845
  model: message.mode.model,
@@ -16764,7 +16862,12 @@ async function runCodex(opts) {
16764
16862
  includeAppendSystemPrompt,
16765
16863
  includeTitleInstruction: first
16766
16864
  });
16767
- const result = await client.sendTurnAndWait(turnPrompt, {
16865
+ const staged = message.attachments?.length ? await stageClaudeAttachments(message.attachments, {
16866
+ happyHomeDir: persistence.configuration.happyHomeDir,
16867
+ sessionId: session.sessionId
16868
+ }) : [];
16869
+ const result = await client.sendTurnAndWait(appendStagedAttachmentsToPrompt(turnPrompt, staged), {
16870
+ images: staged.filter((file) => ["image/jpeg", "image/png", "image/gif", "image/webp"].includes(file.mimeType)).map((file) => file.path),
16768
16871
  model: message.mode.model,
16769
16872
  approvalPolicy: executionPolicy.approvalPolicy,
16770
16873
  sandbox: executionPolicy.sandbox,
@@ -16999,7 +17102,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
16999
17102
  process.exit(0);
17000
17103
  } else if (subcommand === "install-terminal-hooks") {
17001
17104
  try {
17002
- const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-C1zwiJJ2.cjs'); });
17105
+ const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-cNXov61F.cjs'); });
17003
17106
  const command = parseTerminalHooksArgs(args.slice(1));
17004
17107
  if (command.action === "help") {
17005
17108
  console.log(TERMINAL_HOOKS_HELP);
@@ -17016,7 +17119,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17016
17119
  }
17017
17120
  } else if (subcommand === "spawn") {
17018
17121
  try {
17019
- const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-DrnCW2QK.cjs'); });
17122
+ const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-6GfCYB5i.cjs'); });
17020
17123
  await handleSpawnCommand(args.slice(1));
17021
17124
  } catch (error) {
17022
17125
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -17028,7 +17131,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17028
17131
  return;
17029
17132
  } else if (subcommand === "sessions") {
17030
17133
  try {
17031
- const { handleSessionsCommand } = await Promise.resolve().then(function () { return require('./sessions-DC0IKaD9.cjs'); });
17134
+ const { handleSessionsCommand } = await Promise.resolve().then(function () { return require('./sessions-eaAew6IP.cjs'); });
17032
17135
  await handleSessionsCommand(args.slice(1));
17033
17136
  } catch (error) {
17034
17137
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -17040,7 +17143,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17040
17143
  return;
17041
17144
  } else if (subcommand === "send") {
17042
17145
  try {
17043
- const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-CPdT1nOg.cjs'); });
17146
+ const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-Di8Q32Ds.cjs'); });
17044
17147
  await handleSendCommand(args.slice(1));
17045
17148
  } catch (error) {
17046
17149
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -17146,9 +17249,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17146
17249
  if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
17147
17250
  const projectId = args[3];
17148
17251
  try {
17149
- const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-Dmkzs3o4.cjs'); });
17150
- const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./limits-CrwtFbi8.cjs'); }).then(function (n) { return n.persistence; });
17151
- const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-DfatCoQL.cjs'); }).then(function (n) { return n.api; });
17252
+ const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-B4Md4FvK.cjs'); });
17253
+ const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./limits-BhK6ovLz.cjs'); }).then(function (n) { return n.persistence; });
17254
+ const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-QB33ckXt.cjs'); }).then(function (n) { return n.api; });
17152
17255
  let userEmail = void 0;
17153
17256
  try {
17154
17257
  const credentials = await readCredentialsForConfiguredRelay2();
@@ -17179,7 +17282,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17179
17282
  }
17180
17283
  if (geminiSubcommand === "project" && args[2] === "get") {
17181
17284
  try {
17182
- const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-Dmkzs3o4.cjs'); });
17285
+ const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-B4Md4FvK.cjs'); });
17183
17286
  const config = readGeminiLocalConfig();
17184
17287
  if (config.googleCloudProject) {
17185
17288
  console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
@@ -17219,7 +17322,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17219
17322
  process.exit(0);
17220
17323
  }
17221
17324
  try {
17222
- const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-B2GesRWm.cjs'); });
17325
+ const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-DvV6X_GE.cjs'); });
17223
17326
  let startedBy = void 0;
17224
17327
  for (let i = 1; i < args.length; i++) {
17225
17328
  if (args[i] === "--started-by") {
@@ -17249,7 +17352,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17249
17352
  }
17250
17353
  };
17251
17354
  try {
17252
- const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-vyTJsT_R.cjs'); });
17355
+ const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-DksoP9b2.cjs'); });
17253
17356
  const parsed = parsePiRunnerArgs(args.slice(1));
17254
17357
  const resolved = resolveAcpAgentConfig(["pi", ...parsed.passthrough]);
17255
17358
  const { credentials } = await authAndSetupMachineIfNeeded();
@@ -17259,6 +17362,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17259
17362
  startedBy: parsed.startedBy,
17260
17363
  verbose: parsed.verbose,
17261
17364
  permissionMode: parsed.permissionMode,
17365
+ model: parsed.model,
17262
17366
  agentName: resolved.agentName,
17263
17367
  command: resolved.command,
17264
17368
  args: resolved.args,
@@ -17276,7 +17380,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17276
17380
  return;
17277
17381
  } else if (subcommand === "acp") {
17278
17382
  try {
17279
- const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-vyTJsT_R.cjs'); });
17383
+ const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-DksoP9b2.cjs'); });
17280
17384
  let startedBy = void 0;
17281
17385
  let verbose = false;
17282
17386
  const acpArgs = [];
@@ -17316,7 +17420,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17316
17420
  return;
17317
17421
  } else if (subcommand === "openclaw") {
17318
17422
  try {
17319
- const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-DCK-R8qe.cjs'); });
17423
+ const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-jxvPz3bo.cjs'); });
17320
17424
  let startedBy = void 0;
17321
17425
  let verbose = false;
17322
17426
  let gatewayUrl;
@@ -17367,7 +17471,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17367
17471
  return;
17368
17472
  } else if (subcommand === "todo") {
17369
17473
  try {
17370
- const { handleTodoCommand } = await Promise.resolve().then(function () { return require('./todo-DrME15xq.cjs'); });
17474
+ const { handleTodoCommand } = await Promise.resolve().then(function () { return require('./todo-C-wktj2K.cjs'); });
17371
17475
  await handleTodoCommand(args.slice(1));
17372
17476
  } catch (error) {
17373
17477
  console.error(JSON.stringify({ error: error instanceof Error ? error.message : "Todo command failed" }));
@@ -17376,7 +17480,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17376
17480
  return;
17377
17481
  } else if (subcommand === "teams") {
17378
17482
  try {
17379
- const { handleTeamsCommand } = await Promise.resolve().then(function () { return require('./teams-CwXEJs9I.cjs'); });
17483
+ const { handleTeamsCommand } = await Promise.resolve().then(function () { return require('./teams-WdwFtptw.cjs'); });
17380
17484
  await handleTeamsCommand(args.slice(1));
17381
17485
  } catch (error) {
17382
17486
  console.error(error instanceof Error ? error.message : "Teams command failed");
@@ -17385,7 +17489,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17385
17489
  return;
17386
17490
  } else if (subcommand === "mcp" && args.length === 1) {
17387
17491
  try {
17388
- const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-Bc_mmJt8.cjs'); });
17492
+ const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-CNX1qErQ.cjs'); });
17389
17493
  await handleMcpCommand();
17390
17494
  } catch (error) {
17391
17495
  process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
@@ -17751,6 +17855,7 @@ exports.ALLOWED_SPAWN_PERMISSION_MODES = ALLOWED_SPAWN_PERMISSION_MODES;
17751
17855
  exports.BasePermissionHandler = BasePermissionHandler;
17752
17856
  exports.BaseReasoningProcessor = BaseReasoningProcessor;
17753
17857
  exports.CHANGE_TITLE_INSTRUCTION = CHANGE_TITLE_INSTRUCTION;
17858
+ exports.CLAUDE_ATTACHMENT_KINDS = CLAUDE_ATTACHMENT_KINDS;
17754
17859
  exports.DEFAULT_GEMINI_MODEL = DEFAULT_GEMINI_MODEL;
17755
17860
  exports.DEFAULT_RECENT_LIMIT = DEFAULT_RECENT_LIMIT;
17756
17861
  exports.GEMINI_API_KEY_ENV = GEMINI_API_KEY_ENV;
@@ -17764,6 +17869,7 @@ exports.SPAWN_AGENTS = SPAWN_AGENTS;
17764
17869
  exports.StreamRelay = StreamRelay;
17765
17870
  exports.TEAM_SKILL = TEAM_SKILL;
17766
17871
  exports.TitleGenerator = TitleGenerator;
17872
+ exports.appendStagedAttachmentsToPrompt = appendStagedAttachmentsToPrompt;
17767
17873
  exports.archiveSession = archiveSession;
17768
17874
  exports.checkIfDaemonRunningAndCleanupStaleState = checkIfDaemonRunningAndCleanupStaleState;
17769
17875
  exports.createSessionMetadata = createSessionMetadata;
@@ -17777,6 +17883,7 @@ exports.notifyDaemonSessionStarted = notifyDaemonSessionStarted;
17777
17883
  exports.pushClipboardViaDaemon = pushClipboardViaDaemon;
17778
17884
  exports.query = query;
17779
17885
  exports.readSessionTranscript = readSessionTranscript;
17886
+ exports.registerAgentAttachmentDownloads = registerAgentAttachmentDownloads;
17780
17887
  exports.registerAssistantSessionTools = registerAssistantSessionTools;
17781
17888
  exports.registerKillSessionHandler = registerKillSessionHandler;
17782
17889
  exports.removeSessionModeFile = removeSessionModeFile;
@@ -17787,6 +17894,7 @@ exports.sessionWebUrl = sessionWebUrl;
17787
17894
  exports.setTerminalTitleViaDaemon = setTerminalTitleViaDaemon;
17788
17895
  exports.setupOfflineReconnection = setupOfflineReconnection;
17789
17896
  exports.spawnDaemonSession = spawnDaemonSession;
17897
+ exports.stageClaudeAttachments = stageClaudeAttachments;
17790
17898
  exports.startHappyServer = startHappyServer;
17791
17899
  exports.stopSession = stopSession;
17792
17900
  exports.tmuxSupportsSessionEnv = tmuxSupportsSessionEnv;