very-happy-cli 0.2.141 → 0.2.143

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 (57) hide show
  1. package/dist/{AcpBackend-CnWSwaHk.cjs → AcpBackend-B8oehrfU.cjs} +2 -2
  2. package/dist/{AcpBackend-CWmjboOm.mjs → AcpBackend-LEgn9vol.mjs} +2 -2
  3. package/dist/{AcpSessionManager-Dxt78rPO.cjs → AcpSessionManager-BomdfyhZ.cjs} +1 -1
  4. package/dist/{AcpSessionManager-CtXoi6PN.mjs → AcpSessionManager-Yfbs5bi2.mjs} +1 -1
  5. package/dist/{agentGuidance-Do7cQka3.mjs → agentGuidance-BU4hxm8M.mjs} +1 -1
  6. package/dist/{agentGuidance-B9ENxSaS.cjs → agentGuidance-CJSl54ua.cjs} +1 -1
  7. package/dist/codex/happyMcpStdioBridge.cjs +2 -2
  8. package/dist/codex/happyMcpStdioBridge.mjs +2 -2
  9. package/dist/{config-Dn7nAHcA.cjs → config-CfqWoHmO.cjs} +5 -4
  10. package/dist/{config-DY57frJF.mjs → config-euZ_K5Lo.mjs} +5 -4
  11. package/dist/{index-BSVgut_Y.cjs → index-BREtikhm.cjs} +5 -4
  12. package/dist/{index-3STVDtNO.cjs → index-Bj68y6ee.cjs} +12 -40
  13. package/dist/{index-ChWePQEd.cjs → index-C510dSUn.cjs} +188 -132
  14. package/dist/{index-C55sW8E9.mjs → index-DoiG88oX.mjs} +169 -114
  15. package/dist/{index-DhfgAB8K.mjs → index-PM_SsRpw.mjs} +5 -4
  16. package/dist/{index-Dz6FgNFg.mjs → index-ZOMC8Gzn.mjs} +11 -39
  17. package/dist/index.cjs +7 -6
  18. package/dist/index.mjs +7 -6
  19. package/dist/installPiTools-BKnXjrVu.cjs +82 -0
  20. package/dist/installPiTools-C-Lxv4Bt.mjs +77 -0
  21. package/dist/{installTerminalHooks-zmtIrf3E.mjs → installTerminalHooks-BGVQqbgq.mjs} +8 -7
  22. package/dist/{installTerminalHooks--jkP17uE.cjs → installTerminalHooks-C_jraM1j.cjs} +9 -8
  23. package/dist/lib.cjs +3 -2
  24. package/dist/lib.d.cts +6 -1
  25. package/dist/lib.d.mts +6 -1
  26. package/dist/lib.mjs +3 -2
  27. package/dist/{limits-DbLWXlJm.cjs → limits-B3oVgqBJ.cjs} +29 -10
  28. package/dist/{limits-DT5Yk_UH.mjs → limits-uABU-yq3.mjs} +29 -11
  29. package/dist/{mcp-Bzy-X9kI.mjs → mcp-CfbTQXyh.mjs} +28 -14
  30. package/dist/{mcp-kE0n1dBF.cjs → mcp-G-3lL_KH.cjs} +29 -15
  31. package/dist/piExtension.d.mts +17 -0
  32. package/dist/piExtension.mjs +84 -0
  33. package/dist/piRuntime-BE6iYQwU.mjs +37 -0
  34. package/dist/piRuntime-CWE-1W-y.cjs +39 -0
  35. package/dist/piTerminal-Dyc_9pGP.cjs +132 -0
  36. package/dist/piTerminal-rqKn1_Zy.mjs +129 -0
  37. package/dist/projectPath-CSpqWdxp.mjs +10 -0
  38. package/dist/projectPath-ChLhdOyt.cjs +13 -0
  39. package/dist/{runGemini-BmdhYEzM.mjs → runGemini-BMlXIaTL.mjs} +8 -7
  40. package/dist/{runGemini-CxUz95A1.cjs → runGemini-C6qMFzcn.cjs} +9 -8
  41. package/dist/{runOpenClaw-RLIFJx61.cjs → runOpenClaw-C2_aCP7v.cjs} +6 -5
  42. package/dist/{runOpenClaw-CYpO3Vv8.mjs → runOpenClaw-CoO5Vp3S.mjs} +6 -5
  43. package/dist/{send-DT04hV8o.mjs → send-CBrJylJc.mjs} +5 -4
  44. package/dist/{send-BGcCrMUT.cjs → send-DGVwmB-p.cjs} +5 -4
  45. package/dist/{sessions-DDWTq2AG.mjs → sessions-DbLubh2N.mjs} +7 -6
  46. package/dist/{sessions-Jt9lrcrG.cjs → sessions-DyQXMN-8.cjs} +7 -6
  47. package/dist/{spawn-CdZgvthE.cjs → spawn-DIyFOn3W.cjs} +5 -4
  48. package/dist/{spawn-Ca0A70dX.mjs → spawn-wkkxEGdF.mjs} +5 -4
  49. package/dist/{teams-CzK1zg0m.mjs → teams-BTyVFK3P.mjs} +5 -4
  50. package/dist/{teams-DfVwVZ4x.cjs → teams-QOkGFjkJ.cjs} +5 -4
  51. package/dist/terminalToolContext-CFeGeaNm.mjs +7 -0
  52. package/dist/terminalToolContext-DoV9Gs7K.cjs +9 -0
  53. package/dist/{todo-4WhOom8k.mjs → todo-DoLkqdBe.mjs} +4 -3
  54. package/dist/{todo-D9nFaYpQ.cjs → todo-Du6pjwx_.cjs} +4 -3
  55. package/dist/{types-Bk3W89Z3.cjs → types-6__wqmmP.cjs} +80 -17
  56. package/dist/{types-CLosaeZT.mjs → types-BG4gFjLL.mjs} +79 -15
  57. package/package.json +11 -7
@@ -1,13 +1,14 @@
1
1
  import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
2
2
  import os, { homedir, userInfo, tmpdir } from 'node:os';
3
3
  import { randomUUID, randomInt, randomBytes, createHash as createHash$1, timingSafeEqual } from 'node:crypto';
4
- import { o as notifyDaemonSessionEvent, q as getProjectPath, l as BUILTIN_TODO_DISCOVERY, p as projectPath, r as initializeSandbox, w as wrapCommand, j as contentLogMetadata, I as InvalidateSync, R as RawJSONLinesSchema, m as delay, t as AsyncLock, S as STREAM_DELTA_MAX_CHARS, M as MAX_CHAT_ATTACHMENT_SOURCE_BYTES, u as notifyDaemonClaudeAuthFailed, v as commandOnPath, c as checkIfDaemonRunningAndCleanupStaleState, x as deriveLocalCliUpdateSummary, y as AGENT_VERSION_SOURCES, z as isClaudeSessionId, C as getLocalHappyAgentCredentialPath, D as readLocalHappyAgentCredentials, E as parseExactVersion, F as compareExactVersions, G as extractCompleteLines, H as decideBackfill, J as parseTerminalHookPayload, K as tmuxArgs, L as scrubTmuxClientEnv, N as decideMirrorBinding, O as MIRROR_BACKFILL_LINES_DEFAULT, P as mirrorLineKey, Q as mirrorLocalId, T as listDaemonSessions, U as stopDaemonSession, V as detectCLIAvailability, W as detectResumeSupport, X as isDaemonRunningCurrentlyInstalledHappyVersion, Y as stopDaemon, Z as TurnActivityTracker, _ as summarizeSpawnSessionForLog, $ as shellescape, A as ApiClient, a0 as fetchCliUpdateState, a1 as resolveCliUpdateCheckInterval, a2 as DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS, a3 as cleanupDaemonState, i as isValidSessionId, s as spawnDaemonSession, a4 as listVhTerminals, a5 as isValidTerminalId, a6 as readVhTerminal, a7 as sendToVhTerminal, a8 as ContextUsageSchema, a9 as TITLE_PROMPT_PREFIX, aa as BOARD_ANALYZER_PROMPT_PREFIX, k as connectionState, ab as startOfflineReconnection, n as notifyDaemonSessionStarted, d as createEnvelope, ac as CodexAppServerClient } from './types-CLosaeZT.mjs';
5
- import { l as logger, D as ensurePrivateDirectory, E as hardenPrivateFile, c as configuration, p as packageJson, g as readSettings, F as readCredentials, u as credentialRelayProblem, o as readDaemonState, i as encodeBase64, G as readSettingsOutcome, H as updateSettings, I as encodeBase64Url, m as decodeBase64, J as writeCredentialsLegacy, K as writeCredentialsDataKey, d as readCredentialsForConfiguredRelay, j as encrypt, r as readPersistedSessions, w as writePrivateFileSync, L as decryptWithDataKey, M as decryptLegacy, N as persistSession, k as decrypt, f as ensurePrivateDirectorySync, O as acquireDaemonLock, P as deletePersistedSessions, Q as writeDaemonState, R as writeSettings, S as releaseDaemonLock, C as CLIPBOARD_TOOL_NAME, a as CLIPBOARD_TOOL_TITLE, b as CLIPBOARD_TOOL_DESCRIPTION, e as CLIPBOARD_MAX_BYTES, T as clearCredentials, U as clearMachineId, V as SandboxConfigSchema, W as getLatestDaemonLog } from './limits-DT5Yk_UH.mjs';
4
+ import { o as notifyDaemonSessionEvent, q as getProjectPath, j as BUILTIN_TODO_DISCOVERY, r as initializeSandbox, w as wrapCommand, l as contentLogMetadata, I as InvalidateSync, R as RawJSONLinesSchema, m as delay, t as AsyncLock, S as STREAM_DELTA_MAX_CHARS, M as MAX_CHAT_ATTACHMENT_SOURCE_BYTES, u as notifyDaemonClaudeAuthFailed, v as commandOnPath, c as checkIfDaemonRunningAndCleanupStaleState, x as deriveLocalCliUpdateSummary, y as AGENT_VERSION_SOURCES, z as isClaudeSessionId, C as getLocalHappyAgentCredentialPath, D as readLocalHappyAgentCredentials, E as parseExactVersion, F as compareExactVersions, G as extractCompleteLines, H as decideBackfill, J as parseTerminalHookPayload, K as tmuxArgs, L as scrubTmuxClientEnv, N as decideMirrorBinding, O as MIRROR_BACKFILL_LINES_DEFAULT, P as mirrorLineKey, Q as mirrorLocalId, T as listDaemonSessions, U as stopDaemonSession, V as detectCLIAvailability, W as detectResumeSupport, X as isDaemonRunningCurrentlyInstalledHappyVersion, Y as stopDaemon, Z as TurnActivityTracker, _ as summarizeSpawnSessionForLog, $ as shellescape, A as ApiClient, a0 as fetchCliUpdateState, a1 as resolveCliUpdateCheckInterval, a2 as DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS, a3 as cleanupDaemonState, i as isValidSessionId, s as spawnDaemonSession, a4 as listVhTerminals, a5 as isValidTerminalId, a6 as readVhTerminal, a7 as sendToVhTerminal, a8 as ContextUsageSchema, a9 as TITLE_PROMPT_PREFIX, aa as BOARD_ANALYZER_PROMPT_PREFIX, h as connectionState, ab as startOfflineReconnection, n as notifyDaemonSessionStarted, d as createEnvelope, ac as CodexAppServerClient } from './types-BG4gFjLL.mjs';
5
+ import { l as logger, E as ensurePrivateDirectory, F as hardenPrivateFile, c as configuration, p as packageJson, f as readSettings, G as readCredentials, v as credentialRelayProblem, o as readDaemonState, g as encodeBase64, H as readSettingsOutcome, I as updateSettings, J as encodeBase64Url, m as decodeBase64, K as writeCredentialsLegacy, L as writeCredentialsDataKey, d as readCredentialsForConfiguredRelay, j as encrypt, r as readPersistedSessions, w as writePrivateFileSync, M as decryptWithDataKey, N as decryptLegacy, O as persistSession, k as decrypt, h as ensurePrivateDirectorySync, P as acquireDaemonLock, Q as deletePersistedSessions, R as writeDaemonState, S as writeSettings, T as releaseDaemonLock, C as CLIPBOARD_TOOL_NAME, a as CLIPBOARD_TOOL_TITLE, b as CLIPBOARD_TOOL_DESCRIPTION, e as CLIPBOARD_MAX_BYTES, U as clearCredentials, V as clearMachineId, W as SandboxConfigSchema, X as getLatestDaemonLog } from './limits-uABU-yq3.mjs';
6
6
  import spawn$1, { spawn } from 'cross-spawn';
7
- import path, { join, resolve, basename, isAbsolute, dirname, sep, delimiter, normalize } from 'node:path';
7
+ import path, { join, resolve, basename, isAbsolute, sep, dirname, delimiter, normalize } from 'node:path';
8
8
  import { createInterface } from 'node:readline';
9
9
  import { existsSync, readFileSync, readdirSync, statSync, mkdirSync, unlinkSync, renameSync, writeFileSync, accessSync, constants, openSync, fsyncSync, closeSync, rmSync as rmSync$1, chmodSync as chmodSync$1 } from 'node:fs';
10
- import { f as trimIdent, A as AGENT_GUIDANCE, t as teamScopePath, T as TeamConnectionPreflightError, e as createTeamsClient, P as PREVIEW_TOOL_NAME, R as REPORT_PROGRESS_TOOL_NAME, g as TEAM_TOOL_NAMES, r as registerTeamsTools, a as PREVIEW_TOOL_TITLE, b as PREVIEW_TOOL_DESCRIPTION, h as REPORT_PROGRESS_TOOL_TITLE, i as REPORT_PROGRESS_TOOL_DESCRIPTION } from './agentGuidance-Do7cQka3.mjs';
10
+ import { p as projectPath } from './projectPath-CSpqWdxp.mjs';
11
+ import { f as trimIdent, A as AGENT_GUIDANCE, t as teamScopePath, T as TeamConnectionPreflightError, e as createTeamsClient, P as PREVIEW_TOOL_NAME, R as REPORT_PROGRESS_TOOL_NAME, g as TEAM_TOOL_NAMES, r as registerTeamsTools, a as PREVIEW_TOOL_TITLE, b as PREVIEW_TOOL_DESCRIPTION, h as REPORT_PROGRESS_TOOL_TITLE, i as REPORT_PROGRESS_TOOL_DESCRIPTION } from './agentGuidance-BU4hxm8M.mjs';
11
12
  import { readFile, writeFile, rename, unlink, mkdir, symlink, rm, readlink, lstat, stat, open as open$1, appendFile } from 'node:fs/promises';
12
13
  import fs, { watch, access } from 'fs/promises';
13
14
  import { useStdout, useInput, Box, Text, render } from 'ink';
@@ -6082,6 +6083,83 @@ function isAuthorizedDaemonControlRequest(authorization, controlToken) {
6082
6083
  return configuredTokenIsUsable && timingSafeEqual(expectedDigest, candidateDigest);
6083
6084
  }
6084
6085
 
6086
+ const DENIED_HOME_DIRS = [
6087
+ ".secrets",
6088
+ ".ssh",
6089
+ ".gnupg",
6090
+ ".aws",
6091
+ ".kube",
6092
+ ".config/rbw"
6093
+ ];
6094
+ const DENIED_HOME_FILES = [
6095
+ ".claude.json",
6096
+ ".claude/.credentials.json",
6097
+ ".netrc",
6098
+ ".pgpass"
6099
+ ];
6100
+ const DENIED_BASENAME_PATTERNS = [
6101
+ /^\.env$/i,
6102
+ /^\.env\./i,
6103
+ /\.env$/i,
6104
+ /\.pem$/i,
6105
+ /\.key$/i,
6106
+ /\.p12$/i,
6107
+ /\.pfx$/i,
6108
+ /^id_(rsa|dsa|ecdsa|ed25519)$/i,
6109
+ /^\.htpasswd$/i
6110
+ ];
6111
+ const DENIED_PATH_SUFFIXES = [
6112
+ `${sep}.git${sep}config`
6113
+ ];
6114
+ function expandHome(input, home) {
6115
+ if (input === "~") return home;
6116
+ if (input.startsWith(`~${sep}`) || input.startsWith("~/")) {
6117
+ return resolve(home, input.slice(2));
6118
+ }
6119
+ return input;
6120
+ }
6121
+ function basenameOf(p) {
6122
+ const parts = p.split(sep);
6123
+ return parts[parts.length - 1] ?? "";
6124
+ }
6125
+ function isUnder(child, parent) {
6126
+ return child === parent || child.startsWith(parent.endsWith(sep) ? parent : parent + sep);
6127
+ }
6128
+ function checkPreviewPath(input, opts) {
6129
+ const home = homedir();
6130
+ const cwd = process.cwd();
6131
+ if (typeof input !== "string" || !input.trim()) {
6132
+ return { resolved: "", deniedReason: "path must be a non-empty string" };
6133
+ }
6134
+ if (input.includes("\0")) {
6135
+ return { resolved: "", deniedReason: "path contains a NUL byte" };
6136
+ }
6137
+ const expanded = expandHome(input.trim(), home);
6138
+ const resolved = isAbsolute(expanded) ? resolve(expanded) : resolve(cwd, expanded);
6139
+ for (const dir of DENIED_HOME_DIRS) {
6140
+ if (isUnder(resolved, resolve(home, dir))) {
6141
+ return { resolved, deniedReason: `refusing to preview anything under ~/${dir} (credential material)` };
6142
+ }
6143
+ }
6144
+ for (const file of DENIED_HOME_FILES) {
6145
+ if (resolved === resolve(home, file)) {
6146
+ return { resolved, deniedReason: `refusing to preview ~/${file} (credential material)` };
6147
+ }
6148
+ }
6149
+ const base = basenameOf(resolved);
6150
+ for (const pattern of DENIED_BASENAME_PATTERNS) {
6151
+ if (pattern.test(base)) {
6152
+ return { resolved, deniedReason: `refusing to preview "${base}" (looks like credential material)` };
6153
+ }
6154
+ }
6155
+ for (const suffix of DENIED_PATH_SUFFIXES) {
6156
+ if (resolved.endsWith(suffix)) {
6157
+ return { resolved, deniedReason: `refusing to preview ${suffix} (may contain credentials)` };
6158
+ }
6159
+ }
6160
+ return { resolved, deniedReason: null };
6161
+ }
6162
+
6085
6163
  function startDaemonControlServer({
6086
6164
  controlToken,
6087
6165
  getChildren,
@@ -6093,6 +6171,7 @@ function startDaemonControlServer({
6093
6171
  onClaudeAuthFailed,
6094
6172
  onSessionTurnEvent,
6095
6173
  pushClipboard,
6174
+ pushFilePreview,
6096
6175
  onTerminalHook,
6097
6176
  setTerminalTitle
6098
6177
  }) {
@@ -6307,7 +6386,8 @@ function startDaemonControlServer({
6307
6386
  typed.post("/clipboard", {
6308
6387
  schema: {
6309
6388
  body: z.object({
6310
- text: z.string()
6389
+ text: z.string(),
6390
+ terminalId: z.string().regex(/^[a-zA-Z0-9_-]{1,64}$/).optional()
6311
6391
  }),
6312
6392
  response: {
6313
6393
  200: z.object({
@@ -6319,9 +6399,25 @@ function startDaemonControlServer({
6319
6399
  }
6320
6400
  }
6321
6401
  }, async (request) => {
6322
- const { text } = request.body;
6402
+ const { text, terminalId } = request.body;
6323
6403
  logger.debug(`[CONTROL SERVER] Clipboard push request (${text.length} chars)`);
6324
- return pushClipboard(text);
6404
+ return terminalId ? pushClipboard(text, terminalId) : pushClipboard(text);
6405
+ });
6406
+ typed.post("/file-preview", {
6407
+ schema: {
6408
+ body: z.object({
6409
+ terminalId: z.string().regex(/^[a-zA-Z0-9_-]{1,64}$/),
6410
+ path: z.string().min(1),
6411
+ mode: z.enum(["file", "diff"]).optional()
6412
+ }),
6413
+ response: { 200: z.object({ delivered: z.boolean(), error: z.string().optional() }) }
6414
+ }
6415
+ }, async (request) => {
6416
+ const { terminalId, path, mode } = request.body;
6417
+ const verdict = checkPreviewPath(path);
6418
+ if (verdict.deniedReason) return { delivered: false, error: verdict.deniedReason };
6419
+ if (!pushFilePreview) return { delivered: false, error: "daemon is still starting up" };
6420
+ return pushFilePreview(terminalId, verdict.resolved, mode ?? "file");
6325
6421
  });
6326
6422
  typed.post("/terminal-title", {
6327
6423
  schema: {
@@ -9044,14 +9140,15 @@ On restart inspect authoritative state and messages before taking new actions. D
9044
9140
  `;
9045
9141
  const PI_TEAMS_EXTENSION = `// Managed by Very Happy Agent Teams.
9046
9142
  export default async function(pi) {
9047
- const endpoint = process.env.HAPPY_MCP_URL;
9143
+ const managed = !!process.env.HAPPY_MCP_URL;
9144
+ const endpoint = process.env.HAPPY_MCP_URL || process.env.HAPPY_TERMINAL_MCP_URL;
9048
9145
  if (!endpoint) return;
9049
9146
  const url = new URL(endpoint);
9050
9147
  if (!['127.0.0.1', 'localhost', '[::1]'].includes(url.hostname) || url.protocol !== 'http:') throw new Error('Very Happy MCP must be local');
9051
9148
  const {readFile} = await import('node:fs/promises');
9052
9149
  const {join} = await import('node:path');
9053
9150
  const {homedir} = await import('node:os');
9054
- const contextEndpoint = process.env.HAPPY_CONTEXT_USAGE_URL;
9151
+ const contextEndpoint = managed && process.env.HAPPY_CONTEXT_USAGE_URL;
9055
9152
  if (contextEndpoint) {
9056
9153
  const target = new URL(contextEndpoint);
9057
9154
  if (target.origin !== url.origin || !target.pathname.startsWith('/runtime-context/')) throw new Error('Very Happy context must be local');
@@ -9069,7 +9166,7 @@ export default async function(pi) {
9069
9166
  });
9070
9167
  }
9071
9168
  }
9072
- pi.on('tool_call', async (event, ctx) => {
9169
+ if (managed) pi.on('tool_call', async (event, ctx) => {
9073
9170
  let mode = process.env.HAPPY_PERMISSION_MODE || 'default';
9074
9171
  const sid = process.env.HAPPY_SESSION_ID;
9075
9172
  if (sid && /^[a-zA-Z0-9_-]+$/.test(sid)) {
@@ -9108,7 +9205,11 @@ export default async function(pi) {
9108
9205
  const available = await rpc('tools/list', {});
9109
9206
  for (const tool of available.tools || []) {
9110
9207
  pi.registerTool({name:tool.name,label:tool.name,description:tool.description || tool.name,parameters:tool.inputSchema,
9111
- async execute(_id, args) { const result = await rpc('tools/call', {name:tool.name,arguments:args}); return {content:result.content,details:{isError:!!result.isError}}; }
9208
+ async execute(_id, args) {
9209
+ const result = await rpc('tools/call', {name:tool.name,arguments:args});
9210
+ if (result.isError) throw new Error((result.content || []).filter(block => block.type === 'text').map(block => block.text).join('\\n') || 'Very Happy tool failed');
9211
+ return {content:result.content,details:{isError:false}};
9212
+ }
9112
9213
  });
9113
9214
  }
9114
9215
  }
@@ -9915,6 +10016,10 @@ Use the teams tools to inspect current task state before acting. This message is
9915
10016
  } };
9916
10017
  }
9917
10018
 
10019
+ function daemonExitCode(source) {
10020
+ return source === "exception" ? 1 : 0;
10021
+ }
10022
+
9918
10023
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
9919
10024
  function sanitizeImportTitle(value) {
9920
10025
  if (typeof value !== "string") return null;
@@ -9994,9 +10099,9 @@ async function startDaemon() {
9994
10099
  requestShutdown = (source, errorMessage) => {
9995
10100
  logger.debug(`[DAEMON RUN] Requesting shutdown (source: ${source}, errorMessage: ${errorMessage})`);
9996
10101
  setTimeout(async () => {
9997
- logger.debug("[DAEMON RUN] Startup malfunctioned, forcing exit with code 1");
10102
+ logger.debug(`[DAEMON RUN] Shutdown did not complete in time, forcing exit with code ${daemonExitCode(source)}`);
9998
10103
  await new Promise((resolve2) => setTimeout(resolve2, 100));
9999
- process.exit(1);
10104
+ process.exit(daemonExitCode(source));
10000
10105
  }, 1e3);
10001
10106
  resolve({ source, errorMessage });
10002
10107
  };
@@ -10984,11 +11089,15 @@ async function startDaemon() {
10984
11089
  onSessionStateEvent,
10985
11090
  onClaudeAuthFailed: (sessionId) => claudeAuthServiceRef?.signalAuthFailed(sessionId),
10986
11091
  onSessionTurnEvent: (sessionId, event) => turnActivity.apply(sessionId, event),
10987
- pushClipboard: (text) => {
11092
+ pushClipboard: (text, terminalId) => {
10988
11093
  if (!apiMachineRef) {
10989
11094
  return { delivered: false, truncated: false, totalBytes: 0, error: "daemon is still starting up" };
10990
11095
  }
10991
- return apiMachineRef.pushClipboard(text);
11096
+ return apiMachineRef.pushClipboard(text, terminalId);
11097
+ },
11098
+ pushFilePreview: (terminalId, path, mode) => {
11099
+ if (!apiMachineRef) return { delivered: false, error: "daemon is still starting up" };
11100
+ return apiMachineRef.pushFilePreview(terminalId, path, mode);
10992
11101
  },
10993
11102
  onTerminalHook: (body) => {
10994
11103
  mirrorManagerRef?.handleHookPayload(body);
@@ -11250,8 +11359,8 @@ async function startDaemon() {
11250
11359
  await cleanupDaemonState();
11251
11360
  await stopCaffeinate();
11252
11361
  await releaseDaemonLock(daemonLockHandle);
11253
- logger.debug("[DAEMON RUN] Cleanup completed, exiting process");
11254
- process.exit(0);
11362
+ logger.debug(`[DAEMON RUN] Cleanup completed, exiting process with code ${daemonExitCode(source)}`);
11363
+ process.exit(daemonExitCode(source));
11255
11364
  };
11256
11365
  logger.debug("[DAEMON RUN] Daemon started successfully, waiting for shutdown request");
11257
11366
  const shutdownRequest = await resolvesWhenShutdownRequested;
@@ -11725,83 +11834,6 @@ function normalizeProgress(value) {
11725
11834
  return flat.length > PROGRESS_MAX_CHARS$1 ? flat.slice(0, PROGRESS_MAX_CHARS$1) : flat;
11726
11835
  }
11727
11836
 
11728
- const DENIED_HOME_DIRS = [
11729
- ".secrets",
11730
- ".ssh",
11731
- ".gnupg",
11732
- ".aws",
11733
- ".kube",
11734
- ".config/rbw"
11735
- ];
11736
- const DENIED_HOME_FILES = [
11737
- ".claude.json",
11738
- ".claude/.credentials.json",
11739
- ".netrc",
11740
- ".pgpass"
11741
- ];
11742
- const DENIED_BASENAME_PATTERNS = [
11743
- /^\.env$/i,
11744
- /^\.env\./i,
11745
- /\.env$/i,
11746
- /\.pem$/i,
11747
- /\.key$/i,
11748
- /\.p12$/i,
11749
- /\.pfx$/i,
11750
- /^id_(rsa|dsa|ecdsa|ed25519)$/i,
11751
- /^\.htpasswd$/i
11752
- ];
11753
- const DENIED_PATH_SUFFIXES = [
11754
- `${sep}.git${sep}config`
11755
- ];
11756
- function expandHome(input, home) {
11757
- if (input === "~") return home;
11758
- if (input.startsWith(`~${sep}`) || input.startsWith("~/")) {
11759
- return resolve(home, input.slice(2));
11760
- }
11761
- return input;
11762
- }
11763
- function basenameOf(p) {
11764
- const parts = p.split(sep);
11765
- return parts[parts.length - 1] ?? "";
11766
- }
11767
- function isUnder(child, parent) {
11768
- return child === parent || child.startsWith(parent.endsWith(sep) ? parent : parent + sep);
11769
- }
11770
- function checkPreviewPath(input, opts) {
11771
- const home = homedir();
11772
- const cwd = process.cwd();
11773
- if (typeof input !== "string" || !input.trim()) {
11774
- return { resolved: "", deniedReason: "path must be a non-empty string" };
11775
- }
11776
- if (input.includes("\0")) {
11777
- return { resolved: "", deniedReason: "path contains a NUL byte" };
11778
- }
11779
- const expanded = expandHome(input.trim(), home);
11780
- const resolved = isAbsolute(expanded) ? resolve(expanded) : resolve(cwd, expanded);
11781
- for (const dir of DENIED_HOME_DIRS) {
11782
- if (isUnder(resolved, resolve(home, dir))) {
11783
- return { resolved, deniedReason: `refusing to preview anything under ~/${dir} (credential material)` };
11784
- }
11785
- }
11786
- for (const file of DENIED_HOME_FILES) {
11787
- if (resolved === resolve(home, file)) {
11788
- return { resolved, deniedReason: `refusing to preview ~/${file} (credential material)` };
11789
- }
11790
- }
11791
- const base = basenameOf(resolved);
11792
- for (const pattern of DENIED_BASENAME_PATTERNS) {
11793
- if (pattern.test(base)) {
11794
- return { resolved, deniedReason: `refusing to preview "${base}" (looks like credential material)` };
11795
- }
11796
- }
11797
- for (const suffix of DENIED_PATH_SUFFIXES) {
11798
- if (resolved.endsWith(suffix)) {
11799
- return { resolved, deniedReason: `refusing to preview ${suffix} (may contain credentials)` };
11800
- }
11801
- }
11802
- return { resolved, deniedReason: null };
11803
- }
11804
-
11805
11837
  function createMcpServer(handlers, options, sessionId) {
11806
11838
  const mcp = new McpServer({
11807
11839
  name: "Very Happy Tools",
@@ -11853,7 +11885,7 @@ function createMcpServer(handlers, options, sessionId) {
11853
11885
  return {
11854
11886
  content: [{
11855
11887
  type: "text",
11856
- text: `Sent to the user's clipboard on their currently open device(s)${note}. If the page was not focused, they may need to tap a confirmation button.`
11888
+ text: `Queued a clipboard request for the user's open Very Happy device(s)${note}. This does not confirm that a browser wrote the clipboard; the user may need to tap a confirmation button.`
11857
11889
  }],
11858
11890
  isError: false
11859
11891
  };
@@ -12322,7 +12354,7 @@ function registerSideQuestionHandler(rpc, deps) {
12322
12354
  const retainMs = deps.retainMs ?? SIDE_QUESTION_RETAIN_MS;
12323
12355
  const maxRunMs = deps.maxRunMs ?? SIDE_QUESTION_MAX_RUN_MS;
12324
12356
  const run = deps.run ?? (async (input) => {
12325
- const { query } = await import('./index-DhfgAB8K.mjs');
12357
+ const { query } = await import('./index-PM_SsRpw.mjs');
12326
12358
  return runSideQuestion(query, input);
12327
12359
  });
12328
12360
  const slots = /* @__PURE__ */ new Map();
@@ -17556,9 +17588,18 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17556
17588
  } else if (subcommand === "bye") {
17557
17589
  console.log("Bye!");
17558
17590
  process.exit(0);
17591
+ } else if (subcommand === "install-pi-tools") {
17592
+ try {
17593
+ const { handleInstallPiTools } = await import('./installPiTools-C-Lxv4Bt.mjs');
17594
+ await handleInstallPiTools(args.slice(1));
17595
+ } catch (error) {
17596
+ console.error(error instanceof Error ? error.message : "Pi tools installation failed");
17597
+ process.exitCode = 1;
17598
+ }
17599
+ return;
17559
17600
  } else if (subcommand === "install-terminal-hooks") {
17560
17601
  try {
17561
- const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await import('./installTerminalHooks-zmtIrf3E.mjs');
17602
+ const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await import('./installTerminalHooks-BGVQqbgq.mjs');
17562
17603
  const command = parseTerminalHooksArgs(args.slice(1));
17563
17604
  if (command.action === "help") {
17564
17605
  console.log(TERMINAL_HOOKS_HELP);
@@ -17575,7 +17616,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17575
17616
  }
17576
17617
  } else if (subcommand === "spawn") {
17577
17618
  try {
17578
- const { handleSpawnCommand } = await import('./spawn-Ca0A70dX.mjs');
17619
+ const { handleSpawnCommand } = await import('./spawn-wkkxEGdF.mjs');
17579
17620
  await handleSpawnCommand(args.slice(1));
17580
17621
  } catch (error) {
17581
17622
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -17587,7 +17628,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17587
17628
  return;
17588
17629
  } else if (subcommand === "sessions") {
17589
17630
  try {
17590
- const { handleSessionsCommand } = await import('./sessions-DDWTq2AG.mjs');
17631
+ const { handleSessionsCommand } = await import('./sessions-DbLubh2N.mjs');
17591
17632
  await handleSessionsCommand(args.slice(1));
17592
17633
  } catch (error) {
17593
17634
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -17599,7 +17640,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17599
17640
  return;
17600
17641
  } else if (subcommand === "send") {
17601
17642
  try {
17602
- const { handleSendCommand } = await import('./send-DT04hV8o.mjs');
17643
+ const { handleSendCommand } = await import('./send-CBrJylJc.mjs');
17603
17644
  await handleSendCommand(args.slice(1));
17604
17645
  } catch (error) {
17605
17646
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -17705,9 +17746,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17705
17746
  if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
17706
17747
  const projectId = args[3];
17707
17748
  try {
17708
- const { saveGoogleCloudProjectToConfig } = await import('./config-DY57frJF.mjs');
17709
- const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await import('./limits-DT5Yk_UH.mjs').then(function (n) { return n.X; });
17710
- const { ApiClient: ApiClient2 } = await import('./types-CLosaeZT.mjs').then(function (n) { return n.ad; });
17749
+ const { saveGoogleCloudProjectToConfig } = await import('./config-euZ_K5Lo.mjs');
17750
+ const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await import('./limits-uABU-yq3.mjs').then(function (n) { return n.Y; });
17751
+ const { ApiClient: ApiClient2 } = await import('./types-BG4gFjLL.mjs').then(function (n) { return n.ad; });
17711
17752
  let userEmail = void 0;
17712
17753
  try {
17713
17754
  const credentials = await readCredentialsForConfiguredRelay2();
@@ -17738,7 +17779,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17738
17779
  }
17739
17780
  if (geminiSubcommand === "project" && args[2] === "get") {
17740
17781
  try {
17741
- const { readGeminiLocalConfig } = await import('./config-DY57frJF.mjs');
17782
+ const { readGeminiLocalConfig } = await import('./config-euZ_K5Lo.mjs');
17742
17783
  const config = readGeminiLocalConfig();
17743
17784
  if (config.googleCloudProject) {
17744
17785
  console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
@@ -17778,7 +17819,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17778
17819
  process.exit(0);
17779
17820
  }
17780
17821
  try {
17781
- const { runGemini } = await import('./runGemini-BmdhYEzM.mjs');
17822
+ const { runGemini } = await import('./runGemini-BMlXIaTL.mjs');
17782
17823
  let startedBy = void 0;
17783
17824
  for (let i = 1; i < args.length; i++) {
17784
17825
  if (args[i] === "--started-by") {
@@ -17799,6 +17840,16 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17799
17840
  }
17800
17841
  return;
17801
17842
  } else if (subcommand === "pi") {
17843
+ if (args[1] === "--terminal") {
17844
+ try {
17845
+ const { runPiTerminal } = await import('./piTerminal-rqKn1_Zy.mjs');
17846
+ process.exitCode = await runPiTerminal(args.slice(2));
17847
+ } catch (error) {
17848
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
17849
+ process.exitCode = 1;
17850
+ }
17851
+ return;
17852
+ }
17802
17853
  let hintPrinted = false;
17803
17854
  const printHint = (detail) => {
17804
17855
  const hint = piAdapterMissingHint(detail);
@@ -17808,7 +17859,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17808
17859
  }
17809
17860
  };
17810
17861
  try {
17811
- const { runAcp, resolveAcpAgentConfig } = await import('./index-Dz6FgNFg.mjs');
17862
+ const { runAcp, resolveAcpAgentConfig } = await import('./index-ZOMC8Gzn.mjs');
17812
17863
  const parsed = parsePiRunnerArgs(args.slice(1));
17813
17864
  const resolved = resolveAcpAgentConfig(["pi", ...parsed.passthrough]);
17814
17865
  const { credentials } = await authAndSetupMachineIfNeeded();
@@ -17836,7 +17887,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17836
17887
  return;
17837
17888
  } else if (subcommand === "acp") {
17838
17889
  try {
17839
- const { runAcp, resolveAcpAgentConfig } = await import('./index-Dz6FgNFg.mjs');
17890
+ const { runAcp, resolveAcpAgentConfig } = await import('./index-ZOMC8Gzn.mjs');
17840
17891
  let startedBy = void 0;
17841
17892
  let verbose = false;
17842
17893
  const acpArgs = [];
@@ -17876,7 +17927,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17876
17927
  return;
17877
17928
  } else if (subcommand === "openclaw") {
17878
17929
  try {
17879
- const { runOpenClaw } = await import('./runOpenClaw-CYpO3Vv8.mjs');
17930
+ const { runOpenClaw } = await import('./runOpenClaw-CoO5Vp3S.mjs');
17880
17931
  let startedBy = void 0;
17881
17932
  let verbose = false;
17882
17933
  let gatewayUrl;
@@ -17927,7 +17978,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17927
17978
  return;
17928
17979
  } else if (subcommand === "todo") {
17929
17980
  try {
17930
- const { handleTodoCommand } = await import('./todo-4WhOom8k.mjs');
17981
+ const { handleTodoCommand } = await import('./todo-DoLkqdBe.mjs');
17931
17982
  await handleTodoCommand(args.slice(1));
17932
17983
  } catch (error) {
17933
17984
  console.error(JSON.stringify({ error: error instanceof Error ? error.message : "Todo command failed" }));
@@ -17936,17 +17987,17 @@ Conversation history is preserved on the server, but in-flight tool calls are in
17936
17987
  return;
17937
17988
  } else if (subcommand === "teams") {
17938
17989
  try {
17939
- const { handleTeamsCommand } = await import('./teams-CzK1zg0m.mjs');
17990
+ const { handleTeamsCommand } = await import('./teams-BTyVFK3P.mjs');
17940
17991
  await handleTeamsCommand(args.slice(1));
17941
17992
  } catch (error) {
17942
17993
  console.error(error instanceof Error ? error.message : "Teams command failed");
17943
17994
  process.exitCode = 1;
17944
17995
  }
17945
17996
  return;
17946
- } else if (subcommand === "mcp" && args.length === 1) {
17997
+ } else if (subcommand === "mcp" && (args.length === 1 || args.length === 2 && args[1] === "--terminal-tools")) {
17947
17998
  try {
17948
- const { handleMcpCommand } = await import('./mcp-Bzy-X9kI.mjs');
17949
- await handleMcpCommand();
17999
+ const { handleMcpCommand } = await import('./mcp-CfbTQXyh.mjs');
18000
+ await handleMcpCommand(args[1] === "--terminal-tools");
17950
18001
  } catch (error) {
17951
18002
  process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
17952
18003
  `);
@@ -18166,6 +18217,10 @@ ${chalk.bold("Usage:")}
18166
18217
  very-happy codex Start Codex mode
18167
18218
  very-happy gemini Start Gemini mode (ACP)
18168
18219
  very-happy pi Start pi mode (ACP via the pi-acp adapter)
18220
+ very-happy pi --terminal Run native pi with title, clipboard and preview tools
18221
+ inside a Very Happy terminal
18222
+ very-happy install-pi-tools Install tools for directly launched pi sessions
18223
+ (add --remove to uninstall)
18169
18224
  very-happy acp Start a generic ACP-compatible agent
18170
18225
  very-happy openclaw Connect through a configured OpenClaw gateway
18171
18226
  very-happy install-terminal-hooks
@@ -18307,4 +18362,4 @@ ${chalk.bold("Examples:")}
18307
18362
  }
18308
18363
  }
18309
18364
 
18310
- export { ALLOWED_SPAWN_PERMISSION_MODES as A, appendStagedAttachmentsToPrompt as B, CLAUDE_ATTACHMENT_KINDS as C, DEFAULT_RECENT_LIMIT as D, BasePermissionHandler as E, writeSessionModeFile as F, GEMINI_MODEL_ENV as G, normalizeAcpPermissionMode as H, removeSessionModeFile as I, GEMINI_API_KEY_ENV as J, GOOGLE_API_KEY_ENV as K, BaseReasoningProcessor as L, MAX_READ_LIMIT as M, MessageBuffer as N, CHANGE_TITLE_INSTRUCTION as O, PI_TEAMS_EXTENSION as P, SPAWN_AGENTS as S, TEAM_SKILL as T, sanitizeSpawnPermissionMode as a, sendUserMessage as b, listSessions as c, stopSession as d, resolvePermissionRequest as e, archiveSession as f, DEFAULT_GEMINI_MODEL as g, registerAssistantSessionTools as h, isValidSpawnOrigin as i, initialMachineMetadata as j, createSessionMetadata as k, listAccountSessions as l, setupOfflineReconnection as m, MessageQueue2 as n, registerKillSessionHandler as o, StreamRelay as p, query as q, readSessionTranscript as r, sessionWebUrl as s, tmuxSupportsSessionEnv as t, hashObject as u, startHappyServer as v, waitForSessionKey as w, registerAgentAttachmentDownloads as x, TitleGenerator as y, stageClaudeAttachments as z };
18365
+ export { ALLOWED_SPAWN_PERMISSION_MODES as A, appendStagedAttachmentsToPrompt as B, CLAUDE_ATTACHMENT_KINDS as C, DEFAULT_RECENT_LIMIT as D, BasePermissionHandler as E, writeSessionModeFile as F, GEMINI_MODEL_ENV as G, normalizeAcpPermissionMode as H, removeSessionModeFile as I, TEAM_SKILL as J, GEMINI_API_KEY_ENV as K, GOOGLE_API_KEY_ENV as L, MAX_READ_LIMIT as M, BaseReasoningProcessor as N, MessageBuffer as O, PI_TEAMS_EXTENSION as P, CHANGE_TITLE_INSTRUCTION as Q, SPAWN_AGENTS as S, TitleGenerator as T, sanitizeSpawnPermissionMode as a, sendUserMessage as b, listSessions as c, stopSession as d, resolvePermissionRequest as e, archiveSession as f, DEFAULT_GEMINI_MODEL as g, checkPreviewPath as h, isValidSpawnOrigin as i, registerAssistantSessionTools as j, initialMachineMetadata as k, listAccountSessions as l, createSessionMetadata as m, setupOfflineReconnection as n, StreamRelay as o, MessageQueue2 as p, query as q, readSessionTranscript as r, sessionWebUrl as s, tmuxSupportsSessionEnv as t, hashObject as u, startHappyServer as v, waitForSessionKey as w, registerAgentAttachmentDownloads as x, registerKillSessionHandler as y, stageClaudeAttachments as z };
@@ -1,11 +1,11 @@
1
- import { q as query } from './index-C55sW8E9.mjs';
1
+ import { q as query } from './index-DoiG88oX.mjs';
2
2
  export { AbortError } from '@anthropic-ai/claude-agent-sdk';
3
3
  import 'chalk';
4
4
  import 'node:os';
5
5
  import 'node:crypto';
6
- import './types-CLosaeZT.mjs';
6
+ import './types-BG4gFjLL.mjs';
7
7
  import 'axios';
8
- import './limits-DT5Yk_UH.mjs';
8
+ import './limits-uABU-yq3.mjs';
9
9
  import 'node:fs/promises';
10
10
  import 'node:fs';
11
11
  import 'node:path';
@@ -21,6 +21,7 @@ import 'fs/promises';
21
21
  import 'crypto';
22
22
  import 'path';
23
23
  import 'cross-spawn';
24
+ import './projectPath-CSpqWdxp.mjs';
24
25
  import 'url';
25
26
  import 'os';
26
27
  import 'node:child_process';
@@ -29,7 +30,7 @@ import 'fs';
29
30
  import 'node:readline';
30
31
  import '@anthropic-ai/sandbox-runtime';
31
32
  import 'expo-server-sdk';
32
- import './agentGuidance-Do7cQka3.mjs';
33
+ import './agentGuidance-BU4hxm8M.mjs';
33
34
  import 'ink';
34
35
  import 'react';
35
36
  import 'ps-list';
@@ -1,14 +1,16 @@
1
- import { D as DefaultTransport, A as AcpBackend } from './AcpBackend-CWmjboOm.mjs';
2
- export { a as DEFAULT_IDLE_TIMEOUT_MS, b as DEFAULT_TOOL_CALL_TIMEOUT_MS, e as extractErrorDetail, f as formatDuration, c as formatDurationMinutes, h as handleAgentMessageChunk, d as handleAgentThoughtChunk, g as handleLegacyMessageChunk, i as handlePlanUpdate, j as handleThinkingUpdate, k as handleToolCall, l as handleToolCallUpdate, p as parseArgsFromContent } from './AcpBackend-CWmjboOm.mjs';
3
- import { c as configuration, g as readSettings, i as encodeBase64, l as logger } from './limits-DT5Yk_UH.mjs';
4
- import { A as AcpSessionManager } from './AcpSessionManager-CtXoi6PN.mjs';
5
- import { k as connectionState, A as ApiClient, n as notifyDaemonSessionStarted, p as projectPath, l as BUILTIN_TODO_DISCOVERY } from './types-CLosaeZT.mjs';
6
- import { P as PI_TEAMS_EXTENSION, j as initialMachineMetadata, k as createSessionMetadata, m as setupOfflineReconnection, p as StreamRelay, n as MessageQueue2, u as hashObject, v as startHappyServer, x as registerAgentAttachmentDownloads, y as TitleGenerator, o as registerKillSessionHandler, C as CLAUDE_ATTACHMENT_KINDS, z as stageClaudeAttachments, B as appendStagedAttachmentsToPrompt, E as BasePermissionHandler, F as writeSessionModeFile, H as normalizeAcpPermissionMode, I as removeSessionModeFile } from './index-C55sW8E9.mjs';
7
- import { mkdir, chmod, writeFile, rename } from 'node:fs/promises';
1
+ import { D as DefaultTransport, A as AcpBackend } from './AcpBackend-LEgn9vol.mjs';
2
+ export { a as DEFAULT_IDLE_TIMEOUT_MS, b as DEFAULT_TOOL_CALL_TIMEOUT_MS, e as extractErrorDetail, f as formatDuration, c as formatDurationMinutes, h as handleAgentMessageChunk, d as handleAgentThoughtChunk, g as handleLegacyMessageChunk, i as handlePlanUpdate, j as handleThinkingUpdate, k as handleToolCall, l as handleToolCallUpdate, p as parseArgsFromContent } from './AcpBackend-LEgn9vol.mjs';
3
+ import { f as readSettings, g as encodeBase64, l as logger, c as configuration } from './limits-uABU-yq3.mjs';
4
+ import { A as AcpSessionManager } from './AcpSessionManager-Yfbs5bi2.mjs';
5
+ import { h as connectionState, A as ApiClient, n as notifyDaemonSessionStarted, j as BUILTIN_TODO_DISCOVERY } from './types-BG4gFjLL.mjs';
6
+ import { k as initialMachineMetadata, m as createSessionMetadata, n as setupOfflineReconnection, o as StreamRelay, p as MessageQueue2, u as hashObject, v as startHappyServer, x as registerAgentAttachmentDownloads, T as TitleGenerator, y as registerKillSessionHandler, C as CLAUDE_ATTACHMENT_KINDS, z as stageClaudeAttachments, B as appendStagedAttachmentsToPrompt, E as BasePermissionHandler, F as writeSessionModeFile, H as normalizeAcpPermissionMode, I as removeSessionModeFile } from './index-DoiG88oX.mjs';
7
+ import { p as preparePiTeamsRuntime } from './piRuntime-BE6iYQwU.mjs';
8
8
  import { randomUUID } from 'node:crypto';
9
9
  import { join } from 'node:path';
10
+ import { p as projectPath } from './projectPath-CSpqWdxp.mjs';
10
11
  import 'node:child_process';
11
12
  import '@agentclientprotocol/sdk';
13
+ import 'node:fs/promises';
12
14
  import 'node:fs';
13
15
  import 'node:os';
14
16
  import 'zod';
@@ -25,14 +27,13 @@ import 'fs/promises';
25
27
  import 'crypto';
26
28
  import 'path';
27
29
  import 'cross-spawn';
28
- import 'url';
29
30
  import 'os';
30
31
  import 'node-pty';
31
32
  import 'fs';
32
33
  import 'node:readline';
33
34
  import '@anthropic-ai/sandbox-runtime';
34
35
  import 'expo-server-sdk';
35
- import './agentGuidance-Do7cQka3.mjs';
36
+ import './agentGuidance-BU4hxm8M.mjs';
36
37
  import 'ink';
37
38
  import 'react';
38
39
  import '@anthropic-ai/claude-agent-sdk';
@@ -49,6 +50,7 @@ import 'http';
49
50
  import 'inquirer';
50
51
  import 'node:url';
51
52
  import 'node:readline/promises';
53
+ import 'url';
52
54
 
53
55
  function createAcpBackend(options) {
54
56
  const backendOptions = {
@@ -64,36 +66,6 @@ function createAcpBackend(options) {
64
66
  return new AcpBackend(backendOptions);
65
67
  }
66
68
 
67
- async function publish(path, content, mode) {
68
- const temporary = `${path}.${randomUUID()}.new`;
69
- await writeFile(temporary, content, { mode, flag: "wx" });
70
- await rename(temporary, path);
71
- }
72
- async function preparePiTeamsRuntime() {
73
- const directory = join(configuration.happyHomeDir, "teams", "pi-runtime");
74
- await mkdir(directory, { recursive: true, mode: 448 });
75
- const extension = join(directory, "very-happy-teams.mjs");
76
- await publish(extension, PI_TEAMS_EXTENSION, 384);
77
- const launcher = join(directory, "pi-teams.mjs");
78
- const script = `#!${process.execPath}
79
- import { spawn } from 'node:child_process';
80
- const child = spawn(process.env.VH_TEAM_PI_COMMAND || 'pi', ['--extension', ${JSON.stringify(extension)}, ...process.argv.slice(2)], {stdio:'inherit',env:process.env,shell:process.platform==='win32'});
81
- child.on('error',()=>{process.stderr.write('Very Happy could not launch pi\\n');process.exitCode=1});
82
- child.on('exit',(code)=>{process.exitCode=code ?? 1});
83
- for(const signal of ['SIGINT','SIGTERM'])process.on(signal,()=>child.kill(signal));
84
- `;
85
- await publish(launcher, script, 448);
86
- await chmod(launcher, 448);
87
- let command = launcher;
88
- if (process.platform === "win32") {
89
- command = join(directory, "pi-teams.cmd");
90
- await publish(command, `@echo off\r
91
- "${process.execPath}" "${launcher}" %*\r
92
- `, 448);
93
- }
94
- return { PI_ACP_PI_COMMAND: command, VH_TEAM_PI_COMMAND: (process.env.PI_ACP_PI_COMMAND === command ? process.env.VH_TEAM_PI_COMMAND : process.env.PI_ACP_PI_COMMAND) || "pi" };
95
- }
96
-
97
69
  const SUPPORTED_CATEGORIES = /* @__PURE__ */ new Set(["mode", "model", "thought_level"]);
98
70
  function isRecord$1(value) {
99
71
  return !!value && typeof value === "object";