very-happy-cli 0.2.108 → 0.2.110

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 (33) hide show
  1. package/dist/{AcpBackend-D4vV6SVl.cjs → AcpBackend-D0_wbTs6.cjs} +1 -1
  2. package/dist/{AcpBackend-DwR8rrkS.mjs → AcpBackend-DzZR7TEv.mjs} +1 -1
  3. package/dist/{AcpSessionManager-CPHDZ-nz.cjs → AcpSessionManager-Dcj_iHw8.cjs} +1 -1
  4. package/dist/{AcpSessionManager-C057dkLF.mjs → AcpSessionManager-tWuFWeIF.mjs} +1 -1
  5. package/dist/{config-BvVwprR0.cjs → config-CTCGilz_.cjs} +2 -2
  6. package/dist/{config-DKMwLc1k.mjs → config-CTyyVXHj.mjs} +2 -2
  7. package/dist/{index-CzSv4d_S.mjs → index-BW9kDx5m.mjs} +237 -91
  8. package/dist/{index-BXnHT-Wu.mjs → index-Brhvj7p0.mjs} +5 -5
  9. package/dist/{index-DM0Ku1Rv.cjs → index-CvnMiYgh.cjs} +247 -94
  10. package/dist/{index-Db5m34eh.cjs → index-D-adqB7g.cjs} +4 -4
  11. package/dist/{index-C7N-ONU_.cjs → index-DW78HyvK.cjs} +2 -2
  12. package/dist/{index-DYY1DUOD.mjs → index-jYltd-ZW.mjs} +2 -2
  13. package/dist/index.cjs +2 -2
  14. package/dist/index.mjs +2 -2
  15. package/dist/{installTerminalHooks-Cs49gg_E.mjs → installTerminalHooks-CJyoR9jp.mjs} +2 -2
  16. package/dist/{installTerminalHooks-BpvWmkZ9.cjs → installTerminalHooks-DhQ6k7YD.cjs} +2 -2
  17. package/dist/lib.cjs +1 -1
  18. package/dist/lib.mjs +1 -1
  19. package/dist/{mcp-DY17lhMH.mjs → mcp-BO9-sxMr.mjs} +2 -2
  20. package/dist/{mcp-rTSmj-tn.cjs → mcp-Dr1PegOw.cjs} +2 -2
  21. package/dist/{runGemini-Bqs52hw_.mjs → runGemini-CuzqF6Ys.mjs} +4 -4
  22. package/dist/{runGemini-B3Mme1zr.cjs → runGemini-D6Wwfk_0.cjs} +4 -4
  23. package/dist/{runOpenClaw-CpbsQ7NZ.mjs → runOpenClaw-B5pkmSTb.mjs} +3 -3
  24. package/dist/{runOpenClaw-B2V9j9Le.cjs → runOpenClaw-BYmlS-4Q.cjs} +3 -3
  25. package/dist/{send-uHgpvIqm.mjs → send-Btz1IZ9U.mjs} +2 -2
  26. package/dist/{send-CLdMBQ8e.cjs → send-CuajooZC.cjs} +2 -2
  27. package/dist/sessions-CVUBS3LG.cjs +204 -0
  28. package/dist/sessions-DDwCphTQ.mjs +200 -0
  29. package/dist/{spawn-BXbVzbMs.cjs → spawn-CwS8CPbr.cjs} +16 -3
  30. package/dist/{spawn-Dt4ujmHH.mjs → spawn-DcA80_VN.mjs} +16 -3
  31. package/dist/{types-D4bwyM-D.cjs → types--t4zLibT.cjs} +18 -10
  32. package/dist/{types-D0-nhvuW.mjs → types-BdO0jg7G.mjs} +18 -10
  33. package/package.json +7 -7
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  require('chalk');
4
- require('./index-DM0Ku1Rv.cjs');
5
- require('./types-D4bwyM-D.cjs');
4
+ require('./index-CvnMiYgh.cjs');
5
+ require('./types--t4zLibT.cjs');
6
6
  require('zod');
7
7
  require('node:child_process');
8
8
  require('node:os');
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import 'chalk';
2
- import './index-CzSv4d_S.mjs';
3
- import './types-D0-nhvuW.mjs';
2
+ import './index-BW9kDx5m.mjs';
3
+ import './types-BdO0jg7G.mjs';
4
4
  import 'zod';
5
5
  import 'node:child_process';
6
6
  import 'node:os';
@@ -3,8 +3,8 @@ import { join, resolve } from 'node:path';
3
3
  import { homedir } from 'node:os';
4
4
  import { spawnSync } from 'node:child_process';
5
5
  import chalk from 'chalk';
6
- import { p as projectPath } from './types-D0-nhvuW.mjs';
7
- import { t as tmuxSupportsSessionEnv } from './index-CzSv4d_S.mjs';
6
+ import { p as projectPath } from './types-BdO0jg7G.mjs';
7
+ import { t as tmuxSupportsSessionEnv } from './index-BW9kDx5m.mjs';
8
8
  import 'axios';
9
9
  import 'node:util';
10
10
  import 'node:fs/promises';
@@ -5,8 +5,8 @@ var path = require('node:path');
5
5
  var os = require('node:os');
6
6
  var node_child_process = require('node:child_process');
7
7
  var chalk = require('chalk');
8
- var persistence = require('./types-D4bwyM-D.cjs');
9
- var index = require('./index-DM0Ku1Rv.cjs');
8
+ var persistence = require('./types--t4zLibT.cjs');
9
+ var index = require('./index-CvnMiYgh.cjs');
10
10
  require('axios');
11
11
  require('node:util');
12
12
  require('node:fs/promises');
package/dist/lib.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var persistence = require('./types-D4bwyM-D.cjs');
3
+ var persistence = require('./types--t4zLibT.cjs');
4
4
  require('axios');
5
5
  require('chalk');
6
6
  require('node:util');
package/dist/lib.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-D0-nhvuW.mjs';
1
+ export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-BdO0jg7G.mjs';
2
2
  import 'axios';
3
3
  import 'chalk';
4
4
  import 'node:util';
@@ -1,9 +1,9 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
3
  import { z } from 'zod';
4
- import { p as pushClipboardViaDaemon } from './index-CzSv4d_S.mjs';
4
+ import { p as pushClipboardViaDaemon } from './index-BW9kDx5m.mjs';
5
5
  import { C as CLIPBOARD_TOOL_NAME, a as CLIPBOARD_TOOL_TITLE, b as CLIPBOARD_TOOL_DESCRIPTION, c as CLIPBOARD_MAX_BYTES } from './limits-CwFb5S2b.mjs';
6
- import { l as logger } from './types-D0-nhvuW.mjs';
6
+ import { l as logger } from './types-BdO0jg7G.mjs';
7
7
  import 'chalk';
8
8
  import 'node:os';
9
9
  import 'node:crypto';
@@ -3,9 +3,9 @@
3
3
  var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
4
4
  var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
5
5
  var z = require('zod');
6
- var index = require('./index-DM0Ku1Rv.cjs');
6
+ var index = require('./index-CvnMiYgh.cjs');
7
7
  var limits = require('./limits-KdWKmwtH.cjs');
8
- var persistence = require('./types-D4bwyM-D.cjs');
8
+ var persistence = require('./types--t4zLibT.cjs');
9
9
  require('chalk');
10
10
  require('node:os');
11
11
  require('node:crypto');
@@ -2,10 +2,10 @@ import { useStdout, useInput, Box, Text, render } from 'ink';
2
2
  import React, { useState, useRef, useEffect, useCallback } from 'react';
3
3
  import { randomUUID } from 'node:crypto';
4
4
  import { join } from 'node:path';
5
- import { l as logger, h as connectionState, A as ApiClient, i as readSettings, e as errorLogMetadata, j as encodeBase64, p as projectPath, d as contentLogMetadata } from './types-D0-nhvuW.mjs';
6
- import { g as GEMINI_API_KEY_ENV, j as GOOGLE_API_KEY_ENV, G as GEMINI_MODEL_ENV, B as BasePermissionHandler, k as BaseReasoningProcessor, i as initialMachineMetadata, d as createSessionMetadata, e as setupOfflineReconnection, n as notifyDaemonSessionStarted, M as MessageQueue2, h as hashObject, l as MessageBuffer, C as CHANGE_TITLE_INSTRUCTION, r as registerKillSessionHandler, f as startHappyServer } from './index-CzSv4d_S.mjs';
7
- import { A as AcpBackend } from './AcpBackend-DwR8rrkS.mjs';
8
- import { readGeminiLocalConfig, determineGeminiModel, getGeminiModelSource, getInitialGeminiModel, saveGeminiModelToConfig } from './config-DKMwLc1k.mjs';
5
+ import { l as logger, h as connectionState, A as ApiClient, j as readSettings, e as errorLogMetadata, k as encodeBase64, p as projectPath, d as contentLogMetadata } from './types-BdO0jg7G.mjs';
6
+ import { v as GEMINI_API_KEY_ENV, x as GOOGLE_API_KEY_ENV, G as GEMINI_MODEL_ENV, B as BasePermissionHandler, y as BaseReasoningProcessor, g as initialMachineMetadata, h as createSessionMetadata, j as setupOfflineReconnection, n as notifyDaemonSessionStarted, k as MessageQueue2, m as hashObject, z as MessageBuffer, C as CHANGE_TITLE_INSTRUCTION, u as registerKillSessionHandler, o as startHappyServer } from './index-BW9kDx5m.mjs';
7
+ import { A as AcpBackend } from './AcpBackend-DzZR7TEv.mjs';
8
+ import { readGeminiLocalConfig, determineGeminiModel, getGeminiModelSource, getInitialGeminiModel, saveGeminiModelToConfig } from './config-CTyyVXHj.mjs';
9
9
  import 'axios';
10
10
  import 'chalk';
11
11
  import 'node:util';
@@ -4,10 +4,10 @@ var ink = require('ink');
4
4
  var React = require('react');
5
5
  var node_crypto = require('node:crypto');
6
6
  var path = require('node:path');
7
- var persistence = require('./types-D4bwyM-D.cjs');
8
- var index = require('./index-DM0Ku1Rv.cjs');
9
- var AcpBackend = require('./AcpBackend-D4vV6SVl.cjs');
10
- var config = require('./config-BvVwprR0.cjs');
7
+ var persistence = require('./types--t4zLibT.cjs');
8
+ var index = require('./index-CvnMiYgh.cjs');
9
+ var AcpBackend = require('./AcpBackend-D0_wbTs6.cjs');
10
+ var config = require('./config-CTCGilz_.cjs');
11
11
  require('axios');
12
12
  require('chalk');
13
13
  require('node:util');
@@ -3,9 +3,9 @@ import { execFileSync } from 'node:child_process';
3
3
  import os from 'node:os';
4
4
  import { existsSync, readFileSync } from 'node:fs';
5
5
  import { join } from 'node:path';
6
- import { k as ensurePrivateDirectorySync, m as hardenPrivateFileSync, w as writePrivateFileSync, e as errorLogMetadata, d as contentLogMetadata, h as connectionState, A as ApiClient, i as readSettings, j as encodeBase64, l as logger, c as configuration } from './types-D0-nhvuW.mjs';
7
- import { A as AcpSessionManager } from './AcpSessionManager-C057dkLF.mjs';
8
- import { i as initialMachineMetadata, d as createSessionMetadata, e as setupOfflineReconnection, n as notifyDaemonSessionStarted, M as MessageQueue2, r as registerKillSessionHandler } from './index-CzSv4d_S.mjs';
6
+ import { m as ensurePrivateDirectorySync, n as hardenPrivateFileSync, w as writePrivateFileSync, e as errorLogMetadata, d as contentLogMetadata, h as connectionState, A as ApiClient, j as readSettings, k as encodeBase64, l as logger, c as configuration } from './types-BdO0jg7G.mjs';
7
+ import { A as AcpSessionManager } from './AcpSessionManager-tWuFWeIF.mjs';
8
+ import { g as initialMachineMetadata, h as createSessionMetadata, j as setupOfflineReconnection, n as notifyDaemonSessionStarted, k as MessageQueue2, u as registerKillSessionHandler } from './index-BW9kDx5m.mjs';
9
9
  import WebSocket from 'ws';
10
10
  import * as ed from '@noble/ed25519';
11
11
  import { sha512 } from '@noble/hashes/sha2.js';
@@ -5,9 +5,9 @@ var node_child_process = require('node:child_process');
5
5
  var os = require('node:os');
6
6
  var node_fs = require('node:fs');
7
7
  var path = require('node:path');
8
- var persistence = require('./types-D4bwyM-D.cjs');
9
- var AcpSessionManager = require('./AcpSessionManager-CPHDZ-nz.cjs');
10
- var index = require('./index-DM0Ku1Rv.cjs');
8
+ var persistence = require('./types--t4zLibT.cjs');
9
+ var AcpSessionManager = require('./AcpSessionManager-Dcj_iHw8.cjs');
10
+ var index = require('./index-CvnMiYgh.cjs');
11
11
  var WebSocket = require('ws');
12
12
  var ed = require('@noble/ed25519');
13
13
  var sha2_js = require('@noble/hashes/sha2.js');
@@ -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-D0-nhvuW.mjs';
5
- import { b as sendUserMessage, a as sessionWebUrl } from './index-CzSv4d_S.mjs';
4
+ import { r as readPersistedSessions, c as configuration } from './types-BdO0jg7G.mjs';
5
+ import { b as sendUserMessage, a as sessionWebUrl } from './index-BW9kDx5m.mjs';
6
6
  import 'axios';
7
7
  import 'node:util';
8
8
  import 'node:os';
@@ -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-D4bwyM-D.cjs');
7
- var index = require('./index-DM0Ku1Rv.cjs');
6
+ var persistence = require('./types--t4zLibT.cjs');
7
+ var index = require('./index-CvnMiYgh.cjs');
8
8
  require('axios');
9
9
  require('node:util');
10
10
  require('node:os');
@@ -0,0 +1,204 @@
1
+ 'use strict';
2
+
3
+ var chalk = require('chalk');
4
+ var index = require('./index-CvnMiYgh.cjs');
5
+ var persistence = require('./types--t4zLibT.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;
@@ -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-BW9kDx5m.mjs';
3
+ import { i as isValidSessionId } from './types-BdO0jg7G.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 };
@@ -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-DM0Ku1Rv.cjs');
7
- var persistence = require('./types-D4bwyM-D.cjs');
6
+ var index = require('./index-CvnMiYgh.cjs');
7
+ var persistence = require('./types--t4zLibT.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
  }