very-happy-cli 0.2.150 → 0.2.151

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/{AcpBackend-C-dhGJgd.mjs → AcpBackend-BjTA5gUB.mjs} +2 -2
  2. package/dist/{AcpBackend-CXawaWWx.cjs → AcpBackend-blE9IEod.cjs} +2 -2
  3. package/dist/{AcpSessionManager-DKOtSqJc.mjs → AcpSessionManager-D-9mrp40.mjs} +1 -1
  4. package/dist/{AcpSessionManager-TrwEZR7y.cjs → AcpSessionManager-bF8PYu_B.cjs} +1 -1
  5. package/dist/{agentGuidance-Dla-BXO8.cjs → agentGuidance-BXa9ikrZ.cjs} +1 -1
  6. package/dist/{agentGuidance-DrfhtVP1.mjs → agentGuidance-Dvo3cZMW.mjs} +1 -1
  7. package/dist/{agentHome-Dm-Wjs38.mjs → agentHome-CeFDNzvq.mjs} +2 -2
  8. package/dist/{agentHome-rylNIkix.cjs → agentHome-D6MSfwnp.cjs} +2 -2
  9. package/dist/codex/happyMcpStdioBridge.cjs +2 -2
  10. package/dist/codex/happyMcpStdioBridge.mjs +2 -2
  11. package/dist/{config-Dhu6LU0h.mjs → config-C-A1XF62.mjs} +4 -4
  12. package/dist/{config-CgPu2wtS.cjs → config-Cadw1sAk.cjs} +4 -4
  13. package/dist/{index-DEVkDRas.cjs → index-BKGspSWk.cjs} +7 -7
  14. package/dist/{index-CpNYvMTJ.mjs → index-CIyjJy8D.mjs} +214 -59
  15. package/dist/{index-K6mUS0jF.cjs → index-CqtfRzug.cjs} +220 -62
  16. package/dist/{index-CzpooENj.mjs → index-DEp6CmmS.mjs} +8 -8
  17. package/dist/{index-BsYH1sjV.mjs → index-DYQgcgL2.mjs} +4 -4
  18. package/dist/{index-DvfCUuDK.cjs → index-vyRqLjDv.cjs} +4 -4
  19. package/dist/index.cjs +4 -4
  20. package/dist/index.mjs +4 -4
  21. package/dist/{installTerminalHooks-NIbsQ1wi.cjs → installTerminalHooks-Bf_adbl3.cjs} +4 -4
  22. package/dist/{installTerminalHooks-BF_tmw9V.mjs → installTerminalHooks-Ch_yTtEA.mjs} +4 -4
  23. package/dist/lib.cjs +2 -2
  24. package/dist/lib.mjs +2 -2
  25. package/dist/{limits-FThmm7WR.mjs → limits-DS-bnYYp.mjs} +7 -7
  26. package/dist/{limits-Dyma1REp.cjs → limits-DwcY3kyi.cjs} +7 -7
  27. package/dist/{mcp-_TVUSg8W.cjs → mcp-CMxEZ6-0.cjs} +4 -4
  28. package/dist/{mcp-DzydgXpf.mjs → mcp-zu8n8TkR.mjs} +4 -4
  29. package/dist/{piRuntime-ACOhil6t.mjs → piRuntime-Cu6cXZ6N.mjs} +2 -2
  30. package/dist/{piRuntime-CSAiJk0X.cjs → piRuntime-D3ny0mVg.cjs} +2 -2
  31. package/dist/{piTerminal-BlE4vbvZ.mjs → piTerminal-M677UP7y.mjs} +6 -6
  32. package/dist/{piTerminal-DHxGB3Ic.cjs → piTerminal-kDSd_r9X.cjs} +6 -6
  33. package/dist/{runGemini-BMYCU16c.cjs → runGemini-DuwdVV1O.cjs} +6 -6
  34. package/dist/{runGemini-D5IV1MoF.mjs → runGemini-DvJwQVGp.mjs} +6 -6
  35. package/dist/{runOpenClaw-CWPXrKMJ.mjs → runOpenClaw-BG82bF18.mjs} +5 -5
  36. package/dist/{runOpenClaw-Qs4eFtcS.cjs → runOpenClaw-BsvtCE_H.cjs} +5 -5
  37. package/dist/{send-qXWGilm8.cjs → send-aUkjhey7.cjs} +20 -6
  38. package/dist/{send-Dv0km8UI.mjs → send-o6WM-1G8.mjs} +20 -6
  39. package/dist/{sessions-CpIdDhH7.cjs → sessions-B3vP18kz.cjs} +56 -10
  40. package/dist/{sessions-DoULfKui.mjs → sessions-DlU3foY_.mjs} +56 -10
  41. package/dist/{spawn-DqzG1bTH.cjs → spawn-DH6_p4-f.cjs} +166 -27
  42. package/dist/spawn-DxHIIqhi.mjs +397 -0
  43. package/dist/{teams-ByEgUzsH.cjs → teams-BW8D1n3o.cjs} +4 -4
  44. package/dist/{teams-4mhNh5cj.mjs → teams-DoAA_CcN.mjs} +4 -4
  45. package/dist/{todo-D7SDXL0c.cjs → todo-Bcc2XxGh.cjs} +3 -3
  46. package/dist/{todo-C9IAUf0K.mjs → todo-BhJbG5eq.mjs} +3 -3
  47. package/dist/{types-BD542hb1.mjs → types-BN3eiipi.mjs} +46 -3
  48. package/dist/{types-D2Gkpe0N.cjs → types-CPubg05Z.cjs} +52 -2
  49. package/package.json +7 -7
  50. package/dist/spawn-DQuOmUP7.mjs +0 -258
@@ -0,0 +1,397 @@
1
+ import chalk from 'chalk';
2
+ import { readFileSync, statSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+ import { k as getAgentCodeDefaults, n as normalizeAgentKey, l as isClaudeOpus55Model, m as supportsClaudeOpus55, o as forkSession, q as getProjectPath, F as ForkSourceMissingError, C as CodexAppServerClient, t as forkCodexThread, u as checkIfDaemonRunningAndCleanupStaleState, v as spawnDaemonSession, w as stopDaemonSession } from './types-BN3eiipi.mjs';
5
+ import { d as readPersistedSessions, l as logger } from './limits-DS-bnYYp.mjs';
6
+ import { i as readSessionMetadata, e as sessionWebUrl, j as isValidSpawnOrigin, k as sanitizeSpawnPermissionMode, A as ALLOWED_SPAWN_PERMISSION_MODES, S as SPAWN_AGENTS, m as waitForSessionKey, d as sendUserMessage } from './index-CIyjJy8D.mjs';
7
+ import 'axios';
8
+ import 'node:events';
9
+ import 'socket.io-client';
10
+ import 'zod';
11
+ import '@paralleldrive/cuid2';
12
+ import 'node:crypto';
13
+ import 'child_process';
14
+ import 'util';
15
+ import 'fs/promises';
16
+ import 'crypto';
17
+ import 'path';
18
+ import 'cross-spawn';
19
+ import './projectPath-CSpqWdxp.mjs';
20
+ import 'url';
21
+ import 'os';
22
+ import 'node:fs/promises';
23
+ import 'node:os';
24
+ import 'node:child_process';
25
+ import 'node-pty';
26
+ import 'fs';
27
+ import 'tweetnacl';
28
+ import 'node:readline';
29
+ import '@anthropic-ai/sandbox-runtime';
30
+ import 'expo-server-sdk';
31
+ import 'node:util';
32
+ import './agentGuidance-Dvo3cZMW.mjs';
33
+ import 'ink';
34
+ import 'react';
35
+ import '@anthropic-ai/claude-agent-sdk';
36
+ import 'ps-list';
37
+ import 'tmp';
38
+ import 'open';
39
+ import 'fastify';
40
+ import 'fastify-type-provider-zod';
41
+ import 'node:module';
42
+ import '@modelcontextprotocol/sdk/server/mcp.js';
43
+ import 'node:http';
44
+ import '@modelcontextprotocol/sdk/server/streamableHttp.js';
45
+ import 'http';
46
+ import 'inquirer';
47
+ import 'node:url';
48
+ import 'node:readline/promises';
49
+
50
+ function resolveSpawnPermissionMode(agent, explicit) {
51
+ return getAgentCodeDefaults(agent ?? "claude").permissionMode;
52
+ }
53
+ function outboundPermissionMode(agent, mode) {
54
+ const key = normalizeAgentKey(agent ?? "claude");
55
+ if ((key === "claude" || key === "pi") && mode === "yolo") return "bypassPermissions";
56
+ return mode;
57
+ }
58
+ function resolveFirstMessageMeta(input) {
59
+ const meta = {
60
+ permissionMode: outboundPermissionMode(input.agent, input.permissionMode)
61
+ };
62
+ if (input.explicitModel !== void 0) {
63
+ meta.model = input.explicitModel === "default" ? null : input.explicitModel;
64
+ }
65
+ if (normalizeAgentKey(input.agent ?? "claude") !== "claude") return meta;
66
+ if (meta.model === void 0) {
67
+ const model = getAgentCodeDefaults("claude").modelMode;
68
+ const runnable = !isClaudeOpus55Model(model) || supportsClaudeOpus55({ capabilities: input.capabilities ?? null });
69
+ meta.model = runnable && model !== "default" ? model : null;
70
+ }
71
+ meta.effort = null;
72
+ return meta;
73
+ }
74
+
75
+ function nonEmpty(value) {
76
+ return typeof value === "string" && value.trim().length > 0;
77
+ }
78
+ function resolveForkSource(sessionId, persisted) {
79
+ if (!persisted) {
80
+ throw new Error(`Session ${sessionId} has no local record \u2014 only sessions spawned by this machine's daemon (in the last 14 days) can be forked from here.`);
81
+ }
82
+ const metadata = persisted.metadata;
83
+ const directory = metadata?.path;
84
+ if (!nonEmpty(directory)) throw new Error(`Session ${sessionId} has no working directory in its metadata.`);
85
+ const permissionMode = nonEmpty(metadata.permissionMode) ? metadata.permissionMode : void 0;
86
+ if (metadata.flavor === "codex") {
87
+ if (!nonEmpty(metadata.codexThreadId)) throw new Error(`Codex session ${sessionId} has no thread id yet (it never ran a turn) \u2014 nothing to fork.`);
88
+ return { agent: "codex", directory, codexThreadId: metadata.codexThreadId, permissionMode, parentSessionId: sessionId };
89
+ }
90
+ if (metadata.flavor && metadata.flavor !== "claude") {
91
+ throw new Error(`Session ${sessionId} runs ${metadata.flavor}; only claude and codex sessions can be forked.`);
92
+ }
93
+ if (!nonEmpty(metadata.claudeSessionId)) throw new Error(`Session ${sessionId} has no Claude conversation id yet (it never ran a turn) \u2014 nothing to fork.`);
94
+ return { agent: "claude", directory, claudeSessionId: metadata.claudeSessionId, permissionMode, parentSessionId: sessionId };
95
+ }
96
+ async function forkProviderConversation(source) {
97
+ if (source.agent === "claude") {
98
+ try {
99
+ return { resumeClaudeSessionId: await forkSession(getProjectPath(source.directory), source.claudeSessionId) };
100
+ } catch (error) {
101
+ if (error instanceof ForkSourceMissingError) throw new Error("Claude session file not found on this machine");
102
+ throw error;
103
+ }
104
+ }
105
+ const client = new CodexAppServerClient();
106
+ await client.connect();
107
+ try {
108
+ const result = await forkCodexThread(client, { threadId: source.codexThreadId, cwd: source.directory });
109
+ return { resumeCodexThreadId: result.newCodexThreadId };
110
+ } finally {
111
+ await client.disconnect();
112
+ }
113
+ }
114
+
115
+ function parseEnvAssignment(raw) {
116
+ const eq = raw.indexOf("=");
117
+ if (eq <= 0) throw new Error(`--env expects KEY=VALUE, got: ${raw}`);
118
+ const key = raw.slice(0, eq);
119
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) throw new Error(`--env key is not a valid variable name: ${key}`);
120
+ return [key, raw.slice(eq + 1)];
121
+ }
122
+ function parseSpawnArgs(args) {
123
+ const options = { json: false, help: false };
124
+ for (let i = 0; i < args.length; i++) {
125
+ const arg = args[i];
126
+ if (arg === "--dir" || arg === "-d") {
127
+ const value = args[++i];
128
+ if (value === void 0) throw new Error("--dir requires a value");
129
+ options.dir = value;
130
+ } else if (arg === "--prompt" || arg === "-p") {
131
+ const value = args[++i];
132
+ if (value === void 0) throw new Error("--prompt requires a value");
133
+ options.prompt = value;
134
+ } else if (arg === "--prompt-file") {
135
+ const value = args[++i];
136
+ if (value === void 0) throw new Error("--prompt-file requires a value");
137
+ options.promptFile = value;
138
+ } else if (arg === "--spawned-by") {
139
+ const value = args[++i];
140
+ if (value === void 0) throw new Error("--spawned-by requires a value");
141
+ if (!isValidSpawnOrigin(value)) {
142
+ throw new Error("--spawned-by must be 1-24 chars of [a-z0-9] plus - or _, starting with a letter or digit");
143
+ }
144
+ options.spawnedBy = value;
145
+ } else if (arg === "--permission-mode") {
146
+ const value = args[++i];
147
+ if (value === void 0) throw new Error("--permission-mode requires a value");
148
+ if (sanitizeSpawnPermissionMode(value) === null) {
149
+ throw new Error(`--permission-mode must be one of: ${ALLOWED_SPAWN_PERMISSION_MODES.join(", ")}`);
150
+ }
151
+ options.permissionMode = value;
152
+ } else if (arg === "--agent") {
153
+ const value = args[++i];
154
+ if (value === void 0) throw new Error("--agent requires a value");
155
+ if (!SPAWN_AGENTS.includes(value)) {
156
+ throw new Error(`--agent must be one of: ${SPAWN_AGENTS.join(", ")}`);
157
+ }
158
+ options.agent = value;
159
+ } else if (arg === "--env") {
160
+ const value = args[++i];
161
+ if (value === void 0) throw new Error("--env requires a value");
162
+ const [key, val] = parseEnvAssignment(value);
163
+ options.env = { ...options.env ?? {}, [key]: val };
164
+ } else if (arg === "--model" || arg === "-m") {
165
+ const value = args[++i];
166
+ if (value === void 0 || value.trim().length === 0) throw new Error("--model requires a value");
167
+ options.model = value;
168
+ } else if (arg === "--fork") {
169
+ const value = args[++i];
170
+ if (value === void 0) throw new Error("--fork requires a session id");
171
+ if (!/^[a-zA-Z0-9_-]{1,128}$/.test(value)) throw new Error(`Invalid session id for --fork: ${value}`);
172
+ options.fork = value;
173
+ } else if (arg === "--json") {
174
+ options.json = true;
175
+ } else if (arg === "--help" || arg === "-h") {
176
+ options.help = true;
177
+ } else {
178
+ throw new Error(`Unknown argument: ${arg}`);
179
+ }
180
+ }
181
+ if (options.prompt !== void 0 && options.promptFile !== void 0) {
182
+ throw new Error("--prompt and --prompt-file are mutually exclusive");
183
+ }
184
+ return options;
185
+ }
186
+ function printHelp() {
187
+ console.log(`
188
+ ${chalk.bold("very-happy spawn")} - Spawn a remote session via the local daemon (for automation)
189
+
190
+ ${chalk.bold("Usage:")}
191
+ very-happy spawn --dir <path> [--prompt <text> | --prompt-file <file>]
192
+ [--spawned-by <name>] [--permission-mode <mode>]
193
+ [--agent <name>] [--model <id>] [--env KEY=VALUE]... [--json]
194
+ very-happy spawn --fork <sessionId> [--prompt \u2026] [--permission-mode <mode>]
195
+ [--model <id>] [--spawned-by <name>] [--json]
196
+
197
+ ${chalk.bold("Options:")}
198
+ --dir, -d <path> Working directory for the new session (required)
199
+ --prompt, -p <text> First message to send after the session starts
200
+ --prompt-file <file> Read the first message from a file (UTF-8)
201
+ --spawned-by <name> Tag the new session with its origin (e.g. tanka).
202
+ 1-24 chars: [a-z0-9] plus - or _. Shows as a chip in
203
+ the web list and is searchable as #<name>.
204
+ --permission-mode <m> Permission mode for the new session: default,
205
+ acceptEdits, plan, yolo, bypassPermissions.
206
+ Default = the web launcher's: yolo for claude /
207
+ codex / pi, 'default' for gemini / openclaw. A fork
208
+ keeps its source's mode. 'default' stops at the first
209
+ un-allowlisted tool until someone approves it (see
210
+ \`sessions approve\`).
211
+ --agent <name> Backend to run: claude (default), codex, gemini,
212
+ openclaw, pi (needs pi-acp on the daemon's PATH).
213
+ --model, -m <id> Model for the session, sent with the first message
214
+ (needs --prompt). Default = the web launcher's:
215
+ claude-opus-5-5 for claude (the machine default when
216
+ its Claude Code is too old for it); other agents use
217
+ their own default. 'default' = the machine default.
218
+ --fork <sessionId> Fork an existing session of THIS machine (same as the
219
+ web's fork): copies its conversation and continues
220
+ it in a new session, in the same directory and with
221
+ the same agent (so --dir / --agent are not needed).
222
+ --env KEY=VALUE Extra environment for the session process. Repeatable.
223
+ \${VAR} is expanded against the daemon's environment;
224
+ an unresolved reference fails the spawn.
225
+ --json Machine-readable output: {"sessionId", "url",
226
+ "permissionMode", \u2026}
227
+ -h, --help Show this help
228
+
229
+ ${chalk.bold("Behavior:")}
230
+ Requires the Very Happy daemon to be running on this machine (same semantics
231
+ as spawning from the web: an offline machine cannot spawn). Without
232
+ --prompt / --prompt-file the session is spawned idle. To collect the reply:
233
+ \`very-happy sessions read <id> --wait --answer\`.
234
+
235
+ ${chalk.bold("Exit codes:")}
236
+ 0 success
237
+ 1 spawn failed (no session created)
238
+ 2 session spawned but first message failed (session URL still printed)
239
+ `);
240
+ }
241
+ async function sendFirstMessage(sessionId, text, metaFor) {
242
+ const persisted = await waitForSessionKey(sessionId, 15e3);
243
+ const meta = metaFor(persisted.metadata?.capabilities ?? null);
244
+ await sendUserMessage(sessionId, persisted, text, "cli-spawn", meta);
245
+ return meta;
246
+ }
247
+ async function handleSpawnCommand(args) {
248
+ let options;
249
+ try {
250
+ options = parseSpawnArgs(args);
251
+ } catch (error) {
252
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
253
+ console.error(`Run ${chalk.cyan("very-happy spawn --help")} for usage.`);
254
+ process.exit(1);
255
+ }
256
+ if (options.help) {
257
+ printHelp();
258
+ process.exit(0);
259
+ }
260
+ let forkSource = null;
261
+ if (options.fork !== void 0) {
262
+ try {
263
+ const persisted = readPersistedSessions()[options.fork];
264
+ const current = persisted ? await readSessionMetadata(options.fork, persisted) : null;
265
+ forkSource = resolveForkSource(options.fork, persisted && current ? { ...persisted, metadata: { ...persisted.metadata, ...current } } : persisted);
266
+ } catch (error) {
267
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
268
+ process.exit(1);
269
+ }
270
+ if (options.dir !== void 0 && resolve(options.dir) !== forkSource.directory) {
271
+ console.error(chalk.red("Error:"), `--dir ${resolve(options.dir)} differs from the forked session's directory ${forkSource.directory}; a fork always continues in its source directory.`);
272
+ process.exit(1);
273
+ }
274
+ if (options.agent !== void 0 && options.agent !== forkSource.agent) {
275
+ console.error(chalk.red("Error:"), `--agent ${options.agent} differs from the forked session's agent ${forkSource.agent}.`);
276
+ process.exit(1);
277
+ }
278
+ } else if (!options.dir) {
279
+ console.error(chalk.red("Error:"), "--dir is required (or --fork <sessionId>)");
280
+ console.error(`Run ${chalk.cyan("very-happy spawn --help")} for usage.`);
281
+ process.exit(1);
282
+ }
283
+ const directory = forkSource ? forkSource.directory : resolve(options.dir);
284
+ const agent = forkSource ? forkSource.agent : options.agent;
285
+ const permissionMode = options.permissionMode ?? forkSource?.permissionMode ?? resolveSpawnPermissionMode(agent);
286
+ let prompt = options.prompt;
287
+ if (options.promptFile !== void 0) {
288
+ try {
289
+ prompt = readFileSync(resolve(options.promptFile), "utf8");
290
+ } catch (error) {
291
+ console.error(chalk.red("Error:"), `Failed to read --prompt-file: ${error instanceof Error ? error.message : String(error)}`);
292
+ process.exit(1);
293
+ }
294
+ }
295
+ if (prompt !== void 0 && prompt.trim().length === 0) {
296
+ console.error(chalk.red("Error:"), "Prompt is empty");
297
+ process.exit(1);
298
+ }
299
+ if (options.model !== void 0 && prompt === void 0) {
300
+ console.error(chalk.red("Error:"), "--model needs --prompt / --prompt-file (the model is sent with the first message); for an idle session pass it later with `very-happy send --model`.");
301
+ process.exit(1);
302
+ }
303
+ try {
304
+ if (!statSync(directory).isDirectory()) {
305
+ console.error(chalk.red("Error:"), `Not a directory: ${directory}`);
306
+ process.exit(1);
307
+ }
308
+ } catch {
309
+ console.error(chalk.red("Error:"), `Directory does not exist: ${directory}`);
310
+ process.exit(1);
311
+ }
312
+ if (!await checkIfDaemonRunningAndCleanupStaleState()) {
313
+ console.error(chalk.red("Error:"), "Happy daemon is not running on this machine.");
314
+ console.error(`Start it with ${chalk.cyan("very-happy daemon start")} and retry.`);
315
+ process.exit(1);
316
+ }
317
+ let resumeIds = {};
318
+ if (forkSource) {
319
+ try {
320
+ resumeIds = await forkProviderConversation(forkSource);
321
+ } catch (error) {
322
+ console.error(chalk.red("Error:"), `Failed to fork session ${forkSource.parentSessionId}: ${error instanceof Error ? error.message : String(error)}`);
323
+ process.exit(1);
324
+ }
325
+ }
326
+ logger.debug(`[SPAWN CMD] Spawning session in ${directory}${forkSource ? ` (fork of ${forkSource.parentSessionId})` : ""}`);
327
+ const result = await spawnDaemonSession(directory, void 0, {
328
+ spawnedBy: options.spawnedBy,
329
+ permissionMode,
330
+ agent,
331
+ environmentVariables: options.env,
332
+ ...resumeIds,
333
+ ...forkSource ? { parentSessionId: forkSource.parentSessionId } : {}
334
+ });
335
+ if (result?.error || !result?.success || !result?.sessionId) {
336
+ const message = result?.error || "Daemon returned no session ID";
337
+ console.error(chalk.red("Error:"), `Failed to spawn session: ${message}`);
338
+ process.exit(1);
339
+ }
340
+ const sessionId = result.sessionId;
341
+ const url = sessionWebUrl(sessionId);
342
+ if (forkSource && result.resumed !== true) {
343
+ await stopDaemonSession(sessionId).catch(() => false);
344
+ console.error(chalk.red("Error:"), "The running daemon is too old to fork from the CLI (it spawned a fresh session, now stopped). Restart the daemon on this CLI version and retry.");
345
+ process.exit(1);
346
+ }
347
+ let promptError = null;
348
+ let sentMeta = null;
349
+ if (prompt !== void 0) {
350
+ try {
351
+ sentMeta = await sendFirstMessage(sessionId, prompt, (capabilities) => resolveFirstMessageMeta({
352
+ agent,
353
+ permissionMode,
354
+ explicitModel: options.model,
355
+ capabilities
356
+ }));
357
+ } catch (error) {
358
+ promptError = error instanceof Error ? error.message : String(error);
359
+ }
360
+ }
361
+ if (options.json) {
362
+ const payload = { sessionId, url, permissionMode };
363
+ if (options.spawnedBy !== void 0) {
364
+ payload.spawnedBy = options.spawnedBy;
365
+ }
366
+ if (agent !== void 0) {
367
+ payload.agent = agent;
368
+ }
369
+ if (forkSource) {
370
+ payload.forkedFrom = forkSource.parentSessionId;
371
+ }
372
+ if (sentMeta && sentMeta.model !== void 0) {
373
+ payload.model = sentMeta.model;
374
+ }
375
+ if (prompt !== void 0) {
376
+ payload.promptDelivered = promptError === null;
377
+ }
378
+ if (promptError !== null) {
379
+ payload.error = `Session spawned but first message failed: ${promptError}`;
380
+ }
381
+ console.log(JSON.stringify(payload));
382
+ } else {
383
+ console.log(`${chalk.bold("Session:")} ${sessionId}`);
384
+ console.log(`${chalk.bold("URL:")} ${url}`);
385
+ if (prompt !== void 0 && promptError === null) {
386
+ console.log(chalk.green("First message sent."));
387
+ }
388
+ }
389
+ if (promptError !== null) {
390
+ console.error(chalk.red("Error:"), `Session ${sessionId} was spawned, but sending the first message failed: ${promptError}`);
391
+ console.error(`The session likely exists \u2014 open ${url} and send the message manually.`);
392
+ process.exit(2);
393
+ }
394
+ process.exit(0);
395
+ }
396
+
397
+ export { SPAWN_AGENTS, handleSpawnCommand, parseEnvAssignment, parseSpawnArgs, sessionWebUrl };
@@ -4,15 +4,15 @@ var os = require('node:os');
4
4
  var promises = require('node:fs/promises');
5
5
  var z = require('zod');
6
6
  var node_crypto = require('node:crypto');
7
- var agentGuidance = require('./agentGuidance-Dla-BXO8.cjs');
8
- var persistence = require('./limits-Dyma1REp.cjs');
7
+ var agentGuidance = require('./agentGuidance-BXa9ikrZ.cjs');
8
+ var persistence = require('./limits-DwcY3kyi.cjs');
9
9
  var path = require('node:path');
10
- var index = require('./index-K6mUS0jF.cjs');
10
+ var index = require('./index-CqtfRzug.cjs');
11
11
  require('node:fs');
12
12
  require('tweetnacl');
13
13
  require('chalk');
14
14
  require('node:util');
15
- require('./types-D2Gkpe0N.cjs');
15
+ require('./types-CPubg05Z.cjs');
16
16
  require('axios');
17
17
  require('node:events');
18
18
  require('socket.io-client');
@@ -2,15 +2,15 @@ import { homedir } from 'node:os';
2
2
  import { unlink, rmdir, mkdir, lstat, readFile, writeFile, rename } from 'node:fs/promises';
3
3
  import { z } from 'zod';
4
4
  import { createHash, randomUUID } from 'node:crypto';
5
- import { d as teamRequest, e as createTeamsClient } from './agentGuidance-DrfhtVP1.mjs';
6
- import { e as readCredentialsForConfiguredRelay } from './limits-FThmm7WR.mjs';
5
+ import { d as teamRequest, e as createTeamsClient } from './agentGuidance-Dvo3cZMW.mjs';
6
+ import { e as readCredentialsForConfiguredRelay } from './limits-DS-bnYYp.mjs';
7
7
  import { join, resolve, dirname } from 'node:path';
8
- import { J as TEAM_SKILL } from './index-CpNYvMTJ.mjs';
8
+ import { N as TEAM_SKILL } from './index-CIyjJy8D.mjs';
9
9
  import 'node:fs';
10
10
  import 'tweetnacl';
11
11
  import 'chalk';
12
12
  import 'node:util';
13
- import './types-BD542hb1.mjs';
13
+ import './types-BN3eiipi.mjs';
14
14
  import 'axios';
15
15
  import 'node:events';
16
16
  import 'socket.io-client';
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var persistence = require('./limits-Dyma1REp.cjs');
4
- var index = require('./types-D2Gkpe0N.cjs');
5
- var agentGuidance = require('./agentGuidance-Dla-BXO8.cjs');
3
+ var persistence = require('./limits-DwcY3kyi.cjs');
4
+ var index = require('./types-CPubg05Z.cjs');
5
+ var agentGuidance = require('./agentGuidance-BXa9ikrZ.cjs');
6
6
  require('node:fs/promises');
7
7
  require('node:fs');
8
8
  require('node:os');
@@ -1,6 +1,6 @@
1
- import { e as readCredentialsForConfiguredRelay, c as configuration } from './limits-FThmm7WR.mjs';
2
- import { h as createBuiltinTodoClient, B as BUILTIN_TODO_SKILL } from './types-BD542hb1.mjs';
3
- import { c as readTeamScope, t as teamScopePath } from './agentGuidance-DrfhtVP1.mjs';
1
+ import { e as readCredentialsForConfiguredRelay, c as configuration } from './limits-DS-bnYYp.mjs';
2
+ import { f as createBuiltinTodoClient, B as BUILTIN_TODO_SKILL } from './types-BN3eiipi.mjs';
3
+ import { c as readTeamScope, t as teamScopePath } from './agentGuidance-Dvo3cZMW.mjs';
4
4
  import 'node:fs/promises';
5
5
  import 'node:fs';
6
6
  import 'node:os';
@@ -1,5 +1,5 @@
1
1
  import axios from 'axios';
2
- import { l as logger, g as encodeBase64, j as encrypt, k as decrypt, m as decodeBase64, c as configuration, o as readDaemonState, q as clearDaemonState, s as decryptBlob, t as prepareClipboardText, v as prepareClipboardHistoryText, r as readSettings, d as readPersistedSessions, x as credentialRelayProblem, p as packageJson, y as readTrackedClaudeSessionIds, z as readTrackedCodexThreadIds, A as libsodiumEncryptForPublicKey, B as libsodiumPublicKeyFromSecretKey, D as getRandomBytes, E as redactLogValue } from './limits-FThmm7WR.mjs';
2
+ import { l as logger, g as encodeBase64, j as encrypt, k as decrypt, m as decodeBase64, c as configuration, o as readDaemonState, q as clearDaemonState, s as decryptBlob, t as prepareClipboardText, v as prepareClipboardHistoryText, r as readSettings, d as readPersistedSessions, x as credentialRelayProblem, p as packageJson, y as readTrackedClaudeSessionIds, z as readTrackedCodexThreadIds, A as libsodiumEncryptForPublicKey, B as libsodiumPublicKeyFromSecretKey, D as getRandomBytes, E as redactLogValue } from './limits-DS-bnYYp.mjs';
3
3
  import { EventEmitter } from 'node:events';
4
4
  import { io } from 'socket.io-client';
5
5
  import * as z from 'zod';
@@ -798,6 +798,46 @@ const AGENT_VERSION_SOURCES = [
798
798
  { id: "openclaw", label: "OpenClaw", command: "openclaw", package: "openclaw", docs: "https://docs.openclaw.ai/install/updating" },
799
799
  { id: "claude-sdk", label: "Claude Agent SDK", command: null, package: "@anthropic-ai/claude-agent-sdk", docs: "https://github.com/anthropics/claude-agent-sdk-typescript" }
800
800
  ];
801
+ const CLAUDE_OPUS_55_MODEL = "claude-opus-5-5";
802
+ const CLAUDE_OPUS_55_CAPABILITY = "claude-opus-5-5-v1";
803
+ function supportsClaudeOpus55(metadata) {
804
+ return metadata?.capabilities?.includes(CLAUDE_OPUS_55_CAPABILITY) === true;
805
+ }
806
+ function isClaudeOpus55Model(model) {
807
+ return model === CLAUDE_OPUS_55_MODEL || model === `${CLAUDE_OPUS_55_MODEL}[1m]`;
808
+ }
809
+ const AGENT_CODE_DEFAULTS = {
810
+ // The Claude UI key for YOLO is `bypassPermissions`; the CLI also accepts
811
+ // `yolo` and maps it to the Claude SDK's bypass mode.
812
+ // model defaults to the pinned Opus 5.5 id (not the `opus` alias, whose
813
+ // target depends on the wrapper's bundled Claude Code). Wrappers that
814
+ // cannot run it fall back to 'default' (see supportsClaudeOpus55).
815
+ // effort null = don't send effort.
816
+ claude: { permissionMode: "bypassPermissions", modelMode: CLAUDE_OPUS_55_MODEL, effortLevel: null },
817
+ codex: { permissionMode: "yolo", modelMode: "gpt-5.5", effortLevel: "medium" },
818
+ gemini: { permissionMode: "default", modelMode: "gemini-2.5-pro", effortLevel: null },
819
+ openclaw: { permissionMode: "default", modelMode: "default", effortLevel: null },
820
+ // pi: the runner keeps Claude's permission vocabulary (B-350 — HAPPY_PERMISSION_MODE +
821
+ // session-modes file, enforced by the pi-side gate; `bypassPermissions` = auto-allow every
822
+ // ask rule), so yolo is the same key as for Claude. Model 'default' = don't send a model:
823
+ // the session runs on whatever the machine's pi is configured with (pi-acp publishes
824
+ // its own registry in metadata.models plus the model really in effect in
825
+ // metadata.currentModelCode, B-362). Thinking levels follow the session
826
+ // catalog and travel through ACP config options, independently of permissions.
827
+ pi: { permissionMode: "bypassPermissions", modelMode: "default", effortLevel: null }
828
+ };
829
+ function normalizeAgentKey(flavor) {
830
+ if (flavor === "codex" || flavor === "gemini" || flavor === "openclaw" || flavor === "pi") {
831
+ return flavor;
832
+ }
833
+ if (flavor === "acp") {
834
+ return "pi";
835
+ }
836
+ return "claude";
837
+ }
838
+ function getAgentCodeDefaults(flavor) {
839
+ return AGENT_CODE_DEFAULTS[normalizeAgentKey(flavor)];
840
+ }
801
841
 
802
842
  z$1.object({
803
843
  teamsVersion: z$1.number().int().positive().optional(),
@@ -3078,7 +3118,10 @@ async function spawnDaemonSession(directory, sessionId, opts) {
3078
3118
  spawnedBy: opts?.spawnedBy,
3079
3119
  permissionMode: opts?.permissionMode,
3080
3120
  agent: opts?.agent,
3081
- environmentVariables: opts?.environmentVariables
3121
+ environmentVariables: opts?.environmentVariables,
3122
+ resumeClaudeSessionId: opts?.resumeClaudeSessionId,
3123
+ resumeCodexThreadId: opts?.resumeCodexThreadId,
3124
+ parentSessionId: opts?.parentSessionId
3082
3125
  });
3083
3126
  return result;
3084
3127
  }
@@ -17397,4 +17440,4 @@ const RawJSONLinesSchema = z$1.discriminatedUnion("type", [
17397
17440
  }).passthrough()
17398
17441
  ]);
17399
17442
 
17400
- export { detectResumeSupport as $, ApiClient as A, BUILTIN_TODO_SKILL as B, notifyDaemonClaudeAuthFailed as C, commandOnPath as D, deriveLocalCliUpdateSummary as E, AGENT_VERSION_SOURCES as F, isClaudeSessionId as G, getLocalHappyAgentCredentialPath as H, InvalidateSync as I, readLocalHappyAgentCredentials as J, parseExactVersion as K, compareExactVersions as L, MAX_CHAT_ATTACHMENT_SOURCE_BYTES as M, extractCompleteLines as N, decideBackfill as O, parseTerminalHookPayload as P, tmuxArgs as Q, RawJSONLinesSchema as R, STREAM_DELTA_MAX_CHARS as S, scrubTmuxClientEnv as T, decideMirrorBinding as U, MIRROR_BACKFILL_LINES_DEFAULT as V, mirrorLineKey as W, mirrorLocalId as X, listDaemonSessions as Y, stopDaemonSession as Z, detectCLIAvailability as _, ApiSessionClient as a, refreshAgentHomes as a0, isDaemonRunningCurrentlyInstalledHappyVersion as a1, stopDaemon as a2, TurnActivityTracker as a3, summarizeSpawnSessionForLog as a4, locateClaudeConversation as a5, agentHomeSpawnEnv as a6, shellescape as a7, fetchCliUpdateState as a8, resolveCliUpdateCheckInterval as a9, DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS as aa, cleanupDaemonState as ab, listVhTerminals as ac, isValidTerminalId as ad, readVhTerminal as ae, sendToVhTerminal as af, ContextUsageSchema as ag, TITLE_PROMPT_PREFIX as ah, BOARD_ANALYZER_PROMPT_PREFIX as ai, startOfflineReconnection as aj, CodexAppServerClient as ak, index as al, api as am, AGENT_HOME_ENV_NAMES as b, checkIfDaemonRunningAndCleanupStaleState as c, describeAgentHome as d, expandHomePath as e, streamKeyOf as f, createEnvelope as g, createBuiltinTodoClient as h, isValidSessionId as i, pushClipboardViaDaemon as j, pushFilePreviewViaDaemon as k, setTerminalTitleViaDaemon as l, connectionState as m, notifyDaemonSessionStarted as n, BUILTIN_TODO_DISCOVERY as o, probeLoginShellEnv as p, errorLogMetadata as q, resolveAgentHomes as r, spawnDaemonSession as s, contentLogMetadata as t, delay as u, notifyDaemonSessionEvent as v, getProjectPath as w, initializeSandbox as x, wrapCommand as y, AsyncLock as z };
17443
+ export { tmuxArgs as $, ApiClient as A, BUILTIN_TODO_SKILL as B, CodexAppServerClient as C, errorLogMetadata as D, contentLogMetadata as E, ForkSourceMissingError as F, delay as G, notifyDaemonSessionEvent as H, initializeSandbox as I, wrapCommand as J, InvalidateSync as K, AsyncLock as L, MAX_CHAT_ATTACHMENT_SOURCE_BYTES as M, notifyDaemonClaudeAuthFailed as N, commandOnPath as O, deriveLocalCliUpdateSummary as P, AGENT_VERSION_SOURCES as Q, RawJSONLinesSchema as R, STREAM_DELTA_MAX_CHARS as S, isClaudeSessionId as T, getLocalHappyAgentCredentialPath as U, readLocalHappyAgentCredentials as V, parseExactVersion as W, compareExactVersions as X, extractCompleteLines as Y, decideBackfill as Z, parseTerminalHookPayload as _, ApiSessionClient as a, scrubTmuxClientEnv as a0, decideMirrorBinding as a1, MIRROR_BACKFILL_LINES_DEFAULT as a2, mirrorLineKey as a3, mirrorLocalId as a4, listDaemonSessions as a5, detectCLIAvailability as a6, detectResumeSupport as a7, refreshAgentHomes as a8, isDaemonRunningCurrentlyInstalledHappyVersion as a9, stopDaemon as aa, TurnActivityTracker as ab, summarizeSpawnSessionForLog as ac, locateClaudeConversation as ad, agentHomeSpawnEnv as ae, shellescape as af, fetchCliUpdateState as ag, resolveCliUpdateCheckInterval as ah, DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS as ai, cleanupDaemonState as aj, listVhTerminals as ak, isValidTerminalId as al, readVhTerminal as am, sendToVhTerminal as an, ContextUsageSchema as ao, TITLE_PROMPT_PREFIX as ap, BOARD_ANALYZER_PROMPT_PREFIX as aq, startOfflineReconnection as ar, index as as, api as at, AGENT_HOME_ENV_NAMES as b, createEnvelope as c, describeAgentHome as d, expandHomePath as e, createBuiltinTodoClient as f, pushClipboardViaDaemon as g, pushFilePreviewViaDaemon as h, isValidSessionId as i, setTerminalTitleViaDaemon as j, getAgentCodeDefaults as k, isClaudeOpus55Model as l, supportsClaudeOpus55 as m, normalizeAgentKey as n, forkSession as o, probeLoginShellEnv as p, getProjectPath as q, resolveAgentHomes as r, streamKeyOf as s, forkCodexThread as t, checkIfDaemonRunningAndCleanupStaleState as u, spawnDaemonSession as v, stopDaemonSession as w, connectionState as x, notifyDaemonSessionStarted as y, BUILTIN_TODO_DISCOVERY as z };
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var axios = require('axios');
4
- var persistence = require('./limits-Dyma1REp.cjs');
4
+ var persistence = require('./limits-DwcY3kyi.cjs');
5
5
  var node_events = require('node:events');
6
6
  var socket_ioClient = require('socket.io-client');
7
7
  var z = require('zod');
@@ -819,6 +819,46 @@ const AGENT_VERSION_SOURCES = [
819
819
  { id: "openclaw", label: "OpenClaw", command: "openclaw", package: "openclaw", docs: "https://docs.openclaw.ai/install/updating" },
820
820
  { id: "claude-sdk", label: "Claude Agent SDK", command: null, package: "@anthropic-ai/claude-agent-sdk", docs: "https://github.com/anthropics/claude-agent-sdk-typescript" }
821
821
  ];
822
+ const CLAUDE_OPUS_55_MODEL = "claude-opus-5-5";
823
+ const CLAUDE_OPUS_55_CAPABILITY = "claude-opus-5-5-v1";
824
+ function supportsClaudeOpus55(metadata) {
825
+ return metadata?.capabilities?.includes(CLAUDE_OPUS_55_CAPABILITY) === true;
826
+ }
827
+ function isClaudeOpus55Model(model) {
828
+ return model === CLAUDE_OPUS_55_MODEL || model === `${CLAUDE_OPUS_55_MODEL}[1m]`;
829
+ }
830
+ const AGENT_CODE_DEFAULTS = {
831
+ // The Claude UI key for YOLO is `bypassPermissions`; the CLI also accepts
832
+ // `yolo` and maps it to the Claude SDK's bypass mode.
833
+ // model defaults to the pinned Opus 5.5 id (not the `opus` alias, whose
834
+ // target depends on the wrapper's bundled Claude Code). Wrappers that
835
+ // cannot run it fall back to 'default' (see supportsClaudeOpus55).
836
+ // effort null = don't send effort.
837
+ claude: { permissionMode: "bypassPermissions", modelMode: CLAUDE_OPUS_55_MODEL, effortLevel: null },
838
+ codex: { permissionMode: "yolo", modelMode: "gpt-5.5", effortLevel: "medium" },
839
+ gemini: { permissionMode: "default", modelMode: "gemini-2.5-pro", effortLevel: null },
840
+ openclaw: { permissionMode: "default", modelMode: "default", effortLevel: null },
841
+ // pi: the runner keeps Claude's permission vocabulary (B-350 — HAPPY_PERMISSION_MODE +
842
+ // session-modes file, enforced by the pi-side gate; `bypassPermissions` = auto-allow every
843
+ // ask rule), so yolo is the same key as for Claude. Model 'default' = don't send a model:
844
+ // the session runs on whatever the machine's pi is configured with (pi-acp publishes
845
+ // its own registry in metadata.models plus the model really in effect in
846
+ // metadata.currentModelCode, B-362). Thinking levels follow the session
847
+ // catalog and travel through ACP config options, independently of permissions.
848
+ pi: { permissionMode: "bypassPermissions", modelMode: "default", effortLevel: null }
849
+ };
850
+ function normalizeAgentKey(flavor) {
851
+ if (flavor === "codex" || flavor === "gemini" || flavor === "openclaw" || flavor === "pi") {
852
+ return flavor;
853
+ }
854
+ if (flavor === "acp") {
855
+ return "pi";
856
+ }
857
+ return "claude";
858
+ }
859
+ function getAgentCodeDefaults(flavor) {
860
+ return AGENT_CODE_DEFAULTS[normalizeAgentKey(flavor)];
861
+ }
822
862
 
823
863
  z.z.object({
824
864
  teamsVersion: z.z.number().int().positive().optional(),
@@ -3099,7 +3139,10 @@ async function spawnDaemonSession(directory, sessionId, opts) {
3099
3139
  spawnedBy: opts?.spawnedBy,
3100
3140
  permissionMode: opts?.permissionMode,
3101
3141
  agent: opts?.agent,
3102
- environmentVariables: opts?.environmentVariables
3142
+ environmentVariables: opts?.environmentVariables,
3143
+ resumeClaudeSessionId: opts?.resumeClaudeSessionId,
3144
+ resumeCodexThreadId: opts?.resumeCodexThreadId,
3145
+ parentSessionId: opts?.parentSessionId
3103
3146
  });
3104
3147
  return result;
3105
3148
  }
@@ -17429,6 +17472,7 @@ exports.BUILTIN_TODO_SKILL = BUILTIN_TODO_SKILL;
17429
17472
  exports.CodexAppServerClient = CodexAppServerClient;
17430
17473
  exports.ContextUsageSchema = ContextUsageSchema;
17431
17474
  exports.DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS = DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS;
17475
+ exports.ForkSourceMissingError = ForkSourceMissingError;
17432
17476
  exports.InvalidateSync = InvalidateSync;
17433
17477
  exports.MAX_CHAT_ATTACHMENT_SOURCE_BYTES = MAX_CHAT_ATTACHMENT_SOURCE_BYTES;
17434
17478
  exports.MIRROR_BACKFILL_LINES_DEFAULT = MIRROR_BACKFILL_LINES_DEFAULT;
@@ -17457,10 +17501,14 @@ exports.errorLogMetadata = errorLogMetadata;
17457
17501
  exports.expandHomePath = expandHomePath;
17458
17502
  exports.extractCompleteLines = extractCompleteLines;
17459
17503
  exports.fetchCliUpdateState = fetchCliUpdateState;
17504
+ exports.forkCodexThread = forkCodexThread;
17505
+ exports.forkSession = forkSession;
17506
+ exports.getAgentCodeDefaults = getAgentCodeDefaults;
17460
17507
  exports.getLocalHappyAgentCredentialPath = getLocalHappyAgentCredentialPath;
17461
17508
  exports.getProjectPath = getProjectPath;
17462
17509
  exports.index = index;
17463
17510
  exports.initializeSandbox = initializeSandbox;
17511
+ exports.isClaudeOpus55Model = isClaudeOpus55Model;
17464
17512
  exports.isClaudeSessionId = isClaudeSessionId;
17465
17513
  exports.isDaemonRunningCurrentlyInstalledHappyVersion = isDaemonRunningCurrentlyInstalledHappyVersion;
17466
17514
  exports.isValidSessionId = isValidSessionId;
@@ -17470,6 +17518,7 @@ exports.listVhTerminals = listVhTerminals;
17470
17518
  exports.locateClaudeConversation = locateClaudeConversation;
17471
17519
  exports.mirrorLineKey = mirrorLineKey;
17472
17520
  exports.mirrorLocalId = mirrorLocalId;
17521
+ exports.normalizeAgentKey = normalizeAgentKey;
17473
17522
  exports.notifyDaemonClaudeAuthFailed = notifyDaemonClaudeAuthFailed;
17474
17523
  exports.notifyDaemonSessionEvent = notifyDaemonSessionEvent;
17475
17524
  exports.notifyDaemonSessionStarted = notifyDaemonSessionStarted;
@@ -17493,5 +17542,6 @@ exports.stopDaemon = stopDaemon;
17493
17542
  exports.stopDaemonSession = stopDaemonSession;
17494
17543
  exports.streamKeyOf = streamKeyOf;
17495
17544
  exports.summarizeSpawnSessionForLog = summarizeSpawnSessionForLog;
17545
+ exports.supportsClaudeOpus55 = supportsClaudeOpus55;
17496
17546
  exports.tmuxArgs = tmuxArgs;
17497
17547
  exports.wrapCommand = wrapCommand;