very-happy-cli 0.2.96 → 0.2.97

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 (32) hide show
  1. package/dist/{AcpBackend-B5Eh8G3W.mjs → AcpBackend-CTUM4dvG.mjs} +1 -1
  2. package/dist/{AcpBackend-BaCt4_zS.cjs → AcpBackend-DrwdVSeJ.cjs} +1 -1
  3. package/dist/{AcpSessionManager-CvgmPlXB.cjs → AcpSessionManager-BieE187D.cjs} +1 -1
  4. package/dist/{AcpSessionManager-grr_aJEI.mjs → AcpSessionManager-BoBuHee3.mjs} +1 -1
  5. package/dist/{config-BjsUeQPA.cjs → config-COq6X7U7.cjs} +3 -3
  6. package/dist/{config-B69TZlJj.mjs → config-DCH33LOM.mjs} +3 -3
  7. package/dist/{index-uc-dtu-3.cjs → index-BD2fHJ8o.cjs} +526 -20
  8. package/dist/{index-BMmbxCTq.mjs → index-Bcgquogx.mjs} +527 -21
  9. package/dist/{index-C-uJXSm3.mjs → index-DkhMvofH.mjs} +6 -6
  10. package/dist/{index-DID1FV_n.cjs → index-Dn0iOBFd.cjs} +5 -5
  11. package/dist/index.cjs +3 -3
  12. package/dist/index.mjs +3 -3
  13. package/dist/{installTerminalHooks-CBHjEQ-a.mjs → installTerminalHooks-DqNtW6a2.mjs} +3 -3
  14. package/dist/{installTerminalHooks-CepXxAM_.cjs → installTerminalHooks-H3kpFEZS.cjs} +3 -3
  15. package/dist/lib.cjs +1 -1
  16. package/dist/lib.d.cts +67 -0
  17. package/dist/lib.d.mts +67 -0
  18. package/dist/lib.mjs +1 -1
  19. package/dist/{mcp-BdSHqi2d.mjs → mcp-BKAuzaLX.mjs} +3 -3
  20. package/dist/{mcp-CAtbtTXF.cjs → mcp-BwNc5eRs.cjs} +3 -3
  21. package/dist/{runGemini-cMZ3_CRf.mjs → runGemini-Brp0UmLx.mjs} +5 -5
  22. package/dist/{runGemini-qStPY5fH.cjs → runGemini-w35qiFBB.cjs} +5 -5
  23. package/dist/{runOpenClaw-BJ36wEbk.mjs → runOpenClaw-BvPRFx-L.mjs} +4 -4
  24. package/dist/{runOpenClaw-B8HR6GnX.cjs → runOpenClaw-CkHtTCpI.cjs} +4 -4
  25. package/dist/{send-TX13v8Xe.mjs → send-c-wEmh5U.mjs} +3 -3
  26. package/dist/{send-6eY55o3C.cjs → send-tyKG13xt.cjs} +3 -3
  27. package/dist/{spawn-vOZA0kOi.cjs → spawn-xdCsG2RT.cjs} +3 -3
  28. package/dist/{spawn-CfCE6JAv.mjs → spawn-yS6yY8Xi.mjs} +3 -3
  29. package/dist/{types-okYCRlgl.cjs → types-DoGaKVfK.cjs} +77 -10
  30. package/dist/{types-CLRl0ET3.mjs → types-xZOYW0_G.mjs} +76 -10
  31. package/package.json +7 -7
  32. package/scripts/shims/keychain-off/security +51 -0
@@ -1,11 +1,11 @@
1
1
  import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
2
- import os, { homedir } from 'node:os';
2
+ import os, { homedir, userInfo } from 'node:os';
3
3
  import { randomUUID, randomBytes, createHash as createHash$1, timingSafeEqual } from 'node:crypto';
4
- import { n as readDaemonState, l as logger, c as configuration, o as clearDaemonState, q as getProjectPath, p as projectPath, s as initializeSandbox, t as wrapCommand, d as contentLogMetadata, I as InvalidateSync, R as RawJSONLinesSchema, g as delay, u as AsyncLock, v as ensurePrivateDirectory, M as MAX_CHAT_ATTACHMENT_SOURCE_BYTES, x as hardenPrivateFile, f as packageJson, i as readSettings, y as readCredentials, z as credentialRelayProblem, B as deriveLocalCliUpdateSummary, j as encodeBase64, C as updateSettings, D as encodeBase64Url, E as decodeBase64, F as writeCredentialsLegacy, G as writeCredentialsDataKey, H as readCredentialsForConfiguredRelay, J as encrypt, r as readPersistedSessions, K as isClaudeSessionId, L as getLocalHappyAgentCredentialPath, N as readLocalHappyAgentCredentials, O as decryptWithDataKey, P as decryptLegacy, Q as extractCompleteLines, S as decideBackfill, T as parseTerminalHookPayload, U as tmuxArgs, V as scrubTmuxClientEnv, W as decideMirrorBinding, X as MIRROR_BACKFILL_LINES_DEFAULT, Y as persistSession, Z as mirrorLineKey, _ as mirrorLocalId, w as writePrivateFileSync, $ as detectResumeSupport, a0 as detectCLIAvailability, a1 as acquireDaemonLock, a2 as summarizeSpawnSessionForLog, a3 as deletePersistedSessions, a4 as decrypt, a5 as writeDaemonState, A as ApiClient, a6 as fetchCliUpdateState, a7 as resolveCliUpdateCheckInterval, a8 as DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS, a9 as releaseDaemonLock, aa as isValidSessionId, ab as listVhTerminals, ac as isValidTerminalId, ad as readVhTerminal, ae as sendToVhTerminal, h as connectionState, af as startOfflineReconnection, ag as clearCredentials, ah as clearMachineId, k as ensurePrivateDirectorySync, ai as SandboxConfigSchema, b as createEnvelope, aj as CodexAppServerClient, ak as getLatestDaemonLog } from './types-CLRl0ET3.mjs';
4
+ import { n as readDaemonState, l as logger, c as configuration, o as clearDaemonState, q as getProjectPath, p as projectPath, s as initializeSandbox, t as wrapCommand, d as contentLogMetadata, I as InvalidateSync, R as RawJSONLinesSchema, g as delay, u as AsyncLock, v as ensurePrivateDirectory, M as MAX_CHAT_ATTACHMENT_SOURCE_BYTES, x as hardenPrivateFile, f as packageJson, i as readSettings, y as readCredentials, z as credentialRelayProblem, B as deriveLocalCliUpdateSummary, j as encodeBase64, C as updateSettings, D as encodeBase64Url, E as decodeBase64, F as writeCredentialsLegacy, G as writeCredentialsDataKey, H as readCredentialsForConfiguredRelay, J as encrypt, r as readPersistedSessions, K as isClaudeSessionId, L as getLocalHappyAgentCredentialPath, N as readLocalHappyAgentCredentials, O as decryptWithDataKey, P as decryptLegacy, Q as extractCompleteLines, S as decideBackfill, T as parseTerminalHookPayload, U as tmuxArgs, V as scrubTmuxClientEnv, W as decideMirrorBinding, X as MIRROR_BACKFILL_LINES_DEFAULT, Y as persistSession, Z as mirrorLineKey, _ as mirrorLocalId, w as writePrivateFileSync, $ as detectResumeSupport, a0 as detectCLIAvailability, a1 as acquireDaemonLock, a2 as summarizeSpawnSessionForLog, a3 as deletePersistedSessions, a4 as decrypt, a5 as writeDaemonState, A as ApiClient, a6 as writeSettings, a7 as fetchCliUpdateState, a8 as resolveCliUpdateCheckInterval, a9 as DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS, aa as releaseDaemonLock, ab as isValidSessionId, ac as listVhTerminals, ad as isValidTerminalId, ae as readVhTerminal, af as sendToVhTerminal, h as connectionState, ag as startOfflineReconnection, ah as clearCredentials, ai as clearMachineId, k as ensurePrivateDirectorySync, aj as SandboxConfigSchema, b as createEnvelope, ak as CodexAppServerClient, al as getLatestDaemonLog } from './types-xZOYW0_G.mjs';
5
5
  import spawn$1, { spawn } from 'cross-spawn';
6
- import path, { join, resolve, basename, isAbsolute, normalize, sep, dirname } from 'node:path';
6
+ import path, { join, resolve, basename, delimiter, isAbsolute, normalize, sep, dirname } from 'node:path';
7
7
  import { createInterface } from 'node:readline';
8
- import { existsSync, readFileSync, readdirSync, statSync, mkdirSync, unlinkSync, renameSync, writeFileSync, rmSync, chmodSync as chmodSync$1 } from 'node:fs';
8
+ import { existsSync, readFileSync, readdirSync, statSync, mkdirSync, unlinkSync, writeFileSync, accessSync, constants, renameSync, rmSync, chmodSync as chmodSync$1 } from 'node:fs';
9
9
  import { t as trimIdent, A as AGENT_GUIDANCE, P as PREVIEW_TOOL_NAME, R as REPORT_PROGRESS_TOOL_NAME, a as PREVIEW_TOOL_TITLE, b as PREVIEW_TOOL_DESCRIPTION, c as REPORT_PROGRESS_TOOL_TITLE, d as REPORT_PROGRESS_TOOL_DESCRIPTION } from './agentGuidance-C2_pkgRI.mjs';
10
10
  import { readFile, writeFile, rename, unlink, mkdir, stat, open as open$1, appendFile } from 'node:fs/promises';
11
11
  import fs, { watch, access } from 'fs/promises';
@@ -19,7 +19,7 @@ import tweetnacl from 'tweetnacl';
19
19
  import os$1, { homedir as homedir$1 } from 'os';
20
20
  import { spawn as spawn$2, execSync as execSync$1, exec } from 'child_process';
21
21
  import { createId } from '@paralleldrive/cuid2';
22
- import { execSync, spawnSync, spawn as spawn$3, execFileSync } from 'node:child_process';
22
+ import { execSync, spawnSync, spawn as spawn$3, execFile, execFileSync } from 'node:child_process';
23
23
  import { existsSync as existsSync$1, statSync as statSync$1, writeFileSync as writeFileSync$1, chmodSync, unlinkSync as unlinkSync$1 } from 'fs';
24
24
  import { join as join$1 } from 'path';
25
25
  import '@anthropic-ai/sandbox-runtime';
@@ -31,11 +31,11 @@ import open from 'open';
31
31
  import fastify from 'fastify';
32
32
  import { z } from 'zod';
33
33
  import { validatorCompiler, serializerCompiler } from 'fastify-type-provider-zod';
34
+ import { createRequire } from 'node:module';
34
35
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
35
36
  import { createServer } from 'node:http';
36
37
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
37
38
  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';
38
- import { createRequire } from 'node:module';
39
39
  import { createServer as createServer$1 } from 'http';
40
40
  import { promisify } from 'util';
41
41
  import inquirer from 'inquirer';
@@ -175,6 +175,9 @@ async function spawnDaemonSession(directory, sessionId, opts) {
175
175
  async function notifyDaemonSessionEvent(sessionId, event, spawnedBy) {
176
176
  return daemonPost("/session-event", { sessionId, event, spawnedBy });
177
177
  }
178
+ async function notifyDaemonClaudeAuthFailed(sessionId) {
179
+ return daemonPost("/session-event", { sessionId, event: "auth_failed" });
180
+ }
178
181
  async function stopDaemonHttp() {
179
182
  await daemonPost("/stop");
180
183
  }
@@ -1744,6 +1747,20 @@ function parseSpecialCommand(message) {
1744
1747
  };
1745
1748
  }
1746
1749
 
1750
+ const AUTH_FAILURE_RESULT_TEXT = /Failed to authenticate|OAuth session expired/i;
1751
+ const QUERY_RECYCLE_NOTICE = {
1752
+ authentication_failed: "\u26A0\uFE0F Claude Code could not refresh its OAuth session. This agent process was ended so your next message starts a fresh one that re-reads the credentials on this machine; if it fails again, run `claude` on the machine to log in again."
1753
+ };
1754
+ function queryRecycleReason(result, lastAssistantError) {
1755
+ if (lastAssistantError === "authentication_failed") {
1756
+ return "authentication_failed";
1757
+ }
1758
+ if (result.is_error && typeof result.result === "string" && AUTH_FAILURE_RESULT_TEXT.test(result.result)) {
1759
+ return "authentication_failed";
1760
+ }
1761
+ return null;
1762
+ }
1763
+
1747
1764
  class PushableAsyncIterable {
1748
1765
  queue = [];
1749
1766
  waiters = [];
@@ -2004,11 +2021,15 @@ async function claudeRemote(opts) {
2004
2021
  }
2005
2022
  });
2006
2023
  }
2024
+ let lastAssistantError;
2007
2025
  updateThinking(true);
2008
2026
  try {
2009
2027
  logger.debug(`[claudeRemote] Starting to iterate over response`);
2010
2028
  for await (const message of response) {
2011
2029
  logger.debug(`[claudeRemote] Message ${message.type}`, contentLogMetadata(message));
2030
+ if (message.type === "assistant" && message.error) {
2031
+ lastAssistantError = message.error;
2032
+ }
2012
2033
  const outboundMessage = isCompactCommand && message.type === "assistant" ? { ...message, isCompactSummary: true } : message;
2013
2034
  opts.onMessage(outboundMessage);
2014
2035
  if (message.type === "system" && message.subtype === "init") {
@@ -2057,6 +2078,15 @@ async function claudeRemote(opts) {
2057
2078
  isCompactCommand = false;
2058
2079
  }
2059
2080
  opts.onReady(message);
2081
+ const recycleReason = queryRecycleReason(message, lastAssistantError);
2082
+ lastAssistantError = void 0;
2083
+ if (recycleReason) {
2084
+ logger.warn(`[claudeRemote] Ending SDK query after ${recycleReason}; the next message starts a fresh Claude Code process`);
2085
+ opts.onCompletionEvent?.(QUERY_RECYCLE_NOTICE[recycleReason]);
2086
+ opts.onAuthFailure?.(recycleReason);
2087
+ messages.end();
2088
+ continue;
2089
+ }
2060
2090
  opts.nextMessage().then((next) => {
2061
2091
  if (!next) {
2062
2092
  messages.end();
@@ -3260,8 +3290,9 @@ async function cleanupStdinAfterInk(opts) {
3260
3290
  }
3261
3291
 
3262
3292
  function applyClaudeResultLifecycle(result, callbacks) {
3263
- if (result && result.subtype !== "success") {
3264
- const error = result.errors?.filter(Boolean).join("\n").trim() || result.subtype;
3293
+ if (result && (result.subtype !== "success" || result.is_error === true)) {
3294
+ const frame = result;
3295
+ const error = frame.errors?.filter(Boolean).join("\n").trim() || (typeof frame.result === "string" ? frame.result.trim() : "") || frame.subtype;
3265
3296
  callbacks.closeFailed(error);
3266
3297
  callbacks.onFailed(error);
3267
3298
  return;
@@ -3733,6 +3764,10 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
3733
3764
  logger.debug("[remote]: Completion event received:", contentLogMetadata(message));
3734
3765
  session.client.sendSessionEvent({ type: "message", message });
3735
3766
  },
3767
+ onAuthFailure: (reason) => {
3768
+ session.client.sendSessionEvent({ type: "message", message: `Claude Code auth: ${reason}`, kind: "claude-auth-failed" });
3769
+ void notifyDaemonClaudeAuthFailed(session.client.sessionId).catch((error) => logger.debug("[remote]: auth_failed report to daemon failed:", error));
3770
+ },
3736
3771
  onSessionReset: () => {
3737
3772
  logger.debug("[remote]: Session reset");
3738
3773
  session.clearSessionId();
@@ -5406,6 +5441,7 @@ function startDaemonControlServer({
5406
5441
  requestShutdown,
5407
5442
  onHappySessionWebhook,
5408
5443
  onSessionStateEvent,
5444
+ onClaudeAuthFailed,
5409
5445
  pushClipboard,
5410
5446
  onTerminalHook
5411
5447
  }) {
@@ -5461,7 +5497,7 @@ function startDaemonControlServer({
5461
5497
  schema: {
5462
5498
  body: z.object({
5463
5499
  sessionId: z.string(),
5464
- event: z.enum(["completed", "needs_input"]),
5500
+ event: z.enum(["completed", "needs_input", "auth_failed"]),
5465
5501
  spawnedBy: z.string().optional()
5466
5502
  }),
5467
5503
  response: {
@@ -5473,6 +5509,10 @@ function startDaemonControlServer({
5473
5509
  }, async (request) => {
5474
5510
  const { sessionId, event, spawnedBy } = request.body;
5475
5511
  logger.debug(`[CONTROL SERVER] Session event: ${sessionId} ${event} (spawnedBy=${spawnedBy ?? "unset"})`);
5512
+ if (event === "auth_failed") {
5513
+ onClaudeAuthFailed?.(sessionId);
5514
+ return { status: "ok" };
5515
+ }
5476
5516
  onSessionStateEvent?.(sessionId, event, spawnedBy);
5477
5517
  return { status: "ok" };
5478
5518
  });
@@ -6646,6 +6686,444 @@ async function handleResumeCommand(args) {
6646
6686
  }
6647
6687
  }
6648
6688
 
6689
+ const CLAUDE_KEYCHAIN_SERVICE_PREFIX = "Claude Code";
6690
+ function keychainIdentity(env = process.env, deps = {}) {
6691
+ const home = deps.home ?? homedir();
6692
+ const secureDir = env.CLAUDE_SECURESTORAGE_CONFIG_DIR?.trim();
6693
+ const configDirEnv = env.CLAUDE_CONFIG_DIR?.trim();
6694
+ const configDir = secureDir || configDirEnv || join(home, ".claude");
6695
+ const hasCustomDir = Boolean(secureDir || configDirEnv);
6696
+ const dirSuffix = hasCustomDir ? "-" + createHash$1("sha256").update(configDir.normalize("NFC")).digest("hex").slice(0, 8) : "";
6697
+ const oauthSuffix = env.CLAUDE_CODE_OAUTH_CLIENT_ID?.trim() ? "-custom-oauth" : "";
6698
+ const rawAccount = env.USER || safeUsername(deps.username);
6699
+ const account = /^[a-zA-Z0-9._-]+$/.test(rawAccount) ? rawAccount : "claude-code-user";
6700
+ return {
6701
+ service: `${CLAUDE_KEYCHAIN_SERVICE_PREFIX}${oauthSuffix}-credentials${dirSuffix}`,
6702
+ account,
6703
+ configDir,
6704
+ credentialsPath: join(configDir, ".credentials.json")
6705
+ };
6706
+ }
6707
+ function safeUsername(provider) {
6708
+ try {
6709
+ return provider ? provider() : userInfo().username;
6710
+ } catch {
6711
+ return "";
6712
+ }
6713
+ }
6714
+
6715
+ const CLAUDE_AUTH_PROBE_VERSION = 1;
6716
+ const LOCAL_CREDENTIAL_SOURCE = "Claude local credentials";
6717
+ function classifyAuthStatus(run, credentialSource) {
6718
+ const localSource = credentialSource === void 0 || credentialSource === LOCAL_CREDENTIAL_SOURCE;
6719
+ if (run.spawnError) {
6720
+ return { status: "error", diagnosis: "probe-crash", detail: `could not run claude auth status: ${run.spawnError}` };
6721
+ }
6722
+ if (run.timedOut) {
6723
+ return { status: "error", diagnosis: "probe-timeout", detail: "claude auth status did not answer within the timeout" };
6724
+ }
6725
+ const parsed = parseJsonObject(run.stdout);
6726
+ if (!parsed) {
6727
+ if (!localSource) return { status: "unknown", authMethod: credentialSource, detail: `auth status unparseable under ${credentialSource}` };
6728
+ return { status: "error", diagnosis: "probe-crash", detail: `claude auth status returned no JSON (exit ${run.exitCode ?? "null"})` };
6729
+ }
6730
+ const authMethod = typeof parsed.authMethod === "string" ? parsed.authMethod : void 0;
6731
+ const subscriptionType = typeof parsed.subscriptionType === "string" ? parsed.subscriptionType : void 0;
6732
+ if (parsed.loggedIn === true) {
6733
+ return { status: "ok", authMethod: localSource ? authMethod : credentialSource, subscriptionType };
6734
+ }
6735
+ if (!localSource) {
6736
+ return { status: "unknown", authMethod: credentialSource, detail: `Claude Code reports loggedIn=false under ${credentialSource}; not a local-credential failure` };
6737
+ }
6738
+ return { status: "not-logged-in", authMethod, subscriptionType, detail: "Claude Code in the daemon context reports it is not logged in" };
6739
+ }
6740
+ function parseJsonObject(text) {
6741
+ const trimmed = text.trim();
6742
+ if (!trimmed) return null;
6743
+ const start = trimmed.indexOf("{");
6744
+ if (start < 0) return null;
6745
+ try {
6746
+ const value = JSON.parse(trimmed.slice(start));
6747
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
6748
+ } catch {
6749
+ return null;
6750
+ }
6751
+ }
6752
+ function resolveSdkClaudeBinary(platform = process.platform, arch = process.arch, resolver = (s) => createRequire(import.meta.url).resolve(s)) {
6753
+ const platformArch = `${platform}-${arch}`;
6754
+ const candidates = [
6755
+ `@anthropic-ai/claude-agent-sdk-${platformArch}/claude`,
6756
+ `@anthropic-ai/claude-agent-sdk-${platformArch}/claude.exe`
6757
+ ];
6758
+ for (const candidate of candidates) {
6759
+ try {
6760
+ return resolver(candidate);
6761
+ } catch {
6762
+ }
6763
+ }
6764
+ return null;
6765
+ }
6766
+ function interpretSecurityRead(result) {
6767
+ if (result.error === "ENOENT") return { kind: "unsupported" };
6768
+ if (result.error === "timeout") return { kind: "error", detail: "security timed out" };
6769
+ if (result.exitCode === 44) return { kind: "absent" };
6770
+ if (result.exitCode === 36) return { kind: "unreadable" };
6771
+ if (result.exitCode !== 0) return { kind: "error", detail: `security exited ${result.exitCode ?? "null"}` };
6772
+ const raw = result.stdout.trim();
6773
+ if (!raw) return { kind: "absent" };
6774
+ const parsed = parseJsonObject(raw);
6775
+ const oauth = parsed && typeof parsed.claudeAiOauth === "object" && parsed.claudeAiOauth ? parsed.claudeAiOauth : null;
6776
+ if (!oauth) return { kind: "present", accessToken: "", refreshToken: "", raw };
6777
+ return {
6778
+ kind: "present",
6779
+ accessToken: typeof oauth.accessToken === "string" ? oauth.accessToken : "",
6780
+ refreshToken: typeof oauth.refreshToken === "string" ? oauth.refreshToken : "",
6781
+ raw
6782
+ };
6783
+ }
6784
+ function interpretCredentialsFile(text) {
6785
+ if (text === null) return { exists: false, hasTokens: false, refreshToken: "" };
6786
+ const parsed = parseJsonObject(text);
6787
+ const oauth = parsed && typeof parsed.claudeAiOauth === "object" && parsed.claudeAiOauth ? parsed.claudeAiOauth : null;
6788
+ const access = oauth && typeof oauth.accessToken === "string" ? oauth.accessToken : "";
6789
+ const refresh = oauth && typeof oauth.refreshToken === "string" ? oauth.refreshToken : "";
6790
+ return { exists: true, hasTokens: access.length > 0 && refresh.length > 0, refreshToken: refresh };
6791
+ }
6792
+ function tokenTail(token) {
6793
+ return token ? createHash$1("sha256").update(token).digest("hex").slice(-6) : "";
6794
+ }
6795
+ function diagnoseStores(input) {
6796
+ const { status, keychain, file } = input;
6797
+ if (keychain.kind === "present") {
6798
+ const empty = keychain.accessToken.length === 0 && keychain.refreshToken.length === 0;
6799
+ if (empty && file.hasTokens && status === "not-logged-in") {
6800
+ return {
6801
+ diagnosis: "keychain-empty-item",
6802
+ repairable: "delete-empty-keychain-item",
6803
+ keychainRaw: keychain.raw,
6804
+ detail: "The login keychain holds a Claude Code credentials item with empty tokens; Claude Code prefers it over the valid ~/.claude/.credentials.json and reports not logged in."
6805
+ };
6806
+ }
6807
+ if (!empty && file.hasTokens && tokenTail(keychain.refreshToken) !== tokenTail(file.refreshToken)) {
6808
+ return {
6809
+ diagnosis: "store-divergence",
6810
+ detail: "Keychain and ~/.claude/.credentials.json hold different refresh tokens; one of them will stop working at its next refresh. Treat the daemon-context login as canonical, or pin credentialStore=file."
6811
+ };
6812
+ }
6813
+ return {};
6814
+ }
6815
+ if ((keychain.kind === "absent" || keychain.kind === "unreadable" || keychain.kind === "unsupported") && !file.hasTokens) {
6816
+ return { diagnosis: "no-credentials", detail: "No Claude Code credentials found for this daemon context; log in with `claude` on this machine." };
6817
+ }
6818
+ if (keychain.kind === "unreadable" && file.hasTokens && status === "not-logged-in") {
6819
+ return { detail: "The daemon context cannot read the keychain and the file credentials were not accepted; compare `claude auth status` on the machine." };
6820
+ }
6821
+ if (keychain.kind === "error") {
6822
+ return { detail: `keychain check failed: ${keychain.detail}` };
6823
+ }
6824
+ return {};
6825
+ }
6826
+ function securityReadArgs(identity) {
6827
+ return ["find-generic-password", "-s", identity.service, "-a", identity.account, "-w"];
6828
+ }
6829
+ function securityDeleteArgs(identity) {
6830
+ return ["delete-generic-password", "-s", identity.service, "-a", identity.account];
6831
+ }
6832
+ const HAPPY_DAEMON_LAUNCHD_LABEL = "com.mereith.happy-daemon";
6833
+ function classifyLineage(input) {
6834
+ if (input.platform !== "darwin") return "other";
6835
+ const label = input.label ?? HAPPY_DAEMON_LAUNCHD_LABEL;
6836
+ if (input.env.XPC_SERVICE_NAME !== label) return "other";
6837
+ if (input.launchdJobPid !== null && input.ancestorPids.includes(input.launchdJobPid)) return "launchd";
6838
+ return "inherited-env";
6839
+ }
6840
+ function parseLaunchctlPid(printOutput) {
6841
+ const match = /^\s*pid\s*=\s*(\d+)/m.exec(printOutput);
6842
+ return match ? Number(match[1]) : null;
6843
+ }
6844
+ function keychainOffShimDir(happyLibDir) {
6845
+ return join(happyLibDir, "scripts", "shims", "keychain-off");
6846
+ }
6847
+ function withKeychainOffPath(path, shimDir) {
6848
+ const parts = (path ?? "").split(delimiter).filter((p) => p && p !== shimDir);
6849
+ return [shimDir, ...parts].join(delimiter);
6850
+ }
6851
+ function buildClaudeAuthState(input) {
6852
+ const { classification, diagnosis } = input;
6853
+ const detail = (diagnosis?.detail ?? classification.detail)?.slice(0, 200);
6854
+ const state = {
6855
+ probeVersion: CLAUDE_AUTH_PROBE_VERSION,
6856
+ daemonPid: input.daemonPid,
6857
+ status: classification.status,
6858
+ context: { platform: input.platform, lineage: input.lineage, credentialStore: input.credentialStore },
6859
+ checkedAt: input.now ?? Date.now()
6860
+ };
6861
+ if (classification.authMethod) state.authMethod = classification.authMethod;
6862
+ if (classification.subscriptionType) state.subscriptionType = classification.subscriptionType;
6863
+ const diag = diagnosis?.diagnosis ?? classification.diagnosis;
6864
+ if (diag) state.diagnosis = diag;
6865
+ if (detail) state.detail = detail;
6866
+ if (diagnosis?.repairable) state.repairable = diagnosis.repairable;
6867
+ return state;
6868
+ }
6869
+ function claudeAuthStateChanged(prev, next) {
6870
+ if (!prev) return true;
6871
+ const strip = ({ checkedAt: _c, ...rest }) => JSON.stringify(rest);
6872
+ return strip(prev) !== strip(next);
6873
+ }
6874
+ function keychainIdentityFor(env) {
6875
+ return keychainIdentity(env);
6876
+ }
6877
+
6878
+ const CLAUDE_AUTH_PROBE_INTERVAL_MS = 10 * 60 * 1e3;
6879
+ const CLAUDE_AUTH_REFRESH_INTERVAL_MS = 30 * 60 * 1e3;
6880
+ const PROBE_TIMEOUT_MS = 8e3;
6881
+ const SECURITY_TIMEOUT_MS = 3e3;
6882
+ const SIGNAL_DEBOUNCE_MS = 1e3;
6883
+ class ClaudeAuthService {
6884
+ constructor(opts) {
6885
+ this.opts = opts;
6886
+ this.env = opts.env ?? process.env;
6887
+ this.platform = opts.platform ?? process.platform;
6888
+ }
6889
+ timer = null;
6890
+ signalTimer = null;
6891
+ inFlight = null;
6892
+ last = null;
6893
+ dirty = false;
6894
+ lastPublishedAt = 0;
6895
+ lineage = null;
6896
+ lastDiagnosis;
6897
+ env;
6898
+ platform;
6899
+ start() {
6900
+ setTimeout(() => void this.probe("startup"), 2e3).unref();
6901
+ this.timer = setInterval(() => void this.probe("interval"), CLAUDE_AUTH_PROBE_INTERVAL_MS);
6902
+ this.timer.unref();
6903
+ }
6904
+ stop() {
6905
+ if (this.timer) clearInterval(this.timer);
6906
+ if (this.signalTimer) clearTimeout(this.signalTimer);
6907
+ this.timer = null;
6908
+ this.signalTimer = null;
6909
+ }
6910
+ current() {
6911
+ return this.last;
6912
+ }
6913
+ /** D3: a session reported `authentication_failed`; re-probe after a short debounce. */
6914
+ signalAuthFailed(sessionId) {
6915
+ logger.debug(`[CLAUDE AUTH] auth_failed signal from session ${sessionId}`);
6916
+ if (this.signalTimer) clearTimeout(this.signalTimer);
6917
+ this.signalTimer = setTimeout(() => {
6918
+ this.signalTimer = null;
6919
+ void this.probe("signal", true);
6920
+ }, SIGNAL_DEBOUNCE_MS);
6921
+ this.signalTimer.unref();
6922
+ }
6923
+ /** Env the SDK/one-shot Claude Code processes should get for the current store setting. */
6924
+ claudeProcessEnvOverrides() {
6925
+ if (this.opts.getCredentialStore() !== "file") return {};
6926
+ const shim = this.resolveShimDir();
6927
+ if (!shim) return {};
6928
+ return { PATH: withKeychainOffPath(this.env.PATH, shim) };
6929
+ }
6930
+ effectiveCredentialStore() {
6931
+ if (this.opts.getCredentialStore() !== "file") return "auto";
6932
+ return this.resolveShimDir() ? "file" : "auto";
6933
+ }
6934
+ async probe(reason, withDiagnosis = false) {
6935
+ if (this.inFlight) return this.inFlight;
6936
+ this.inFlight = this.runProbe(reason, withDiagnosis).finally(() => {
6937
+ this.inFlight = null;
6938
+ });
6939
+ return this.inFlight;
6940
+ }
6941
+ async setStore(store) {
6942
+ await this.opts.setCredentialStore(store);
6943
+ return this.probe("set-store", true);
6944
+ }
6945
+ /** D4: delete the empty-token keychain item after re-validating every precondition. */
6946
+ async repair(action) {
6947
+ if (action !== "delete-empty-keychain-item") return { error: "unknown-action", claudeAuth: this.last };
6948
+ if (this.platform !== "darwin" || this.effectiveCredentialStore() === "file") return { error: "precondition-failed", claudeAuth: this.last };
6949
+ const state = await this.probe("repair-precheck", true);
6950
+ const seen = this.lastDiagnosis;
6951
+ if (state.diagnosis !== "keychain-empty-item" || !seen?.keychainRaw) return { error: "precondition-failed", claudeAuth: state };
6952
+ const identity = keychainIdentityFor(this.env);
6953
+ const again = interpretSecurityRead(await this.security(securityReadArgs(identity)));
6954
+ if (again.kind !== "present" || again.raw !== seen.keychainRaw || again.accessToken || again.refreshToken) {
6955
+ return { error: "precondition-failed", claudeAuth: state };
6956
+ }
6957
+ try {
6958
+ const dir = join(this.opts.happyHomeDir, "backups");
6959
+ mkdirSync(dir, { recursive: true, mode: 448 });
6960
+ writeFileSync(join(dir, `claude-keychain-${Date.now()}.json`), again.raw + "\n", { mode: 384 });
6961
+ } catch (error) {
6962
+ return { error: `backup-failed: ${String(error)}`, claudeAuth: state };
6963
+ }
6964
+ const del = await this.security(securityDeleteArgs(identity));
6965
+ if (del.exitCode !== 0) return { error: `delete-failed: security exited ${del.exitCode ?? "null"}`, claudeAuth: state };
6966
+ logger.debug("[CLAUDE AUTH] deleted empty-token keychain item after backup");
6967
+ const after = await this.probe("repair-done", true);
6968
+ return { ok: true, claudeAuth: after };
6969
+ }
6970
+ // ── internals ────────────────────────────────────────────────────────
6971
+ resolveShimDir() {
6972
+ const dir = keychainOffShimDir(this.opts.happyLibDir);
6973
+ const bin = join(dir, "security");
6974
+ try {
6975
+ if (!statSync(bin).isFile()) return null;
6976
+ accessSync(bin, constants.X_OK);
6977
+ return dir;
6978
+ } catch {
6979
+ return null;
6980
+ }
6981
+ }
6982
+ async runProbe(reason, withDiagnosis) {
6983
+ const store = this.effectiveCredentialStore();
6984
+ const storeRequested = this.opts.getCredentialStore();
6985
+ const classification = await this.runAuthStatus();
6986
+ let diagnosis;
6987
+ this.lastDiagnosis = void 0;
6988
+ if (this.platform === "darwin" && store !== "file" && (classification.status === "not-logged-in" || withDiagnosis && classification.status !== "unknown")) {
6989
+ diagnosis = await this.diagnose(classification.status);
6990
+ this.lastDiagnosis = diagnosis;
6991
+ } else if (classification.status === "not-logged-in" && store === "file") {
6992
+ const file = interpretCredentialsFile(this.readCredentialsFile());
6993
+ if (!file.hasTokens) diagnosis = { diagnosis: "no-credentials", detail: "credentialStore=file and ~/.claude/.credentials.json has no tokens; log in with `claude` from a terminal on this machine." };
6994
+ }
6995
+ if (storeRequested === "file" && store === "auto") {
6996
+ diagnosis = { ...diagnosis ?? {}, detail: `credentialStore=file requested but the keychain-off shim is missing under ${keychainOffShimDir(this.opts.happyLibDir)}; running in auto mode.` };
6997
+ }
6998
+ const state = buildClaudeAuthState({
6999
+ daemonPid: process.pid,
7000
+ platform: this.platform,
7001
+ lineage: await this.resolveLineage(),
7002
+ credentialStore: store,
7003
+ classification,
7004
+ diagnosis,
7005
+ now: this.opts.now?.() ?? Date.now()
7006
+ });
7007
+ const changed = claudeAuthStateChanged(this.last, state);
7008
+ const stale = state.checkedAt - this.lastPublishedAt >= CLAUDE_AUTH_REFRESH_INTERVAL_MS;
7009
+ if (changed) {
7010
+ logger.debug(`[CLAUDE AUTH] ${reason}: status=${state.status} diagnosis=${state.diagnosis ?? "-"} lineage=${state.context.lineage} store=${state.context.credentialStore}`);
7011
+ }
7012
+ this.last = state;
7013
+ if (changed || stale || this.dirty) {
7014
+ const ok = await this.opts.publish(state).catch((error) => {
7015
+ logger.debug("[CLAUDE AUTH] publish failed:", error);
7016
+ return false;
7017
+ });
7018
+ this.dirty = !ok;
7019
+ if (ok) this.lastPublishedAt = state.checkedAt;
7020
+ else logger.warn("[CLAUDE AUTH] daemonState publish did not land; will force resend on the next probe");
7021
+ }
7022
+ return state;
7023
+ }
7024
+ async runAuthStatus() {
7025
+ const binary = resolveSdkClaudeBinary(this.platform, process.arch);
7026
+ if (!binary) {
7027
+ return { status: "claude-missing", diagnosis: "sdk-binary-missing", detail: "The Claude Code binary bundled with the Agent SDK is missing; remote sessions cannot start." };
7028
+ }
7029
+ const cwd = join(this.opts.happyHomeDir, "tmp", "auth-probe");
7030
+ try {
7031
+ mkdirSync(cwd, { recursive: true });
7032
+ } catch {
7033
+ }
7034
+ const env = { ...this.env, ...this.claudeProcessEnvOverrides() };
7035
+ const run = await new Promise((resolve) => {
7036
+ let stdout = "";
7037
+ let settled = false;
7038
+ const done = (r) => {
7039
+ if (!settled) {
7040
+ settled = true;
7041
+ resolve(r);
7042
+ }
7043
+ };
7044
+ let child;
7045
+ try {
7046
+ child = spawn$3(binary, ["auth", "status"], { cwd, env, stdio: ["ignore", "pipe", "ignore"] });
7047
+ } catch (error) {
7048
+ done({ stdout: "", exitCode: null, timedOut: false, spawnError: String(error) });
7049
+ return;
7050
+ }
7051
+ const timer = setTimeout(() => {
7052
+ try {
7053
+ child.kill("SIGKILL");
7054
+ } catch {
7055
+ }
7056
+ done({ stdout, exitCode: null, timedOut: true });
7057
+ }, PROBE_TIMEOUT_MS);
7058
+ child.stdout?.on("data", (chunk) => {
7059
+ if (stdout.length < 65536) stdout += chunk.toString("utf8");
7060
+ });
7061
+ child.on("error", (error) => {
7062
+ clearTimeout(timer);
7063
+ done({ stdout, exitCode: null, timedOut: false, spawnError: String(error) });
7064
+ });
7065
+ child.on("close", (code) => {
7066
+ clearTimeout(timer);
7067
+ done({ stdout, exitCode: code, timedOut: false });
7068
+ });
7069
+ });
7070
+ return classifyAuthStatus(run, this.opts.credentialSource);
7071
+ }
7072
+ async diagnose(status) {
7073
+ const identity = keychainIdentityFor(this.env);
7074
+ const keychain = interpretSecurityRead(await this.security(securityReadArgs(identity)));
7075
+ const file = interpretCredentialsFile(this.readCredentialsFile(identity.credentialsPath));
7076
+ return diagnoseStores({ status, keychain, file });
7077
+ }
7078
+ readCredentialsFile(path) {
7079
+ const target = path ?? keychainIdentityFor(this.env).credentialsPath;
7080
+ try {
7081
+ return existsSync(target) ? readFileSync(target, "utf8") : null;
7082
+ } catch {
7083
+ return null;
7084
+ }
7085
+ }
7086
+ security(args) {
7087
+ return new Promise((resolve) => {
7088
+ execFile("security", args, { env: this.env, timeout: SECURITY_TIMEOUT_MS, maxBuffer: 65536 }, (error, stdout) => {
7089
+ const err = error;
7090
+ if (err && err.code === "ENOENT") return resolve({ exitCode: null, stdout: "", error: "ENOENT" });
7091
+ if (err && err.killed) return resolve({ exitCode: null, stdout: "", error: "timeout" });
7092
+ const exitCode = err ? typeof err.code === "number" ? err.code : 1 : 0;
7093
+ resolve({ exitCode, stdout: String(stdout ?? "") });
7094
+ });
7095
+ });
7096
+ }
7097
+ async resolveLineage() {
7098
+ if (this.lineage) return this.lineage;
7099
+ if (this.platform !== "darwin") {
7100
+ this.lineage = "other";
7101
+ return this.lineage;
7102
+ }
7103
+ const uid = typeof process.getuid === "function" ? process.getuid() : null;
7104
+ const launchdJobPid = uid === null ? null : parseLaunchctlPid(await this.exec("launchctl", ["print", `gui/${uid}/${HAPPY_DAEMON_LAUNCHD_LABEL}`]));
7105
+ const ancestors = await this.ancestorPids();
7106
+ this.lineage = classifyLineage({ platform: this.platform, env: this.env, launchdJobPid, ancestorPids: ancestors });
7107
+ return this.lineage;
7108
+ }
7109
+ async ancestorPids() {
7110
+ const out = [];
7111
+ let pid = process.ppid;
7112
+ for (let i = 0; i < 10 && pid > 1; i++) {
7113
+ out.push(pid);
7114
+ const ppid = Number((await this.exec("ps", ["-o", "ppid=", "-p", String(pid)])).trim());
7115
+ if (!Number.isFinite(ppid) || ppid === pid) break;
7116
+ pid = ppid;
7117
+ }
7118
+ return out;
7119
+ }
7120
+ exec(cmd, args) {
7121
+ return new Promise((resolve) => {
7122
+ execFile(cmd, args, { env: this.env, timeout: SECURITY_TIMEOUT_MS, maxBuffer: 65536 }, (_error, stdout) => resolve(String(stdout ?? "")));
7123
+ });
7124
+ }
7125
+ }
7126
+
6649
7127
  const INTERNAL_CLAUDE_EVENT_TYPES = /* @__PURE__ */ new Set(["file-history-snapshot", "change", "queue-operation"]);
6650
7128
  function parseLines(lines) {
6651
7129
  const out = [];
@@ -7365,6 +7843,8 @@ const initialMachineMetadata = {
7365
7843
  resumeSupport: { ...detectResumeSupport(), rpcAvailable: true }
7366
7844
  };
7367
7845
  async function startDaemon() {
7846
+ let claudeAuthServiceRef = null;
7847
+ let claudeCredentialStoreSetting = (await readSettings()).claudeCredentialStore === "file" ? "file" : "auto";
7368
7848
  let requestShutdown;
7369
7849
  let resolvesWhenShutdownRequested = new Promise((resolve) => {
7370
7850
  requestShutdown = (source, errorMessage) => {
@@ -7671,7 +8151,11 @@ async function startDaemon() {
7671
8151
  }
7672
8152
  let extraEnv = {
7673
8153
  ...authEnv,
7674
- ...options.environmentVariables ?? {}
8154
+ ...options.environmentVariables ?? {},
8155
+ // B-276 D8: credentialStore=file pins the spawned Claude Code (SDK
8156
+ // Query, title/board one-shots — all inside this wrapper) to
8157
+ // ~/.claude/.credentials.json via the keychain-off `security` shim.
8158
+ ...claudeAuthServiceRef?.claudeProcessEnvOverrides() ?? {}
7675
8159
  };
7676
8160
  if (options.parentSessionId) {
7677
8161
  extraEnv.HAPPY_FORKED_FROM_SESSION_ID = options.parentSessionId;
@@ -8297,6 +8781,7 @@ async function startDaemon() {
8297
8781
  requestShutdown: () => requestShutdown("happy-cli"),
8298
8782
  onHappySessionWebhook,
8299
8783
  onSessionStateEvent,
8784
+ onClaudeAuthFailed: (sessionId) => claudeAuthServiceRef?.signalAuthFailed(sessionId),
8300
8785
  pushClipboard: (text) => {
8301
8786
  if (!apiMachineRef) {
8302
8787
  return { delivered: false, truncated: false, totalBytes: 0, error: "daemon is still starting up" };
@@ -8367,6 +8852,25 @@ async function startDaemon() {
8367
8852
  listTrackedSessionIds: () => [...pidToTrackedSession.values()].map((session) => session.happySessionId).filter((sessionId) => typeof sessionId === "string"),
8368
8853
  requestShutdown: () => requestShutdown("happy-app")
8369
8854
  });
8855
+ const claudeAuthService = new ClaudeAuthService({
8856
+ happyHomeDir: configuration.happyHomeDir,
8857
+ happyLibDir: projectPath(),
8858
+ credentialSource: daemonClaudeCredentials.source,
8859
+ getCredentialStore: () => claudeCredentialStoreSetting,
8860
+ setCredentialStore: async (store) => {
8861
+ const settings = await readSettings();
8862
+ await writeSettings({ ...settings, claudeCredentialStore: store });
8863
+ claudeCredentialStoreSetting = store;
8864
+ },
8865
+ publish: (state) => apiMachine.setClaudeAuthState(state)
8866
+ });
8867
+ claudeAuthServiceRef = claudeAuthService;
8868
+ apiMachine.setClaudeAuthHandlers({
8869
+ probe: () => claudeAuthService.probe("rpc", true),
8870
+ repair: (action) => claudeAuthService.repair(action),
8871
+ setStore: (store) => claudeAuthService.setStore(store)
8872
+ });
8873
+ claudeAuthService.start();
8370
8874
  apiMachine.connect();
8371
8875
  let cliUpdateCheckRunning = false;
8372
8876
  const refreshCliUpdate = async () => {
@@ -8421,6 +8925,8 @@ async function startDaemon() {
8421
8925
  logger.debug("[DAEMON RUN] Daemon bundle replaced on disk, handing off to new daemon");
8422
8926
  clearInterval(restartOnStaleVersionAndHeartbeat);
8423
8927
  clearInterval(cliUpdateInterval);
8928
+ claudeAuthService.stop();
8929
+ claudeAuthService.stop();
8424
8930
  apiMachine.shutdown();
8425
8931
  await stopControlServer();
8426
8932
  await cleanupDaemonState();
@@ -14235,7 +14741,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14235
14741
  process.exit(0);
14236
14742
  } else if (subcommand === "install-terminal-hooks") {
14237
14743
  try {
14238
- const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await import('./installTerminalHooks-CBHjEQ-a.mjs');
14744
+ const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await import('./installTerminalHooks-DqNtW6a2.mjs');
14239
14745
  const command = parseTerminalHooksArgs(args.slice(1));
14240
14746
  if (command.action === "help") {
14241
14747
  console.log(TERMINAL_HOOKS_HELP);
@@ -14252,7 +14758,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14252
14758
  }
14253
14759
  } else if (subcommand === "spawn") {
14254
14760
  try {
14255
- const { handleSpawnCommand } = await import('./spawn-CfCE6JAv.mjs');
14761
+ const { handleSpawnCommand } = await import('./spawn-yS6yY8Xi.mjs');
14256
14762
  await handleSpawnCommand(args.slice(1));
14257
14763
  } catch (error) {
14258
14764
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -14264,7 +14770,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14264
14770
  return;
14265
14771
  } else if (subcommand === "send") {
14266
14772
  try {
14267
- const { handleSendCommand } = await import('./send-TX13v8Xe.mjs');
14773
+ const { handleSendCommand } = await import('./send-c-wEmh5U.mjs');
14268
14774
  await handleSendCommand(args.slice(1));
14269
14775
  } catch (error) {
14270
14776
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -14370,9 +14876,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14370
14876
  if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
14371
14877
  const projectId = args[3];
14372
14878
  try {
14373
- const { saveGoogleCloudProjectToConfig } = await import('./config-B69TZlJj.mjs');
14374
- const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await import('./types-CLRl0ET3.mjs').then(function (n) { return n.al; });
14375
- const { ApiClient: ApiClient2 } = await import('./types-CLRl0ET3.mjs').then(function (n) { return n.am; });
14879
+ const { saveGoogleCloudProjectToConfig } = await import('./config-DCH33LOM.mjs');
14880
+ const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await import('./types-xZOYW0_G.mjs').then(function (n) { return n.am; });
14881
+ const { ApiClient: ApiClient2 } = await import('./types-xZOYW0_G.mjs').then(function (n) { return n.an; });
14376
14882
  let userEmail = void 0;
14377
14883
  try {
14378
14884
  const credentials = await readCredentialsForConfiguredRelay2();
@@ -14403,7 +14909,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14403
14909
  }
14404
14910
  if (geminiSubcommand === "project" && args[2] === "get") {
14405
14911
  try {
14406
- const { readGeminiLocalConfig } = await import('./config-B69TZlJj.mjs');
14912
+ const { readGeminiLocalConfig } = await import('./config-DCH33LOM.mjs');
14407
14913
  const config = readGeminiLocalConfig();
14408
14914
  if (config.googleCloudProject) {
14409
14915
  console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
@@ -14443,7 +14949,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14443
14949
  process.exit(0);
14444
14950
  }
14445
14951
  try {
14446
- const { runGemini } = await import('./runGemini-cMZ3_CRf.mjs');
14952
+ const { runGemini } = await import('./runGemini-Brp0UmLx.mjs');
14447
14953
  let startedBy = void 0;
14448
14954
  for (let i = 1; i < args.length; i++) {
14449
14955
  if (args[i] === "--started-by") {
@@ -14465,7 +14971,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14465
14971
  return;
14466
14972
  } else if (subcommand === "acp") {
14467
14973
  try {
14468
- const { runAcp, resolveAcpAgentConfig } = await import('./index-C-uJXSm3.mjs');
14974
+ const { runAcp, resolveAcpAgentConfig } = await import('./index-DkhMvofH.mjs');
14469
14975
  let startedBy = void 0;
14470
14976
  let verbose = false;
14471
14977
  const acpArgs = [];
@@ -14505,7 +15011,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14505
15011
  return;
14506
15012
  } else if (subcommand === "openclaw") {
14507
15013
  try {
14508
- const { runOpenClaw } = await import('./runOpenClaw-BJ36wEbk.mjs');
15014
+ const { runOpenClaw } = await import('./runOpenClaw-BvPRFx-L.mjs');
14509
15015
  let startedBy = void 0;
14510
15016
  let verbose = false;
14511
15017
  let gatewayUrl;
@@ -14556,7 +15062,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14556
15062
  return;
14557
15063
  } else if (subcommand === "mcp" && args.length === 1) {
14558
15064
  try {
14559
- const { handleMcpCommand } = await import('./mcp-BdSHqi2d.mjs');
15065
+ const { handleMcpCommand } = await import('./mcp-BKAuzaLX.mjs');
14560
15066
  await handleMcpCommand();
14561
15067
  } catch (error) {
14562
15068
  process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}