very-happy-cli 0.2.108 → 0.2.109
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-D4vV6SVl.cjs → AcpBackend-Cc4Ilypg.cjs} +1 -1
- package/dist/{AcpBackend-DwR8rrkS.mjs → AcpBackend-DOzPxcth.mjs} +1 -1
- package/dist/{AcpSessionManager-CPHDZ-nz.cjs → AcpSessionManager-CLfzatC_.cjs} +1 -1
- package/dist/{AcpSessionManager-C057dkLF.mjs → AcpSessionManager-DDN-Yir4.mjs} +1 -1
- package/dist/{config-BvVwprR0.cjs → config-DiVKfYr0.cjs} +2 -2
- package/dist/{config-DKMwLc1k.mjs → config-DnvzvFHR.mjs} +2 -2
- package/dist/{index-C7N-ONU_.cjs → index-B2U15moC.cjs} +2 -2
- package/dist/{index-DYY1DUOD.mjs → index-CGKxZKlo.mjs} +2 -2
- package/dist/{index-Db5m34eh.cjs → index-D2qU5HP4.cjs} +4 -4
- package/dist/{index-CzSv4d_S.mjs → index-DO-9Ep72.mjs} +175 -89
- package/dist/{index-BXnHT-Wu.mjs → index-DaQIcHvY.mjs} +5 -5
- package/dist/{index-DM0Ku1Rv.cjs → index-dd2R8uSE.cjs} +185 -92
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{installTerminalHooks-Cs49gg_E.mjs → installTerminalHooks-BDagPTQW.mjs} +2 -2
- package/dist/{installTerminalHooks-BpvWmkZ9.cjs → installTerminalHooks-BoUmuYdq.cjs} +2 -2
- package/dist/lib.cjs +1 -1
- package/dist/lib.mjs +1 -1
- package/dist/{mcp-DY17lhMH.mjs → mcp-Ck_y0mCB.mjs} +2 -2
- package/dist/{mcp-rTSmj-tn.cjs → mcp-Du1QEnIf.cjs} +2 -2
- package/dist/{runGemini-Bqs52hw_.mjs → runGemini-D20S6Lc3.mjs} +4 -4
- package/dist/{runGemini-B3Mme1zr.cjs → runGemini-DV2M0A_k.cjs} +4 -4
- package/dist/{runOpenClaw-B2V9j9Le.cjs → runOpenClaw-C1Q2zl--.cjs} +3 -3
- package/dist/{runOpenClaw-CpbsQ7NZ.mjs → runOpenClaw-CuuXkfDE.mjs} +3 -3
- package/dist/{send-CLdMBQ8e.cjs → send-CtgnnJic.cjs} +2 -2
- package/dist/{send-uHgpvIqm.mjs → send-yUiBqHHL.mjs} +2 -2
- package/dist/sessions-BsaCq0Do.mjs +200 -0
- package/dist/sessions-CbbZhOTy.cjs +204 -0
- package/dist/{spawn-Dt4ujmHH.mjs → spawn-BKBY9P3J.mjs} +16 -3
- package/dist/{spawn-BXbVzbMs.cjs → spawn-CTO_hR8v.cjs} +16 -3
- package/dist/{types-D0-nhvuW.mjs → types-BKCvo4Cv.mjs} +8 -8
- package/dist/{types-D4bwyM-D.cjs → types-Cg8zzX_f.cjs} +8 -8
- package/package.json +7 -7
|
@@ -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-Cg8zzX_f.cjs');
|
|
7
|
+
var index = require('./index-dd2R8uSE.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 { b as sendUserMessage, a as sessionWebUrl } from './index-
|
|
4
|
+
import { r as readPersistedSessions, c as configuration } from './types-BKCvo4Cv.mjs';
|
|
5
|
+
import { b as sendUserMessage, a as sessionWebUrl } from './index-DO-9Ep72.mjs';
|
|
6
6
|
import 'axios';
|
|
7
7
|
import 'node:util';
|
|
8
8
|
import 'node:os';
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { D as DEFAULT_RECENT_LIMIT, M as MAX_READ_LIMIT, l as listSessions, r as readSessionTranscript, d as stopSession, e as archiveSession } from './index-DO-9Ep72.mjs';
|
|
3
|
+
import { i as isValidSessionId } from './types-BKCvo4Cv.mjs';
|
|
4
|
+
import 'node:os';
|
|
5
|
+
import 'node:crypto';
|
|
6
|
+
import 'cross-spawn';
|
|
7
|
+
import 'node:path';
|
|
8
|
+
import 'node:readline';
|
|
9
|
+
import 'node:fs';
|
|
10
|
+
import './agentGuidance-C2_pkgRI.mjs';
|
|
11
|
+
import 'node:fs/promises';
|
|
12
|
+
import 'fs/promises';
|
|
13
|
+
import 'ink';
|
|
14
|
+
import 'react';
|
|
15
|
+
import '@anthropic-ai/claude-agent-sdk';
|
|
16
|
+
import 'axios';
|
|
17
|
+
import 'node:events';
|
|
18
|
+
import 'socket.io-client';
|
|
19
|
+
import 'tweetnacl';
|
|
20
|
+
import 'os';
|
|
21
|
+
import 'child_process';
|
|
22
|
+
import '@paralleldrive/cuid2';
|
|
23
|
+
import 'node:child_process';
|
|
24
|
+
import 'fs';
|
|
25
|
+
import 'path';
|
|
26
|
+
import '@anthropic-ai/sandbox-runtime';
|
|
27
|
+
import 'expo-server-sdk';
|
|
28
|
+
import 'crypto';
|
|
29
|
+
import 'ps-list';
|
|
30
|
+
import 'tmp';
|
|
31
|
+
import 'open';
|
|
32
|
+
import 'fastify';
|
|
33
|
+
import 'zod';
|
|
34
|
+
import 'fastify-type-provider-zod';
|
|
35
|
+
import 'node:module';
|
|
36
|
+
import '@modelcontextprotocol/sdk/server/mcp.js';
|
|
37
|
+
import 'node:http';
|
|
38
|
+
import '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
39
|
+
import './limits-CwFb5S2b.mjs';
|
|
40
|
+
import 'http';
|
|
41
|
+
import 'util';
|
|
42
|
+
import 'inquirer';
|
|
43
|
+
import 'node:url';
|
|
44
|
+
import 'node:readline/promises';
|
|
45
|
+
import 'node:util';
|
|
46
|
+
import 'url';
|
|
47
|
+
import 'node-pty';
|
|
48
|
+
|
|
49
|
+
const ACTIONS_NEEDING_ID = /* @__PURE__ */ new Set(["read", "stop", "archive"]);
|
|
50
|
+
function parseSessionsArgs(args) {
|
|
51
|
+
const options = { action: "help", json: false };
|
|
52
|
+
let actionSeen = false;
|
|
53
|
+
const positionals = [];
|
|
54
|
+
for (let i = 0; i < args.length; i++) {
|
|
55
|
+
const arg = args[i];
|
|
56
|
+
if (arg === "--help" || arg === "-h") {
|
|
57
|
+
return { action: "help", json: false };
|
|
58
|
+
} else if (arg === "--json") {
|
|
59
|
+
options.json = true;
|
|
60
|
+
} else if (arg === "--tag") {
|
|
61
|
+
const value = args[++i];
|
|
62
|
+
if (value === void 0) throw new Error("--tag requires a value");
|
|
63
|
+
options.tag = value;
|
|
64
|
+
} else if (arg === "--limit") {
|
|
65
|
+
const value = args[++i];
|
|
66
|
+
if (value === void 0) throw new Error("--limit requires a value");
|
|
67
|
+
const parsed = Number(value);
|
|
68
|
+
if (!Number.isInteger(parsed) || parsed < 1) throw new Error("--limit must be a positive integer");
|
|
69
|
+
options.limit = parsed;
|
|
70
|
+
} else if (arg.startsWith("-")) {
|
|
71
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
72
|
+
} else if (!actionSeen) {
|
|
73
|
+
if (arg !== "list" && arg !== "read" && arg !== "stop" && arg !== "archive") {
|
|
74
|
+
throw new Error(`Unknown action: ${arg} (expected list, read, stop or archive)`);
|
|
75
|
+
}
|
|
76
|
+
options.action = arg;
|
|
77
|
+
actionSeen = true;
|
|
78
|
+
} else {
|
|
79
|
+
positionals.push(arg);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (!actionSeen) return { action: "help", json: false };
|
|
83
|
+
if (positionals.length > 1) throw new Error(`Unexpected extra argument: ${positionals[1]}`);
|
|
84
|
+
if (ACTIONS_NEEDING_ID.has(options.action)) {
|
|
85
|
+
const id = positionals[0];
|
|
86
|
+
if (id === void 0) throw new Error(`${options.action} requires a session id`);
|
|
87
|
+
if (!isValidSessionId(id)) throw new Error(`Invalid session id: ${id}`);
|
|
88
|
+
options.sessionId = id;
|
|
89
|
+
} else if (positionals.length > 0) {
|
|
90
|
+
throw new Error(`Unexpected argument: ${positionals[0]}`);
|
|
91
|
+
}
|
|
92
|
+
if (options.action !== "list" && options.tag !== void 0) {
|
|
93
|
+
throw new Error("--tag only applies to `sessions list`");
|
|
94
|
+
}
|
|
95
|
+
return options;
|
|
96
|
+
}
|
|
97
|
+
const SESSIONS_HELP = `
|
|
98
|
+
${chalk.bold("very-happy sessions")} - Inspect and control sessions on this machine (for automation)
|
|
99
|
+
|
|
100
|
+
${chalk.bold("Usage:")}
|
|
101
|
+
very-happy sessions list [--tag <name>] [--limit <n>] [--json]
|
|
102
|
+
very-happy sessions read <id> [--limit <n>] [--json]
|
|
103
|
+
very-happy sessions stop <id> [--json]
|
|
104
|
+
very-happy sessions archive <id> [--json]
|
|
105
|
+
|
|
106
|
+
${chalk.bold("Actions:")}
|
|
107
|
+
list Running sessions plus recently seen ones, newest first.
|
|
108
|
+
read The tail of a session as a role-tagged transcript.
|
|
109
|
+
stop SIGTERM the session's process via the local daemon.
|
|
110
|
+
archive Mark the session inactive server-side (it stays resumable).
|
|
111
|
+
|
|
112
|
+
${chalk.bold("Options:")}
|
|
113
|
+
--tag <name> list only: keep sessions carrying this origin tag (see
|
|
114
|
+
\`spawn --spawned-by\`).
|
|
115
|
+
--limit <n> list: how many NOT-running sessions to include (default ${DEFAULT_RECENT_LIMIT};
|
|
116
|
+
running ones are never cut). read: how many messages
|
|
117
|
+
(default 20, max ${MAX_READ_LIMIT}).
|
|
118
|
+
--json Machine-readable output.
|
|
119
|
+
-h, --help Show this help
|
|
120
|
+
|
|
121
|
+
${chalk.bold("Scope:")}
|
|
122
|
+
This machine only. Reads need the session key from ~/.happy/sessions.json,
|
|
123
|
+
which exists for sessions this machine's daemon spawned and is pruned after
|
|
124
|
+
14 days. A session on another machine cannot be read or stopped from here.
|
|
125
|
+
|
|
126
|
+
${chalk.bold("Exit codes:")}
|
|
127
|
+
0 success
|
|
128
|
+
1 bad arguments, unknown session, no local key, or the operation failed
|
|
129
|
+
(including \`stop\` on a session the daemon is not running)
|
|
130
|
+
`;
|
|
131
|
+
function formatSummaryLine(summary) {
|
|
132
|
+
const parts = [summary.id, summary.live ? "[running]" : "[not running]"];
|
|
133
|
+
if (summary.title) parts.push(`title="${summary.title}"`);
|
|
134
|
+
if (summary.flavor) parts.push(`agent=${summary.flavor}`);
|
|
135
|
+
if (summary.tags?.length) parts.push(`tags=${summary.tags.join(",")}`);
|
|
136
|
+
if (summary.variant) parts.push(`variant=${summary.variant}`);
|
|
137
|
+
if (summary.cwd) parts.push(`cwd=${summary.cwd}`);
|
|
138
|
+
if (summary.pid !== void 0) parts.push(`pid=${summary.pid}`);
|
|
139
|
+
parts.push(summary.url);
|
|
140
|
+
return parts.join(" ");
|
|
141
|
+
}
|
|
142
|
+
async function handleSessionsCommand(args) {
|
|
143
|
+
let options;
|
|
144
|
+
try {
|
|
145
|
+
options = parseSessionsArgs(args);
|
|
146
|
+
} catch (error) {
|
|
147
|
+
console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
|
|
148
|
+
console.error(`Run ${chalk.cyan("very-happy sessions --help")} for usage.`);
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
if (options.action === "help") {
|
|
152
|
+
console.log(SESSIONS_HELP);
|
|
153
|
+
process.exit(0);
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
if (options.action === "list") {
|
|
157
|
+
const sessions = await listSessions({ tag: options.tag, recentLimit: options.limit });
|
|
158
|
+
if (options.json) {
|
|
159
|
+
console.log(JSON.stringify({ sessions }));
|
|
160
|
+
} else if (sessions.length === 0) {
|
|
161
|
+
console.log(options.tag ? `No sessions tagged "${options.tag}" on this machine.` : "No sessions found on this machine.");
|
|
162
|
+
} else {
|
|
163
|
+
for (const summary of sessions) console.log(formatSummaryLine(summary));
|
|
164
|
+
}
|
|
165
|
+
process.exit(0);
|
|
166
|
+
}
|
|
167
|
+
const sessionId = options.sessionId;
|
|
168
|
+
if (options.action === "read") {
|
|
169
|
+
const result = await readSessionTranscript(sessionId, options.limit ?? 20);
|
|
170
|
+
if (options.json) {
|
|
171
|
+
console.log(JSON.stringify(result));
|
|
172
|
+
} else {
|
|
173
|
+
console.log(formatSummaryLine(result.summary));
|
|
174
|
+
console.log(`--- last ${result.messageCount} message(s) ---`);
|
|
175
|
+
console.log(result.transcript.length > 0 ? result.transcript : "(no readable conversation content in this range)");
|
|
176
|
+
}
|
|
177
|
+
process.exit(0);
|
|
178
|
+
}
|
|
179
|
+
if (options.action === "stop") {
|
|
180
|
+
const stopped = await stopSession(sessionId);
|
|
181
|
+
if (!stopped) {
|
|
182
|
+
if (options.json) console.log(JSON.stringify({ sessionId, stopped: false }));
|
|
183
|
+
console.error(chalk.red("Error:"), `Session ${sessionId} is not among the daemon's running sessions.`);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
if (options.json) console.log(JSON.stringify({ sessionId, stopped: true }));
|
|
187
|
+
else console.log(`Stopped ${sessionId}`);
|
|
188
|
+
process.exit(0);
|
|
189
|
+
}
|
|
190
|
+
await archiveSession(sessionId);
|
|
191
|
+
if (options.json) console.log(JSON.stringify({ sessionId, archived: true }));
|
|
192
|
+
else console.log(`Archived ${sessionId}`);
|
|
193
|
+
process.exit(0);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export { SESSIONS_HELP, handleSessionsCommand, parseSessionsArgs };
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chalk = require('chalk');
|
|
4
|
+
var index = require('./index-dd2R8uSE.cjs');
|
|
5
|
+
var persistence = require('./types-Cg8zzX_f.cjs');
|
|
6
|
+
require('node:os');
|
|
7
|
+
require('node:crypto');
|
|
8
|
+
require('cross-spawn');
|
|
9
|
+
require('node:path');
|
|
10
|
+
require('node:readline');
|
|
11
|
+
require('node:fs');
|
|
12
|
+
require('./agentGuidance-BifkGXdE.cjs');
|
|
13
|
+
require('node:fs/promises');
|
|
14
|
+
require('fs/promises');
|
|
15
|
+
require('ink');
|
|
16
|
+
require('react');
|
|
17
|
+
require('@anthropic-ai/claude-agent-sdk');
|
|
18
|
+
require('axios');
|
|
19
|
+
require('node:events');
|
|
20
|
+
require('socket.io-client');
|
|
21
|
+
require('tweetnacl');
|
|
22
|
+
require('os');
|
|
23
|
+
require('child_process');
|
|
24
|
+
require('@paralleldrive/cuid2');
|
|
25
|
+
require('node:child_process');
|
|
26
|
+
require('fs');
|
|
27
|
+
require('path');
|
|
28
|
+
require('@anthropic-ai/sandbox-runtime');
|
|
29
|
+
require('expo-server-sdk');
|
|
30
|
+
require('crypto');
|
|
31
|
+
require('ps-list');
|
|
32
|
+
require('tmp');
|
|
33
|
+
require('open');
|
|
34
|
+
require('fastify');
|
|
35
|
+
require('zod');
|
|
36
|
+
require('fastify-type-provider-zod');
|
|
37
|
+
require('node:module');
|
|
38
|
+
require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
39
|
+
require('node:http');
|
|
40
|
+
require('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
41
|
+
require('./limits-KdWKmwtH.cjs');
|
|
42
|
+
require('http');
|
|
43
|
+
require('util');
|
|
44
|
+
require('inquirer');
|
|
45
|
+
require('node:url');
|
|
46
|
+
require('node:readline/promises');
|
|
47
|
+
require('node:util');
|
|
48
|
+
require('url');
|
|
49
|
+
require('node-pty');
|
|
50
|
+
|
|
51
|
+
const ACTIONS_NEEDING_ID = /* @__PURE__ */ new Set(["read", "stop", "archive"]);
|
|
52
|
+
function parseSessionsArgs(args) {
|
|
53
|
+
const options = { action: "help", json: false };
|
|
54
|
+
let actionSeen = false;
|
|
55
|
+
const positionals = [];
|
|
56
|
+
for (let i = 0; i < args.length; i++) {
|
|
57
|
+
const arg = args[i];
|
|
58
|
+
if (arg === "--help" || arg === "-h") {
|
|
59
|
+
return { action: "help", json: false };
|
|
60
|
+
} else if (arg === "--json") {
|
|
61
|
+
options.json = true;
|
|
62
|
+
} else if (arg === "--tag") {
|
|
63
|
+
const value = args[++i];
|
|
64
|
+
if (value === void 0) throw new Error("--tag requires a value");
|
|
65
|
+
options.tag = value;
|
|
66
|
+
} else if (arg === "--limit") {
|
|
67
|
+
const value = args[++i];
|
|
68
|
+
if (value === void 0) throw new Error("--limit requires a value");
|
|
69
|
+
const parsed = Number(value);
|
|
70
|
+
if (!Number.isInteger(parsed) || parsed < 1) throw new Error("--limit must be a positive integer");
|
|
71
|
+
options.limit = parsed;
|
|
72
|
+
} else if (arg.startsWith("-")) {
|
|
73
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
74
|
+
} else if (!actionSeen) {
|
|
75
|
+
if (arg !== "list" && arg !== "read" && arg !== "stop" && arg !== "archive") {
|
|
76
|
+
throw new Error(`Unknown action: ${arg} (expected list, read, stop or archive)`);
|
|
77
|
+
}
|
|
78
|
+
options.action = arg;
|
|
79
|
+
actionSeen = true;
|
|
80
|
+
} else {
|
|
81
|
+
positionals.push(arg);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (!actionSeen) return { action: "help", json: false };
|
|
85
|
+
if (positionals.length > 1) throw new Error(`Unexpected extra argument: ${positionals[1]}`);
|
|
86
|
+
if (ACTIONS_NEEDING_ID.has(options.action)) {
|
|
87
|
+
const id = positionals[0];
|
|
88
|
+
if (id === void 0) throw new Error(`${options.action} requires a session id`);
|
|
89
|
+
if (!persistence.isValidSessionId(id)) throw new Error(`Invalid session id: ${id}`);
|
|
90
|
+
options.sessionId = id;
|
|
91
|
+
} else if (positionals.length > 0) {
|
|
92
|
+
throw new Error(`Unexpected argument: ${positionals[0]}`);
|
|
93
|
+
}
|
|
94
|
+
if (options.action !== "list" && options.tag !== void 0) {
|
|
95
|
+
throw new Error("--tag only applies to `sessions list`");
|
|
96
|
+
}
|
|
97
|
+
return options;
|
|
98
|
+
}
|
|
99
|
+
const SESSIONS_HELP = `
|
|
100
|
+
${chalk.bold("very-happy sessions")} - Inspect and control sessions on this machine (for automation)
|
|
101
|
+
|
|
102
|
+
${chalk.bold("Usage:")}
|
|
103
|
+
very-happy sessions list [--tag <name>] [--limit <n>] [--json]
|
|
104
|
+
very-happy sessions read <id> [--limit <n>] [--json]
|
|
105
|
+
very-happy sessions stop <id> [--json]
|
|
106
|
+
very-happy sessions archive <id> [--json]
|
|
107
|
+
|
|
108
|
+
${chalk.bold("Actions:")}
|
|
109
|
+
list Running sessions plus recently seen ones, newest first.
|
|
110
|
+
read The tail of a session as a role-tagged transcript.
|
|
111
|
+
stop SIGTERM the session's process via the local daemon.
|
|
112
|
+
archive Mark the session inactive server-side (it stays resumable).
|
|
113
|
+
|
|
114
|
+
${chalk.bold("Options:")}
|
|
115
|
+
--tag <name> list only: keep sessions carrying this origin tag (see
|
|
116
|
+
\`spawn --spawned-by\`).
|
|
117
|
+
--limit <n> list: how many NOT-running sessions to include (default ${index.DEFAULT_RECENT_LIMIT};
|
|
118
|
+
running ones are never cut). read: how many messages
|
|
119
|
+
(default 20, max ${index.MAX_READ_LIMIT}).
|
|
120
|
+
--json Machine-readable output.
|
|
121
|
+
-h, --help Show this help
|
|
122
|
+
|
|
123
|
+
${chalk.bold("Scope:")}
|
|
124
|
+
This machine only. Reads need the session key from ~/.happy/sessions.json,
|
|
125
|
+
which exists for sessions this machine's daemon spawned and is pruned after
|
|
126
|
+
14 days. A session on another machine cannot be read or stopped from here.
|
|
127
|
+
|
|
128
|
+
${chalk.bold("Exit codes:")}
|
|
129
|
+
0 success
|
|
130
|
+
1 bad arguments, unknown session, no local key, or the operation failed
|
|
131
|
+
(including \`stop\` on a session the daemon is not running)
|
|
132
|
+
`;
|
|
133
|
+
function formatSummaryLine(summary) {
|
|
134
|
+
const parts = [summary.id, summary.live ? "[running]" : "[not running]"];
|
|
135
|
+
if (summary.title) parts.push(`title="${summary.title}"`);
|
|
136
|
+
if (summary.flavor) parts.push(`agent=${summary.flavor}`);
|
|
137
|
+
if (summary.tags?.length) parts.push(`tags=${summary.tags.join(",")}`);
|
|
138
|
+
if (summary.variant) parts.push(`variant=${summary.variant}`);
|
|
139
|
+
if (summary.cwd) parts.push(`cwd=${summary.cwd}`);
|
|
140
|
+
if (summary.pid !== void 0) parts.push(`pid=${summary.pid}`);
|
|
141
|
+
parts.push(summary.url);
|
|
142
|
+
return parts.join(" ");
|
|
143
|
+
}
|
|
144
|
+
async function handleSessionsCommand(args) {
|
|
145
|
+
let options;
|
|
146
|
+
try {
|
|
147
|
+
options = parseSessionsArgs(args);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
|
|
150
|
+
console.error(`Run ${chalk.cyan("very-happy sessions --help")} for usage.`);
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
if (options.action === "help") {
|
|
154
|
+
console.log(SESSIONS_HELP);
|
|
155
|
+
process.exit(0);
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
if (options.action === "list") {
|
|
159
|
+
const sessions = await index.listSessions({ tag: options.tag, recentLimit: options.limit });
|
|
160
|
+
if (options.json) {
|
|
161
|
+
console.log(JSON.stringify({ sessions }));
|
|
162
|
+
} else if (sessions.length === 0) {
|
|
163
|
+
console.log(options.tag ? `No sessions tagged "${options.tag}" on this machine.` : "No sessions found on this machine.");
|
|
164
|
+
} else {
|
|
165
|
+
for (const summary of sessions) console.log(formatSummaryLine(summary));
|
|
166
|
+
}
|
|
167
|
+
process.exit(0);
|
|
168
|
+
}
|
|
169
|
+
const sessionId = options.sessionId;
|
|
170
|
+
if (options.action === "read") {
|
|
171
|
+
const result = await index.readSessionTranscript(sessionId, options.limit ?? 20);
|
|
172
|
+
if (options.json) {
|
|
173
|
+
console.log(JSON.stringify(result));
|
|
174
|
+
} else {
|
|
175
|
+
console.log(formatSummaryLine(result.summary));
|
|
176
|
+
console.log(`--- last ${result.messageCount} message(s) ---`);
|
|
177
|
+
console.log(result.transcript.length > 0 ? result.transcript : "(no readable conversation content in this range)");
|
|
178
|
+
}
|
|
179
|
+
process.exit(0);
|
|
180
|
+
}
|
|
181
|
+
if (options.action === "stop") {
|
|
182
|
+
const stopped = await index.stopSession(sessionId);
|
|
183
|
+
if (!stopped) {
|
|
184
|
+
if (options.json) console.log(JSON.stringify({ sessionId, stopped: false }));
|
|
185
|
+
console.error(chalk.red("Error:"), `Session ${sessionId} is not among the daemon's running sessions.`);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
if (options.json) console.log(JSON.stringify({ sessionId, stopped: true }));
|
|
189
|
+
else console.log(`Stopped ${sessionId}`);
|
|
190
|
+
process.exit(0);
|
|
191
|
+
}
|
|
192
|
+
await index.archiveSession(sessionId);
|
|
193
|
+
if (options.json) console.log(JSON.stringify({ sessionId, archived: true }));
|
|
194
|
+
else console.log(`Archived ${sessionId}`);
|
|
195
|
+
process.exit(0);
|
|
196
|
+
} catch (error) {
|
|
197
|
+
console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
exports.SESSIONS_HELP = SESSIONS_HELP;
|
|
203
|
+
exports.handleSessionsCommand = handleSessionsCommand;
|
|
204
|
+
exports.parseSessionsArgs = parseSessionsArgs;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { readFileSync, statSync } from 'node:fs';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
|
-
import { c as checkIfDaemonRunningAndCleanupStaleState, s as spawnDaemonSession, a as sessionWebUrl, w as waitForSessionKey, b as sendUserMessage } from './index-
|
|
5
|
-
import { l as logger } from './types-
|
|
4
|
+
import { c as checkIfDaemonRunningAndCleanupStaleState, s as spawnDaemonSession, a as sessionWebUrl, i as isValidSpawnOrigin, w as waitForSessionKey, b as sendUserMessage } from './index-DO-9Ep72.mjs';
|
|
5
|
+
import { l as logger } from './types-BKCvo4Cv.mjs';
|
|
6
6
|
import 'node:os';
|
|
7
7
|
import 'node:crypto';
|
|
8
8
|
import 'cross-spawn';
|
|
@@ -62,6 +62,13 @@ function parseSpawnArgs(args) {
|
|
|
62
62
|
const value = args[++i];
|
|
63
63
|
if (value === void 0) throw new Error("--prompt-file requires a value");
|
|
64
64
|
options.promptFile = value;
|
|
65
|
+
} else if (arg === "--spawned-by") {
|
|
66
|
+
const value = args[++i];
|
|
67
|
+
if (value === void 0) throw new Error("--spawned-by requires a value");
|
|
68
|
+
if (!isValidSpawnOrigin(value)) {
|
|
69
|
+
throw new Error("--spawned-by must be 1-24 chars of [a-z0-9] plus - or _, starting with a letter or digit");
|
|
70
|
+
}
|
|
71
|
+
options.spawnedBy = value;
|
|
65
72
|
} else if (arg === "--json") {
|
|
66
73
|
options.json = true;
|
|
67
74
|
} else if (arg === "--help" || arg === "-h") {
|
|
@@ -86,6 +93,9 @@ ${chalk.bold("Options:")}
|
|
|
86
93
|
--dir, -d <path> Working directory for the new session (required)
|
|
87
94
|
--prompt, -p <text> First message to send after the session starts
|
|
88
95
|
--prompt-file <file> Read the first message from a file (UTF-8)
|
|
96
|
+
--spawned-by <name> Tag the new session with its origin (e.g. tanka).
|
|
97
|
+
1-24 chars: [a-z0-9] plus - or _. Shows as a chip in
|
|
98
|
+
the web list and is searchable as #<name>.
|
|
89
99
|
--json Machine-readable output: {"sessionId", "url"}
|
|
90
100
|
-h, --help Show this help
|
|
91
101
|
|
|
@@ -151,7 +161,7 @@ async function handleSpawnCommand(args) {
|
|
|
151
161
|
process.exit(1);
|
|
152
162
|
}
|
|
153
163
|
logger.debug(`[SPAWN CMD] Spawning session in ${directory}`);
|
|
154
|
-
const result = await spawnDaemonSession(directory);
|
|
164
|
+
const result = await spawnDaemonSession(directory, void 0, { spawnedBy: options.spawnedBy });
|
|
155
165
|
if (result?.error || !result?.success || !result?.sessionId) {
|
|
156
166
|
const message = result?.error || "Daemon returned no session ID";
|
|
157
167
|
console.error(chalk.red("Error:"), `Failed to spawn session: ${message}`);
|
|
@@ -169,6 +179,9 @@ async function handleSpawnCommand(args) {
|
|
|
169
179
|
}
|
|
170
180
|
if (options.json) {
|
|
171
181
|
const payload = { sessionId, url };
|
|
182
|
+
if (options.spawnedBy !== void 0) {
|
|
183
|
+
payload.spawnedBy = options.spawnedBy;
|
|
184
|
+
}
|
|
172
185
|
if (prompt !== void 0) {
|
|
173
186
|
payload.promptDelivered = promptError === null;
|
|
174
187
|
}
|
|
@@ -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-dd2R8uSE.cjs');
|
|
7
|
+
var persistence = require('./types-Cg8zzX_f.cjs');
|
|
8
8
|
require('node:os');
|
|
9
9
|
require('node:crypto');
|
|
10
10
|
require('cross-spawn');
|
|
@@ -64,6 +64,13 @@ function parseSpawnArgs(args) {
|
|
|
64
64
|
const value = args[++i];
|
|
65
65
|
if (value === void 0) throw new Error("--prompt-file requires a value");
|
|
66
66
|
options.promptFile = value;
|
|
67
|
+
} else if (arg === "--spawned-by") {
|
|
68
|
+
const value = args[++i];
|
|
69
|
+
if (value === void 0) throw new Error("--spawned-by requires a value");
|
|
70
|
+
if (!index.isValidSpawnOrigin(value)) {
|
|
71
|
+
throw new Error("--spawned-by must be 1-24 chars of [a-z0-9] plus - or _, starting with a letter or digit");
|
|
72
|
+
}
|
|
73
|
+
options.spawnedBy = value;
|
|
67
74
|
} else if (arg === "--json") {
|
|
68
75
|
options.json = true;
|
|
69
76
|
} else if (arg === "--help" || arg === "-h") {
|
|
@@ -88,6 +95,9 @@ ${chalk.bold("Options:")}
|
|
|
88
95
|
--dir, -d <path> Working directory for the new session (required)
|
|
89
96
|
--prompt, -p <text> First message to send after the session starts
|
|
90
97
|
--prompt-file <file> Read the first message from a file (UTF-8)
|
|
98
|
+
--spawned-by <name> Tag the new session with its origin (e.g. tanka).
|
|
99
|
+
1-24 chars: [a-z0-9] plus - or _. Shows as a chip in
|
|
100
|
+
the web list and is searchable as #<name>.
|
|
91
101
|
--json Machine-readable output: {"sessionId", "url"}
|
|
92
102
|
-h, --help Show this help
|
|
93
103
|
|
|
@@ -153,7 +163,7 @@ async function handleSpawnCommand(args) {
|
|
|
153
163
|
process.exit(1);
|
|
154
164
|
}
|
|
155
165
|
persistence.logger.debug(`[SPAWN CMD] Spawning session in ${directory}`);
|
|
156
|
-
const result = await index.spawnDaemonSession(directory);
|
|
166
|
+
const result = await index.spawnDaemonSession(directory, void 0, { spawnedBy: options.spawnedBy });
|
|
157
167
|
if (result?.error || !result?.success || !result?.sessionId) {
|
|
158
168
|
const message = result?.error || "Daemon returned no session ID";
|
|
159
169
|
console.error(chalk.red("Error:"), `Failed to spawn session: ${message}`);
|
|
@@ -171,6 +181,9 @@ async function handleSpawnCommand(args) {
|
|
|
171
181
|
}
|
|
172
182
|
if (options.json) {
|
|
173
183
|
const payload = { sessionId, url };
|
|
184
|
+
if (options.spawnedBy !== void 0) {
|
|
185
|
+
payload.spawnedBy = options.spawnedBy;
|
|
186
|
+
}
|
|
174
187
|
if (prompt !== void 0) {
|
|
175
188
|
payload.promptDelivered = promptError === null;
|
|
176
189
|
}
|
|
@@ -29,7 +29,7 @@ import { SandboxManager } from '@anthropic-ai/sandbox-runtime';
|
|
|
29
29
|
import { Expo } from 'expo-server-sdk';
|
|
30
30
|
|
|
31
31
|
var name = "very-happy-cli";
|
|
32
|
-
var version = "0.2.
|
|
32
|
+
var version = "0.2.109";
|
|
33
33
|
var description = "Remote multi-agent workspace CLI with deep Claude integration, native terminal streaming, and self-hosting.";
|
|
34
34
|
var author = "Kirill Dubovitskiy";
|
|
35
35
|
var contributors = [
|
|
@@ -142,12 +142,12 @@ var dependencies = {
|
|
|
142
142
|
zod: "^4.0.0"
|
|
143
143
|
};
|
|
144
144
|
var optionalDependencies = {
|
|
145
|
-
"very-happy-tools-arm64-darwin": "0.2.
|
|
146
|
-
"very-happy-tools-x64-darwin": "0.2.
|
|
147
|
-
"very-happy-tools-arm64-linux": "0.2.
|
|
148
|
-
"very-happy-tools-x64-linux": "0.2.
|
|
149
|
-
"very-happy-tools-arm64-win32": "0.2.
|
|
150
|
-
"very-happy-tools-x64-win32": "0.2.
|
|
145
|
+
"very-happy-tools-arm64-darwin": "0.2.109",
|
|
146
|
+
"very-happy-tools-x64-darwin": "0.2.109",
|
|
147
|
+
"very-happy-tools-arm64-linux": "0.2.109",
|
|
148
|
+
"very-happy-tools-x64-linux": "0.2.109",
|
|
149
|
+
"very-happy-tools-arm64-win32": "0.2.109",
|
|
150
|
+
"very-happy-tools-x64-win32": "0.2.109"
|
|
151
151
|
};
|
|
152
152
|
var devDependencies = {
|
|
153
153
|
"@slopus/happy-wire": "workspace:*",
|
|
@@ -16294,4 +16294,4 @@ const RawJSONLinesSchema = z$1.discriminatedUnion("type", [
|
|
|
16294
16294
|
}).passthrough()
|
|
16295
16295
|
]);
|
|
16296
16296
|
|
|
16297
|
-
export {
|
|
16297
|
+
export { mirrorLocalId as $, ApiClient as A, credentialRelayProblem as B, deriveLocalCliUpdateSummary as C, updateSettings as D, encodeBase64Url as E, decodeBase64 as F, writeCredentialsLegacy as G, writeCredentialsDataKey as H, InvalidateSync as I, readCredentialsForConfiguredRelay as J, encrypt as K, isClaudeSessionId as L, MAX_CHAT_ATTACHMENT_SOURCE_BYTES as M, getLocalHappyAgentCredentialPath as N, readLocalHappyAgentCredentials as O, decryptWithDataKey as P, decryptLegacy as Q, RawJSONLinesSchema as R, extractCompleteLines as S, decideBackfill as T, parseTerminalHookPayload as U, tmuxArgs as V, scrubTmuxClientEnv as W, decideMirrorBinding as X, MIRROR_BACKFILL_LINES_DEFAULT as Y, persistSession as Z, mirrorLineKey as _, ApiSessionClient as a, detectResumeSupport as a0, detectCLIAvailability as a1, acquireDaemonLock as a2, summarizeSpawnSessionForLog as a3, deletePersistedSessions as a4, shellescape as a5, decrypt as a6, writeDaemonState as a7, writeSettings as a8, fetchCliUpdateState as a9, resolveCliUpdateCheckInterval as aa, DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS as ab, releaseDaemonLock as ac, listVhTerminals as ad, isValidTerminalId as ae, readVhTerminal as af, sendToVhTerminal as ag, TITLE_PROMPT_PREFIX as ah, BOARD_ANALYZER_PROMPT_PREFIX as ai, startOfflineReconnection as aj, clearCredentials as ak, clearMachineId as al, SandboxConfigSchema as am, CodexAppServerClient as an, getLatestDaemonLog as ao, persistence as ap, api as aq, createEnvelope as b, configuration as c, contentLogMetadata as d, errorLogMetadata as e, packageJson as f, delay as g, connectionState as h, isValidSessionId as i, readSettings as j, encodeBase64 as k, logger as l, ensurePrivateDirectorySync as m, hardenPrivateFileSync as n, readDaemonState as o, projectPath as p, clearDaemonState as q, readPersistedSessions as r, getProjectPath as s, initializeSandbox as t, wrapCommand as u, AsyncLock as v, writePrivateFileSync as w, ensurePrivateDirectory as x, hardenPrivateFile as y, readCredentials as z };
|
|
@@ -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.109";
|
|
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.109",
|
|
168
|
+
"very-happy-tools-x64-darwin": "0.2.109",
|
|
169
|
+
"very-happy-tools-arm64-linux": "0.2.109",
|
|
170
|
+
"very-happy-tools-x64-linux": "0.2.109",
|
|
171
|
+
"very-happy-tools-arm64-win32": "0.2.109",
|
|
172
|
+
"very-happy-tools-x64-win32": "0.2.109"
|
|
173
173
|
};
|
|
174
174
|
var devDependencies = {
|
|
175
175
|
"@slopus/happy-wire": "workspace:*",
|
|
@@ -1603,7 +1603,7 @@ class RpcHandlerManager {
|
|
|
1603
1603
|
}
|
|
1604
1604
|
}
|
|
1605
1605
|
|
|
1606
|
-
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-
|
|
1606
|
+
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-Cg8zzX_f.cjs', document.baseURI).href))));
|
|
1607
1607
|
function projectPath() {
|
|
1608
1608
|
const path = path$1.resolve(__dirname$1, "..");
|
|
1609
1609
|
return path;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "very-happy-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.109",
|
|
4
4
|
"description": "Remote multi-agent workspace CLI with deep Claude integration, native terminal streaming, and self-hosting.",
|
|
5
5
|
"author": "Kirill Dubovitskiy",
|
|
6
6
|
"contributors": [
|
|
@@ -113,12 +113,12 @@
|
|
|
113
113
|
"zod": "^4.0.0"
|
|
114
114
|
},
|
|
115
115
|
"optionalDependencies": {
|
|
116
|
-
"very-happy-tools-arm64-darwin": "0.2.
|
|
117
|
-
"very-happy-tools-x64-darwin": "0.2.
|
|
118
|
-
"very-happy-tools-arm64-linux": "0.2.
|
|
119
|
-
"very-happy-tools-x64-linux": "0.2.
|
|
120
|
-
"very-happy-tools-arm64-win32": "0.2.
|
|
121
|
-
"very-happy-tools-x64-win32": "0.2.
|
|
116
|
+
"very-happy-tools-arm64-darwin": "0.2.109",
|
|
117
|
+
"very-happy-tools-x64-darwin": "0.2.109",
|
|
118
|
+
"very-happy-tools-arm64-linux": "0.2.109",
|
|
119
|
+
"very-happy-tools-x64-linux": "0.2.109",
|
|
120
|
+
"very-happy-tools-arm64-win32": "0.2.109",
|
|
121
|
+
"very-happy-tools-x64-win32": "0.2.109"
|
|
122
122
|
},
|
|
123
123
|
"devDependencies": {
|
|
124
124
|
"@slopus/happy-wire": "workspace:*",
|