very-happy-cli 0.2.153 → 0.2.155
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-YDGv4E-g.mjs → AcpBackend-DVB0nzgR.mjs} +2 -2
- package/dist/{AcpBackend-DSt8nTYm.cjs → AcpBackend-DmFcRh54.cjs} +3 -3
- package/dist/{AcpSessionManager-uov6I9C8.cjs → AcpSessionManager-CWaSYTnT.cjs} +1 -1
- package/dist/{AcpSessionManager-Cxf5HQX1.mjs → AcpSessionManager-dGDgNb-p.mjs} +1 -1
- package/dist/agentGuidance-BWxFC6UL.mjs +1613 -0
- package/dist/agentGuidance-un7YPryB.cjs +1665 -0
- package/dist/{agentHome-D68Xh2ae.mjs → agentHome-ByLb2HFg.mjs} +5 -5
- package/dist/{agentHome-BJ7bde35.cjs → agentHome-aucT8BHw.cjs} +5 -5
- package/dist/{auto-CcXxfqkC.mjs → auto-BQnD6gVx.mjs} +21 -21
- package/dist/{auto-C-90ojIH.cjs → auto-P9RoJaY0.cjs} +24 -24
- package/dist/codex/happyMcpStdioBridge.cjs +6 -3
- package/dist/codex/happyMcpStdioBridge.mjs +6 -3
- package/dist/{config-CHJ189UJ.mjs → config-BPZ2Y6o8.mjs} +8 -8
- package/dist/{config-D23kF0_u.cjs → config-BoePh9PX.cjs} +8 -8
- package/dist/{index-D49WvbDT.cjs → index--KCpVs1c.cjs} +7 -7
- package/dist/{index-BacwoXzs.mjs → index-B4oXnbYw.mjs} +522 -729
- package/dist/{index-BgYZGODP.mjs → index-BjzdXb9x.mjs} +21 -13
- package/dist/{index-DEOVn46R.cjs → index-DRrLaljt.cjs} +21 -13
- package/dist/{index-BXA9fxbK.mjs → index-DVVRqaVG.mjs} +7 -7
- package/dist/{index-DHrwHxHf.cjs → index-D_fYUxVg.cjs} +579 -798
- package/dist/index.cjs +6 -6
- package/dist/index.mjs +6 -6
- package/dist/{install-BiOXBnnS.cjs → install-CGigiocs.cjs} +1 -1
- package/dist/{install-Ca7_Z3bV.mjs → install-DP5aPNEX.mjs} +1 -1
- package/dist/{installTerminalHooks-BF0kL0ae.cjs → installTerminalHooks-XrcPvfBs.cjs} +5 -5
- package/dist/{installTerminalHooks-Bpl32K75.mjs → installTerminalHooks-tIg7mANc.mjs} +5 -5
- package/dist/lib.cjs +2 -2
- package/dist/lib.mjs +2 -2
- package/dist/{limits-BtAuKRl2.mjs → limits-C_DW0M0q.mjs} +309 -13
- package/dist/{limits-DY_sFA3J.cjs → limits-DkfHJ3nS.cjs} +329 -12
- package/dist/{mcp-JpqI2POW.cjs → mcp-BqlXl10F.cjs} +23 -23
- package/dist/{mcp-DQkmk4VV.mjs → mcp-o7QglAQM.mjs} +17 -17
- package/dist/{piRuntime-DRbbeQ72.cjs → piRuntime-BxP4B_zY.cjs} +2 -2
- package/dist/{piRuntime-DBpe12NN.mjs → piRuntime-MjiJI-nV.mjs} +2 -2
- package/dist/{piTerminal-qdJ9KZVL.cjs → piTerminal-DYzRcwgb.cjs} +6 -6
- package/dist/{piTerminal-BoHvPEZ_.mjs → piTerminal-Dpq6yqKU.mjs} +6 -6
- package/dist/{runGemini-CtOEFvhf.cjs → runGemini-8Pxh94Fm.cjs} +7 -7
- package/dist/{runGemini-YqH7a-7O.mjs → runGemini-CDlcQ-OA.mjs} +6 -6
- package/dist/{runOpenClaw-DoqZXBvL.cjs → runOpenClaw-B5FSZIbK.cjs} +6 -6
- package/dist/{runOpenClaw-DSSyFQBb.mjs → runOpenClaw-YkhsgPs0.mjs} +5 -5
- package/dist/{send-9075kHZP.cjs → send-CwrYXTPr.cjs} +58 -54
- package/dist/{send-Cs-RwqNf.mjs → send-DJStmLBv.mjs} +56 -53
- package/dist/{sessions-iBnYzVUK.mjs → sessions-JaVXlSqj.mjs} +88 -45
- package/dist/{sessions-qULzUzlI.cjs → sessions-MX21NJXd.cjs} +99 -56
- package/dist/{spawn-C6fRkedx.mjs → spawn-BaPnjClT.mjs} +22 -22
- package/dist/{spawn-od9V23cc.cjs → spawn-cIoglKVf.cjs} +30 -30
- package/dist/{teams-CkrWQ4uM.mjs → teams-DXV5Pwwt.mjs} +8 -8
- package/dist/{teams-CrCzU-AV.cjs → teams-Dqk7F3D-.cjs} +8 -8
- package/dist/{todo-aCZmSt27.mjs → todo-2Z1REhfx.mjs} +8 -6
- package/dist/{todo-BCT_ZPuV.cjs → todo-Buuqn9gm.cjs} +8 -6
- package/dist/{types-BvqOVUOW.mjs → types-CkbfdRzq.mjs} +7 -267
- package/dist/{types-CUCU7Vw8.cjs → types-a2xsH2UI.cjs} +19 -295
- package/package.json +7 -7
- package/dist/agentGuidance-BM4kMNyr.cjs +0 -553
- package/dist/agentGuidance-C8unGWp7.mjs +0 -529
|
@@ -1,54 +1,20 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { D as DEFAULT_RECENT_LIMIT, M as MAX_READ_LIMIT, l as listAccountSessions,
|
|
3
|
-
import { i as isValidSessionId } from './
|
|
4
|
-
import 'node:
|
|
2
|
+
import { D as DEFAULT_RECENT_LIMIT, M as MAX_READ_LIMIT, l as listAccountSessions, e as listSessions, f as cliPeerSelf, g as listPeerSessions, s as sendPeerMessage, w as waitForTurnEnd, T as TurnWaitTimeoutError, h as readSessionTranscript, i as stopSession, j as resolvePermissionRequest, k as archiveSession, m as PEER_SCOPES } from './agentGuidance-BWxFC6UL.mjs';
|
|
3
|
+
import { d as readPersistedSessions, i as isValidSessionId } from './limits-C_DW0M0q.mjs';
|
|
4
|
+
import { resolve } from 'node:path';
|
|
5
|
+
import 'zod';
|
|
5
6
|
import 'node:crypto';
|
|
6
|
-
import './limits-BtAuKRl2.mjs';
|
|
7
7
|
import 'node:fs/promises';
|
|
8
8
|
import 'node:fs';
|
|
9
|
-
import 'node:
|
|
10
|
-
import 'zod';
|
|
11
|
-
import 'tweetnacl';
|
|
12
|
-
import 'node:util';
|
|
13
|
-
import '@paralleldrive/cuid2';
|
|
14
|
-
import 'cross-spawn';
|
|
15
|
-
import 'node:readline';
|
|
16
|
-
import './terminalTitleSuggest-DKgX3osW.mjs';
|
|
17
|
-
import 'path';
|
|
18
|
-
import 'url';
|
|
19
|
-
import './agentGuidance-C8unGWp7.mjs';
|
|
20
|
-
import 'fs/promises';
|
|
21
|
-
import 'ink';
|
|
22
|
-
import 'react';
|
|
23
|
-
import '@anthropic-ai/claude-agent-sdk';
|
|
9
|
+
import 'node:os';
|
|
24
10
|
import 'axios';
|
|
25
|
-
import 'node:events';
|
|
26
11
|
import 'socket.io-client';
|
|
27
|
-
import '
|
|
28
|
-
import '
|
|
29
|
-
import 'node:
|
|
30
|
-
import 'fs';
|
|
31
|
-
import '@anthropic-ai/sandbox-runtime';
|
|
32
|
-
import 'expo-server-sdk';
|
|
33
|
-
import 'crypto';
|
|
34
|
-
import 'ps-list';
|
|
35
|
-
import 'tmp';
|
|
36
|
-
import 'open';
|
|
37
|
-
import 'fastify';
|
|
38
|
-
import 'fastify-type-provider-zod';
|
|
39
|
-
import 'node:module';
|
|
40
|
-
import '@modelcontextprotocol/sdk/server/mcp.js';
|
|
41
|
-
import 'node:http';
|
|
42
|
-
import '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
43
|
-
import 'http';
|
|
44
|
-
import 'util';
|
|
45
|
-
import 'inquirer';
|
|
46
|
-
import 'node:url';
|
|
47
|
-
import 'node:readline/promises';
|
|
48
|
-
import 'node-pty';
|
|
12
|
+
import '@paralleldrive/cuid2';
|
|
13
|
+
import 'tweetnacl';
|
|
14
|
+
import 'node:util';
|
|
49
15
|
|
|
50
|
-
const ACTIONS = ["list", "read", "stop", "archive", "approve", "deny"];
|
|
51
|
-
const ACTIONS_NEEDING_ID = /* @__PURE__ */ new Set(["read", "stop", "archive", "approve", "deny"]);
|
|
16
|
+
const ACTIONS = ["list", "read", "stop", "archive", "approve", "deny", "peers", "message"];
|
|
17
|
+
const ACTIONS_NEEDING_ID = /* @__PURE__ */ new Set(["read", "stop", "archive", "approve", "deny", "message"]);
|
|
52
18
|
const ACTIONS_NEEDING_REQUEST_ID = /* @__PURE__ */ new Set(["approve", "deny"]);
|
|
53
19
|
const REQUEST_ID_RE = /^[a-zA-Z0-9_.:-]{1,128}$/;
|
|
54
20
|
function defaultOptions() {
|
|
@@ -86,6 +52,19 @@ function parseSessionsArgs(args) {
|
|
|
86
52
|
const value = args[++i];
|
|
87
53
|
if (value === void 0) throw new Error("--reason requires a value");
|
|
88
54
|
options.reason = value;
|
|
55
|
+
} else if (arg === "--scope") {
|
|
56
|
+
const value = args[++i];
|
|
57
|
+
if (value === void 0) throw new Error("--scope requires a value");
|
|
58
|
+
if (!PEER_SCOPES.includes(value)) throw new Error(`--scope must be one of ${PEER_SCOPES.join(", ")}`);
|
|
59
|
+
options.scope = value;
|
|
60
|
+
} else if (arg === "--cwd") {
|
|
61
|
+
const value = args[++i];
|
|
62
|
+
if (value === void 0) throw new Error("--cwd requires a value");
|
|
63
|
+
options.cwd = value;
|
|
64
|
+
} else if (arg === "--reply-to") {
|
|
65
|
+
const value = args[++i];
|
|
66
|
+
if (value === void 0 || value.trim() === "") throw new Error("--reply-to requires a value");
|
|
67
|
+
options.replyTo = value;
|
|
89
68
|
} else if (arg === "--tag") {
|
|
90
69
|
const value = args[++i];
|
|
91
70
|
if (value === void 0) throw new Error("--tag requires a value");
|
|
@@ -109,7 +88,7 @@ function parseSessionsArgs(args) {
|
|
|
109
88
|
}
|
|
110
89
|
}
|
|
111
90
|
if (!actionSeen) return defaultOptions();
|
|
112
|
-
const expectedPositionals = ACTIONS_NEEDING_REQUEST_ID.has(options.action) ? 2 : ACTIONS_NEEDING_ID.has(options.action) ? 1 : 0;
|
|
91
|
+
const expectedPositionals = ACTIONS_NEEDING_REQUEST_ID.has(options.action) || options.action === "message" ? 2 : ACTIONS_NEEDING_ID.has(options.action) ? 1 : 0;
|
|
113
92
|
if (positionals.length > expectedPositionals) {
|
|
114
93
|
throw new Error(`Unexpected ${expectedPositionals > 0 ? "extra " : ""}argument: ${positionals[expectedPositionals]}`);
|
|
115
94
|
}
|
|
@@ -119,6 +98,12 @@ function parseSessionsArgs(args) {
|
|
|
119
98
|
if (!isValidSessionId(id)) throw new Error(`Invalid session id: ${id}`);
|
|
120
99
|
options.sessionId = id;
|
|
121
100
|
}
|
|
101
|
+
if (options.action === "message") {
|
|
102
|
+
const text = positionals[1];
|
|
103
|
+
if (text === void 0) throw new Error("message requires a session id and the text to send");
|
|
104
|
+
if (text.trim() === "") throw new Error("message text is empty");
|
|
105
|
+
options.text = text;
|
|
106
|
+
}
|
|
122
107
|
if (ACTIONS_NEEDING_REQUEST_ID.has(options.action)) {
|
|
123
108
|
const requestId = positionals[1];
|
|
124
109
|
if (requestId === void 0) throw new Error(`${options.action} requires a session id and a request id`);
|
|
@@ -140,6 +125,11 @@ function parseSessionsArgs(args) {
|
|
|
140
125
|
if (options.wait) throw new Error("--wait only applies to `sessions read`");
|
|
141
126
|
}
|
|
142
127
|
if (options.timeoutSec !== void 0 && !options.wait) throw new Error("--timeout only applies to `sessions read --wait`");
|
|
128
|
+
if (options.action !== "peers") {
|
|
129
|
+
if (options.scope !== void 0) throw new Error("--scope only applies to `sessions peers`");
|
|
130
|
+
if (options.cwd !== void 0) throw new Error("--cwd only applies to `sessions peers`");
|
|
131
|
+
}
|
|
132
|
+
if (options.replyTo !== void 0 && options.action !== "message") throw new Error("--reply-to only applies to `sessions message`");
|
|
143
133
|
return options;
|
|
144
134
|
}
|
|
145
135
|
const SESSIONS_HELP = `
|
|
@@ -153,6 +143,8 @@ ${chalk.bold("Usage:")}
|
|
|
153
143
|
very-happy sessions archive <id> [--json]
|
|
154
144
|
very-happy sessions approve <id> <requestId> [--for-session] [--json]
|
|
155
145
|
very-happy sessions deny <id> <requestId> [--reason <text>] [--json]
|
|
146
|
+
very-happy sessions peers [--scope repo|cwd|machine] [--cwd <dir>] [--json]
|
|
147
|
+
very-happy sessions message <id> <text> [--reply-to <msgId>] [--json]
|
|
156
148
|
|
|
157
149
|
${chalk.bold("Actions:")}
|
|
158
150
|
list Running sessions plus recently seen ones, newest first.
|
|
@@ -169,6 +161,17 @@ ${chalk.bold("Actions:")}
|
|
|
169
161
|
the same RPC the web permission card sends. --for-session makes
|
|
170
162
|
it \`approved_for_session\` (the card's "allow for this session").
|
|
171
163
|
deny Answer it with deny (optional --reason is shown to the agent).
|
|
164
|
+
peers Other live sessions on this machine and the files each edited in
|
|
165
|
+
the last 30 minutes. Default scope \`repo\`: same git repository,
|
|
166
|
+
including its other worktrees (\`sameWorktree\` says which share
|
|
167
|
+
your checkout); \`cwd\`: same directory; \`machine\`: everything.
|
|
168
|
+
message Send <text> into a running session here. It arrives tagged with
|
|
169
|
+
the sender (the session named by HAPPY_SESSION_ID when run from a
|
|
170
|
+
managed session's shell, else this CLI) and tells the peer how to
|
|
171
|
+
reply. Refused for sessions that are not running here, not
|
|
172
|
+
spawned by this machine, or terminal mirrors. \`delivered\`
|
|
173
|
+
follows \`very-happy send\`: true only when a wrapper was attached
|
|
174
|
+
before and after the POST (\`stored\` = it is on the server anyway).
|
|
172
175
|
|
|
173
176
|
${chalk.bold("Options:")}
|
|
174
177
|
--all list only: account-wide over REST instead of this
|
|
@@ -190,6 +193,10 @@ ${chalk.bold("Options:")}
|
|
|
190
193
|
--timeout <s> read --wait only: give up after <s> seconds (default 600).
|
|
191
194
|
--for-session approve only: approved_for_session instead of approved.
|
|
192
195
|
--reason <text> deny only: reason forwarded to the wrapper.
|
|
196
|
+
--scope <s> peers only: repo (default) | cwd | machine.
|
|
197
|
+
--cwd <dir> peers only: directory the scope is computed from
|
|
198
|
+
(default: the process cwd, or HAPPY_SESSION_ID's cwd).
|
|
199
|
+
--reply-to <id> message only: the peer message id being answered.
|
|
193
200
|
--json Machine-readable output.
|
|
194
201
|
-h, --help Show this help
|
|
195
202
|
|
|
@@ -290,6 +297,42 @@ async function handleSessionsCommand(args) {
|
|
|
290
297
|
}
|
|
291
298
|
process.exit(0);
|
|
292
299
|
}
|
|
300
|
+
if (options.action === "peers" || options.action === "message") {
|
|
301
|
+
const cwd = options.cwd ? resolve(options.cwd) : process.cwd();
|
|
302
|
+
const persisted = readPersistedSessions();
|
|
303
|
+
const context = { self: () => cliPeerSelf(process.env, cwd, persisted), readPersisted: () => persisted };
|
|
304
|
+
if (options.action === "peers") {
|
|
305
|
+
const listing = await listPeerSessions(context, options.scope ?? "repo");
|
|
306
|
+
if (options.json) {
|
|
307
|
+
console.log(JSON.stringify(listing));
|
|
308
|
+
} else if (listing.peers.length === 0) {
|
|
309
|
+
console.log(`No other live sessions in scope "${listing.scope}"${listing.self.repoRoot ? ` (repo ${listing.self.repoRoot})` : ""}.`);
|
|
310
|
+
} else {
|
|
311
|
+
for (const peer of listing.peers) {
|
|
312
|
+
const parts = [peer.sessionId, `[${peer.kind === "mirror" ? "terminal" : "running"}]`];
|
|
313
|
+
if (peer.title) parts.push(`title="${peer.title}"`);
|
|
314
|
+
if (peer.flavor) parts.push(`agent=${peer.flavor}`);
|
|
315
|
+
if (peer.cwd) parts.push(`cwd=${peer.cwd}${peer.sameWorktree ? "" : " (other worktree)"}`);
|
|
316
|
+
parts.push(peer.url);
|
|
317
|
+
console.log(parts.join(" "));
|
|
318
|
+
for (const edit of peer.edits) console.log(chalk.dim(` ${edit.tool} ${edit.path} (${Math.round((Date.now() - edit.at) / 6e4)}m ago)`));
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
process.exit(0);
|
|
322
|
+
}
|
|
323
|
+
const target = options.sessionId;
|
|
324
|
+
try {
|
|
325
|
+
const result = await sendPeerMessage(context, { to: target, body: options.text, replyTo: options.replyTo });
|
|
326
|
+
if (options.json) console.log(JSON.stringify(result));
|
|
327
|
+
else if (result.delivered) console.log(`Message ${result.messageId} delivered to ${target}
|
|
328
|
+
${result.url}`);
|
|
329
|
+
else console.error(chalk.yellow("Not delivered:"), result.error ?? `session is ${result.status}`, result.stored ? "(stored server-side, unread)" : "");
|
|
330
|
+
process.exit(result.delivered ? 0 : 1);
|
|
331
|
+
} catch (error) {
|
|
332
|
+
if (options.json) console.log(JSON.stringify({ delivered: false, to: target, error: error instanceof Error ? error.message : String(error) }));
|
|
333
|
+
throw error;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
293
336
|
const sessionId = options.sessionId;
|
|
294
337
|
if (options.action === "read") {
|
|
295
338
|
let timedOut = false;
|
|
@@ -1,56 +1,22 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chalk = require('chalk');
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
require('node:
|
|
4
|
+
var agentGuidance = require('./agentGuidance-un7YPryB.cjs');
|
|
5
|
+
var persistence = require('./limits-DkfHJ3nS.cjs');
|
|
6
|
+
var path = require('node:path');
|
|
7
|
+
require('zod');
|
|
7
8
|
require('node:crypto');
|
|
8
|
-
require('./limits-DY_sFA3J.cjs');
|
|
9
9
|
require('node:fs/promises');
|
|
10
10
|
require('node:fs');
|
|
11
|
-
require('node:
|
|
12
|
-
require('zod');
|
|
13
|
-
require('tweetnacl');
|
|
14
|
-
require('node:util');
|
|
15
|
-
require('@paralleldrive/cuid2');
|
|
16
|
-
require('cross-spawn');
|
|
17
|
-
require('node:readline');
|
|
18
|
-
require('./terminalTitleSuggest-Dji8I0Jy.cjs');
|
|
19
|
-
require('path');
|
|
20
|
-
require('url');
|
|
21
|
-
require('./agentGuidance-BM4kMNyr.cjs');
|
|
22
|
-
require('fs/promises');
|
|
23
|
-
require('ink');
|
|
24
|
-
require('react');
|
|
25
|
-
require('@anthropic-ai/claude-agent-sdk');
|
|
11
|
+
require('node:os');
|
|
26
12
|
require('axios');
|
|
27
|
-
require('node:events');
|
|
28
13
|
require('socket.io-client');
|
|
29
|
-
require('
|
|
30
|
-
require('
|
|
31
|
-
require('node:
|
|
32
|
-
require('fs');
|
|
33
|
-
require('@anthropic-ai/sandbox-runtime');
|
|
34
|
-
require('expo-server-sdk');
|
|
35
|
-
require('crypto');
|
|
36
|
-
require('ps-list');
|
|
37
|
-
require('tmp');
|
|
38
|
-
require('open');
|
|
39
|
-
require('fastify');
|
|
40
|
-
require('fastify-type-provider-zod');
|
|
41
|
-
require('node:module');
|
|
42
|
-
require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
43
|
-
require('node:http');
|
|
44
|
-
require('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
45
|
-
require('http');
|
|
46
|
-
require('util');
|
|
47
|
-
require('inquirer');
|
|
48
|
-
require('node:url');
|
|
49
|
-
require('node:readline/promises');
|
|
50
|
-
require('node-pty');
|
|
14
|
+
require('@paralleldrive/cuid2');
|
|
15
|
+
require('tweetnacl');
|
|
16
|
+
require('node:util');
|
|
51
17
|
|
|
52
|
-
const ACTIONS = ["list", "read", "stop", "archive", "approve", "deny"];
|
|
53
|
-
const ACTIONS_NEEDING_ID = /* @__PURE__ */ new Set(["read", "stop", "archive", "approve", "deny"]);
|
|
18
|
+
const ACTIONS = ["list", "read", "stop", "archive", "approve", "deny", "peers", "message"];
|
|
19
|
+
const ACTIONS_NEEDING_ID = /* @__PURE__ */ new Set(["read", "stop", "archive", "approve", "deny", "message"]);
|
|
54
20
|
const ACTIONS_NEEDING_REQUEST_ID = /* @__PURE__ */ new Set(["approve", "deny"]);
|
|
55
21
|
const REQUEST_ID_RE = /^[a-zA-Z0-9_.:-]{1,128}$/;
|
|
56
22
|
function defaultOptions() {
|
|
@@ -88,6 +54,19 @@ function parseSessionsArgs(args) {
|
|
|
88
54
|
const value = args[++i];
|
|
89
55
|
if (value === void 0) throw new Error("--reason requires a value");
|
|
90
56
|
options.reason = value;
|
|
57
|
+
} else if (arg === "--scope") {
|
|
58
|
+
const value = args[++i];
|
|
59
|
+
if (value === void 0) throw new Error("--scope requires a value");
|
|
60
|
+
if (!agentGuidance.PEER_SCOPES.includes(value)) throw new Error(`--scope must be one of ${agentGuidance.PEER_SCOPES.join(", ")}`);
|
|
61
|
+
options.scope = value;
|
|
62
|
+
} else if (arg === "--cwd") {
|
|
63
|
+
const value = args[++i];
|
|
64
|
+
if (value === void 0) throw new Error("--cwd requires a value");
|
|
65
|
+
options.cwd = value;
|
|
66
|
+
} else if (arg === "--reply-to") {
|
|
67
|
+
const value = args[++i];
|
|
68
|
+
if (value === void 0 || value.trim() === "") throw new Error("--reply-to requires a value");
|
|
69
|
+
options.replyTo = value;
|
|
91
70
|
} else if (arg === "--tag") {
|
|
92
71
|
const value = args[++i];
|
|
93
72
|
if (value === void 0) throw new Error("--tag requires a value");
|
|
@@ -111,16 +90,22 @@ function parseSessionsArgs(args) {
|
|
|
111
90
|
}
|
|
112
91
|
}
|
|
113
92
|
if (!actionSeen) return defaultOptions();
|
|
114
|
-
const expectedPositionals = ACTIONS_NEEDING_REQUEST_ID.has(options.action) ? 2 : ACTIONS_NEEDING_ID.has(options.action) ? 1 : 0;
|
|
93
|
+
const expectedPositionals = ACTIONS_NEEDING_REQUEST_ID.has(options.action) || options.action === "message" ? 2 : ACTIONS_NEEDING_ID.has(options.action) ? 1 : 0;
|
|
115
94
|
if (positionals.length > expectedPositionals) {
|
|
116
95
|
throw new Error(`Unexpected ${expectedPositionals > 0 ? "extra " : ""}argument: ${positionals[expectedPositionals]}`);
|
|
117
96
|
}
|
|
118
97
|
if (ACTIONS_NEEDING_ID.has(options.action)) {
|
|
119
98
|
const id = positionals[0];
|
|
120
99
|
if (id === void 0) throw new Error(`${options.action} requires a session id`);
|
|
121
|
-
if (!
|
|
100
|
+
if (!persistence.isValidSessionId(id)) throw new Error(`Invalid session id: ${id}`);
|
|
122
101
|
options.sessionId = id;
|
|
123
102
|
}
|
|
103
|
+
if (options.action === "message") {
|
|
104
|
+
const text = positionals[1];
|
|
105
|
+
if (text === void 0) throw new Error("message requires a session id and the text to send");
|
|
106
|
+
if (text.trim() === "") throw new Error("message text is empty");
|
|
107
|
+
options.text = text;
|
|
108
|
+
}
|
|
124
109
|
if (ACTIONS_NEEDING_REQUEST_ID.has(options.action)) {
|
|
125
110
|
const requestId = positionals[1];
|
|
126
111
|
if (requestId === void 0) throw new Error(`${options.action} requires a session id and a request id`);
|
|
@@ -142,6 +127,11 @@ function parseSessionsArgs(args) {
|
|
|
142
127
|
if (options.wait) throw new Error("--wait only applies to `sessions read`");
|
|
143
128
|
}
|
|
144
129
|
if (options.timeoutSec !== void 0 && !options.wait) throw new Error("--timeout only applies to `sessions read --wait`");
|
|
130
|
+
if (options.action !== "peers") {
|
|
131
|
+
if (options.scope !== void 0) throw new Error("--scope only applies to `sessions peers`");
|
|
132
|
+
if (options.cwd !== void 0) throw new Error("--cwd only applies to `sessions peers`");
|
|
133
|
+
}
|
|
134
|
+
if (options.replyTo !== void 0 && options.action !== "message") throw new Error("--reply-to only applies to `sessions message`");
|
|
145
135
|
return options;
|
|
146
136
|
}
|
|
147
137
|
const SESSIONS_HELP = `
|
|
@@ -155,6 +145,8 @@ ${chalk.bold("Usage:")}
|
|
|
155
145
|
very-happy sessions archive <id> [--json]
|
|
156
146
|
very-happy sessions approve <id> <requestId> [--for-session] [--json]
|
|
157
147
|
very-happy sessions deny <id> <requestId> [--reason <text>] [--json]
|
|
148
|
+
very-happy sessions peers [--scope repo|cwd|machine] [--cwd <dir>] [--json]
|
|
149
|
+
very-happy sessions message <id> <text> [--reply-to <msgId>] [--json]
|
|
158
150
|
|
|
159
151
|
${chalk.bold("Actions:")}
|
|
160
152
|
list Running sessions plus recently seen ones, newest first.
|
|
@@ -171,6 +163,17 @@ ${chalk.bold("Actions:")}
|
|
|
171
163
|
the same RPC the web permission card sends. --for-session makes
|
|
172
164
|
it \`approved_for_session\` (the card's "allow for this session").
|
|
173
165
|
deny Answer it with deny (optional --reason is shown to the agent).
|
|
166
|
+
peers Other live sessions on this machine and the files each edited in
|
|
167
|
+
the last 30 minutes. Default scope \`repo\`: same git repository,
|
|
168
|
+
including its other worktrees (\`sameWorktree\` says which share
|
|
169
|
+
your checkout); \`cwd\`: same directory; \`machine\`: everything.
|
|
170
|
+
message Send <text> into a running session here. It arrives tagged with
|
|
171
|
+
the sender (the session named by HAPPY_SESSION_ID when run from a
|
|
172
|
+
managed session's shell, else this CLI) and tells the peer how to
|
|
173
|
+
reply. Refused for sessions that are not running here, not
|
|
174
|
+
spawned by this machine, or terminal mirrors. \`delivered\`
|
|
175
|
+
follows \`very-happy send\`: true only when a wrapper was attached
|
|
176
|
+
before and after the POST (\`stored\` = it is on the server anyway).
|
|
174
177
|
|
|
175
178
|
${chalk.bold("Options:")}
|
|
176
179
|
--all list only: account-wide over REST instead of this
|
|
@@ -180,8 +183,8 @@ ${chalk.bold("Options:")}
|
|
|
180
183
|
\`spawn --spawned-by\`). With --all only decryptable rows
|
|
181
184
|
can match.
|
|
182
185
|
--limit <n> list: how many NOT-running / not-attention sessions to
|
|
183
|
-
include (default ${
|
|
184
|
-
never cut). read: how many messages (default 20, max ${
|
|
186
|
+
include (default ${agentGuidance.DEFAULT_RECENT_LIMIT}; running and attention rows are
|
|
187
|
+
never cut). read: how many messages (default 20, max ${agentGuidance.MAX_READ_LIMIT}).
|
|
185
188
|
--full read only: do not truncate entries (default caps each
|
|
186
189
|
line at 500 chars).
|
|
187
190
|
--answer read only: print just the agent's reply to the latest
|
|
@@ -192,6 +195,10 @@ ${chalk.bold("Options:")}
|
|
|
192
195
|
--timeout <s> read --wait only: give up after <s> seconds (default 600).
|
|
193
196
|
--for-session approve only: approved_for_session instead of approved.
|
|
194
197
|
--reason <text> deny only: reason forwarded to the wrapper.
|
|
198
|
+
--scope <s> peers only: repo (default) | cwd | machine.
|
|
199
|
+
--cwd <dir> peers only: directory the scope is computed from
|
|
200
|
+
(default: the process cwd, or HAPPY_SESSION_ID's cwd).
|
|
201
|
+
--reply-to <id> message only: the peer message id being answered.
|
|
195
202
|
--json Machine-readable output.
|
|
196
203
|
-h, --help Show this help
|
|
197
204
|
|
|
@@ -267,7 +274,7 @@ async function handleSessionsCommand(args) {
|
|
|
267
274
|
}
|
|
268
275
|
try {
|
|
269
276
|
if (options.action === "list" && options.all) {
|
|
270
|
-
const sessions = await
|
|
277
|
+
const sessions = await agentGuidance.listAccountSessions({ tag: options.tag, recentLimit: options.limit, includeArchived: options.includeArchived });
|
|
271
278
|
if (options.json) {
|
|
272
279
|
console.log(JSON.stringify({ sessions, scope: "account" }));
|
|
273
280
|
} else if (sessions.length === 0) {
|
|
@@ -282,7 +289,7 @@ async function handleSessionsCommand(args) {
|
|
|
282
289
|
process.exit(0);
|
|
283
290
|
}
|
|
284
291
|
if (options.action === "list") {
|
|
285
|
-
const sessions = await
|
|
292
|
+
const sessions = await agentGuidance.listSessions({ tag: options.tag, recentLimit: options.limit });
|
|
286
293
|
if (options.json) {
|
|
287
294
|
console.log(JSON.stringify({ sessions }));
|
|
288
295
|
} else if (sessions.length === 0) {
|
|
@@ -292,19 +299,55 @@ async function handleSessionsCommand(args) {
|
|
|
292
299
|
}
|
|
293
300
|
process.exit(0);
|
|
294
301
|
}
|
|
302
|
+
if (options.action === "peers" || options.action === "message") {
|
|
303
|
+
const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd();
|
|
304
|
+
const persisted = persistence.readPersistedSessions();
|
|
305
|
+
const context = { self: () => agentGuidance.cliPeerSelf(process.env, cwd, persisted), readPersisted: () => persisted };
|
|
306
|
+
if (options.action === "peers") {
|
|
307
|
+
const listing = await agentGuidance.listPeerSessions(context, options.scope ?? "repo");
|
|
308
|
+
if (options.json) {
|
|
309
|
+
console.log(JSON.stringify(listing));
|
|
310
|
+
} else if (listing.peers.length === 0) {
|
|
311
|
+
console.log(`No other live sessions in scope "${listing.scope}"${listing.self.repoRoot ? ` (repo ${listing.self.repoRoot})` : ""}.`);
|
|
312
|
+
} else {
|
|
313
|
+
for (const peer of listing.peers) {
|
|
314
|
+
const parts = [peer.sessionId, `[${peer.kind === "mirror" ? "terminal" : "running"}]`];
|
|
315
|
+
if (peer.title) parts.push(`title="${peer.title}"`);
|
|
316
|
+
if (peer.flavor) parts.push(`agent=${peer.flavor}`);
|
|
317
|
+
if (peer.cwd) parts.push(`cwd=${peer.cwd}${peer.sameWorktree ? "" : " (other worktree)"}`);
|
|
318
|
+
parts.push(peer.url);
|
|
319
|
+
console.log(parts.join(" "));
|
|
320
|
+
for (const edit of peer.edits) console.log(chalk.dim(` ${edit.tool} ${edit.path} (${Math.round((Date.now() - edit.at) / 6e4)}m ago)`));
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
process.exit(0);
|
|
324
|
+
}
|
|
325
|
+
const target = options.sessionId;
|
|
326
|
+
try {
|
|
327
|
+
const result = await agentGuidance.sendPeerMessage(context, { to: target, body: options.text, replyTo: options.replyTo });
|
|
328
|
+
if (options.json) console.log(JSON.stringify(result));
|
|
329
|
+
else if (result.delivered) console.log(`Message ${result.messageId} delivered to ${target}
|
|
330
|
+
${result.url}`);
|
|
331
|
+
else console.error(chalk.yellow("Not delivered:"), result.error ?? `session is ${result.status}`, result.stored ? "(stored server-side, unread)" : "");
|
|
332
|
+
process.exit(result.delivered ? 0 : 1);
|
|
333
|
+
} catch (error) {
|
|
334
|
+
if (options.json) console.log(JSON.stringify({ delivered: false, to: target, error: error instanceof Error ? error.message : String(error) }));
|
|
335
|
+
throw error;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
295
338
|
const sessionId = options.sessionId;
|
|
296
339
|
if (options.action === "read") {
|
|
297
340
|
let timedOut = false;
|
|
298
341
|
if (options.wait) {
|
|
299
342
|
try {
|
|
300
|
-
await
|
|
343
|
+
await agentGuidance.waitForTurnEnd(sessionId, { timeoutMs: (options.timeoutSec ?? 600) * 1e3 });
|
|
301
344
|
} catch (error) {
|
|
302
|
-
if (!(error instanceof
|
|
345
|
+
if (!(error instanceof agentGuidance.TurnWaitTimeoutError)) throw error;
|
|
303
346
|
timedOut = true;
|
|
304
347
|
console.error(chalk.yellow("Timeout:"), error.message);
|
|
305
348
|
}
|
|
306
349
|
}
|
|
307
|
-
const result = await
|
|
350
|
+
const result = await agentGuidance.readSessionTranscript(sessionId, options.limit ?? 20, { full: options.full });
|
|
308
351
|
if (options.json) {
|
|
309
352
|
console.log(JSON.stringify(options.answer ? { sessionId, turn: result.turn } : result));
|
|
310
353
|
} else if (options.answer) {
|
|
@@ -320,7 +363,7 @@ async function handleSessionsCommand(args) {
|
|
|
320
363
|
process.exit(timedOut ? 2 : 0);
|
|
321
364
|
}
|
|
322
365
|
if (options.action === "stop") {
|
|
323
|
-
const stopped = await
|
|
366
|
+
const stopped = await agentGuidance.stopSession(sessionId);
|
|
324
367
|
if (!stopped) {
|
|
325
368
|
if (options.json) console.log(JSON.stringify({ sessionId, stopped: false }));
|
|
326
369
|
console.error(chalk.red("Error:"), `Session ${sessionId} is not among the daemon's running sessions.`);
|
|
@@ -335,7 +378,7 @@ async function handleSessionsCommand(args) {
|
|
|
335
378
|
const verdict = options.action === "approve" ? { kind: "approve", forSession: options.forSession } : { kind: "deny", reason: options.reason };
|
|
336
379
|
let result;
|
|
337
380
|
try {
|
|
338
|
-
result = await
|
|
381
|
+
result = await agentGuidance.resolvePermissionRequest(sessionId, requestId, verdict, {
|
|
339
382
|
// T-014: a rate refusal waits (bounded) before re-sending;
|
|
340
383
|
// say so on stderr so the wait does not look like a hang.
|
|
341
384
|
onRateLimited: ({ attempt, waitMs, serverError }) => {
|
|
@@ -360,7 +403,7 @@ async function handleSessionsCommand(args) {
|
|
|
360
403
|
}
|
|
361
404
|
process.exit(0);
|
|
362
405
|
}
|
|
363
|
-
await
|
|
406
|
+
await agentGuidance.archiveSession(sessionId);
|
|
364
407
|
if (options.json) console.log(JSON.stringify({ sessionId, archived: true }));
|
|
365
408
|
else console.log(`Archived ${sessionId}`);
|
|
366
409
|
process.exit(0);
|
|
@@ -1,38 +1,36 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { readFileSync, statSync } from 'node:fs';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import '
|
|
8
|
-
import 'node:events';
|
|
9
|
-
import 'socket.io-client';
|
|
4
|
+
import { d as readPersistedSessions, k as checkIfDaemonRunningAndCleanupStaleState, l as logger, m as spawnDaemonSession, n as stopDaemonSession } from './limits-C_DW0M0q.mjs';
|
|
5
|
+
import { r as resolveSpawnPermissionMode, c as resolveFirstMessageMeta, i as isValidSpawnOrigin, s as sanitizeSpawnPermissionMode, A as ALLOWED_SPAWN_PERMISSION_MODES, S as SPAWN_AGENTS } from './index-B4oXnbYw.mjs';
|
|
6
|
+
import { f as forkSession, g as getProjectPath, F as ForkSourceMissingError, C as CodexAppServerClient, c as forkCodexThread } from './types-CkbfdRzq.mjs';
|
|
7
|
+
import { x as readSessionMetadata, o as sessionWebUrl, y as waitForSessionKey, z as sendUserMessage } from './agentGuidance-BWxFC6UL.mjs';
|
|
10
8
|
import 'zod';
|
|
9
|
+
import '@paralleldrive/cuid2';
|
|
10
|
+
import 'node:fs/promises';
|
|
11
11
|
import 'node:crypto';
|
|
12
|
-
import '
|
|
13
|
-
import 'util';
|
|
14
|
-
import '
|
|
15
|
-
import 'crypto';
|
|
16
|
-
import 'path';
|
|
12
|
+
import 'tweetnacl';
|
|
13
|
+
import 'node:util';
|
|
14
|
+
import 'node:os';
|
|
17
15
|
import 'cross-spawn';
|
|
16
|
+
import 'node:readline';
|
|
18
17
|
import './terminalTitleSuggest-DKgX3osW.mjs';
|
|
18
|
+
import 'path';
|
|
19
19
|
import 'url';
|
|
20
|
+
import 'fs/promises';
|
|
21
|
+
import 'ink';
|
|
22
|
+
import 'react';
|
|
23
|
+
import '@anthropic-ai/claude-agent-sdk';
|
|
24
|
+
import 'axios';
|
|
25
|
+
import 'node:events';
|
|
26
|
+
import 'socket.io-client';
|
|
20
27
|
import 'os';
|
|
21
|
-
import '
|
|
22
|
-
import 'node:fs/promises';
|
|
23
|
-
import 'node:os';
|
|
28
|
+
import 'child_process';
|
|
24
29
|
import 'node:child_process';
|
|
25
|
-
import 'node-pty';
|
|
26
30
|
import 'fs';
|
|
27
|
-
import 'tweetnacl';
|
|
28
|
-
import 'node:readline';
|
|
29
31
|
import '@anthropic-ai/sandbox-runtime';
|
|
30
32
|
import 'expo-server-sdk';
|
|
31
|
-
import '
|
|
32
|
-
import './agentGuidance-C8unGWp7.mjs';
|
|
33
|
-
import 'ink';
|
|
34
|
-
import 'react';
|
|
35
|
-
import '@anthropic-ai/claude-agent-sdk';
|
|
33
|
+
import 'crypto';
|
|
36
34
|
import 'ps-list';
|
|
37
35
|
import 'tmp';
|
|
38
36
|
import 'open';
|
|
@@ -43,9 +41,11 @@ import '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
43
41
|
import 'node:http';
|
|
44
42
|
import '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
45
43
|
import 'http';
|
|
44
|
+
import 'util';
|
|
46
45
|
import 'inquirer';
|
|
47
46
|
import 'node:url';
|
|
48
47
|
import 'node:readline/promises';
|
|
48
|
+
import 'node-pty';
|
|
49
49
|
|
|
50
50
|
function nonEmpty(value) {
|
|
51
51
|
return typeof value === "string" && value.trim().length > 0;
|