very-happy-cli 0.2.119 → 0.2.121
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.
- package/dist/{AcpBackend-DpsLyp2y.mjs → AcpBackend-BxvQ6O4k.mjs} +1 -1
- package/dist/{AcpBackend-BpwOAcgu.cjs → AcpBackend-Cdj56ZfU.cjs} +1 -1
- package/dist/{AcpSessionManager-Ck6heffK.cjs → AcpSessionManager-DahCU78z.cjs} +51 -11
- package/dist/{AcpSessionManager-CM0PcgwO.mjs → AcpSessionManager-DlWlQVhw.mjs} +51 -11
- package/dist/{config-CtQJKe8h.cjs → config-DxOhdFEx.cjs} +2 -2
- package/dist/{config-DpE-aSHW.mjs → config-osO37dR1.mjs} +2 -2
- package/dist/{index-BITXLEZo.mjs → index-BcwAnM9k.mjs} +25 -11
- package/dist/{index-CK-yge8m.cjs → index-Bv53Zygv.cjs} +24 -10
- package/dist/{index-CRhOD3CQ.cjs → index-DObePs_K.cjs} +176 -54
- package/dist/{index-CGpkGfDj.mjs → index-DtZFY8aS.mjs} +2 -2
- package/dist/{index-DNXCQz_A.mjs → index-Iz-M3qbz.mjs} +172 -51
- package/dist/{index-DY7g3UWq.cjs → index-Vjo1jIJH.cjs} +2 -2
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{installTerminalHooks-Dmr3JUJR.mjs → installTerminalHooks-Bq11vOqF.mjs} +2 -2
- package/dist/{installTerminalHooks-BOOg7NNs.cjs → installTerminalHooks-DehsXLmV.cjs} +2 -2
- package/dist/lib.cjs +1 -1
- package/dist/lib.d.cts +25 -1
- package/dist/lib.d.mts +25 -1
- package/dist/lib.mjs +1 -1
- package/dist/{mcp-D4N7yn98.mjs → mcp-Bx1B3uny.mjs} +2 -2
- package/dist/{mcp-CxIk4Mes.cjs → mcp-Cpx9Qlch.cjs} +2 -2
- package/dist/{runGemini-Bexbg8pA.mjs → runGemini-CMgudbJs.mjs} +9 -5
- package/dist/{runGemini-TbGYRy0V.cjs → runGemini-DI8DipUx.cjs} +9 -5
- package/dist/{runOpenClaw-B-TV4EkO.cjs → runOpenClaw-CetdjTl-.cjs} +3 -3
- package/dist/{runOpenClaw-BpoIQWbe.mjs → runOpenClaw-DR3fLtVf.mjs} +3 -3
- package/dist/{send-U9UJvqNA.cjs → send-Cq0NZCn8.cjs} +2 -2
- package/dist/{send-z5SeDtKA.mjs → send-M4b_hD7t.mjs} +2 -2
- package/dist/{sessions-DNALvNe8.mjs → sessions-CelkWhqX.mjs} +11 -4
- package/dist/{sessions-BAZGALtl.cjs → sessions-DW4lrLOp.cjs} +11 -4
- package/dist/{spawn-CsV0SKkw.mjs → spawn-C4fF0q3Z.mjs} +2 -2
- package/dist/{spawn-dBxu-RAv.cjs → spawn-D3cwBlWI.cjs} +2 -2
- package/dist/{types-Bw_6p8NP.cjs → types-COOYpI8_.cjs} +176 -33
- package/dist/{types-DdyNuB7D.mjs → types-P2cJWD0E.mjs} +174 -33
- package/package.json +7 -7
|
@@ -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, k as setTerminalTitleViaDaemon, m as registerAssistantSessionTools } from './index-
|
|
4
|
+
import { p as pushClipboardViaDaemon, k as setTerminalTitleViaDaemon, m as registerAssistantSessionTools } from './index-Iz-M3qbz.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-
|
|
6
|
+
import { l as logger } from './types-P2cJWD0E.mjs';
|
|
7
7
|
import 'node:fs/promises';
|
|
8
8
|
import 'node:os';
|
|
9
9
|
import 'node:crypto';
|
|
@@ -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-
|
|
6
|
+
var index = require('./index-DObePs_K.cjs');
|
|
7
7
|
var limits = require('./limits-KdWKmwtH.cjs');
|
|
8
|
-
var persistence = require('./types-
|
|
8
|
+
var persistence = require('./types-COOYpI8_.cjs');
|
|
9
9
|
require('node:fs/promises');
|
|
10
10
|
require('node:os');
|
|
11
11
|
require('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, d as connectionState, A as ApiClient, e as readSettings, h as errorLogMetadata, f as encodeBase64, p as projectPath, g as contentLogMetadata } from './types-
|
|
6
|
-
import {
|
|
7
|
-
import { A as AcpBackend } from './AcpBackend-
|
|
8
|
-
import { readGeminiLocalConfig, determineGeminiModel, getGeminiModelSource, getInitialGeminiModel, saveGeminiModelToConfig } from './config-
|
|
5
|
+
import { l as logger, d as connectionState, A as ApiClient, e as readSettings, h as errorLogMetadata, f as encodeBase64, p as projectPath, g as contentLogMetadata } from './types-P2cJWD0E.mjs';
|
|
6
|
+
import { J as GEMINI_API_KEY_ENV, K as GOOGLE_API_KEY_ENV, G as GEMINI_MODEL_ENV, E as BasePermissionHandler, L as BaseReasoningProcessor, n as initialMachineMetadata, o as createSessionMetadata, u as setupOfflineReconnection, v as notifyDaemonSessionStarted, y as MessageQueue2, z as hashObject, N as MessageBuffer, O as CHANGE_TITLE_INSTRUCTION, C as registerKillSessionHandler, B as startHappyServer } from './index-Iz-M3qbz.mjs';
|
|
7
|
+
import { A as AcpBackend } from './AcpBackend-BxvQ6O4k.mjs';
|
|
8
|
+
import { readGeminiLocalConfig, determineGeminiModel, getGeminiModelSource, getInitialGeminiModel, saveGeminiModelToConfig } from './config-osO37dR1.mjs';
|
|
9
9
|
import 'axios';
|
|
10
10
|
import 'chalk';
|
|
11
11
|
import 'node:util';
|
|
@@ -960,6 +960,10 @@ async function runGemini(opts) {
|
|
|
960
960
|
permissionMode: mode.permissionMode,
|
|
961
961
|
model: mode.model
|
|
962
962
|
}));
|
|
963
|
+
messageQueue.setOnDiscard((entries) => {
|
|
964
|
+
const keys = entries.map((entry) => entry.sourceId).filter((key) => typeof key === "string");
|
|
965
|
+
if (keys.length > 0) session.sendQueueCancelReason(keys, entries[0].reason);
|
|
966
|
+
});
|
|
963
967
|
const conversationHistory = new ConversationHistory({ maxMessages: 20, maxCharacters: 5e4 });
|
|
964
968
|
let currentPermissionMode = void 0;
|
|
965
969
|
let currentModel = void 0;
|
|
@@ -1010,7 +1014,7 @@ async function runGemini(opts) {
|
|
|
1010
1014
|
originalUserMessage
|
|
1011
1015
|
// Store original message separately
|
|
1012
1016
|
};
|
|
1013
|
-
messageQueue.push(fullPrompt, mode);
|
|
1017
|
+
messageQueue.push(fullPrompt, mode, void 0, message.localKey);
|
|
1014
1018
|
conversationHistory.addUserMessage(originalUserMessage);
|
|
1015
1019
|
});
|
|
1016
1020
|
let thinking = false;
|
|
@@ -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-
|
|
8
|
-
var index = require('./index-
|
|
9
|
-
var AcpBackend = require('./AcpBackend-
|
|
10
|
-
var config = require('./config-
|
|
7
|
+
var persistence = require('./types-COOYpI8_.cjs');
|
|
8
|
+
var index = require('./index-DObePs_K.cjs');
|
|
9
|
+
var AcpBackend = require('./AcpBackend-Cdj56ZfU.cjs');
|
|
10
|
+
var config = require('./config-DxOhdFEx.cjs');
|
|
11
11
|
require('axios');
|
|
12
12
|
require('chalk');
|
|
13
13
|
require('node:util');
|
|
@@ -962,6 +962,10 @@ async function runGemini(opts) {
|
|
|
962
962
|
permissionMode: mode.permissionMode,
|
|
963
963
|
model: mode.model
|
|
964
964
|
}));
|
|
965
|
+
messageQueue.setOnDiscard((entries) => {
|
|
966
|
+
const keys = entries.map((entry) => entry.sourceId).filter((key) => typeof key === "string");
|
|
967
|
+
if (keys.length > 0) session.sendQueueCancelReason(keys, entries[0].reason);
|
|
968
|
+
});
|
|
965
969
|
const conversationHistory = new ConversationHistory({ maxMessages: 20, maxCharacters: 5e4 });
|
|
966
970
|
let currentPermissionMode = void 0;
|
|
967
971
|
let currentModel = void 0;
|
|
@@ -1012,7 +1016,7 @@ async function runGemini(opts) {
|
|
|
1012
1016
|
originalUserMessage
|
|
1013
1017
|
// Store original message separately
|
|
1014
1018
|
};
|
|
1015
|
-
messageQueue.push(fullPrompt, mode);
|
|
1019
|
+
messageQueue.push(fullPrompt, mode, void 0, message.localKey);
|
|
1016
1020
|
conversationHistory.addUserMessage(originalUserMessage);
|
|
1017
1021
|
});
|
|
1018
1022
|
let thinking = false;
|
|
@@ -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-
|
|
9
|
-
var AcpSessionManager = require('./AcpSessionManager-
|
|
10
|
-
var index = require('./index-
|
|
8
|
+
var persistence = require('./types-COOYpI8_.cjs');
|
|
9
|
+
var AcpSessionManager = require('./AcpSessionManager-DahCU78z.cjs');
|
|
10
|
+
var index = require('./index-DObePs_K.cjs');
|
|
11
11
|
var WebSocket = require('ws');
|
|
12
12
|
var ed = require('@noble/ed25519');
|
|
13
13
|
var sha2_js = require('@noble/hashes/sha2.js');
|
|
@@ -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 { m as ensurePrivateDirectorySync, n as hardenPrivateFileSync, w as writePrivateFileSync, h as errorLogMetadata, g as contentLogMetadata, d as connectionState, A as ApiClient, e as readSettings, f as encodeBase64, l as logger, c as configuration } from './types-
|
|
7
|
-
import { A as AcpSessionManager } from './AcpSessionManager-
|
|
8
|
-
import { n as initialMachineMetadata, o as createSessionMetadata, u as setupOfflineReconnection, v as notifyDaemonSessionStarted,
|
|
6
|
+
import { m as ensurePrivateDirectorySync, n as hardenPrivateFileSync, w as writePrivateFileSync, h as errorLogMetadata, g as contentLogMetadata, d as connectionState, A as ApiClient, e as readSettings, f as encodeBase64, l as logger, c as configuration } from './types-P2cJWD0E.mjs';
|
|
7
|
+
import { A as AcpSessionManager } from './AcpSessionManager-DlWlQVhw.mjs';
|
|
8
|
+
import { n as initialMachineMetadata, o as createSessionMetadata, u as setupOfflineReconnection, v as notifyDaemonSessionStarted, y as MessageQueue2, C as registerKillSessionHandler } from './index-Iz-M3qbz.mjs';
|
|
9
9
|
import WebSocket from 'ws';
|
|
10
10
|
import * as ed from '@noble/ed25519';
|
|
11
11
|
import { sha512 } from '@noble/hashes/sha2.js';
|
|
@@ -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-
|
|
7
|
-
var index = require('./index-
|
|
6
|
+
var persistence = require('./types-COOYpI8_.cjs');
|
|
7
|
+
var index = require('./index-DObePs_K.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 } from 'node:fs';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
|
-
import { r as readPersistedSessions, c as configuration } from './types-
|
|
5
|
-
import { d as sendUserMessage, a as sessionWebUrl } from './index-
|
|
4
|
+
import { r as readPersistedSessions, c as configuration } from './types-P2cJWD0E.mjs';
|
|
5
|
+
import { d as sendUserMessage, a as sessionWebUrl } from './index-Iz-M3qbz.mjs';
|
|
6
6
|
import 'axios';
|
|
7
7
|
import 'node:util';
|
|
8
8
|
import 'node:os';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { D as DEFAULT_RECENT_LIMIT, M as MAX_READ_LIMIT, l as listAccountSessions, e as listSessions, r as readSessionTranscript, f as stopSession, g as resolvePermissionRequest, h as archiveSession } from './index-
|
|
3
|
-
import { i as isValidSessionId } from './types-
|
|
2
|
+
import { D as DEFAULT_RECENT_LIMIT, M as MAX_READ_LIMIT, l as listAccountSessions, e as listSessions, r as readSessionTranscript, f as stopSession, g as resolvePermissionRequest, h as archiveSession } from './index-Iz-M3qbz.mjs';
|
|
3
|
+
import { i as isValidSessionId } from './types-P2cJWD0E.mjs';
|
|
4
4
|
import 'node:os';
|
|
5
5
|
import 'node:crypto';
|
|
6
6
|
import 'cross-spawn';
|
|
@@ -286,14 +286,21 @@ async function handleSessionsCommand(args) {
|
|
|
286
286
|
const verdict = options.action === "approve" ? { kind: "approve", forSession: options.forSession } : { kind: "deny", reason: options.reason };
|
|
287
287
|
let result;
|
|
288
288
|
try {
|
|
289
|
-
result = await resolvePermissionRequest(sessionId, requestId, verdict
|
|
289
|
+
result = await resolvePermissionRequest(sessionId, requestId, verdict, {
|
|
290
|
+
// T-014: a rate refusal waits (bounded) before re-sending;
|
|
291
|
+
// say so on stderr so the wait does not look like a hang.
|
|
292
|
+
onRateLimited: ({ attempt, waitMs, serverError }) => {
|
|
293
|
+
console.error(chalk.yellow("Rate limited:"), `${serverError} \u2014 waiting ${Math.ceil(waitMs / 1e3)}s before retry ${attempt}`);
|
|
294
|
+
}
|
|
295
|
+
});
|
|
290
296
|
} catch (error) {
|
|
291
297
|
if (options.json) console.log(JSON.stringify(permissionFailureRecord(sessionId, requestId, error)));
|
|
292
298
|
throw error;
|
|
293
299
|
}
|
|
294
300
|
if (result.outcome.status !== "acknowledged") {
|
|
295
301
|
if (options.json) console.log(JSON.stringify(result));
|
|
296
|
-
|
|
302
|
+
const hint = result.outcome.status === "rate-limited" ? ` \u2014 the request is still pending; re-run in ~${Math.ceil(result.outcome.retryAfterMs / 1e3)}s` : "";
|
|
303
|
+
console.error(chalk.red("Error:"), `${options.action} of ${requestId} on ${sessionId} was not delivered (${result.outcome.status}): ${result.outcome.message}${hint}`);
|
|
297
304
|
process.exit(1);
|
|
298
305
|
}
|
|
299
306
|
if (options.json) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chalk = require('chalk');
|
|
4
|
-
var index = require('./index-
|
|
5
|
-
var persistence = require('./types-
|
|
4
|
+
var index = require('./index-DObePs_K.cjs');
|
|
5
|
+
var persistence = require('./types-COOYpI8_.cjs');
|
|
6
6
|
require('node:os');
|
|
7
7
|
require('node:crypto');
|
|
8
8
|
require('cross-spawn');
|
|
@@ -288,14 +288,21 @@ async function handleSessionsCommand(args) {
|
|
|
288
288
|
const verdict = options.action === "approve" ? { kind: "approve", forSession: options.forSession } : { kind: "deny", reason: options.reason };
|
|
289
289
|
let result;
|
|
290
290
|
try {
|
|
291
|
-
result = await index.resolvePermissionRequest(sessionId, requestId, verdict
|
|
291
|
+
result = await index.resolvePermissionRequest(sessionId, requestId, verdict, {
|
|
292
|
+
// T-014: a rate refusal waits (bounded) before re-sending;
|
|
293
|
+
// say so on stderr so the wait does not look like a hang.
|
|
294
|
+
onRateLimited: ({ attempt, waitMs, serverError }) => {
|
|
295
|
+
console.error(chalk.yellow("Rate limited:"), `${serverError} \u2014 waiting ${Math.ceil(waitMs / 1e3)}s before retry ${attempt}`);
|
|
296
|
+
}
|
|
297
|
+
});
|
|
292
298
|
} catch (error) {
|
|
293
299
|
if (options.json) console.log(JSON.stringify(permissionFailureRecord(sessionId, requestId, error)));
|
|
294
300
|
throw error;
|
|
295
301
|
}
|
|
296
302
|
if (result.outcome.status !== "acknowledged") {
|
|
297
303
|
if (options.json) console.log(JSON.stringify(result));
|
|
298
|
-
|
|
304
|
+
const hint = result.outcome.status === "rate-limited" ? ` \u2014 the request is still pending; re-run in ~${Math.ceil(result.outcome.retryAfterMs / 1e3)}s` : "";
|
|
305
|
+
console.error(chalk.red("Error:"), `${options.action} of ${requestId} on ${sessionId} was not delivered (${result.outcome.status}): ${result.outcome.message}${hint}`);
|
|
299
306
|
process.exit(1);
|
|
300
307
|
}
|
|
301
308
|
if (options.json) {
|
|
@@ -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, i as isValidSpawnOrigin, b as sanitizeSpawnPermissionMode, A as ALLOWED_SPAWN_PERMISSION_MODES, S as SPAWN_AGENTS, w as waitForSessionKey, d as sendUserMessage } from './index-
|
|
5
|
-
import { l as logger } from './types-
|
|
4
|
+
import { c as checkIfDaemonRunningAndCleanupStaleState, s as spawnDaemonSession, a as sessionWebUrl, i as isValidSpawnOrigin, b as sanitizeSpawnPermissionMode, A as ALLOWED_SPAWN_PERMISSION_MODES, S as SPAWN_AGENTS, w as waitForSessionKey, d as sendUserMessage } from './index-Iz-M3qbz.mjs';
|
|
5
|
+
import { l as logger } from './types-P2cJWD0E.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-
|
|
7
|
-
var persistence = require('./types-
|
|
6
|
+
var index = require('./index-DObePs_K.cjs');
|
|
7
|
+
var persistence = require('./types-COOYpI8_.cjs');
|
|
8
8
|
require('node:os');
|
|
9
9
|
require('node:crypto');
|
|
10
10
|
require('cross-spawn');
|
|
@@ -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.
|
|
54
|
+
var version = "0.2.121";
|
|
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.
|
|
168
|
-
"very-happy-tools-x64-darwin": "0.2.
|
|
169
|
-
"very-happy-tools-arm64-linux": "0.2.
|
|
170
|
-
"very-happy-tools-x64-linux": "0.2.
|
|
171
|
-
"very-happy-tools-arm64-win32": "0.2.
|
|
172
|
-
"very-happy-tools-x64-win32": "0.2.
|
|
167
|
+
"very-happy-tools-arm64-darwin": "0.2.121",
|
|
168
|
+
"very-happy-tools-x64-darwin": "0.2.121",
|
|
169
|
+
"very-happy-tools-arm64-linux": "0.2.121",
|
|
170
|
+
"very-happy-tools-x64-linux": "0.2.121",
|
|
171
|
+
"very-happy-tools-arm64-win32": "0.2.121",
|
|
172
|
+
"very-happy-tools-x64-win32": "0.2.121"
|
|
173
173
|
};
|
|
174
174
|
var devDependencies = {
|
|
175
175
|
"@slopus/happy-wire": "workspace:*",
|
|
@@ -742,6 +742,11 @@ const sessionProgressEventSchema = z__namespace.object({
|
|
|
742
742
|
durationMs: z__namespace.number().optional(),
|
|
743
743
|
summary: z__namespace.string().optional()
|
|
744
744
|
});
|
|
745
|
+
const sessionQueueCancelEventSchema = z__namespace.object({
|
|
746
|
+
t: z__namespace.literal("queue-cancel"),
|
|
747
|
+
targetLocalKeys: z__namespace.array(z__namespace.string().min(1)).min(1),
|
|
748
|
+
reason: z__namespace.string().min(1).optional()
|
|
749
|
+
});
|
|
745
750
|
const sessionEventSchema = z__namespace.discriminatedUnion("t", [
|
|
746
751
|
sessionTextEventSchema,
|
|
747
752
|
sessionServiceMessageEventSchema,
|
|
@@ -752,7 +757,8 @@ const sessionEventSchema = z__namespace.discriminatedUnion("t", [
|
|
|
752
757
|
sessionStartEventSchema,
|
|
753
758
|
sessionTurnEndEventSchema,
|
|
754
759
|
sessionStopEventSchema,
|
|
755
|
-
sessionProgressEventSchema
|
|
760
|
+
sessionProgressEventSchema,
|
|
761
|
+
sessionQueueCancelEventSchema
|
|
756
762
|
]);
|
|
757
763
|
const sessionEnvelopeSchema = z__namespace.object({
|
|
758
764
|
id: z__namespace.string(),
|
|
@@ -1685,7 +1691,7 @@ class RpcHandlerManager {
|
|
|
1685
1691
|
}
|
|
1686
1692
|
}
|
|
1687
1693
|
|
|
1688
|
-
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-
|
|
1694
|
+
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-COOYpI8_.cjs', document.baseURI).href))));
|
|
1689
1695
|
function projectPath() {
|
|
1690
1696
|
const path = path$1.resolve(__dirname$1, "..");
|
|
1691
1697
|
return path;
|
|
@@ -3135,6 +3141,48 @@ class InvalidateSync {
|
|
|
3135
3141
|
};
|
|
3136
3142
|
}
|
|
3137
3143
|
|
|
3144
|
+
function sessionEnvelopeOf(body) {
|
|
3145
|
+
if (!body || typeof body !== "object") return null;
|
|
3146
|
+
const record = body;
|
|
3147
|
+
if (record.role !== "session" || !record.content || typeof record.content !== "object") return null;
|
|
3148
|
+
const content = record.content;
|
|
3149
|
+
if (content.type === "session" && content.data && typeof content.data === "object") {
|
|
3150
|
+
return content.data;
|
|
3151
|
+
}
|
|
3152
|
+
if (content.ev !== void 0) return content;
|
|
3153
|
+
return null;
|
|
3154
|
+
}
|
|
3155
|
+
function isQueuedUserText(body) {
|
|
3156
|
+
if (!body || typeof body !== "object") return false;
|
|
3157
|
+
const record = body;
|
|
3158
|
+
return record.role === "user" && record.content?.type === "text" && typeof record.meta?.queuedAt === "number";
|
|
3159
|
+
}
|
|
3160
|
+
function scanUndeliveredQueuedInputs(records, prior) {
|
|
3161
|
+
const canceled = prior?.canceled ?? /* @__PURE__ */ new Set();
|
|
3162
|
+
const undelivered = [];
|
|
3163
|
+
let reachedBoundary = false;
|
|
3164
|
+
for (const record of records) {
|
|
3165
|
+
const envelope = sessionEnvelopeOf(record.body);
|
|
3166
|
+
if (envelope) {
|
|
3167
|
+
const t = envelope.ev?.t;
|
|
3168
|
+
if (t === "turn-end") {
|
|
3169
|
+
reachedBoundary = true;
|
|
3170
|
+
break;
|
|
3171
|
+
}
|
|
3172
|
+
if (t === "queue-cancel" && Array.isArray(envelope.ev?.targetLocalKeys)) {
|
|
3173
|
+
for (const key of envelope.ev.targetLocalKeys) {
|
|
3174
|
+
if (typeof key === "string") canceled.add(key);
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
continue;
|
|
3178
|
+
}
|
|
3179
|
+
if (isQueuedUserText(record.body) && record.localId && !canceled.has(record.localId)) {
|
|
3180
|
+
undelivered.push(record.localId);
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3183
|
+
return { undeliveredLocalKeys: undelivered, reachedBoundary, canceled };
|
|
3184
|
+
}
|
|
3185
|
+
|
|
3138
3186
|
function record(value) {
|
|
3139
3187
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
3140
3188
|
}
|
|
@@ -3778,8 +3826,75 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
3778
3826
|
this.sendSync.invalidate();
|
|
3779
3827
|
}
|
|
3780
3828
|
}
|
|
3829
|
+
/** B-332: emit a queue-cancel tombstone, mirroring the web's own signal. */
|
|
3830
|
+
sendQueueCancelReason(localKeys, reason) {
|
|
3831
|
+
if (localKeys.length === 0) return;
|
|
3832
|
+
const envelope = createEnvelope("user", { t: "queue-cancel", targetLocalKeys: localKeys, reason });
|
|
3833
|
+
this.sendSessionProtocolMessage(envelope);
|
|
3834
|
+
}
|
|
3781
3835
|
/**
|
|
3782
|
-
*
|
|
3836
|
+
* B-332 site ③: find queued user input this wrapper destroyed (it was still
|
|
3837
|
+
* in the previous wrapper's in-memory queue when it died) and tell the web.
|
|
3838
|
+
*
|
|
3839
|
+
* Walks NEWEST → OLDEST via `before_seq`, decrypting each page, and stops at
|
|
3840
|
+
* the first turn-end. The runner calls this on EVERY reconnect (runClaude /
|
|
3841
|
+
* runCodex), seeded or not: a cursor seeded at the server's latest seq skips
|
|
3842
|
+
* the undelivered tail just as thoroughly as skipExistingMessages does —
|
|
3843
|
+
* and the daemon's resume/restart always seeds, so gating on the skip path
|
|
3844
|
+
* would miss the common case. Best-effort: a failed scan must not take a
|
|
3845
|
+
* session down. Needs no socket; POSTs through the same session-message
|
|
3846
|
+
* channel so the web receives it identically to a cancel-button tombstone.
|
|
3847
|
+
*/
|
|
3848
|
+
async cancelUndeliveredQueuedInputs() {
|
|
3849
|
+
const MAX_SCAN_PAGES = 10;
|
|
3850
|
+
const canceled = /* @__PURE__ */ new Set();
|
|
3851
|
+
const undelivered = [];
|
|
3852
|
+
let beforeSeq = 2147483647;
|
|
3853
|
+
let reachedBoundary = false;
|
|
3854
|
+
let pages = 0;
|
|
3855
|
+
try {
|
|
3856
|
+
while (!reachedBoundary && pages < MAX_SCAN_PAGES) {
|
|
3857
|
+
pages += 1;
|
|
3858
|
+
const response = await axios.get(
|
|
3859
|
+
`${configuration.serverUrl}/v3/sessions/${encodeURIComponent(this.sessionId)}/messages`,
|
|
3860
|
+
{
|
|
3861
|
+
params: { before_seq: beforeSeq, limit: 100 },
|
|
3862
|
+
headers: this.authHeaders(),
|
|
3863
|
+
timeout: 6e4
|
|
3864
|
+
}
|
|
3865
|
+
);
|
|
3866
|
+
const messages = Array.isArray(response.data.messages) ? response.data.messages : [];
|
|
3867
|
+
if (messages.length === 0) break;
|
|
3868
|
+
const records = messages.map((message) => {
|
|
3869
|
+
let body = null;
|
|
3870
|
+
try {
|
|
3871
|
+
body = message.content?.t === "encrypted" ? decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(message.content.c)) : null;
|
|
3872
|
+
} catch (error) {
|
|
3873
|
+
logger.debug("[API] Failed to decrypt during undelivered scan:", error);
|
|
3874
|
+
}
|
|
3875
|
+
return { seq: message.seq, localId: message.localId, body };
|
|
3876
|
+
});
|
|
3877
|
+
const scan = scanUndeliveredQueuedInputs(records, { canceled });
|
|
3878
|
+
for (const key of scan.canceled) canceled.add(key);
|
|
3879
|
+
undelivered.push(...scan.undeliveredLocalKeys);
|
|
3880
|
+
reachedBoundary = scan.reachedBoundary;
|
|
3881
|
+
const oldest = records.at(-1)?.seq;
|
|
3882
|
+
if (oldest === void 0 || messages.length < 100) break;
|
|
3883
|
+
beforeSeq = oldest;
|
|
3884
|
+
}
|
|
3885
|
+
} catch (error) {
|
|
3886
|
+
logger.debug("[API] cancelUndeliveredQueuedInputs scan failed:", error);
|
|
3887
|
+
return;
|
|
3888
|
+
}
|
|
3889
|
+
if (!reachedBoundary) {
|
|
3890
|
+
logger.debug("[API] cancelUndeliveredQueuedInputs found no turn boundary; leaving messages as-is");
|
|
3891
|
+
return;
|
|
3892
|
+
}
|
|
3893
|
+
undelivered.reverse();
|
|
3894
|
+
this.sendQueueCancelReason(undelivered, "restarted");
|
|
3895
|
+
}
|
|
3896
|
+
/**
|
|
3897
|
+
* Send a message to session
|
|
3783
3898
|
* @param body - Message body (can be MessageContent or raw content for agent messages)
|
|
3784
3899
|
*/
|
|
3785
3900
|
sendClaudeSessionMessage(body, opts) {
|
|
@@ -4472,34 +4587,44 @@ function migrateSettings(raw, fromVersion) {
|
|
|
4472
4587
|
let migrated = { ...raw };
|
|
4473
4588
|
return migrated;
|
|
4474
4589
|
}
|
|
4475
|
-
async function
|
|
4590
|
+
async function readSettingsOutcome() {
|
|
4476
4591
|
if (!node_fs.existsSync(configuration.settingsFile)) {
|
|
4477
|
-
return {
|
|
4592
|
+
return { kind: "absent" };
|
|
4478
4593
|
}
|
|
4479
4594
|
try {
|
|
4480
|
-
|
|
4481
|
-
const raw = JSON.parse(content);
|
|
4482
|
-
const schemaVersion = raw.schemaVersion ?? 1;
|
|
4483
|
-
if (schemaVersion > SUPPORTED_SCHEMA_VERSION) {
|
|
4484
|
-
logger.warn(
|
|
4485
|
-
`\u26A0\uFE0F Settings schema v${schemaVersion} > supported v${SUPPORTED_SCHEMA_VERSION}. Update happy-cli for full functionality.`
|
|
4486
|
-
);
|
|
4487
|
-
}
|
|
4488
|
-
const migrated = migrateSettings(raw, schemaVersion);
|
|
4489
|
-
if (migrated.sandboxConfig !== void 0) {
|
|
4490
|
-
try {
|
|
4491
|
-
migrated.sandboxConfig = SandboxConfigSchema.parse(migrated.sandboxConfig);
|
|
4492
|
-
} catch (error) {
|
|
4493
|
-
logger.warn(`\u26A0\uFE0F Invalid sandbox config - skipping. Error: ${error.message}`);
|
|
4494
|
-
migrated.sandboxConfig = void 0;
|
|
4495
|
-
}
|
|
4496
|
-
}
|
|
4497
|
-
return { ...defaultSettings, ...migrated };
|
|
4595
|
+
return { kind: "ok", settings: await parseSettingsFile() };
|
|
4498
4596
|
} catch (error) {
|
|
4499
|
-
|
|
4500
|
-
return { ...defaultSettings };
|
|
4597
|
+
return { kind: "unreadable", error: error?.message ?? String(error) };
|
|
4501
4598
|
}
|
|
4502
4599
|
}
|
|
4600
|
+
async function readSettings() {
|
|
4601
|
+
const outcome = await readSettingsOutcome();
|
|
4602
|
+
if (outcome.kind === "ok") return outcome.settings;
|
|
4603
|
+
if (outcome.kind === "unreadable") {
|
|
4604
|
+
logger.warn(`Failed to read settings: ${outcome.error}`);
|
|
4605
|
+
}
|
|
4606
|
+
return { ...defaultSettings };
|
|
4607
|
+
}
|
|
4608
|
+
async function parseSettingsFile() {
|
|
4609
|
+
const content = await promises.readFile(configuration.settingsFile, "utf8");
|
|
4610
|
+
const raw = JSON.parse(content);
|
|
4611
|
+
const schemaVersion = raw.schemaVersion ?? 1;
|
|
4612
|
+
if (schemaVersion > SUPPORTED_SCHEMA_VERSION) {
|
|
4613
|
+
logger.warn(
|
|
4614
|
+
`\u26A0\uFE0F Settings schema v${schemaVersion} > supported v${SUPPORTED_SCHEMA_VERSION}. Update happy-cli for full functionality.`
|
|
4615
|
+
);
|
|
4616
|
+
}
|
|
4617
|
+
const migrated = migrateSettings(raw);
|
|
4618
|
+
if (migrated.sandboxConfig !== void 0) {
|
|
4619
|
+
try {
|
|
4620
|
+
migrated.sandboxConfig = SandboxConfigSchema.parse(migrated.sandboxConfig);
|
|
4621
|
+
} catch (error) {
|
|
4622
|
+
logger.warn(`\u26A0\uFE0F Invalid sandbox config - skipping. Error: ${error.message}`);
|
|
4623
|
+
migrated.sandboxConfig = void 0;
|
|
4624
|
+
}
|
|
4625
|
+
}
|
|
4626
|
+
return { ...defaultSettings, ...migrated };
|
|
4627
|
+
}
|
|
4503
4628
|
async function writeSettings(settings) {
|
|
4504
4629
|
await ensurePrivateDirectory(configuration.happyHomeDir);
|
|
4505
4630
|
const settingsWithVersion = {
|
|
@@ -4541,7 +4666,13 @@ async function updateSettings(updater) {
|
|
|
4541
4666
|
throw new Error(`Failed to acquire settings lock after ${MAX_LOCK_ATTEMPTS * LOCK_RETRY_INTERVAL_MS / 1e3} seconds`);
|
|
4542
4667
|
}
|
|
4543
4668
|
try {
|
|
4544
|
-
const
|
|
4669
|
+
const outcome = await readSettingsOutcome();
|
|
4670
|
+
if (outcome.kind === "unreadable") {
|
|
4671
|
+
throw new Error(
|
|
4672
|
+
`Settings file ${configuration.settingsFile} exists but could not be read (${outcome.error}). Refusing to overwrite it \u2014 fix or remove the file (a removed file is recreated with defaults).`
|
|
4673
|
+
);
|
|
4674
|
+
}
|
|
4675
|
+
const current = outcome.kind === "ok" ? outcome.settings : { ...defaultSettings };
|
|
4545
4676
|
const updated = await updater(current);
|
|
4546
4677
|
await ensurePrivateDirectory(configuration.happyHomeDir);
|
|
4547
4678
|
await writePrivateFile(tmpFile, JSON.stringify(updated, null, 2));
|
|
@@ -4788,6 +4919,7 @@ var persistence = /*#__PURE__*/Object.freeze({
|
|
|
4788
4919
|
readDaemonState: readDaemonState,
|
|
4789
4920
|
readPersistedSessions: readPersistedSessions,
|
|
4790
4921
|
readSettings: readSettings,
|
|
4922
|
+
readSettingsOutcome: readSettingsOutcome,
|
|
4791
4923
|
readTrackedClaudeSessionIds: readTrackedClaudeSessionIds,
|
|
4792
4924
|
releaseDaemonLock: releaseDaemonLock,
|
|
4793
4925
|
updateSettings: updateSettings,
|
|
@@ -14535,6 +14667,7 @@ async function withCodexAppServerClient(handler) {
|
|
|
14535
14667
|
await client.disconnect();
|
|
14536
14668
|
}
|
|
14537
14669
|
}
|
|
14670
|
+
const CLI_AVAILABILITY_RECHECK_MS = 5 * 60 * 1e3;
|
|
14538
14671
|
class ApiMachineClient {
|
|
14539
14672
|
constructor(token, machine) {
|
|
14540
14673
|
this.token = token;
|
|
@@ -14558,6 +14691,10 @@ class ApiMachineClient {
|
|
|
14558
14691
|
keepAliveInterval = null;
|
|
14559
14692
|
lastKnownCLIAvailability = null;
|
|
14560
14693
|
lastKnownResumeSupport = null;
|
|
14694
|
+
/** Wall-clock of the last CLI availability probe. Initialised as "already
|
|
14695
|
+
* stale" so the FIRST keep-alive tick always probes and populates the
|
|
14696
|
+
* machine metadata that a connecting/reconnecting web client reads. */
|
|
14697
|
+
lastCliProbeAt = Date.now() - CLI_AVAILABILITY_RECHECK_MS;
|
|
14561
14698
|
cliUpdateState = null;
|
|
14562
14699
|
cliUpdatePushChain = Promise.resolve();
|
|
14563
14700
|
claudeAuthState = null;
|
|
@@ -15425,6 +15562,10 @@ class ApiMachineClient {
|
|
|
15425
15562
|
}
|
|
15426
15563
|
this.socket.emit("machine-alive", payload);
|
|
15427
15564
|
void this.refreshRelayConnection();
|
|
15565
|
+
if (Date.now() - this.lastCliProbeAt < CLI_AVAILABILITY_RECHECK_MS) {
|
|
15566
|
+
return;
|
|
15567
|
+
}
|
|
15568
|
+
this.lastCliProbeAt = Date.now();
|
|
15428
15569
|
const newAvailability = detectCLIAvailability();
|
|
15429
15570
|
const prev = this.lastKnownCLIAvailability;
|
|
15430
15571
|
const newResumeSupport = detectResumeSupport();
|
|
@@ -16720,6 +16861,7 @@ exports.readDaemonState = readDaemonState;
|
|
|
16720
16861
|
exports.readLocalHappyAgentCredentials = readLocalHappyAgentCredentials;
|
|
16721
16862
|
exports.readPersistedSessions = readPersistedSessions;
|
|
16722
16863
|
exports.readSettings = readSettings;
|
|
16864
|
+
exports.readSettingsOutcome = readSettingsOutcome;
|
|
16723
16865
|
exports.readVhTerminal = readVhTerminal;
|
|
16724
16866
|
exports.releaseDaemonLock = releaseDaemonLock;
|
|
16725
16867
|
exports.resolveCliUpdateCheckInterval = resolveCliUpdateCheckInterval;
|
|
@@ -16727,6 +16869,7 @@ exports.scrubTmuxClientEnv = scrubTmuxClientEnv;
|
|
|
16727
16869
|
exports.sendToVhTerminal = sendToVhTerminal;
|
|
16728
16870
|
exports.shellescape = shellescape;
|
|
16729
16871
|
exports.startOfflineReconnection = startOfflineReconnection;
|
|
16872
|
+
exports.streamKeyOf = streamKeyOf;
|
|
16730
16873
|
exports.summarizeSpawnSessionForLog = summarizeSpawnSessionForLog;
|
|
16731
16874
|
exports.tmuxArgs = tmuxArgs;
|
|
16732
16875
|
exports.updateSettings = updateSettings;
|