very-happy-cli 0.2.78 → 0.2.79

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-BxZ-KvBy.cjs → AcpBackend-BuxJntPo.cjs} +1 -1
  2. package/dist/{AcpBackend-CDngyx5G.mjs → AcpBackend-DPcRh_3n.mjs} +1 -1
  3. package/dist/{AcpSessionManager-BWFM_8f9.cjs → AcpSessionManager-BOZPQZUQ.cjs} +1 -1
  4. package/dist/{AcpSessionManager-Dcq8dl4l.mjs → AcpSessionManager-DVGWPtBC.mjs} +1 -1
  5. package/dist/{config-Byay91xM.cjs → config-DB0v5eoc.cjs} +2 -2
  6. package/dist/{config-Co1Tpb5e.mjs → config-T7eM_8eT.mjs} +2 -2
  7. package/dist/{index-CuvhWx_d.cjs → index-BGvGqzc1.cjs} +252 -73
  8. package/dist/{index-DdOYA0qe.mjs → index-CuLe9SB7.mjs} +5 -5
  9. package/dist/{index-CkjEzh-Y.cjs → index-D_ZjCYNI.cjs} +4 -4
  10. package/dist/{index-w0zkr6EM.mjs → index-HYOkniru.mjs} +249 -70
  11. package/dist/index.cjs +2 -2
  12. package/dist/index.mjs +2 -2
  13. package/dist/{installTerminalHooks-nXjKPP3D.cjs → installTerminalHooks-CAViJyYh.cjs} +2 -2
  14. package/dist/{installTerminalHooks-DFmjn6EQ.mjs → installTerminalHooks-CPKThY28.mjs} +2 -2
  15. package/dist/lib.cjs +1 -1
  16. package/dist/lib.d.cts +8 -2
  17. package/dist/lib.d.mts +8 -2
  18. package/dist/lib.mjs +1 -1
  19. package/dist/{mcp-BreMIH5r.cjs → mcp-DhQcmKO7.cjs} +2 -2
  20. package/dist/{mcp-nlZLEkmO.mjs → mcp-DhUA22wj.mjs} +2 -2
  21. package/dist/{runGemini-DEZ0neEl.mjs → runGemini-BVxviS8T.mjs} +4 -4
  22. package/dist/{runGemini-by29Tp8r.cjs → runGemini-CfWCL9K7.cjs} +4 -4
  23. package/dist/{runOpenClaw-DyJQFzoX.mjs → runOpenClaw-DVTaZJtj.mjs} +3 -3
  24. package/dist/{runOpenClaw-DENpTXhw.cjs → runOpenClaw-kSy7Os3C.cjs} +3 -3
  25. package/dist/{send-pX36Sd4p.mjs → send-DjjJQXJt.mjs} +2 -2
  26. package/dist/{send-e6BSMl0m.cjs → send-jzwPToBN.cjs} +2 -2
  27. package/dist/{spawn-Da-94Ejo.mjs → spawn-DBpgsEkS.mjs} +2 -2
  28. package/dist/{spawn-C87d_KDj.cjs → spawn-DFnYIiKP.cjs} +2 -2
  29. package/dist/{types-Clmu74iY.mjs → types-BRDN6zN2.mjs} +25 -11
  30. package/dist/{types-Dua2iF5S.cjs → types-Dy7P_1bh.cjs} +26 -12
  31. package/package.json +7 -7
package/dist/lib.d.cts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as _anthropic_ai_claude_agent_sdk from '@anthropic-ai/claude-agent-sdk';
1
2
  import * as z from 'zod';
2
3
  import { z as z$1 } from 'zod';
3
4
  import { EventEmitter } from 'node:events';
@@ -67,6 +68,7 @@ declare const sessionEnvelopeSchema: z.ZodObject<{
67
68
  failed: "failed";
68
69
  cancelled: "cancelled";
69
70
  }>;
71
+ error: z.ZodOptional<z.ZodString>;
70
72
  costUsd: z.ZodOptional<z.ZodNumber>;
71
73
  durationMs: z.ZodOptional<z.ZodNumber>;
72
74
  numTurns: z.ZodOptional<z.ZodNumber>;
@@ -476,6 +478,8 @@ type AgentState$1 = {
476
478
  tool: string;
477
479
  arguments: any;
478
480
  createdAt: number;
481
+ kind?: 'tool' | 'elicitation' | 'user_dialog';
482
+ permissionSuggestions?: _anthropic_ai_claude_agent_sdk.PermissionUpdate[];
479
483
  };
480
484
  };
481
485
  completedRequests?: {
@@ -488,7 +492,7 @@ type AgentState$1 = {
488
492
  reason?: string;
489
493
  mode?: PermissionMode;
490
494
  decision?: 'approved' | 'approved_for_session' | 'denied' | 'abort';
491
- allowTools?: string[];
495
+ allowedTools?: string[];
492
496
  };
493
497
  };
494
498
  };
@@ -734,7 +738,9 @@ declare class ApiSessionClient extends EventEmitter {
734
738
  * unique constraint swallow every envelope after the first. */
735
739
  localIdFor?: (envelopeIndex: number) => string;
736
740
  }): void;
737
- closeClaudeSessionTurn(status?: SessionTurnEndStatus): void;
741
+ closeClaudeSessionTurn(status?: SessionTurnEndStatus, meta?: {
742
+ error?: string;
743
+ }): void;
738
744
  sendCodexMessage(body: any): void;
739
745
  private enqueueSessionProtocolEnvelope;
740
746
  sendSessionProtocolMessage(envelope: SessionEnvelope, localId?: string): void;
package/dist/lib.d.mts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as _anthropic_ai_claude_agent_sdk from '@anthropic-ai/claude-agent-sdk';
1
2
  import * as z from 'zod';
2
3
  import { z as z$1 } from 'zod';
3
4
  import { EventEmitter } from 'node:events';
@@ -67,6 +68,7 @@ declare const sessionEnvelopeSchema: z.ZodObject<{
67
68
  failed: "failed";
68
69
  cancelled: "cancelled";
69
70
  }>;
71
+ error: z.ZodOptional<z.ZodString>;
70
72
  costUsd: z.ZodOptional<z.ZodNumber>;
71
73
  durationMs: z.ZodOptional<z.ZodNumber>;
72
74
  numTurns: z.ZodOptional<z.ZodNumber>;
@@ -476,6 +478,8 @@ type AgentState$1 = {
476
478
  tool: string;
477
479
  arguments: any;
478
480
  createdAt: number;
481
+ kind?: 'tool' | 'elicitation' | 'user_dialog';
482
+ permissionSuggestions?: _anthropic_ai_claude_agent_sdk.PermissionUpdate[];
479
483
  };
480
484
  };
481
485
  completedRequests?: {
@@ -488,7 +492,7 @@ type AgentState$1 = {
488
492
  reason?: string;
489
493
  mode?: PermissionMode;
490
494
  decision?: 'approved' | 'approved_for_session' | 'denied' | 'abort';
491
- allowTools?: string[];
495
+ allowedTools?: string[];
492
496
  };
493
497
  };
494
498
  };
@@ -734,7 +738,9 @@ declare class ApiSessionClient extends EventEmitter {
734
738
  * unique constraint swallow every envelope after the first. */
735
739
  localIdFor?: (envelopeIndex: number) => string;
736
740
  }): void;
737
- closeClaudeSessionTurn(status?: SessionTurnEndStatus): void;
741
+ closeClaudeSessionTurn(status?: SessionTurnEndStatus, meta?: {
742
+ error?: string;
743
+ }): void;
738
744
  sendCodexMessage(body: any): void;
739
745
  private enqueueSessionProtocolEnvelope;
740
746
  sendSessionProtocolMessage(envelope: SessionEnvelope, localId?: string): void;
package/dist/lib.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-Clmu74iY.mjs';
1
+ export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-BRDN6zN2.mjs';
2
2
  import 'axios';
3
3
  import 'chalk';
4
4
  import 'node:util';
@@ -3,9 +3,9 @@
3
3
  var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
4
4
  var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
5
5
  var z = require('zod');
6
- var index = require('./index-CuvhWx_d.cjs');
6
+ var index = require('./index-BGvGqzc1.cjs');
7
7
  var limits = require('./limits-KdWKmwtH.cjs');
8
- var persistence = require('./types-Dua2iF5S.cjs');
8
+ var persistence = require('./types-Dy7P_1bh.cjs');
9
9
  require('chalk');
10
10
  require('node:os');
11
11
  require('node:crypto');
@@ -1,9 +1,9 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
3
  import { z } from 'zod';
4
- import { p as pushClipboardViaDaemon } from './index-w0zkr6EM.mjs';
4
+ import { p as pushClipboardViaDaemon } from './index-HYOkniru.mjs';
5
5
  import { C as CLIPBOARD_TOOL_NAME, a as CLIPBOARD_TOOL_TITLE, b as CLIPBOARD_TOOL_DESCRIPTION, c as CLIPBOARD_MAX_BYTES } from './limits-CwFb5S2b.mjs';
6
- import { l as logger } from './types-Clmu74iY.mjs';
6
+ import { l as logger } from './types-BRDN6zN2.mjs';
7
7
  import 'chalk';
8
8
  import 'node:os';
9
9
  import 'node:crypto';
@@ -2,10 +2,10 @@ import { useStdout, useInput, Box, Text, render } from 'ink';
2
2
  import React, { useState, useRef, useEffect, useCallback } from 'react';
3
3
  import { randomUUID } from 'node:crypto';
4
4
  import { join } from 'node:path';
5
- import { l as logger, h as connectionState, A as ApiClient, i as readSettings, e as errorLogMetadata, j as encodeBase64, p as projectPath, d as contentLogMetadata } from './types-Clmu74iY.mjs';
6
- import { g as GEMINI_API_KEY_ENV, j as GOOGLE_API_KEY_ENV, G as GEMINI_MODEL_ENV, B as BasePermissionHandler, k as BaseReasoningProcessor, i as initialMachineMetadata, d as createSessionMetadata, e as setupOfflineReconnection, n as notifyDaemonSessionStarted, M as MessageQueue2, h as hashObject, l as MessageBuffer, C as CHANGE_TITLE_INSTRUCTION, r as registerKillSessionHandler, f as startHappyServer } from './index-w0zkr6EM.mjs';
7
- import { A as AcpBackend } from './AcpBackend-CDngyx5G.mjs';
8
- import { readGeminiLocalConfig, determineGeminiModel, getGeminiModelSource, getInitialGeminiModel, saveGeminiModelToConfig } from './config-Co1Tpb5e.mjs';
5
+ import { l as logger, h as connectionState, A as ApiClient, i as readSettings, e as errorLogMetadata, j as encodeBase64, p as projectPath, d as contentLogMetadata } from './types-BRDN6zN2.mjs';
6
+ import { g as GEMINI_API_KEY_ENV, j as GOOGLE_API_KEY_ENV, G as GEMINI_MODEL_ENV, B as BasePermissionHandler, k as BaseReasoningProcessor, i as initialMachineMetadata, d as createSessionMetadata, e as setupOfflineReconnection, n as notifyDaemonSessionStarted, M as MessageQueue2, h as hashObject, l as MessageBuffer, C as CHANGE_TITLE_INSTRUCTION, r as registerKillSessionHandler, f as startHappyServer } from './index-HYOkniru.mjs';
7
+ import { A as AcpBackend } from './AcpBackend-DPcRh_3n.mjs';
8
+ import { readGeminiLocalConfig, determineGeminiModel, getGeminiModelSource, getInitialGeminiModel, saveGeminiModelToConfig } from './config-T7eM_8eT.mjs';
9
9
  import 'axios';
10
10
  import 'chalk';
11
11
  import 'node:util';
@@ -4,10 +4,10 @@ var ink = require('ink');
4
4
  var React = require('react');
5
5
  var node_crypto = require('node:crypto');
6
6
  var path = require('node:path');
7
- var persistence = require('./types-Dua2iF5S.cjs');
8
- var index = require('./index-CuvhWx_d.cjs');
9
- var AcpBackend = require('./AcpBackend-BxZ-KvBy.cjs');
10
- var config = require('./config-Byay91xM.cjs');
7
+ var persistence = require('./types-Dy7P_1bh.cjs');
8
+ var index = require('./index-BGvGqzc1.cjs');
9
+ var AcpBackend = require('./AcpBackend-BuxJntPo.cjs');
10
+ var config = require('./config-DB0v5eoc.cjs');
11
11
  require('axios');
12
12
  require('chalk');
13
13
  require('node:util');
@@ -3,9 +3,9 @@ import { execFileSync } from 'node:child_process';
3
3
  import os from 'node:os';
4
4
  import { existsSync, readFileSync } from 'node:fs';
5
5
  import { join } from 'node:path';
6
- import { k as ensurePrivateDirectorySync, m as hardenPrivateFileSync, w as writePrivateFileSync, e as errorLogMetadata, d as contentLogMetadata, h as connectionState, A as ApiClient, i as readSettings, j as encodeBase64, l as logger, c as configuration } from './types-Clmu74iY.mjs';
7
- import { A as AcpSessionManager } from './AcpSessionManager-Dcq8dl4l.mjs';
8
- import { i as initialMachineMetadata, d as createSessionMetadata, e as setupOfflineReconnection, n as notifyDaemonSessionStarted, M as MessageQueue2, r as registerKillSessionHandler } from './index-w0zkr6EM.mjs';
6
+ import { k as ensurePrivateDirectorySync, m as hardenPrivateFileSync, w as writePrivateFileSync, e as errorLogMetadata, d as contentLogMetadata, h as connectionState, A as ApiClient, i as readSettings, j as encodeBase64, l as logger, c as configuration } from './types-BRDN6zN2.mjs';
7
+ import { A as AcpSessionManager } from './AcpSessionManager-DVGWPtBC.mjs';
8
+ import { i as initialMachineMetadata, d as createSessionMetadata, e as setupOfflineReconnection, n as notifyDaemonSessionStarted, M as MessageQueue2, r as registerKillSessionHandler } from './index-HYOkniru.mjs';
9
9
  import WebSocket from 'ws';
10
10
  import * as ed from '@noble/ed25519';
11
11
  import { sha512 } from '@noble/hashes/sha2.js';
@@ -5,9 +5,9 @@ var node_child_process = require('node:child_process');
5
5
  var os = require('node:os');
6
6
  var node_fs = require('node:fs');
7
7
  var path = require('node:path');
8
- var persistence = require('./types-Dua2iF5S.cjs');
9
- var AcpSessionManager = require('./AcpSessionManager-BWFM_8f9.cjs');
10
- var index = require('./index-CuvhWx_d.cjs');
8
+ var persistence = require('./types-Dy7P_1bh.cjs');
9
+ var AcpSessionManager = require('./AcpSessionManager-BOZPQZUQ.cjs');
10
+ var index = require('./index-BGvGqzc1.cjs');
11
11
  var WebSocket = require('ws');
12
12
  var ed = require('@noble/ed25519');
13
13
  var sha2_js = require('@noble/hashes/sha2.js');
@@ -1,8 +1,8 @@
1
1
  import chalk from 'chalk';
2
2
  import { readFileSync } from 'node:fs';
3
3
  import { resolve } from 'node:path';
4
- import { r as readPersistedSessions, c as configuration } from './types-Clmu74iY.mjs';
5
- import { b as sendUserMessage, a as sessionWebUrl } from './index-w0zkr6EM.mjs';
4
+ import { r as readPersistedSessions, c as configuration } from './types-BRDN6zN2.mjs';
5
+ import { b as sendUserMessage, a as sessionWebUrl } from './index-HYOkniru.mjs';
6
6
  import 'axios';
7
7
  import 'node:util';
8
8
  import 'node:os';
@@ -3,8 +3,8 @@
3
3
  var chalk = require('chalk');
4
4
  var node_fs = require('node:fs');
5
5
  var path = require('node:path');
6
- var persistence = require('./types-Dua2iF5S.cjs');
7
- var index = require('./index-CuvhWx_d.cjs');
6
+ var persistence = require('./types-Dy7P_1bh.cjs');
7
+ var index = require('./index-BGvGqzc1.cjs');
8
8
  require('axios');
9
9
  require('node:util');
10
10
  require('node:os');
@@ -1,8 +1,8 @@
1
1
  import chalk from 'chalk';
2
2
  import { readFileSync, statSync } from 'node:fs';
3
3
  import { resolve } from 'node:path';
4
- import { c as checkIfDaemonRunningAndCleanupStaleState, s as spawnDaemonSession, a as sessionWebUrl, w as waitForSessionKey, b as sendUserMessage } from './index-w0zkr6EM.mjs';
5
- import { l as logger } from './types-Clmu74iY.mjs';
4
+ import { c as checkIfDaemonRunningAndCleanupStaleState, s as spawnDaemonSession, a as sessionWebUrl, w as waitForSessionKey, b as sendUserMessage } from './index-HYOkniru.mjs';
5
+ import { l as logger } from './types-BRDN6zN2.mjs';
6
6
  import 'node:os';
7
7
  import 'node:crypto';
8
8
  import 'cross-spawn';
@@ -3,8 +3,8 @@
3
3
  var chalk = require('chalk');
4
4
  var node_fs = require('node:fs');
5
5
  var path = require('node:path');
6
- var index = require('./index-CuvhWx_d.cjs');
7
- var persistence = require('./types-Dua2iF5S.cjs');
6
+ var index = require('./index-BGvGqzc1.cjs');
7
+ var persistence = require('./types-Dy7P_1bh.cjs');
8
8
  require('node:os');
9
9
  require('node:crypto');
10
10
  require('cross-spawn');
@@ -29,7 +29,7 @@ import { SandboxManager } from '@anthropic-ai/sandbox-runtime';
29
29
  import { Expo } from 'expo-server-sdk';
30
30
 
31
31
  var name = "very-happy-cli";
32
- var version = "0.2.78";
32
+ var version = "0.2.79";
33
33
  var description = "Remote multi-agent workspace CLI with deep Claude integration, native terminal streaming, and self-hosting.";
34
34
  var author = "Kirill Dubovitskiy";
35
35
  var contributors = [
@@ -142,12 +142,12 @@ var dependencies = {
142
142
  zod: "^4.0.0"
143
143
  };
144
144
  var optionalDependencies = {
145
- "very-happy-tools-arm64-darwin": "0.2.78",
146
- "very-happy-tools-x64-darwin": "0.2.78",
147
- "very-happy-tools-arm64-linux": "0.2.78",
148
- "very-happy-tools-x64-linux": "0.2.78",
149
- "very-happy-tools-arm64-win32": "0.2.78",
150
- "very-happy-tools-x64-win32": "0.2.78"
145
+ "very-happy-tools-arm64-darwin": "0.2.79",
146
+ "very-happy-tools-x64-darwin": "0.2.79",
147
+ "very-happy-tools-arm64-linux": "0.2.79",
148
+ "very-happy-tools-x64-linux": "0.2.79",
149
+ "very-happy-tools-arm64-win32": "0.2.79",
150
+ "very-happy-tools-x64-win32": "0.2.79"
151
151
  };
152
152
  var devDependencies = {
153
153
  "@slopus/happy-wire": "workspace:*",
@@ -672,6 +672,9 @@ const sessionTurnUsageSchema = z.object({
672
672
  const sessionTurnEndEventSchema = z.object({
673
673
  t: z.literal("turn-end"),
674
674
  status: sessionTurnEndStatusSchema,
675
+ // Human-readable SDK failure detail. Optional for backward compatibility;
676
+ // successful and cancelled turns normally omit it.
677
+ error: z.string().optional(),
675
678
  // Optional per-turn metadata sourced from the SDK result message. Present
676
679
  // only on turns ended by a result event; absent on lazily-closed turns.
677
680
  costUsd: z.number().optional(),
@@ -2447,12 +2450,14 @@ function closeTurn(state, status, envelopes, meta) {
2447
2450
  envelopes.push(createEnvelope("agent", {
2448
2451
  t: "turn-end",
2449
2452
  status,
2453
+ ...meta?.error ? { error: meta.error } : {},
2450
2454
  ...typeof meta?.costUsd === "number" ? { costUsd: meta.costUsd } : {},
2451
2455
  ...typeof meta?.durationMs === "number" ? { durationMs: meta.durationMs } : {},
2452
2456
  ...typeof meta?.numTurns === "number" ? { numTurns: meta.numTurns } : {},
2453
2457
  ...meta?.usage ? { usage: meta.usage } : {}
2454
2458
  }, { turn: state.currentTurnId }));
2455
2459
  state.currentTurnId = null;
2460
+ state.pendingAssistantError = void 0;
2456
2461
  clearSubagentTracking(state);
2457
2462
  }
2458
2463
  function toolTitle(name, input) {
@@ -2473,9 +2478,9 @@ function toToolArgs(input) {
2473
2478
  }
2474
2479
  return { input };
2475
2480
  }
2476
- function closeClaudeTurnWithStatus(state, status) {
2481
+ function closeClaudeTurnWithStatus(state, status, meta) {
2477
2482
  const envelopes = [];
2478
- closeTurn(state, status, envelopes);
2483
+ closeTurn(state, status, envelopes, meta);
2479
2484
  return {
2480
2485
  currentTurnId: state.currentTurnId,
2481
2486
  envelopes
@@ -2516,6 +2521,10 @@ function mapClaudeLogMessageToSessionEnvelopesInternal(message, state) {
2516
2521
  };
2517
2522
  }
2518
2523
  if (message.type === "assistant") {
2524
+ const assistantError = message.error;
2525
+ if (!message.isSidechain && typeof assistantError === "string" && assistantError.trim()) {
2526
+ state.pendingAssistantError = assistantError.trim();
2527
+ }
2519
2528
  const turnId = ensureTurn(state, envelopes);
2520
2529
  maybeEmitSubagentStart(state, turnId, subagent, envelopes);
2521
2530
  const usage = pickAssistantUsage(message);
@@ -2637,6 +2646,10 @@ function mapClaudeLogMessageToSessionEnvelopesInternal(message, state) {
2637
2646
  if (message.type === "result") {
2638
2647
  const raw = message;
2639
2648
  const status = raw.is_error === true ? "failed" : "completed";
2649
+ const error = status === "failed" ? raw.errors?.filter((item) => typeof item === "string" && item.trim()).join("\n") || state.pendingAssistantError || raw.subtype || "Claude turn failed" : void 0;
2650
+ if (status === "failed" && !state.currentTurnId) {
2651
+ ensureTurn(state, envelopes);
2652
+ }
2640
2653
  const usage = raw.usage && typeof raw.usage.input_tokens === "number" && typeof raw.usage.output_tokens === "number" ? {
2641
2654
  input_tokens: raw.usage.input_tokens,
2642
2655
  output_tokens: raw.usage.output_tokens,
@@ -2644,6 +2657,7 @@ function mapClaudeLogMessageToSessionEnvelopesInternal(message, state) {
2644
2657
  ...typeof raw.usage.cache_read_input_tokens === "number" ? { cache_read_input_tokens: raw.usage.cache_read_input_tokens } : {}
2645
2658
  } : void 0;
2646
2659
  closeTurn(state, status, envelopes, {
2660
+ error,
2647
2661
  costUsd: typeof raw.total_cost_usd === "number" ? raw.total_cost_usd : void 0,
2648
2662
  durationMs: typeof raw.duration_ms === "number" ? raw.duration_ms : void 0,
2649
2663
  numTurns: typeof raw.num_turns === "number" ? raw.num_turns : void 0,
@@ -3379,9 +3393,9 @@ class ApiSessionClient extends EventEmitter {
3379
3393
  }));
3380
3394
  }
3381
3395
  }
3382
- closeClaudeSessionTurn(status = "completed") {
3396
+ closeClaudeSessionTurn(status = "completed", meta) {
3383
3397
  this.emit("turn-ended", status);
3384
- const mapped = closeClaudeTurnWithStatus(this.claudeSessionProtocolState, status);
3398
+ const mapped = closeClaudeTurnWithStatus(this.claudeSessionProtocolState, status, meta);
3385
3399
  this.claudeSessionProtocolState.currentTurnId = mapped.currentTurnId;
3386
3400
  for (const envelope of mapped.envelopes) {
3387
3401
  this.sendSessionProtocolMessage(envelope);
@@ -51,7 +51,7 @@ var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
51
51
  var pty__namespace = /*#__PURE__*/_interopNamespaceDefault(pty);
52
52
 
53
53
  var name = "very-happy-cli";
54
- var version = "0.2.78";
54
+ var version = "0.2.79";
55
55
  var description = "Remote multi-agent workspace CLI with deep Claude integration, native terminal streaming, and self-hosting.";
56
56
  var author = "Kirill Dubovitskiy";
57
57
  var contributors = [
@@ -164,12 +164,12 @@ var dependencies = {
164
164
  zod: "^4.0.0"
165
165
  };
166
166
  var optionalDependencies = {
167
- "very-happy-tools-arm64-darwin": "0.2.78",
168
- "very-happy-tools-x64-darwin": "0.2.78",
169
- "very-happy-tools-arm64-linux": "0.2.78",
170
- "very-happy-tools-x64-linux": "0.2.78",
171
- "very-happy-tools-arm64-win32": "0.2.78",
172
- "very-happy-tools-x64-win32": "0.2.78"
167
+ "very-happy-tools-arm64-darwin": "0.2.79",
168
+ "very-happy-tools-x64-darwin": "0.2.79",
169
+ "very-happy-tools-arm64-linux": "0.2.79",
170
+ "very-happy-tools-x64-linux": "0.2.79",
171
+ "very-happy-tools-arm64-win32": "0.2.79",
172
+ "very-happy-tools-x64-win32": "0.2.79"
173
173
  };
174
174
  var devDependencies = {
175
175
  "@slopus/happy-wire": "workspace:*",
@@ -694,6 +694,9 @@ const sessionTurnUsageSchema = z__namespace.object({
694
694
  const sessionTurnEndEventSchema = z__namespace.object({
695
695
  t: z__namespace.literal("turn-end"),
696
696
  status: sessionTurnEndStatusSchema,
697
+ // Human-readable SDK failure detail. Optional for backward compatibility;
698
+ // successful and cancelled turns normally omit it.
699
+ error: z__namespace.string().optional(),
697
700
  // Optional per-turn metadata sourced from the SDK result message. Present
698
701
  // only on turns ended by a result event; absent on lazily-closed turns.
699
702
  costUsd: z__namespace.number().optional(),
@@ -1477,7 +1480,7 @@ class RpcHandlerManager {
1477
1480
  }
1478
1481
  }
1479
1482
 
1480
- const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-Dua2iF5S.cjs', document.baseURI).href))));
1483
+ const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-Dy7P_1bh.cjs', document.baseURI).href))));
1481
1484
  function projectPath() {
1482
1485
  const path = path$1.resolve(__dirname$1, "..");
1483
1486
  return path;
@@ -2469,12 +2472,14 @@ function closeTurn(state, status, envelopes, meta) {
2469
2472
  envelopes.push(createEnvelope("agent", {
2470
2473
  t: "turn-end",
2471
2474
  status,
2475
+ ...meta?.error ? { error: meta.error } : {},
2472
2476
  ...typeof meta?.costUsd === "number" ? { costUsd: meta.costUsd } : {},
2473
2477
  ...typeof meta?.durationMs === "number" ? { durationMs: meta.durationMs } : {},
2474
2478
  ...typeof meta?.numTurns === "number" ? { numTurns: meta.numTurns } : {},
2475
2479
  ...meta?.usage ? { usage: meta.usage } : {}
2476
2480
  }, { turn: state.currentTurnId }));
2477
2481
  state.currentTurnId = null;
2482
+ state.pendingAssistantError = void 0;
2478
2483
  clearSubagentTracking(state);
2479
2484
  }
2480
2485
  function toolTitle(name, input) {
@@ -2495,9 +2500,9 @@ function toToolArgs(input) {
2495
2500
  }
2496
2501
  return { input };
2497
2502
  }
2498
- function closeClaudeTurnWithStatus(state, status) {
2503
+ function closeClaudeTurnWithStatus(state, status, meta) {
2499
2504
  const envelopes = [];
2500
- closeTurn(state, status, envelopes);
2505
+ closeTurn(state, status, envelopes, meta);
2501
2506
  return {
2502
2507
  currentTurnId: state.currentTurnId,
2503
2508
  envelopes
@@ -2538,6 +2543,10 @@ function mapClaudeLogMessageToSessionEnvelopesInternal(message, state) {
2538
2543
  };
2539
2544
  }
2540
2545
  if (message.type === "assistant") {
2546
+ const assistantError = message.error;
2547
+ if (!message.isSidechain && typeof assistantError === "string" && assistantError.trim()) {
2548
+ state.pendingAssistantError = assistantError.trim();
2549
+ }
2541
2550
  const turnId = ensureTurn(state, envelopes);
2542
2551
  maybeEmitSubagentStart(state, turnId, subagent, envelopes);
2543
2552
  const usage = pickAssistantUsage(message);
@@ -2659,6 +2668,10 @@ function mapClaudeLogMessageToSessionEnvelopesInternal(message, state) {
2659
2668
  if (message.type === "result") {
2660
2669
  const raw = message;
2661
2670
  const status = raw.is_error === true ? "failed" : "completed";
2671
+ const error = status === "failed" ? raw.errors?.filter((item) => typeof item === "string" && item.trim()).join("\n") || state.pendingAssistantError || raw.subtype || "Claude turn failed" : void 0;
2672
+ if (status === "failed" && !state.currentTurnId) {
2673
+ ensureTurn(state, envelopes);
2674
+ }
2662
2675
  const usage = raw.usage && typeof raw.usage.input_tokens === "number" && typeof raw.usage.output_tokens === "number" ? {
2663
2676
  input_tokens: raw.usage.input_tokens,
2664
2677
  output_tokens: raw.usage.output_tokens,
@@ -2666,6 +2679,7 @@ function mapClaudeLogMessageToSessionEnvelopesInternal(message, state) {
2666
2679
  ...typeof raw.usage.cache_read_input_tokens === "number" ? { cache_read_input_tokens: raw.usage.cache_read_input_tokens } : {}
2667
2680
  } : void 0;
2668
2681
  closeTurn(state, status, envelopes, {
2682
+ error,
2669
2683
  costUsd: typeof raw.total_cost_usd === "number" ? raw.total_cost_usd : void 0,
2670
2684
  durationMs: typeof raw.duration_ms === "number" ? raw.duration_ms : void 0,
2671
2685
  numTurns: typeof raw.num_turns === "number" ? raw.num_turns : void 0,
@@ -3401,9 +3415,9 @@ class ApiSessionClient extends node_events.EventEmitter {
3401
3415
  }));
3402
3416
  }
3403
3417
  }
3404
- closeClaudeSessionTurn(status = "completed") {
3418
+ closeClaudeSessionTurn(status = "completed", meta) {
3405
3419
  this.emit("turn-ended", status);
3406
- const mapped = closeClaudeTurnWithStatus(this.claudeSessionProtocolState, status);
3420
+ const mapped = closeClaudeTurnWithStatus(this.claudeSessionProtocolState, status, meta);
3407
3421
  this.claudeSessionProtocolState.currentTurnId = mapped.currentTurnId;
3408
3422
  for (const envelope of mapped.envelopes) {
3409
3423
  this.sendSessionProtocolMessage(envelope);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "very-happy-cli",
3
- "version": "0.2.78",
3
+ "version": "0.2.79",
4
4
  "description": "Remote multi-agent workspace CLI with deep Claude integration, native terminal streaming, and self-hosting.",
5
5
  "author": "Kirill Dubovitskiy",
6
6
  "contributors": [
@@ -113,12 +113,12 @@
113
113
  "zod": "^4.0.0"
114
114
  },
115
115
  "optionalDependencies": {
116
- "very-happy-tools-arm64-darwin": "0.2.78",
117
- "very-happy-tools-x64-darwin": "0.2.78",
118
- "very-happy-tools-arm64-linux": "0.2.78",
119
- "very-happy-tools-x64-linux": "0.2.78",
120
- "very-happy-tools-arm64-win32": "0.2.78",
121
- "very-happy-tools-x64-win32": "0.2.78"
116
+ "very-happy-tools-arm64-darwin": "0.2.79",
117
+ "very-happy-tools-x64-darwin": "0.2.79",
118
+ "very-happy-tools-arm64-linux": "0.2.79",
119
+ "very-happy-tools-x64-linux": "0.2.79",
120
+ "very-happy-tools-arm64-win32": "0.2.79",
121
+ "very-happy-tools-x64-win32": "0.2.79"
122
122
  },
123
123
  "devDependencies": {
124
124
  "@slopus/happy-wire": "workspace:*",