@zhigang1992/happy-cli 0.12.3 → 0.12.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,15 @@
1
1
  import chalk from 'chalk';
2
2
  import os$1, { homedir } from 'node:os';
3
3
  import { randomUUID, randomBytes, createHmac } from 'node:crypto';
4
- import { l as logger, p as projectPath, j as backoff, k as delay, R as RawJSONLinesSchema, m as AsyncLock, c as configuration, n as readDaemonState, o as clearDaemonState, i as packageJson, r as readSettings, q as readCredentials, g as encodeBase64, u as updateSettings, s as encodeBase64Url, d as decodeBase64, w as writeCredentialsLegacy, t as writeCredentialsDataKey, v as acquireDaemonLock, x as writeDaemonState, A as ApiClient, y as releaseDaemonLock, z as authChallenge, B as clearCredentials, C as clearMachineId, D as getLatestDaemonLog } from './types-D4_aCy-H.mjs';
4
+ import { l as logger, p as projectPath, j as backoff, k as delay, R as RawJSONLinesSchema, m as AsyncLock, c as configuration, n as readDaemonState, o as clearDaemonState, i as packageJson, r as readSettings, q as readCredentials, g as encodeBase64, u as updateSettings, s as encodeBase64Url, d as decodeBase64, w as writeCredentialsLegacy, t as writeCredentialsDataKey, v as acquireDaemonLock, x as writeDaemonState, A as ApiClient, y as releaseDaemonLock, z as authChallenge, B as clearCredentials, C as clearMachineId, D as getLatestDaemonLog } from './types-BmcSXhbq.mjs';
5
5
  import { spawn, execSync, execFileSync } from 'node:child_process';
6
6
  import { resolve, join } from 'node:path';
7
7
  import { createInterface } from 'node:readline';
8
8
  import { existsSync, readFileSync, mkdirSync, watch, readdirSync, statSync, rmSync } from 'node:fs';
9
+ import { exec, spawn as spawn$1, execSync as execSync$1 } from 'child_process';
10
+ import { promisify } from 'util';
11
+ import { existsSync as existsSync$1, readFileSync as readFileSync$1, writeFileSync, chmodSync, unlinkSync } from 'fs';
12
+ import { join as join$1, dirname, basename } from 'path';
9
13
  import { readFile } from 'node:fs/promises';
10
14
  import fs, { watch as watch$1, access } from 'fs/promises';
11
15
  import { useStdout, useInput, Box, Text, render } from 'ink';
@@ -16,10 +20,7 @@ import 'node:events';
16
20
  import 'socket.io-client';
17
21
  import tweetnacl from 'tweetnacl';
18
22
  import 'expo-server-sdk';
19
- import { basename, join as join$1 } from 'path';
20
23
  import { createHash, randomBytes as randomBytes$1 } from 'crypto';
21
- import { spawn as spawn$1, execSync as execSync$1, exec } from 'child_process';
22
- import { readFileSync as readFileSync$1, existsSync as existsSync$1, writeFileSync, chmodSync, unlinkSync } from 'fs';
23
24
  import psList from 'ps-list';
24
25
  import spawn$2 from 'cross-spawn';
25
26
  import os from 'os';
@@ -34,7 +35,6 @@ import { createServer } from 'node:http';
34
35
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
35
36
  import * as hex from '@stablelib/hex';
36
37
  import { createServer as createServer$1 } from 'http';
37
- import { promisify } from 'util';
38
38
 
39
39
  class Session {
40
40
  path;
@@ -218,6 +218,99 @@ const systemPrompt = (() => {
218
218
  }
219
219
  })();
220
220
 
221
+ const execAsync$1 = promisify(exec);
222
+ let direnvAvailable = null;
223
+ async function isDirenvAvailable() {
224
+ if (direnvAvailable !== null) {
225
+ return direnvAvailable;
226
+ }
227
+ try {
228
+ await execAsync$1("direnv version", { timeout: 5e3 });
229
+ direnvAvailable = true;
230
+ logger.debug("[direnv] direnv is available");
231
+ } catch {
232
+ direnvAvailable = false;
233
+ logger.debug("[direnv] direnv is not available");
234
+ }
235
+ return direnvAvailable;
236
+ }
237
+ function findEnvrcDirectory(startDir) {
238
+ let dir = startDir;
239
+ const root = "/";
240
+ while (dir !== root) {
241
+ const envrcPath = join$1(dir, ".envrc");
242
+ if (existsSync$1(envrcPath)) {
243
+ logger.debug(`[direnv] Found .envrc at: ${envrcPath}`);
244
+ return dir;
245
+ }
246
+ const parent = dirname(dir);
247
+ if (parent === dir) {
248
+ break;
249
+ }
250
+ dir = parent;
251
+ }
252
+ logger.debug(`[direnv] No .envrc found in directory tree for: ${startDir}`);
253
+ return null;
254
+ }
255
+ async function loadDirenvEnvironment(cwd) {
256
+ if (!await isDirenvAvailable()) {
257
+ return {};
258
+ }
259
+ const envrcDir = findEnvrcDirectory(cwd);
260
+ if (!envrcDir) {
261
+ return {};
262
+ }
263
+ try {
264
+ logger.debug(`[direnv] Loading environment for: ${cwd}`);
265
+ const { stdout, stderr } = await execAsync$1("direnv export json", {
266
+ cwd,
267
+ timeout: 1e4,
268
+ // 10 second timeout
269
+ env: {
270
+ ...process.env,
271
+ // Ensure direnv doesn't prompt for allowance interactively
272
+ DIRENV_LOG_FORMAT: ""
273
+ }
274
+ });
275
+ if (stderr) {
276
+ logger.debug(`[direnv] stderr: ${stderr}`);
277
+ }
278
+ const trimmed = stdout.trim();
279
+ if (!trimmed) {
280
+ logger.debug("[direnv] No environment changes from direnv");
281
+ return {};
282
+ }
283
+ const direnvVars = JSON.parse(trimmed);
284
+ const varCount = Object.keys(direnvVars).length;
285
+ logger.debug(`[direnv] Loaded ${varCount} environment variables`);
286
+ return direnvVars;
287
+ } catch (error) {
288
+ if (error instanceof Error) {
289
+ logger.debug(`[direnv] Failed to load environment: ${error.message}`);
290
+ if (error.message.includes("is blocked")) {
291
+ logger.debug('[direnv] Hint: Run "direnv allow" in the project directory to allow the .envrc');
292
+ }
293
+ }
294
+ return {};
295
+ }
296
+ }
297
+ async function loadAndMergeEnvironment(cwd, existingEnv = process.env, overrideEnv = {}) {
298
+ const direnvVars = await loadDirenvEnvironment(cwd);
299
+ const merged = {};
300
+ for (const [key, value] of Object.entries(existingEnv)) {
301
+ if (value !== void 0) {
302
+ merged[key] = value;
303
+ }
304
+ }
305
+ for (const [key, value] of Object.entries(direnvVars)) {
306
+ merged[key] = value;
307
+ }
308
+ for (const [key, value] of Object.entries(overrideEnv)) {
309
+ merged[key] = value;
310
+ }
311
+ return merged;
312
+ }
313
+
221
314
  const claudeCliPath = resolve(join(projectPath(), "scripts", "claude_local_launcher.cjs"));
222
315
  async function claudeLocal(opts) {
223
316
  const projectDir = getProjectPath(opts.path);
@@ -259,6 +352,15 @@ async function claudeLocal(opts) {
259
352
  }
260
353
  };
261
354
  try {
355
+ const direnvVars = await loadDirenvEnvironment(opts.path);
356
+ if (Object.keys(direnvVars).length > 0) {
357
+ logger.debug(`[ClaudeLocal] Loaded ${Object.keys(direnvVars).length} direnv environment variables`);
358
+ }
359
+ const env = {
360
+ ...process.env,
361
+ ...direnvVars,
362
+ ...opts.claudeEnvVars
363
+ };
262
364
  process.stdin.pause();
263
365
  await new Promise((r, reject) => {
264
366
  const args = [];
@@ -278,10 +380,6 @@ async function claudeLocal(opts) {
278
380
  if (!claudeCliPath || !existsSync(claudeCliPath)) {
279
381
  throw new Error("Claude local launcher not found. Please ensure HAPPY_PROJECT_ROOT is set correctly for development.");
280
382
  }
281
- const env = {
282
- ...process.env,
283
- ...opts.claudeEnvVars
284
- };
285
383
  const child = spawn("node", [claudeCliPath, ...args], {
286
384
  stdio: ["inherit", "inherit", "inherit", "pipe"],
287
385
  signal: opts.abort,
@@ -1522,6 +1620,13 @@ async function claudeRemote(opts) {
1522
1620
  }
1523
1621
  }
1524
1622
  }
1623
+ const direnvVars = await loadDirenvEnvironment(opts.path);
1624
+ if (Object.keys(direnvVars).length > 0) {
1625
+ logger.debug(`[claudeRemote] Loaded ${Object.keys(direnvVars).length} direnv environment variables`);
1626
+ }
1627
+ Object.entries(direnvVars).forEach(([key, value]) => {
1628
+ process.env[key] = value;
1629
+ });
1525
1630
  if (opts.claudeEnvVars) {
1526
1631
  Object.entries(opts.claudeEnvVars).forEach(([key, value]) => {
1527
1632
  process.env[key] = value;
@@ -1628,12 +1733,32 @@ Echo message: ${echoMessage}` : "");
1628
1733
  }
1629
1734
  }
1630
1735
  };
1736
+ async function buildMessageContent(text, imageRefs) {
1737
+ if (!imageRefs || imageRefs.length === 0 || !opts.resolveImageRefs) {
1738
+ return text;
1739
+ }
1740
+ logger.debug(`[claudeRemote] Resolving ${imageRefs.length} image references`);
1741
+ const resolvedImages = await opts.resolveImageRefs(imageRefs);
1742
+ logger.debug(`[claudeRemote] Resolved ${resolvedImages.length} images`);
1743
+ if (resolvedImages.length === 0) {
1744
+ return text;
1745
+ }
1746
+ const content = [];
1747
+ for (const img of resolvedImages) {
1748
+ content.push(img);
1749
+ }
1750
+ if (text) {
1751
+ content.push({ type: "text", text });
1752
+ }
1753
+ return content;
1754
+ }
1631
1755
  let messages = new PushableAsyncIterable();
1756
+ const initialContent = await buildMessageContent(initial.message, initial.mode.imageRefs);
1632
1757
  messages.push({
1633
1758
  type: "user",
1634
1759
  message: {
1635
1760
  role: "user",
1636
- content: initial.message
1761
+ content: initialContent
1637
1762
  }
1638
1763
  });
1639
1764
  const response = query({
@@ -1674,7 +1799,8 @@ Echo message: ${echoMessage}` : "");
1674
1799
  return;
1675
1800
  }
1676
1801
  mode = next.mode;
1677
- messages.push({ type: "user", message: { role: "user", content: next.message } });
1802
+ const nextContent = await buildMessageContent(next.message, next.mode.imageRefs);
1803
+ messages.push({ type: "user", message: { role: "user", content: nextContent } });
1678
1804
  }
1679
1805
  if (message.type === "user") {
1680
1806
  const msg = message;
@@ -2780,6 +2906,18 @@ async function claudeRemoteLauncher(session) {
2780
2906
  isAborted: (toolCallId) => {
2781
2907
  return permissionHandler.isAborted(toolCallId);
2782
2908
  },
2909
+ resolveImageRefs: async (imageRefs) => {
2910
+ const resolved = [];
2911
+ for (const imageRef of imageRefs) {
2912
+ const image = await session.client.resolveImageRef(imageRef);
2913
+ if (image) {
2914
+ resolved.push(image);
2915
+ } else {
2916
+ logger.debug(`[remote]: Failed to resolve image ref: ${imageRef.blobId}`);
2917
+ }
2918
+ }
2919
+ return resolved;
2920
+ },
2783
2921
  nextMessage: async () => {
2784
2922
  if (pending) {
2785
2923
  let p = pending;
@@ -2885,6 +3023,16 @@ async function claudeRemoteLauncher(session) {
2885
3023
 
2886
3024
  async function loop(opts) {
2887
3025
  const logPath = logger.logFilePath;
3026
+ const sessionEnv = await loadAndMergeEnvironment(
3027
+ opts.path,
3028
+ process.env,
3029
+ opts.claudeEnvVars ?? {}
3030
+ );
3031
+ logger.debug(`[loop] Loaded session environment with ${Object.keys(sessionEnv).length} variables`);
3032
+ opts.session.rpcHandlerManager.setSessionContext({
3033
+ path: opts.path,
3034
+ env: sessionEnv
3035
+ });
2888
3036
  let session = new Session({
2889
3037
  api: opts.api,
2890
3038
  client: opts.session,
@@ -4808,6 +4956,27 @@ function registerKillSessionHandler(rpcHandlerManager, killThisHappy) {
4808
4956
  });
4809
4957
  }
4810
4958
 
4959
+ function extractTextFromContent(content) {
4960
+ if (!Array.isArray(content)) {
4961
+ if (content.type === "text") {
4962
+ return content.text;
4963
+ }
4964
+ return "";
4965
+ }
4966
+ const textParts = [];
4967
+ for (const block of content) {
4968
+ if (block.type === "text") {
4969
+ textParts.push(block.text);
4970
+ }
4971
+ }
4972
+ return textParts.join("\n");
4973
+ }
4974
+ function extractImageRefs(content) {
4975
+ if (!Array.isArray(content)) {
4976
+ return [];
4977
+ }
4978
+ return content.filter((block) => block.type === "image_ref");
4979
+ }
4811
4980
  async function runClaude(credentials, options = {}) {
4812
4981
  const workingDirectory = process.cwd();
4813
4982
  const sessionTag = randomUUID();
@@ -4974,7 +5143,12 @@ async function runClaude(credentials, options = {}) {
4974
5143
  } else {
4975
5144
  logger.debug(`[loop] User message received with no disallowed tools override, using current: ${currentDisallowedTools ? currentDisallowedTools.join(", ") : "none"}`);
4976
5145
  }
4977
- const specialCommand = parseSpecialCommand(message.content.text);
5146
+ const textContent = extractTextFromContent(message.content);
5147
+ const imageRefs = extractImageRefs(message.content);
5148
+ if (imageRefs.length > 0) {
5149
+ logger.debug(`[loop] User message contains ${imageRefs.length} image(s)`);
5150
+ }
5151
+ const specialCommand = parseSpecialCommand(textContent);
4978
5152
  if (specialCommand.type === "compact") {
4979
5153
  logger.debug("[start] Detected /compact command");
4980
5154
  const enhancedMode2 = {
@@ -4984,9 +5158,10 @@ async function runClaude(credentials, options = {}) {
4984
5158
  customSystemPrompt: messageCustomSystemPrompt,
4985
5159
  appendSystemPrompt: messageAppendSystemPrompt,
4986
5160
  allowedTools: messageAllowedTools,
4987
- disallowedTools: messageDisallowedTools
5161
+ disallowedTools: messageDisallowedTools,
5162
+ imageRefs: imageRefs.length > 0 ? imageRefs : void 0
4988
5163
  };
4989
- messageQueue.pushIsolateAndClear(specialCommand.originalMessage || message.content.text, enhancedMode2);
5164
+ messageQueue.pushIsolateAndClear(specialCommand.originalMessage || textContent, enhancedMode2);
4990
5165
  logger.debugLargeJson("[start] /compact command pushed to queue:", message);
4991
5166
  return;
4992
5167
  }
@@ -4999,9 +5174,10 @@ async function runClaude(credentials, options = {}) {
4999
5174
  customSystemPrompt: messageCustomSystemPrompt,
5000
5175
  appendSystemPrompt: messageAppendSystemPrompt,
5001
5176
  allowedTools: messageAllowedTools,
5002
- disallowedTools: messageDisallowedTools
5177
+ disallowedTools: messageDisallowedTools,
5178
+ imageRefs: imageRefs.length > 0 ? imageRefs : void 0
5003
5179
  };
5004
- messageQueue.pushIsolateAndClear(specialCommand.originalMessage || message.content.text, enhancedMode2);
5180
+ messageQueue.pushIsolateAndClear(specialCommand.originalMessage || textContent, enhancedMode2);
5005
5181
  logger.debugLargeJson("[start] /compact command pushed to queue:", message);
5006
5182
  return;
5007
5183
  }
@@ -5012,9 +5188,10 @@ async function runClaude(credentials, options = {}) {
5012
5188
  customSystemPrompt: messageCustomSystemPrompt,
5013
5189
  appendSystemPrompt: messageAppendSystemPrompt,
5014
5190
  allowedTools: messageAllowedTools,
5015
- disallowedTools: messageDisallowedTools
5191
+ disallowedTools: messageDisallowedTools,
5192
+ imageRefs: imageRefs.length > 0 ? imageRefs : void 0
5016
5193
  };
5017
- messageQueue.push(message.content.text, enhancedMode);
5194
+ messageQueue.push(textContent, enhancedMode);
5018
5195
  logger.debugLargeJson("User message pushed to queue:", message);
5019
5196
  });
5020
5197
  const cleanup = async () => {
@@ -6193,7 +6370,7 @@ async function handleConnectVendor(vendor, displayName) {
6193
6370
  return;
6194
6371
  } else if (subcommand === "codex") {
6195
6372
  try {
6196
- const { runCodex } = await import('./runCodex-B5ZlUUec.mjs');
6373
+ const { runCodex } = await import('./runCodex-Cxhf8ktE.mjs');
6197
6374
  let startedBy = void 0;
6198
6375
  for (let i = 1; i < args.length; i++) {
6199
6376
  if (args[i] === "--started-by") {
@@ -6238,7 +6415,7 @@ async function handleConnectVendor(vendor, displayName) {
6238
6415
  } else if (subcommand === "list") {
6239
6416
  try {
6240
6417
  const { credentials } = await authAndSetupMachineIfNeeded();
6241
- const { listSessions } = await import('./list-D_NjiLPx.mjs');
6418
+ const { listSessions } = await import('./list-B0EZS1nk.mjs');
6242
6419
  let sessionId;
6243
6420
  let titleFilter;
6244
6421
  let recentMsgs;
@@ -6340,7 +6517,7 @@ Examples:
6340
6517
  process.exit(1);
6341
6518
  }
6342
6519
  const { credentials } = await authAndSetupMachineIfNeeded();
6343
- const { promptSession } = await import('./prompt-CJh1Mo2A.mjs');
6520
+ const { promptSession } = await import('./prompt-COmkBtjd.mjs');
6344
6521
  await promptSession(credentials, sessionId, promptText, timeoutMinutes ?? void 0);
6345
6522
  } catch (error) {
6346
6523
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  require('chalk');
4
- require('./index-y8CVImEp.cjs');
5
- require('./types-CllU28mx.cjs');
4
+ require('./index-B8KwpPnt.cjs');
5
+ require('./types-0ILrOpLt.cjs');
6
6
  require('zod');
7
7
  require('node:child_process');
8
8
  require('node:os');
@@ -10,6 +10,10 @@ require('node:crypto');
10
10
  require('node:path');
11
11
  require('node:readline');
12
12
  require('node:fs');
13
+ require('child_process');
14
+ require('util');
15
+ require('fs');
16
+ require('path');
13
17
  require('node:fs/promises');
14
18
  require('fs/promises');
15
19
  require('ink');
@@ -20,10 +24,7 @@ require('node:events');
20
24
  require('socket.io-client');
21
25
  require('tweetnacl');
22
26
  require('expo-server-sdk');
23
- require('path');
24
27
  require('crypto');
25
- require('child_process');
26
- require('fs');
27
28
  require('ps-list');
28
29
  require('cross-spawn');
29
30
  require('os');
@@ -37,6 +38,5 @@ require('node:http');
37
38
  require('@modelcontextprotocol/sdk/server/streamableHttp.js');
38
39
  require('@stablelib/hex');
39
40
  require('http');
40
- require('util');
41
41
  require('url');
42
42
 
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import 'chalk';
2
- import './index-DNeoLdzx.mjs';
3
- import './types-D4_aCy-H.mjs';
2
+ import './index-BfGA--2C.mjs';
3
+ import './types-BmcSXhbq.mjs';
4
4
  import 'zod';
5
5
  import 'node:child_process';
6
6
  import 'node:os';
@@ -8,6 +8,10 @@ import 'node:crypto';
8
8
  import 'node:path';
9
9
  import 'node:readline';
10
10
  import 'node:fs';
11
+ import 'child_process';
12
+ import 'util';
13
+ import 'fs';
14
+ import 'path';
11
15
  import 'node:fs/promises';
12
16
  import 'fs/promises';
13
17
  import 'ink';
@@ -18,10 +22,7 @@ import 'node:events';
18
22
  import 'socket.io-client';
19
23
  import 'tweetnacl';
20
24
  import 'expo-server-sdk';
21
- import 'path';
22
25
  import 'crypto';
23
- import 'child_process';
24
- import 'fs';
25
26
  import 'ps-list';
26
27
  import 'cross-spawn';
27
28
  import 'os';
@@ -35,5 +36,4 @@ import 'node:http';
35
36
  import '@modelcontextprotocol/sdk/server/streamableHttp.js';
36
37
  import '@stablelib/hex';
37
38
  import 'http';
38
- import 'util';
39
39
  import 'url';
package/dist/lib.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var types = require('./types-CllU28mx.cjs');
3
+ var types = require('./types-0ILrOpLt.cjs');
4
4
  require('axios');
5
5
  require('chalk');
6
6
  require('fs');
package/dist/lib.d.cts CHANGED
@@ -291,6 +291,16 @@ type RawJSONLines = z.infer<typeof RawJSONLinesSchema>;
291
291
  /**
292
292
  * Common RPC types and interfaces for both session and machine clients
293
293
  */
294
+ /**
295
+ * Session context for RPC handlers
296
+ * Contains environment and path information for the current session
297
+ */
298
+ interface RpcSessionContext {
299
+ /** Working directory path for the session */
300
+ path: string;
301
+ /** Environment variables (includes direnv if available) */
302
+ env: Record<string, string>;
303
+ }
294
304
  /**
295
305
  * Generic RPC handler function type
296
306
  * @template TRequest - The request data type
@@ -326,7 +336,19 @@ declare class RpcHandlerManager {
326
336
  private readonly encryptionVariant;
327
337
  private readonly logger;
328
338
  private socket;
339
+ private sessionContext;
329
340
  constructor(config: RpcHandlerConfig);
341
+ /**
342
+ * Set the session context (path and environment)
343
+ * This should be called after direnv environment is loaded
344
+ * @param context - The session context with path and environment
345
+ */
346
+ setSessionContext(context: RpcSessionContext): void;
347
+ /**
348
+ * Get the current session context
349
+ * @returns The session context or null if not set
350
+ */
351
+ getSessionContext(): RpcSessionContext | null;
330
352
  /**
331
353
  * Register an RPC handler for a specific method
332
354
  * @param method - The method name (without prefix)
@@ -423,6 +445,30 @@ declare class ApiSessionClient extends EventEmitter {
423
445
  */
424
446
  flush(): Promise<void>;
425
447
  close(): Promise<void>;
448
+ /**
449
+ * Download and decrypt a blob from the server
450
+ * @param blobId - The blob ID to download
451
+ * @returns The decrypted binary data and metadata, or null if download/decryption fails
452
+ */
453
+ downloadBlob(blobId: string): Promise<{
454
+ data: Uint8Array;
455
+ mimeType: string;
456
+ size: number;
457
+ } | null>;
458
+ /**
459
+ * Convert an image_ref content block to a Claude API image content block
460
+ * Downloads, decrypts, and base64 encodes the image
461
+ * @param imageRef - The image reference content block
462
+ * @returns Claude API image content block, or null if conversion fails
463
+ */
464
+ resolveImageRef(imageRef: ImageRefContent): Promise<{
465
+ type: 'image';
466
+ source: {
467
+ type: 'base64';
468
+ media_type: string;
469
+ data: string;
470
+ };
471
+ } | null>;
426
472
  }
427
473
 
428
474
  type PermissionMode = 'default' | 'acceptEdits' | 'bypassPermissions' | 'plan';
@@ -505,9 +551,32 @@ type Machine = {
505
551
  daemonState: DaemonState | null;
506
552
  daemonStateVersion: number;
507
553
  };
554
+ /**
555
+ * Image reference content block for user messages (E2E encrypted images)
556
+ */
557
+ declare const ImageRefContentSchema: z.ZodObject<{
558
+ type: z.ZodLiteral<"image_ref">;
559
+ blobId: z.ZodString;
560
+ mimeType: z.ZodEnum<["image/jpeg", "image/png", "image/gif", "image/webp"]>;
561
+ width: z.ZodOptional<z.ZodNumber>;
562
+ height: z.ZodOptional<z.ZodNumber>;
563
+ }, "strip", z.ZodTypeAny, {
564
+ type: "image_ref";
565
+ blobId: string;
566
+ mimeType: "image/jpeg" | "image/png" | "image/gif" | "image/webp";
567
+ width?: number | undefined;
568
+ height?: number | undefined;
569
+ }, {
570
+ type: "image_ref";
571
+ blobId: string;
572
+ mimeType: "image/jpeg" | "image/png" | "image/gif" | "image/webp";
573
+ width?: number | undefined;
574
+ height?: number | undefined;
575
+ }>;
576
+ type ImageRefContent = z.infer<typeof ImageRefContentSchema>;
508
577
  declare const UserMessageSchema: z.ZodObject<{
509
578
  role: z.ZodLiteral<"user">;
510
- content: z.ZodObject<{
579
+ content: z.ZodUnion<[z.ZodObject<{
511
580
  type: z.ZodLiteral<"text">;
512
581
  text: z.ZodString;
513
582
  }, "strip", z.ZodTypeAny, {
@@ -516,7 +585,34 @@ declare const UserMessageSchema: z.ZodObject<{
516
585
  }, {
517
586
  type: "text";
518
587
  text: string;
519
- }>;
588
+ }>, z.ZodArray<z.ZodUnion<[z.ZodObject<{
589
+ type: z.ZodLiteral<"text">;
590
+ text: z.ZodString;
591
+ }, "strip", z.ZodTypeAny, {
592
+ type: "text";
593
+ text: string;
594
+ }, {
595
+ type: "text";
596
+ text: string;
597
+ }>, z.ZodObject<{
598
+ type: z.ZodLiteral<"image_ref">;
599
+ blobId: z.ZodString;
600
+ mimeType: z.ZodEnum<["image/jpeg", "image/png", "image/gif", "image/webp"]>;
601
+ width: z.ZodOptional<z.ZodNumber>;
602
+ height: z.ZodOptional<z.ZodNumber>;
603
+ }, "strip", z.ZodTypeAny, {
604
+ type: "image_ref";
605
+ blobId: string;
606
+ mimeType: "image/jpeg" | "image/png" | "image/gif" | "image/webp";
607
+ width?: number | undefined;
608
+ height?: number | undefined;
609
+ }, {
610
+ type: "image_ref";
611
+ blobId: string;
612
+ mimeType: "image/jpeg" | "image/png" | "image/gif" | "image/webp";
613
+ width?: number | undefined;
614
+ height?: number | undefined;
615
+ }>]>, "many">]>;
520
616
  localKey: z.ZodOptional<z.ZodString>;
521
617
  meta: z.ZodOptional<z.ZodObject<{
522
618
  sentFrom: z.ZodOptional<z.ZodString>;
@@ -550,7 +646,16 @@ declare const UserMessageSchema: z.ZodObject<{
550
646
  content: {
551
647
  type: "text";
552
648
  text: string;
553
- };
649
+ } | ({
650
+ type: "text";
651
+ text: string;
652
+ } | {
653
+ type: "image_ref";
654
+ blobId: string;
655
+ mimeType: "image/jpeg" | "image/png" | "image/gif" | "image/webp";
656
+ width?: number | undefined;
657
+ height?: number | undefined;
658
+ })[];
554
659
  role: "user";
555
660
  localKey?: string | undefined;
556
661
  meta?: {
@@ -567,7 +672,16 @@ declare const UserMessageSchema: z.ZodObject<{
567
672
  content: {
568
673
  type: "text";
569
674
  text: string;
570
- };
675
+ } | ({
676
+ type: "text";
677
+ text: string;
678
+ } | {
679
+ type: "image_ref";
680
+ blobId: string;
681
+ mimeType: "image/jpeg" | "image/png" | "image/gif" | "image/webp";
682
+ width?: number | undefined;
683
+ height?: number | undefined;
684
+ })[];
571
685
  role: "user";
572
686
  localKey?: string | undefined;
573
687
  meta?: {