very-happy-cli 0.2.116 → 0.2.118
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-CfKPvoTU.mjs → AcpBackend-Bk9b823B.mjs} +116 -12
- package/dist/{AcpBackend-CauAQpC1.cjs → AcpBackend-p_KNJkHc.cjs} +116 -12
- package/dist/{AcpSessionManager-CA6xeET_.cjs → AcpSessionManager-B9FTbpGQ.cjs} +15 -2
- package/dist/{AcpSessionManager-BQ6pBRW4.mjs → AcpSessionManager-CDvqVHKf.mjs} +15 -2
- package/dist/{config-BpR_CwZu.mjs → config-CIpgmGLR.mjs} +2 -2
- package/dist/{config-BoteFn-v.cjs → config-CkUn1dI4.cjs} +2 -2
- package/dist/{index-C45xN8s0.mjs → index-B6cpyG_G.mjs} +78 -8
- package/dist/{index-D7azxfcs.mjs → index-BUVQf9PI.mjs} +2 -2
- package/dist/{index-4jiUeiUz.cjs → index-BXOXRblP.cjs} +513 -47
- package/dist/{index-DWmhmji9.cjs → index-BzgtwTxC.cjs} +77 -7
- package/dist/{index-lX1UliOs.cjs → index-CxjX8DGz.cjs} +2 -2
- package/dist/{index-Dq-eFp89.mjs → index-DIXjhnV1.mjs} +502 -45
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{installTerminalHooks-k3TrBHD0.mjs → installTerminalHooks-BAa6LaQQ.mjs} +2 -2
- package/dist/{installTerminalHooks-DnaFkrTF.cjs → installTerminalHooks-lXQa6bQU.cjs} +2 -2
- package/dist/lib.cjs +1 -1
- package/dist/lib.d.cts +43 -1
- package/dist/lib.d.mts +43 -1
- package/dist/lib.mjs +1 -1
- package/dist/{mcp-DSpEpM_2.cjs → mcp-DMD7FxBI.cjs} +62 -16
- package/dist/{mcp-DRePTOap.mjs → mcp-Dwc299mU.mjs} +62 -17
- package/dist/{runGemini-_9-a7duU.mjs → runGemini-BaxGXE9w.mjs} +4 -4
- package/dist/{runGemini-IWHyBq0A.cjs → runGemini-Bj4Egq7j.cjs} +4 -4
- package/dist/{runOpenClaw-0myYIz1U.cjs → runOpenClaw-BJhSvXYy.cjs} +3 -3
- package/dist/{runOpenClaw-Boq6LQ9a.mjs → runOpenClaw-BwJhbIKU.mjs} +3 -3
- package/dist/{send-CwWvFfay.cjs → send-BWGUkWhi.cjs} +2 -2
- package/dist/{send-Cyo6mgMl.mjs → send-DX13svrS.mjs} +2 -2
- package/dist/sessions-CGhpBNqn.cjs +322 -0
- package/dist/sessions-L7O3ypda.mjs +317 -0
- package/dist/{spawn-DQ6FTUK9.cjs → spawn-CbY233Eg.cjs} +6 -7
- package/dist/{spawn-CU0DMauA.mjs → spawn-DPDWZdoW.mjs} +3 -4
- package/dist/{types-Ds0SiQ1D.mjs → types-BtuOM9lw.mjs} +52 -19
- package/dist/{types-C5kEpkcZ.cjs → types-ClvvHves.cjs} +54 -19
- package/package.json +7 -7
- package/dist/sessions-CbzqYiAy.cjs +0 -204
- package/dist/sessions-lvfTH_ql.mjs +0 -200
package/dist/index.cjs
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -3,8 +3,8 @@ import { join, resolve } from 'node:path';
|
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
|
-
import { p as projectPath } from './types-
|
|
7
|
-
import { t as tmuxSupportsSessionEnv } from './index-
|
|
6
|
+
import { p as projectPath } from './types-BtuOM9lw.mjs';
|
|
7
|
+
import { t as tmuxSupportsSessionEnv } from './index-DIXjhnV1.mjs';
|
|
8
8
|
import 'axios';
|
|
9
9
|
import 'node:util';
|
|
10
10
|
import 'node:fs/promises';
|
|
@@ -5,8 +5,8 @@ var path = require('node:path');
|
|
|
5
5
|
var os = require('node:os');
|
|
6
6
|
var node_child_process = require('node:child_process');
|
|
7
7
|
var chalk = require('chalk');
|
|
8
|
-
var persistence = require('./types-
|
|
9
|
-
var index = require('./index-
|
|
8
|
+
var persistence = require('./types-ClvvHves.cjs');
|
|
9
|
+
var index = require('./index-BXOXRblP.cjs');
|
|
10
10
|
require('axios');
|
|
11
11
|
require('node:util');
|
|
12
12
|
require('node:fs/promises');
|
package/dist/lib.cjs
CHANGED
package/dist/lib.d.cts
CHANGED
|
@@ -315,6 +315,7 @@ declare const MachineMetadataSchema: z$1.ZodObject<{
|
|
|
315
315
|
codex: z$1.ZodBoolean;
|
|
316
316
|
gemini: z$1.ZodBoolean;
|
|
317
317
|
openclaw: z$1.ZodBoolean;
|
|
318
|
+
pi: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
318
319
|
detectedAt: z$1.ZodNumber;
|
|
319
320
|
}, z$1.core.$strip>>;
|
|
320
321
|
resumeSupport: z$1.ZodOptional<z$1.ZodObject<{
|
|
@@ -335,6 +336,7 @@ declare const CliUpdateStateSchema: z$1.ZodObject<{
|
|
|
335
336
|
available: "available";
|
|
336
337
|
required: "required";
|
|
337
338
|
}>;
|
|
339
|
+
autoUpdateVersion: z$1.ZodOptional<z$1.ZodNullable<z$1.ZodString>>;
|
|
338
340
|
checkedAt: z$1.ZodNumber;
|
|
339
341
|
handoverHold: z$1.ZodOptional<z$1.ZodNullable<z$1.ZodObject<{
|
|
340
342
|
reason: z$1.ZodString;
|
|
@@ -429,6 +431,7 @@ declare const DaemonStateSchema: z$1.ZodObject<{
|
|
|
429
431
|
available: "available";
|
|
430
432
|
required: "required";
|
|
431
433
|
}>;
|
|
434
|
+
autoUpdateVersion: z$1.ZodOptional<z$1.ZodNullable<z$1.ZodString>>;
|
|
432
435
|
checkedAt: z$1.ZodNumber;
|
|
433
436
|
handoverHold: z$1.ZodOptional<z$1.ZodNullable<z$1.ZodObject<{
|
|
434
437
|
reason: z$1.ZodString;
|
|
@@ -1045,12 +1048,24 @@ declare class ApiSessionClient extends EventEmitter {
|
|
|
1045
1048
|
private startSmartReconnect;
|
|
1046
1049
|
}
|
|
1047
1050
|
|
|
1051
|
+
/**
|
|
1052
|
+
* The backends the daemon can spawn as a remote session.
|
|
1053
|
+
*
|
|
1054
|
+
* One list, four consumers: the `spawn --agent` CLI validator, the daemon's
|
|
1055
|
+
* `/spawn-session` zod enum, the machine RPC `SpawnSessionOptions` type and
|
|
1056
|
+
* the daemon's argv switch in `daemon/run.ts`. Before this module each site
|
|
1057
|
+
* carried its own copy and adding a backend meant finding all of them (B-306
|
|
1058
|
+
* found the CLI one missing). Import from here; do not re-list.
|
|
1059
|
+
*/
|
|
1060
|
+
declare const SPAWN_AGENTS: readonly ["claude", "codex", "gemini", "openclaw", "pi"];
|
|
1061
|
+
type SpawnAgent = (typeof SPAWN_AGENTS)[number];
|
|
1062
|
+
|
|
1048
1063
|
interface SpawnSessionOptions {
|
|
1049
1064
|
machineId?: string;
|
|
1050
1065
|
directory: string;
|
|
1051
1066
|
sessionId?: string;
|
|
1052
1067
|
approvedNewDirectoryCreation?: boolean;
|
|
1053
|
-
agent?:
|
|
1068
|
+
agent?: SpawnAgent;
|
|
1054
1069
|
environmentVariables?: Record<string, string>;
|
|
1055
1070
|
token?: string;
|
|
1056
1071
|
/**
|
|
@@ -1235,6 +1250,21 @@ interface TerminalListItem {
|
|
|
1235
1250
|
paneRows?: number;
|
|
1236
1251
|
}
|
|
1237
1252
|
|
|
1253
|
+
interface CLIAvailability {
|
|
1254
|
+
claude: boolean;
|
|
1255
|
+
codex: boolean;
|
|
1256
|
+
gemini: boolean;
|
|
1257
|
+
openclaw: boolean;
|
|
1258
|
+
/**
|
|
1259
|
+
* pi is spawnable only through the pi-acp adapter (`very-happy pi`), so this
|
|
1260
|
+
* is "both `pi` and `pi-acp` resolve on PATH". Older daemons never send the
|
|
1261
|
+
* field; the Web launcher treats absence as unavailable (unlike the other
|
|
1262
|
+
* agents), because such a daemon cannot spawn pi at all.
|
|
1263
|
+
*/
|
|
1264
|
+
pi: boolean;
|
|
1265
|
+
detectedAt: number;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1238
1268
|
/**
|
|
1239
1269
|
* WebSocket client for machine/daemon communication with Happy server
|
|
1240
1270
|
* Similar to ApiSessionClient but for machine-scoped connections
|
|
@@ -1281,6 +1311,18 @@ declare class ApiMachineClient {
|
|
|
1281
1311
|
* waits until there are none. */
|
|
1282
1312
|
hasLiveTerminals(): boolean;
|
|
1283
1313
|
private webTerminal;
|
|
1314
|
+
/**
|
|
1315
|
+
* The CLI availability last advertised in machine metadata (re-probed by
|
|
1316
|
+
* the keep-alive). Null until the first keep-alive tick; the daemon falls
|
|
1317
|
+
* back to its startup probe then.
|
|
1318
|
+
*/
|
|
1319
|
+
getCLIAvailability(): CLIAvailability | null;
|
|
1320
|
+
/**
|
|
1321
|
+
* Title a web terminal from inside it (`very-happy mcp` change_title →
|
|
1322
|
+
* daemon /terminal-title → here). Same tmux truthfulness as the
|
|
1323
|
+
* `set-terminal-title` RPC.
|
|
1324
|
+
*/
|
|
1325
|
+
setTerminalTitle(terminalId: string, title: string, ifAbsent: boolean): boolean;
|
|
1284
1326
|
/**
|
|
1285
1327
|
* Push text to the clipboard of every web client the user has open
|
|
1286
1328
|
* (terminal-path claude → `very-happy mcp` → daemon /clipboard → here).
|
package/dist/lib.d.mts
CHANGED
|
@@ -315,6 +315,7 @@ declare const MachineMetadataSchema: z$1.ZodObject<{
|
|
|
315
315
|
codex: z$1.ZodBoolean;
|
|
316
316
|
gemini: z$1.ZodBoolean;
|
|
317
317
|
openclaw: z$1.ZodBoolean;
|
|
318
|
+
pi: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
318
319
|
detectedAt: z$1.ZodNumber;
|
|
319
320
|
}, z$1.core.$strip>>;
|
|
320
321
|
resumeSupport: z$1.ZodOptional<z$1.ZodObject<{
|
|
@@ -335,6 +336,7 @@ declare const CliUpdateStateSchema: z$1.ZodObject<{
|
|
|
335
336
|
available: "available";
|
|
336
337
|
required: "required";
|
|
337
338
|
}>;
|
|
339
|
+
autoUpdateVersion: z$1.ZodOptional<z$1.ZodNullable<z$1.ZodString>>;
|
|
338
340
|
checkedAt: z$1.ZodNumber;
|
|
339
341
|
handoverHold: z$1.ZodOptional<z$1.ZodNullable<z$1.ZodObject<{
|
|
340
342
|
reason: z$1.ZodString;
|
|
@@ -429,6 +431,7 @@ declare const DaemonStateSchema: z$1.ZodObject<{
|
|
|
429
431
|
available: "available";
|
|
430
432
|
required: "required";
|
|
431
433
|
}>;
|
|
434
|
+
autoUpdateVersion: z$1.ZodOptional<z$1.ZodNullable<z$1.ZodString>>;
|
|
432
435
|
checkedAt: z$1.ZodNumber;
|
|
433
436
|
handoverHold: z$1.ZodOptional<z$1.ZodNullable<z$1.ZodObject<{
|
|
434
437
|
reason: z$1.ZodString;
|
|
@@ -1045,12 +1048,24 @@ declare class ApiSessionClient extends EventEmitter {
|
|
|
1045
1048
|
private startSmartReconnect;
|
|
1046
1049
|
}
|
|
1047
1050
|
|
|
1051
|
+
/**
|
|
1052
|
+
* The backends the daemon can spawn as a remote session.
|
|
1053
|
+
*
|
|
1054
|
+
* One list, four consumers: the `spawn --agent` CLI validator, the daemon's
|
|
1055
|
+
* `/spawn-session` zod enum, the machine RPC `SpawnSessionOptions` type and
|
|
1056
|
+
* the daemon's argv switch in `daemon/run.ts`. Before this module each site
|
|
1057
|
+
* carried its own copy and adding a backend meant finding all of them (B-306
|
|
1058
|
+
* found the CLI one missing). Import from here; do not re-list.
|
|
1059
|
+
*/
|
|
1060
|
+
declare const SPAWN_AGENTS: readonly ["claude", "codex", "gemini", "openclaw", "pi"];
|
|
1061
|
+
type SpawnAgent = (typeof SPAWN_AGENTS)[number];
|
|
1062
|
+
|
|
1048
1063
|
interface SpawnSessionOptions {
|
|
1049
1064
|
machineId?: string;
|
|
1050
1065
|
directory: string;
|
|
1051
1066
|
sessionId?: string;
|
|
1052
1067
|
approvedNewDirectoryCreation?: boolean;
|
|
1053
|
-
agent?:
|
|
1068
|
+
agent?: SpawnAgent;
|
|
1054
1069
|
environmentVariables?: Record<string, string>;
|
|
1055
1070
|
token?: string;
|
|
1056
1071
|
/**
|
|
@@ -1235,6 +1250,21 @@ interface TerminalListItem {
|
|
|
1235
1250
|
paneRows?: number;
|
|
1236
1251
|
}
|
|
1237
1252
|
|
|
1253
|
+
interface CLIAvailability {
|
|
1254
|
+
claude: boolean;
|
|
1255
|
+
codex: boolean;
|
|
1256
|
+
gemini: boolean;
|
|
1257
|
+
openclaw: boolean;
|
|
1258
|
+
/**
|
|
1259
|
+
* pi is spawnable only through the pi-acp adapter (`very-happy pi`), so this
|
|
1260
|
+
* is "both `pi` and `pi-acp` resolve on PATH". Older daemons never send the
|
|
1261
|
+
* field; the Web launcher treats absence as unavailable (unlike the other
|
|
1262
|
+
* agents), because such a daemon cannot spawn pi at all.
|
|
1263
|
+
*/
|
|
1264
|
+
pi: boolean;
|
|
1265
|
+
detectedAt: number;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1238
1268
|
/**
|
|
1239
1269
|
* WebSocket client for machine/daemon communication with Happy server
|
|
1240
1270
|
* Similar to ApiSessionClient but for machine-scoped connections
|
|
@@ -1281,6 +1311,18 @@ declare class ApiMachineClient {
|
|
|
1281
1311
|
* waits until there are none. */
|
|
1282
1312
|
hasLiveTerminals(): boolean;
|
|
1283
1313
|
private webTerminal;
|
|
1314
|
+
/**
|
|
1315
|
+
* The CLI availability last advertised in machine metadata (re-probed by
|
|
1316
|
+
* the keep-alive). Null until the first keep-alive tick; the daemon falls
|
|
1317
|
+
* back to its startup probe then.
|
|
1318
|
+
*/
|
|
1319
|
+
getCLIAvailability(): CLIAvailability | null;
|
|
1320
|
+
/**
|
|
1321
|
+
* Title a web terminal from inside it (`very-happy mcp` change_title →
|
|
1322
|
+
* daemon /terminal-title → here). Same tmux truthfulness as the
|
|
1323
|
+
* `set-terminal-title` RPC.
|
|
1324
|
+
*/
|
|
1325
|
+
setTerminalTitle(terminalId: string, title: string, ifAbsent: boolean): boolean;
|
|
1284
1326
|
/**
|
|
1285
1327
|
* Push text to the clipboard of every web client the user has open
|
|
1286
1328
|
* (terminal-path claude → `very-happy mcp` → daemon /clipboard → here).
|
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-
|
|
1
|
+
export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-BtuOM9lw.mjs';
|
|
2
2
|
import 'axios';
|
|
3
3
|
import 'chalk';
|
|
4
4
|
import 'node:util';
|
|
@@ -3,30 +3,30 @@
|
|
|
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-BXOXRblP.cjs');
|
|
7
7
|
var limits = require('./limits-KdWKmwtH.cjs');
|
|
8
|
-
var persistence = require('./types-
|
|
9
|
-
require('
|
|
8
|
+
var persistence = require('./types-ClvvHves.cjs');
|
|
9
|
+
require('node:fs/promises');
|
|
10
10
|
require('node:os');
|
|
11
11
|
require('node:crypto');
|
|
12
|
-
require('
|
|
12
|
+
require('axios');
|
|
13
|
+
require('tweetnacl');
|
|
14
|
+
require('socket.io-client');
|
|
15
|
+
require('node:child_process');
|
|
16
|
+
require('node:fs');
|
|
13
17
|
require('node:path');
|
|
18
|
+
require('chalk');
|
|
19
|
+
require('cross-spawn');
|
|
14
20
|
require('node:readline');
|
|
15
|
-
require('node:fs');
|
|
16
21
|
require('./agentGuidance-BifkGXdE.cjs');
|
|
17
|
-
require('node:fs/promises');
|
|
18
22
|
require('fs/promises');
|
|
19
23
|
require('ink');
|
|
20
24
|
require('react');
|
|
21
25
|
require('@anthropic-ai/claude-agent-sdk');
|
|
22
|
-
require('axios');
|
|
23
26
|
require('node:events');
|
|
24
|
-
require('socket.io-client');
|
|
25
|
-
require('tweetnacl');
|
|
26
27
|
require('os');
|
|
27
28
|
require('child_process');
|
|
28
29
|
require('@paralleldrive/cuid2');
|
|
29
|
-
require('node:child_process');
|
|
30
30
|
require('fs');
|
|
31
31
|
require('path');
|
|
32
32
|
require('@anthropic-ai/sandbox-runtime');
|
|
@@ -49,11 +49,19 @@ require('node:util');
|
|
|
49
49
|
require('url');
|
|
50
50
|
require('node-pty');
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
});
|
|
52
|
+
const TERMINAL_TITLE_TOOL_NAME = "change_title";
|
|
53
|
+
function resolveMcpTerminalId(env) {
|
|
54
|
+
if (env.HAPPY_MCP_URL) return null;
|
|
55
|
+
const id = env.VH_TERMINAL_ID;
|
|
56
|
+
return id && /^[a-zA-Z0-9_-]{1,64}$/.test(id) ? id : null;
|
|
57
|
+
}
|
|
58
|
+
function resolveMcpToolSurface(env) {
|
|
59
|
+
if (env.HAPPY_SESSION_VARIANT !== "assistant") return "clipboard";
|
|
60
|
+
if (env.HAPPY_MANAGED === "1") return "clipboard";
|
|
61
|
+
return "assistant";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function registerMcpTools(server, surface, terminalId = null) {
|
|
57
65
|
server.registerTool(limits.CLIPBOARD_TOOL_NAME, {
|
|
58
66
|
description: limits.CLIPBOARD_TOOL_DESCRIPTION,
|
|
59
67
|
title: limits.CLIPBOARD_TOOL_TITLE,
|
|
@@ -81,9 +89,46 @@ async function handleMcpCommand() {
|
|
|
81
89
|
isError: true
|
|
82
90
|
};
|
|
83
91
|
});
|
|
92
|
+
if (terminalId) {
|
|
93
|
+
server.registerTool(TERMINAL_TITLE_TOOL_NAME, {
|
|
94
|
+
description: "Change the title of the very-happy web terminal this agent is running in",
|
|
95
|
+
title: "Change Terminal Title",
|
|
96
|
+
inputSchema: {
|
|
97
|
+
title: z.z.string().min(1).max(200).describe("The new title for this terminal")
|
|
98
|
+
}
|
|
99
|
+
}, async (args) => {
|
|
100
|
+
persistence.logger.debug(`[MCP] change_title called for terminal ${terminalId}`);
|
|
101
|
+
const result = await index.setTerminalTitleViaDaemon(terminalId, args.title);
|
|
102
|
+
if (result.ok) {
|
|
103
|
+
return {
|
|
104
|
+
content: [{ type: "text", text: `Successfully changed terminal title to: "${args.title}"` }],
|
|
105
|
+
isError: false
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
content: [{
|
|
110
|
+
type: "text",
|
|
111
|
+
text: `Failed to change terminal title: ${result.error || "unknown error"}. The very-happy daemon must be running on this machine (start it with \`very-happy daemon start\`).`
|
|
112
|
+
}],
|
|
113
|
+
isError: true
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
if (surface === "assistant") {
|
|
118
|
+
index.registerAssistantSessionTools(server);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async function handleMcpCommand() {
|
|
122
|
+
const server = new mcp_js.McpServer({
|
|
123
|
+
name: "very-happy",
|
|
124
|
+
version: "1.0.0"
|
|
125
|
+
});
|
|
126
|
+
const surface = resolveMcpToolSurface(process.env);
|
|
127
|
+
const terminalId = resolveMcpTerminalId(process.env);
|
|
128
|
+
registerMcpTools(server, surface, terminalId);
|
|
84
129
|
const transport = new stdio_js.StdioServerTransport();
|
|
85
130
|
await server.connect(transport);
|
|
86
|
-
persistence.logger.debug(
|
|
131
|
+
persistence.logger.debug(`[MCP] very-happy stdio MCP server started (surface=${surface}, terminal=${terminalId ?? "none"})`);
|
|
87
132
|
await new Promise((resolve) => {
|
|
88
133
|
process.stdin.on("close", resolve);
|
|
89
134
|
process.stdin.on("end", resolve);
|
|
@@ -91,3 +136,4 @@ async function handleMcpCommand() {
|
|
|
91
136
|
}
|
|
92
137
|
|
|
93
138
|
exports.handleMcpCommand = handleMcpCommand;
|
|
139
|
+
exports.registerMcpTools = registerMcpTools;
|
|
@@ -1,30 +1,30 @@
|
|
|
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-
|
|
4
|
+
import { p as pushClipboardViaDaemon, k as setTerminalTitleViaDaemon, m as registerAssistantSessionTools } from './index-DIXjhnV1.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-
|
|
7
|
-
import '
|
|
6
|
+
import { l as logger } from './types-BtuOM9lw.mjs';
|
|
7
|
+
import 'node:fs/promises';
|
|
8
8
|
import 'node:os';
|
|
9
9
|
import 'node:crypto';
|
|
10
|
-
import '
|
|
10
|
+
import 'axios';
|
|
11
|
+
import 'tweetnacl';
|
|
12
|
+
import 'socket.io-client';
|
|
13
|
+
import 'node:child_process';
|
|
14
|
+
import 'node:fs';
|
|
11
15
|
import 'node:path';
|
|
16
|
+
import 'chalk';
|
|
17
|
+
import 'cross-spawn';
|
|
12
18
|
import 'node:readline';
|
|
13
|
-
import 'node:fs';
|
|
14
19
|
import './agentGuidance-C2_pkgRI.mjs';
|
|
15
|
-
import 'node:fs/promises';
|
|
16
20
|
import 'fs/promises';
|
|
17
21
|
import 'ink';
|
|
18
22
|
import 'react';
|
|
19
23
|
import '@anthropic-ai/claude-agent-sdk';
|
|
20
|
-
import 'axios';
|
|
21
24
|
import 'node:events';
|
|
22
|
-
import 'socket.io-client';
|
|
23
|
-
import 'tweetnacl';
|
|
24
25
|
import 'os';
|
|
25
26
|
import 'child_process';
|
|
26
27
|
import '@paralleldrive/cuid2';
|
|
27
|
-
import 'node:child_process';
|
|
28
28
|
import 'fs';
|
|
29
29
|
import 'path';
|
|
30
30
|
import '@anthropic-ai/sandbox-runtime';
|
|
@@ -47,11 +47,19 @@ import 'node:util';
|
|
|
47
47
|
import 'url';
|
|
48
48
|
import 'node-pty';
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
});
|
|
50
|
+
const TERMINAL_TITLE_TOOL_NAME = "change_title";
|
|
51
|
+
function resolveMcpTerminalId(env) {
|
|
52
|
+
if (env.HAPPY_MCP_URL) return null;
|
|
53
|
+
const id = env.VH_TERMINAL_ID;
|
|
54
|
+
return id && /^[a-zA-Z0-9_-]{1,64}$/.test(id) ? id : null;
|
|
55
|
+
}
|
|
56
|
+
function resolveMcpToolSurface(env) {
|
|
57
|
+
if (env.HAPPY_SESSION_VARIANT !== "assistant") return "clipboard";
|
|
58
|
+
if (env.HAPPY_MANAGED === "1") return "clipboard";
|
|
59
|
+
return "assistant";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function registerMcpTools(server, surface, terminalId = null) {
|
|
55
63
|
server.registerTool(CLIPBOARD_TOOL_NAME, {
|
|
56
64
|
description: CLIPBOARD_TOOL_DESCRIPTION,
|
|
57
65
|
title: CLIPBOARD_TOOL_TITLE,
|
|
@@ -79,13 +87,50 @@ async function handleMcpCommand() {
|
|
|
79
87
|
isError: true
|
|
80
88
|
};
|
|
81
89
|
});
|
|
90
|
+
if (terminalId) {
|
|
91
|
+
server.registerTool(TERMINAL_TITLE_TOOL_NAME, {
|
|
92
|
+
description: "Change the title of the very-happy web terminal this agent is running in",
|
|
93
|
+
title: "Change Terminal Title",
|
|
94
|
+
inputSchema: {
|
|
95
|
+
title: z.string().min(1).max(200).describe("The new title for this terminal")
|
|
96
|
+
}
|
|
97
|
+
}, async (args) => {
|
|
98
|
+
logger.debug(`[MCP] change_title called for terminal ${terminalId}`);
|
|
99
|
+
const result = await setTerminalTitleViaDaemon(terminalId, args.title);
|
|
100
|
+
if (result.ok) {
|
|
101
|
+
return {
|
|
102
|
+
content: [{ type: "text", text: `Successfully changed terminal title to: "${args.title}"` }],
|
|
103
|
+
isError: false
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
content: [{
|
|
108
|
+
type: "text",
|
|
109
|
+
text: `Failed to change terminal title: ${result.error || "unknown error"}. The very-happy daemon must be running on this machine (start it with \`very-happy daemon start\`).`
|
|
110
|
+
}],
|
|
111
|
+
isError: true
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
if (surface === "assistant") {
|
|
116
|
+
registerAssistantSessionTools(server);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async function handleMcpCommand() {
|
|
120
|
+
const server = new McpServer({
|
|
121
|
+
name: "very-happy",
|
|
122
|
+
version: "1.0.0"
|
|
123
|
+
});
|
|
124
|
+
const surface = resolveMcpToolSurface(process.env);
|
|
125
|
+
const terminalId = resolveMcpTerminalId(process.env);
|
|
126
|
+
registerMcpTools(server, surface, terminalId);
|
|
82
127
|
const transport = new StdioServerTransport();
|
|
83
128
|
await server.connect(transport);
|
|
84
|
-
logger.debug(
|
|
129
|
+
logger.debug(`[MCP] very-happy stdio MCP server started (surface=${surface}, terminal=${terminalId ?? "none"})`);
|
|
85
130
|
await new Promise((resolve) => {
|
|
86
131
|
process.stdin.on("close", resolve);
|
|
87
132
|
process.stdin.on("end", resolve);
|
|
88
133
|
});
|
|
89
134
|
}
|
|
90
135
|
|
|
91
|
-
export { handleMcpCommand };
|
|
136
|
+
export { handleMcpCommand, registerMcpTools };
|
|
@@ -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,
|
|
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-BtuOM9lw.mjs';
|
|
6
|
+
import { I as GEMINI_API_KEY_ENV, J as GOOGLE_API_KEY_ENV, G as GEMINI_MODEL_ENV, C as BasePermissionHandler, K as BaseReasoningProcessor, n as initialMachineMetadata, o as createSessionMetadata, u as setupOfflineReconnection, v as notifyDaemonSessionStarted, x as MessageQueue2, y as hashObject, L as MessageBuffer, N as CHANGE_TITLE_INSTRUCTION, B as registerKillSessionHandler, z as startHappyServer } from './index-DIXjhnV1.mjs';
|
|
7
|
+
import { A as AcpBackend } from './AcpBackend-Bk9b823B.mjs';
|
|
8
|
+
import { readGeminiLocalConfig, determineGeminiModel, getGeminiModelSource, getInitialGeminiModel, saveGeminiModelToConfig } from './config-CIpgmGLR.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-
|
|
8
|
-
var index = require('./index-
|
|
9
|
-
var AcpBackend = require('./AcpBackend-
|
|
10
|
-
var config = require('./config-
|
|
7
|
+
var persistence = require('./types-ClvvHves.cjs');
|
|
8
|
+
var index = require('./index-BXOXRblP.cjs');
|
|
9
|
+
var AcpBackend = require('./AcpBackend-p_KNJkHc.cjs');
|
|
10
|
+
var config = require('./config-CkUn1dI4.cjs');
|
|
11
11
|
require('axios');
|
|
12
12
|
require('chalk');
|
|
13
13
|
require('node:util');
|
|
@@ -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-ClvvHves.cjs');
|
|
9
|
+
var AcpSessionManager = require('./AcpSessionManager-B9FTbpGQ.cjs');
|
|
10
|
+
var index = require('./index-BXOXRblP.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,
|
|
7
|
-
import { A as AcpSessionManager } from './AcpSessionManager-
|
|
8
|
-
import {
|
|
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-BtuOM9lw.mjs';
|
|
7
|
+
import { A as AcpSessionManager } from './AcpSessionManager-CDvqVHKf.mjs';
|
|
8
|
+
import { n as initialMachineMetadata, o as createSessionMetadata, u as setupOfflineReconnection, v as notifyDaemonSessionStarted, x as MessageQueue2, B as registerKillSessionHandler } from './index-DIXjhnV1.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-ClvvHves.cjs');
|
|
7
|
+
var index = require('./index-BXOXRblP.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-BtuOM9lw.mjs';
|
|
5
|
+
import { d as sendUserMessage, a as sessionWebUrl } from './index-DIXjhnV1.mjs';
|
|
6
6
|
import 'axios';
|
|
7
7
|
import 'node:util';
|
|
8
8
|
import 'node:os';
|