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
@@ -3,7 +3,7 @@
3
3
  var chalk = require('chalk');
4
4
  var os = require('node:os');
5
5
  var node_crypto = require('node:crypto');
6
- var persistence = require('./types-okYCRlgl.cjs');
6
+ var persistence = require('./types-DoGaKVfK.cjs');
7
7
  var spawn = require('cross-spawn');
8
8
  var path = require('node:path');
9
9
  var node_readline = require('node:readline');
@@ -33,11 +33,11 @@ var open = require('open');
33
33
  var fastify = require('fastify');
34
34
  var z = require('zod');
35
35
  var fastifyTypeProviderZod = require('fastify-type-provider-zod');
36
+ var node_module = require('node:module');
36
37
  var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
37
38
  var node_http = require('node:http');
38
39
  var streamableHttp_js = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
39
40
  var limits = require('./limits-KdWKmwtH.cjs');
40
- var node_module = require('node:module');
41
41
  var http = require('http');
42
42
  var util = require('util');
43
43
  var inquirer = require('inquirer');
@@ -197,6 +197,9 @@ async function spawnDaemonSession(directory, sessionId, opts) {
197
197
  async function notifyDaemonSessionEvent(sessionId, event, spawnedBy) {
198
198
  return daemonPost("/session-event", { sessionId, event, spawnedBy });
199
199
  }
200
+ async function notifyDaemonClaudeAuthFailed(sessionId) {
201
+ return daemonPost("/session-event", { sessionId, event: "auth_failed" });
202
+ }
200
203
  async function stopDaemonHttp() {
201
204
  await daemonPost("/stop");
202
205
  }
@@ -1766,6 +1769,20 @@ function parseSpecialCommand(message) {
1766
1769
  };
1767
1770
  }
1768
1771
 
1772
+ const AUTH_FAILURE_RESULT_TEXT = /Failed to authenticate|OAuth session expired/i;
1773
+ const QUERY_RECYCLE_NOTICE = {
1774
+ 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."
1775
+ };
1776
+ function queryRecycleReason(result, lastAssistantError) {
1777
+ if (lastAssistantError === "authentication_failed") {
1778
+ return "authentication_failed";
1779
+ }
1780
+ if (result.is_error && typeof result.result === "string" && AUTH_FAILURE_RESULT_TEXT.test(result.result)) {
1781
+ return "authentication_failed";
1782
+ }
1783
+ return null;
1784
+ }
1785
+
1769
1786
  class PushableAsyncIterable {
1770
1787
  queue = [];
1771
1788
  waiters = [];
@@ -2026,11 +2043,15 @@ async function claudeRemote(opts) {
2026
2043
  }
2027
2044
  });
2028
2045
  }
2046
+ let lastAssistantError;
2029
2047
  updateThinking(true);
2030
2048
  try {
2031
2049
  persistence.logger.debug(`[claudeRemote] Starting to iterate over response`);
2032
2050
  for await (const message of response) {
2033
2051
  persistence.logger.debug(`[claudeRemote] Message ${message.type}`, persistence.contentLogMetadata(message));
2052
+ if (message.type === "assistant" && message.error) {
2053
+ lastAssistantError = message.error;
2054
+ }
2034
2055
  const outboundMessage = isCompactCommand && message.type === "assistant" ? { ...message, isCompactSummary: true } : message;
2035
2056
  opts.onMessage(outboundMessage);
2036
2057
  if (message.type === "system" && message.subtype === "init") {
@@ -2079,6 +2100,15 @@ async function claudeRemote(opts) {
2079
2100
  isCompactCommand = false;
2080
2101
  }
2081
2102
  opts.onReady(message);
2103
+ const recycleReason = queryRecycleReason(message, lastAssistantError);
2104
+ lastAssistantError = void 0;
2105
+ if (recycleReason) {
2106
+ persistence.logger.warn(`[claudeRemote] Ending SDK query after ${recycleReason}; the next message starts a fresh Claude Code process`);
2107
+ opts.onCompletionEvent?.(QUERY_RECYCLE_NOTICE[recycleReason]);
2108
+ opts.onAuthFailure?.(recycleReason);
2109
+ messages.end();
2110
+ continue;
2111
+ }
2082
2112
  opts.nextMessage().then((next) => {
2083
2113
  if (!next) {
2084
2114
  messages.end();
@@ -3282,8 +3312,9 @@ async function cleanupStdinAfterInk(opts) {
3282
3312
  }
3283
3313
 
3284
3314
  function applyClaudeResultLifecycle(result, callbacks) {
3285
- if (result && result.subtype !== "success") {
3286
- const error = result.errors?.filter(Boolean).join("\n").trim() || result.subtype;
3315
+ if (result && (result.subtype !== "success" || result.is_error === true)) {
3316
+ const frame = result;
3317
+ const error = frame.errors?.filter(Boolean).join("\n").trim() || (typeof frame.result === "string" ? frame.result.trim() : "") || frame.subtype;
3287
3318
  callbacks.closeFailed(error);
3288
3319
  callbacks.onFailed(error);
3289
3320
  return;
@@ -3755,6 +3786,10 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
3755
3786
  persistence.logger.debug("[remote]: Completion event received:", persistence.contentLogMetadata(message));
3756
3787
  session.client.sendSessionEvent({ type: "message", message });
3757
3788
  },
3789
+ onAuthFailure: (reason) => {
3790
+ session.client.sendSessionEvent({ type: "message", message: `Claude Code auth: ${reason}`, kind: "claude-auth-failed" });
3791
+ void notifyDaemonClaudeAuthFailed(session.client.sessionId).catch((error) => persistence.logger.debug("[remote]: auth_failed report to daemon failed:", error));
3792
+ },
3758
3793
  onSessionReset: () => {
3759
3794
  persistence.logger.debug("[remote]: Session reset");
3760
3795
  session.clearSessionId();
@@ -5428,6 +5463,7 @@ function startDaemonControlServer({
5428
5463
  requestShutdown,
5429
5464
  onHappySessionWebhook,
5430
5465
  onSessionStateEvent,
5466
+ onClaudeAuthFailed,
5431
5467
  pushClipboard,
5432
5468
  onTerminalHook
5433
5469
  }) {
@@ -5483,7 +5519,7 @@ function startDaemonControlServer({
5483
5519
  schema: {
5484
5520
  body: z.z.object({
5485
5521
  sessionId: z.z.string(),
5486
- event: z.z.enum(["completed", "needs_input"]),
5522
+ event: z.z.enum(["completed", "needs_input", "auth_failed"]),
5487
5523
  spawnedBy: z.z.string().optional()
5488
5524
  }),
5489
5525
  response: {
@@ -5495,6 +5531,10 @@ function startDaemonControlServer({
5495
5531
  }, async (request) => {
5496
5532
  const { sessionId, event, spawnedBy } = request.body;
5497
5533
  persistence.logger.debug(`[CONTROL SERVER] Session event: ${sessionId} ${event} (spawnedBy=${spawnedBy ?? "unset"})`);
5534
+ if (event === "auth_failed") {
5535
+ onClaudeAuthFailed?.(sessionId);
5536
+ return { status: "ok" };
5537
+ }
5498
5538
  onSessionStateEvent?.(sessionId, event, spawnedBy);
5499
5539
  return { status: "ok" };
5500
5540
  });
@@ -6668,6 +6708,444 @@ async function handleResumeCommand(args) {
6668
6708
  }
6669
6709
  }
6670
6710
 
6711
+ const CLAUDE_KEYCHAIN_SERVICE_PREFIX = "Claude Code";
6712
+ function keychainIdentity(env = process.env, deps = {}) {
6713
+ const home = deps.home ?? os.homedir();
6714
+ const secureDir = env.CLAUDE_SECURESTORAGE_CONFIG_DIR?.trim();
6715
+ const configDirEnv = env.CLAUDE_CONFIG_DIR?.trim();
6716
+ const configDir = secureDir || configDirEnv || path.join(home, ".claude");
6717
+ const hasCustomDir = Boolean(secureDir || configDirEnv);
6718
+ const dirSuffix = hasCustomDir ? "-" + node_crypto.createHash("sha256").update(configDir.normalize("NFC")).digest("hex").slice(0, 8) : "";
6719
+ const oauthSuffix = env.CLAUDE_CODE_OAUTH_CLIENT_ID?.trim() ? "-custom-oauth" : "";
6720
+ const rawAccount = env.USER || safeUsername(deps.username);
6721
+ const account = /^[a-zA-Z0-9._-]+$/.test(rawAccount) ? rawAccount : "claude-code-user";
6722
+ return {
6723
+ service: `${CLAUDE_KEYCHAIN_SERVICE_PREFIX}${oauthSuffix}-credentials${dirSuffix}`,
6724
+ account,
6725
+ configDir,
6726
+ credentialsPath: path.join(configDir, ".credentials.json")
6727
+ };
6728
+ }
6729
+ function safeUsername(provider) {
6730
+ try {
6731
+ return provider ? provider() : os.userInfo().username;
6732
+ } catch {
6733
+ return "";
6734
+ }
6735
+ }
6736
+
6737
+ const CLAUDE_AUTH_PROBE_VERSION = 1;
6738
+ const LOCAL_CREDENTIAL_SOURCE = "Claude local credentials";
6739
+ function classifyAuthStatus(run, credentialSource) {
6740
+ const localSource = credentialSource === void 0 || credentialSource === LOCAL_CREDENTIAL_SOURCE;
6741
+ if (run.spawnError) {
6742
+ return { status: "error", diagnosis: "probe-crash", detail: `could not run claude auth status: ${run.spawnError}` };
6743
+ }
6744
+ if (run.timedOut) {
6745
+ return { status: "error", diagnosis: "probe-timeout", detail: "claude auth status did not answer within the timeout" };
6746
+ }
6747
+ const parsed = parseJsonObject(run.stdout);
6748
+ if (!parsed) {
6749
+ if (!localSource) return { status: "unknown", authMethod: credentialSource, detail: `auth status unparseable under ${credentialSource}` };
6750
+ return { status: "error", diagnosis: "probe-crash", detail: `claude auth status returned no JSON (exit ${run.exitCode ?? "null"})` };
6751
+ }
6752
+ const authMethod = typeof parsed.authMethod === "string" ? parsed.authMethod : void 0;
6753
+ const subscriptionType = typeof parsed.subscriptionType === "string" ? parsed.subscriptionType : void 0;
6754
+ if (parsed.loggedIn === true) {
6755
+ return { status: "ok", authMethod: localSource ? authMethod : credentialSource, subscriptionType };
6756
+ }
6757
+ if (!localSource) {
6758
+ return { status: "unknown", authMethod: credentialSource, detail: `Claude Code reports loggedIn=false under ${credentialSource}; not a local-credential failure` };
6759
+ }
6760
+ return { status: "not-logged-in", authMethod, subscriptionType, detail: "Claude Code in the daemon context reports it is not logged in" };
6761
+ }
6762
+ function parseJsonObject(text) {
6763
+ const trimmed = text.trim();
6764
+ if (!trimmed) return null;
6765
+ const start = trimmed.indexOf("{");
6766
+ if (start < 0) return null;
6767
+ try {
6768
+ const value = JSON.parse(trimmed.slice(start));
6769
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
6770
+ } catch {
6771
+ return null;
6772
+ }
6773
+ }
6774
+ function resolveSdkClaudeBinary(platform = process.platform, arch = process.arch, resolver = (s) => node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-BD2fHJ8o.cjs', document.baseURI).href))).resolve(s)) {
6775
+ const platformArch = `${platform}-${arch}`;
6776
+ const candidates = [
6777
+ `@anthropic-ai/claude-agent-sdk-${platformArch}/claude`,
6778
+ `@anthropic-ai/claude-agent-sdk-${platformArch}/claude.exe`
6779
+ ];
6780
+ for (const candidate of candidates) {
6781
+ try {
6782
+ return resolver(candidate);
6783
+ } catch {
6784
+ }
6785
+ }
6786
+ return null;
6787
+ }
6788
+ function interpretSecurityRead(result) {
6789
+ if (result.error === "ENOENT") return { kind: "unsupported" };
6790
+ if (result.error === "timeout") return { kind: "error", detail: "security timed out" };
6791
+ if (result.exitCode === 44) return { kind: "absent" };
6792
+ if (result.exitCode === 36) return { kind: "unreadable" };
6793
+ if (result.exitCode !== 0) return { kind: "error", detail: `security exited ${result.exitCode ?? "null"}` };
6794
+ const raw = result.stdout.trim();
6795
+ if (!raw) return { kind: "absent" };
6796
+ const parsed = parseJsonObject(raw);
6797
+ const oauth = parsed && typeof parsed.claudeAiOauth === "object" && parsed.claudeAiOauth ? parsed.claudeAiOauth : null;
6798
+ if (!oauth) return { kind: "present", accessToken: "", refreshToken: "", raw };
6799
+ return {
6800
+ kind: "present",
6801
+ accessToken: typeof oauth.accessToken === "string" ? oauth.accessToken : "",
6802
+ refreshToken: typeof oauth.refreshToken === "string" ? oauth.refreshToken : "",
6803
+ raw
6804
+ };
6805
+ }
6806
+ function interpretCredentialsFile(text) {
6807
+ if (text === null) return { exists: false, hasTokens: false, refreshToken: "" };
6808
+ const parsed = parseJsonObject(text);
6809
+ const oauth = parsed && typeof parsed.claudeAiOauth === "object" && parsed.claudeAiOauth ? parsed.claudeAiOauth : null;
6810
+ const access = oauth && typeof oauth.accessToken === "string" ? oauth.accessToken : "";
6811
+ const refresh = oauth && typeof oauth.refreshToken === "string" ? oauth.refreshToken : "";
6812
+ return { exists: true, hasTokens: access.length > 0 && refresh.length > 0, refreshToken: refresh };
6813
+ }
6814
+ function tokenTail(token) {
6815
+ return token ? node_crypto.createHash("sha256").update(token).digest("hex").slice(-6) : "";
6816
+ }
6817
+ function diagnoseStores(input) {
6818
+ const { status, keychain, file } = input;
6819
+ if (keychain.kind === "present") {
6820
+ const empty = keychain.accessToken.length === 0 && keychain.refreshToken.length === 0;
6821
+ if (empty && file.hasTokens && status === "not-logged-in") {
6822
+ return {
6823
+ diagnosis: "keychain-empty-item",
6824
+ repairable: "delete-empty-keychain-item",
6825
+ keychainRaw: keychain.raw,
6826
+ 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."
6827
+ };
6828
+ }
6829
+ if (!empty && file.hasTokens && tokenTail(keychain.refreshToken) !== tokenTail(file.refreshToken)) {
6830
+ return {
6831
+ diagnosis: "store-divergence",
6832
+ 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."
6833
+ };
6834
+ }
6835
+ return {};
6836
+ }
6837
+ if ((keychain.kind === "absent" || keychain.kind === "unreadable" || keychain.kind === "unsupported") && !file.hasTokens) {
6838
+ return { diagnosis: "no-credentials", detail: "No Claude Code credentials found for this daemon context; log in with `claude` on this machine." };
6839
+ }
6840
+ if (keychain.kind === "unreadable" && file.hasTokens && status === "not-logged-in") {
6841
+ return { detail: "The daemon context cannot read the keychain and the file credentials were not accepted; compare `claude auth status` on the machine." };
6842
+ }
6843
+ if (keychain.kind === "error") {
6844
+ return { detail: `keychain check failed: ${keychain.detail}` };
6845
+ }
6846
+ return {};
6847
+ }
6848
+ function securityReadArgs(identity) {
6849
+ return ["find-generic-password", "-s", identity.service, "-a", identity.account, "-w"];
6850
+ }
6851
+ function securityDeleteArgs(identity) {
6852
+ return ["delete-generic-password", "-s", identity.service, "-a", identity.account];
6853
+ }
6854
+ const HAPPY_DAEMON_LAUNCHD_LABEL = "com.mereith.happy-daemon";
6855
+ function classifyLineage(input) {
6856
+ if (input.platform !== "darwin") return "other";
6857
+ const label = input.label ?? HAPPY_DAEMON_LAUNCHD_LABEL;
6858
+ if (input.env.XPC_SERVICE_NAME !== label) return "other";
6859
+ if (input.launchdJobPid !== null && input.ancestorPids.includes(input.launchdJobPid)) return "launchd";
6860
+ return "inherited-env";
6861
+ }
6862
+ function parseLaunchctlPid(printOutput) {
6863
+ const match = /^\s*pid\s*=\s*(\d+)/m.exec(printOutput);
6864
+ return match ? Number(match[1]) : null;
6865
+ }
6866
+ function keychainOffShimDir(happyLibDir) {
6867
+ return path.join(happyLibDir, "scripts", "shims", "keychain-off");
6868
+ }
6869
+ function withKeychainOffPath(path$1, shimDir) {
6870
+ const parts = (path$1 ?? "").split(path.delimiter).filter((p) => p && p !== shimDir);
6871
+ return [shimDir, ...parts].join(path.delimiter);
6872
+ }
6873
+ function buildClaudeAuthState(input) {
6874
+ const { classification, diagnosis } = input;
6875
+ const detail = (diagnosis?.detail ?? classification.detail)?.slice(0, 200);
6876
+ const state = {
6877
+ probeVersion: CLAUDE_AUTH_PROBE_VERSION,
6878
+ daemonPid: input.daemonPid,
6879
+ status: classification.status,
6880
+ context: { platform: input.platform, lineage: input.lineage, credentialStore: input.credentialStore },
6881
+ checkedAt: input.now ?? Date.now()
6882
+ };
6883
+ if (classification.authMethod) state.authMethod = classification.authMethod;
6884
+ if (classification.subscriptionType) state.subscriptionType = classification.subscriptionType;
6885
+ const diag = diagnosis?.diagnosis ?? classification.diagnosis;
6886
+ if (diag) state.diagnosis = diag;
6887
+ if (detail) state.detail = detail;
6888
+ if (diagnosis?.repairable) state.repairable = diagnosis.repairable;
6889
+ return state;
6890
+ }
6891
+ function claudeAuthStateChanged(prev, next) {
6892
+ if (!prev) return true;
6893
+ const strip = ({ checkedAt: _c, ...rest }) => JSON.stringify(rest);
6894
+ return strip(prev) !== strip(next);
6895
+ }
6896
+ function keychainIdentityFor(env) {
6897
+ return keychainIdentity(env);
6898
+ }
6899
+
6900
+ const CLAUDE_AUTH_PROBE_INTERVAL_MS = 10 * 60 * 1e3;
6901
+ const CLAUDE_AUTH_REFRESH_INTERVAL_MS = 30 * 60 * 1e3;
6902
+ const PROBE_TIMEOUT_MS = 8e3;
6903
+ const SECURITY_TIMEOUT_MS = 3e3;
6904
+ const SIGNAL_DEBOUNCE_MS = 1e3;
6905
+ class ClaudeAuthService {
6906
+ constructor(opts) {
6907
+ this.opts = opts;
6908
+ this.env = opts.env ?? process.env;
6909
+ this.platform = opts.platform ?? process.platform;
6910
+ }
6911
+ timer = null;
6912
+ signalTimer = null;
6913
+ inFlight = null;
6914
+ last = null;
6915
+ dirty = false;
6916
+ lastPublishedAt = 0;
6917
+ lineage = null;
6918
+ lastDiagnosis;
6919
+ env;
6920
+ platform;
6921
+ start() {
6922
+ setTimeout(() => void this.probe("startup"), 2e3).unref();
6923
+ this.timer = setInterval(() => void this.probe("interval"), CLAUDE_AUTH_PROBE_INTERVAL_MS);
6924
+ this.timer.unref();
6925
+ }
6926
+ stop() {
6927
+ if (this.timer) clearInterval(this.timer);
6928
+ if (this.signalTimer) clearTimeout(this.signalTimer);
6929
+ this.timer = null;
6930
+ this.signalTimer = null;
6931
+ }
6932
+ current() {
6933
+ return this.last;
6934
+ }
6935
+ /** D3: a session reported `authentication_failed`; re-probe after a short debounce. */
6936
+ signalAuthFailed(sessionId) {
6937
+ persistence.logger.debug(`[CLAUDE AUTH] auth_failed signal from session ${sessionId}`);
6938
+ if (this.signalTimer) clearTimeout(this.signalTimer);
6939
+ this.signalTimer = setTimeout(() => {
6940
+ this.signalTimer = null;
6941
+ void this.probe("signal", true);
6942
+ }, SIGNAL_DEBOUNCE_MS);
6943
+ this.signalTimer.unref();
6944
+ }
6945
+ /** Env the SDK/one-shot Claude Code processes should get for the current store setting. */
6946
+ claudeProcessEnvOverrides() {
6947
+ if (this.opts.getCredentialStore() !== "file") return {};
6948
+ const shim = this.resolveShimDir();
6949
+ if (!shim) return {};
6950
+ return { PATH: withKeychainOffPath(this.env.PATH, shim) };
6951
+ }
6952
+ effectiveCredentialStore() {
6953
+ if (this.opts.getCredentialStore() !== "file") return "auto";
6954
+ return this.resolveShimDir() ? "file" : "auto";
6955
+ }
6956
+ async probe(reason, withDiagnosis = false) {
6957
+ if (this.inFlight) return this.inFlight;
6958
+ this.inFlight = this.runProbe(reason, withDiagnosis).finally(() => {
6959
+ this.inFlight = null;
6960
+ });
6961
+ return this.inFlight;
6962
+ }
6963
+ async setStore(store) {
6964
+ await this.opts.setCredentialStore(store);
6965
+ return this.probe("set-store", true);
6966
+ }
6967
+ /** D4: delete the empty-token keychain item after re-validating every precondition. */
6968
+ async repair(action) {
6969
+ if (action !== "delete-empty-keychain-item") return { error: "unknown-action", claudeAuth: this.last };
6970
+ if (this.platform !== "darwin" || this.effectiveCredentialStore() === "file") return { error: "precondition-failed", claudeAuth: this.last };
6971
+ const state = await this.probe("repair-precheck", true);
6972
+ const seen = this.lastDiagnosis;
6973
+ if (state.diagnosis !== "keychain-empty-item" || !seen?.keychainRaw) return { error: "precondition-failed", claudeAuth: state };
6974
+ const identity = keychainIdentityFor(this.env);
6975
+ const again = interpretSecurityRead(await this.security(securityReadArgs(identity)));
6976
+ if (again.kind !== "present" || again.raw !== seen.keychainRaw || again.accessToken || again.refreshToken) {
6977
+ return { error: "precondition-failed", claudeAuth: state };
6978
+ }
6979
+ try {
6980
+ const dir = path.join(this.opts.happyHomeDir, "backups");
6981
+ node_fs.mkdirSync(dir, { recursive: true, mode: 448 });
6982
+ node_fs.writeFileSync(path.join(dir, `claude-keychain-${Date.now()}.json`), again.raw + "\n", { mode: 384 });
6983
+ } catch (error) {
6984
+ return { error: `backup-failed: ${String(error)}`, claudeAuth: state };
6985
+ }
6986
+ const del = await this.security(securityDeleteArgs(identity));
6987
+ if (del.exitCode !== 0) return { error: `delete-failed: security exited ${del.exitCode ?? "null"}`, claudeAuth: state };
6988
+ persistence.logger.debug("[CLAUDE AUTH] deleted empty-token keychain item after backup");
6989
+ const after = await this.probe("repair-done", true);
6990
+ return { ok: true, claudeAuth: after };
6991
+ }
6992
+ // ── internals ────────────────────────────────────────────────────────
6993
+ resolveShimDir() {
6994
+ const dir = keychainOffShimDir(this.opts.happyLibDir);
6995
+ const bin = path.join(dir, "security");
6996
+ try {
6997
+ if (!node_fs.statSync(bin).isFile()) return null;
6998
+ node_fs.accessSync(bin, node_fs.constants.X_OK);
6999
+ return dir;
7000
+ } catch {
7001
+ return null;
7002
+ }
7003
+ }
7004
+ async runProbe(reason, withDiagnosis) {
7005
+ const store = this.effectiveCredentialStore();
7006
+ const storeRequested = this.opts.getCredentialStore();
7007
+ const classification = await this.runAuthStatus();
7008
+ let diagnosis;
7009
+ this.lastDiagnosis = void 0;
7010
+ if (this.platform === "darwin" && store !== "file" && (classification.status === "not-logged-in" || withDiagnosis && classification.status !== "unknown")) {
7011
+ diagnosis = await this.diagnose(classification.status);
7012
+ this.lastDiagnosis = diagnosis;
7013
+ } else if (classification.status === "not-logged-in" && store === "file") {
7014
+ const file = interpretCredentialsFile(this.readCredentialsFile());
7015
+ 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." };
7016
+ }
7017
+ if (storeRequested === "file" && store === "auto") {
7018
+ diagnosis = { ...diagnosis ?? {}, detail: `credentialStore=file requested but the keychain-off shim is missing under ${keychainOffShimDir(this.opts.happyLibDir)}; running in auto mode.` };
7019
+ }
7020
+ const state = buildClaudeAuthState({
7021
+ daemonPid: process.pid,
7022
+ platform: this.platform,
7023
+ lineage: await this.resolveLineage(),
7024
+ credentialStore: store,
7025
+ classification,
7026
+ diagnosis,
7027
+ now: this.opts.now?.() ?? Date.now()
7028
+ });
7029
+ const changed = claudeAuthStateChanged(this.last, state);
7030
+ const stale = state.checkedAt - this.lastPublishedAt >= CLAUDE_AUTH_REFRESH_INTERVAL_MS;
7031
+ if (changed) {
7032
+ persistence.logger.debug(`[CLAUDE AUTH] ${reason}: status=${state.status} diagnosis=${state.diagnosis ?? "-"} lineage=${state.context.lineage} store=${state.context.credentialStore}`);
7033
+ }
7034
+ this.last = state;
7035
+ if (changed || stale || this.dirty) {
7036
+ const ok = await this.opts.publish(state).catch((error) => {
7037
+ persistence.logger.debug("[CLAUDE AUTH] publish failed:", error);
7038
+ return false;
7039
+ });
7040
+ this.dirty = !ok;
7041
+ if (ok) this.lastPublishedAt = state.checkedAt;
7042
+ else persistence.logger.warn("[CLAUDE AUTH] daemonState publish did not land; will force resend on the next probe");
7043
+ }
7044
+ return state;
7045
+ }
7046
+ async runAuthStatus() {
7047
+ const binary = resolveSdkClaudeBinary(this.platform, process.arch);
7048
+ if (!binary) {
7049
+ return { status: "claude-missing", diagnosis: "sdk-binary-missing", detail: "The Claude Code binary bundled with the Agent SDK is missing; remote sessions cannot start." };
7050
+ }
7051
+ const cwd = path.join(this.opts.happyHomeDir, "tmp", "auth-probe");
7052
+ try {
7053
+ node_fs.mkdirSync(cwd, { recursive: true });
7054
+ } catch {
7055
+ }
7056
+ const env = { ...this.env, ...this.claudeProcessEnvOverrides() };
7057
+ const run = await new Promise((resolve) => {
7058
+ let stdout = "";
7059
+ let settled = false;
7060
+ const done = (r) => {
7061
+ if (!settled) {
7062
+ settled = true;
7063
+ resolve(r);
7064
+ }
7065
+ };
7066
+ let child;
7067
+ try {
7068
+ child = node_child_process.spawn(binary, ["auth", "status"], { cwd, env, stdio: ["ignore", "pipe", "ignore"] });
7069
+ } catch (error) {
7070
+ done({ stdout: "", exitCode: null, timedOut: false, spawnError: String(error) });
7071
+ return;
7072
+ }
7073
+ const timer = setTimeout(() => {
7074
+ try {
7075
+ child.kill("SIGKILL");
7076
+ } catch {
7077
+ }
7078
+ done({ stdout, exitCode: null, timedOut: true });
7079
+ }, PROBE_TIMEOUT_MS);
7080
+ child.stdout?.on("data", (chunk) => {
7081
+ if (stdout.length < 65536) stdout += chunk.toString("utf8");
7082
+ });
7083
+ child.on("error", (error) => {
7084
+ clearTimeout(timer);
7085
+ done({ stdout, exitCode: null, timedOut: false, spawnError: String(error) });
7086
+ });
7087
+ child.on("close", (code) => {
7088
+ clearTimeout(timer);
7089
+ done({ stdout, exitCode: code, timedOut: false });
7090
+ });
7091
+ });
7092
+ return classifyAuthStatus(run, this.opts.credentialSource);
7093
+ }
7094
+ async diagnose(status) {
7095
+ const identity = keychainIdentityFor(this.env);
7096
+ const keychain = interpretSecurityRead(await this.security(securityReadArgs(identity)));
7097
+ const file = interpretCredentialsFile(this.readCredentialsFile(identity.credentialsPath));
7098
+ return diagnoseStores({ status, keychain, file });
7099
+ }
7100
+ readCredentialsFile(path) {
7101
+ const target = path ?? keychainIdentityFor(this.env).credentialsPath;
7102
+ try {
7103
+ return node_fs.existsSync(target) ? node_fs.readFileSync(target, "utf8") : null;
7104
+ } catch {
7105
+ return null;
7106
+ }
7107
+ }
7108
+ security(args) {
7109
+ return new Promise((resolve) => {
7110
+ node_child_process.execFile("security", args, { env: this.env, timeout: SECURITY_TIMEOUT_MS, maxBuffer: 65536 }, (error, stdout) => {
7111
+ const err = error;
7112
+ if (err && err.code === "ENOENT") return resolve({ exitCode: null, stdout: "", error: "ENOENT" });
7113
+ if (err && err.killed) return resolve({ exitCode: null, stdout: "", error: "timeout" });
7114
+ const exitCode = err ? typeof err.code === "number" ? err.code : 1 : 0;
7115
+ resolve({ exitCode, stdout: String(stdout ?? "") });
7116
+ });
7117
+ });
7118
+ }
7119
+ async resolveLineage() {
7120
+ if (this.lineage) return this.lineage;
7121
+ if (this.platform !== "darwin") {
7122
+ this.lineage = "other";
7123
+ return this.lineage;
7124
+ }
7125
+ const uid = typeof process.getuid === "function" ? process.getuid() : null;
7126
+ const launchdJobPid = uid === null ? null : parseLaunchctlPid(await this.exec("launchctl", ["print", `gui/${uid}/${HAPPY_DAEMON_LAUNCHD_LABEL}`]));
7127
+ const ancestors = await this.ancestorPids();
7128
+ this.lineage = classifyLineage({ platform: this.platform, env: this.env, launchdJobPid, ancestorPids: ancestors });
7129
+ return this.lineage;
7130
+ }
7131
+ async ancestorPids() {
7132
+ const out = [];
7133
+ let pid = process.ppid;
7134
+ for (let i = 0; i < 10 && pid > 1; i++) {
7135
+ out.push(pid);
7136
+ const ppid = Number((await this.exec("ps", ["-o", "ppid=", "-p", String(pid)])).trim());
7137
+ if (!Number.isFinite(ppid) || ppid === pid) break;
7138
+ pid = ppid;
7139
+ }
7140
+ return out;
7141
+ }
7142
+ exec(cmd, args) {
7143
+ return new Promise((resolve) => {
7144
+ node_child_process.execFile(cmd, args, { env: this.env, timeout: SECURITY_TIMEOUT_MS, maxBuffer: 65536 }, (_error, stdout) => resolve(String(stdout ?? "")));
7145
+ });
7146
+ }
7147
+ }
7148
+
6671
7149
  const INTERNAL_CLAUDE_EVENT_TYPES = /* @__PURE__ */ new Set(["file-history-snapshot", "change", "queue-operation"]);
6672
7150
  function parseLines(lines) {
6673
7151
  const out = [];
@@ -7387,6 +7865,8 @@ const initialMachineMetadata = {
7387
7865
  resumeSupport: { ...persistence.detectResumeSupport(), rpcAvailable: true }
7388
7866
  };
7389
7867
  async function startDaemon() {
7868
+ let claudeAuthServiceRef = null;
7869
+ let claudeCredentialStoreSetting = (await persistence.readSettings()).claudeCredentialStore === "file" ? "file" : "auto";
7390
7870
  let requestShutdown;
7391
7871
  let resolvesWhenShutdownRequested = new Promise((resolve) => {
7392
7872
  requestShutdown = (source, errorMessage) => {
@@ -7693,7 +8173,11 @@ async function startDaemon() {
7693
8173
  }
7694
8174
  let extraEnv = {
7695
8175
  ...authEnv,
7696
- ...options.environmentVariables ?? {}
8176
+ ...options.environmentVariables ?? {},
8177
+ // B-276 D8: credentialStore=file pins the spawned Claude Code (SDK
8178
+ // Query, title/board one-shots — all inside this wrapper) to
8179
+ // ~/.claude/.credentials.json via the keychain-off `security` shim.
8180
+ ...claudeAuthServiceRef?.claudeProcessEnvOverrides() ?? {}
7697
8181
  };
7698
8182
  if (options.parentSessionId) {
7699
8183
  extraEnv.HAPPY_FORKED_FROM_SESSION_ID = options.parentSessionId;
@@ -8319,6 +8803,7 @@ async function startDaemon() {
8319
8803
  requestShutdown: () => requestShutdown("happy-cli"),
8320
8804
  onHappySessionWebhook,
8321
8805
  onSessionStateEvent,
8806
+ onClaudeAuthFailed: (sessionId) => claudeAuthServiceRef?.signalAuthFailed(sessionId),
8322
8807
  pushClipboard: (text) => {
8323
8808
  if (!apiMachineRef) {
8324
8809
  return { delivered: false, truncated: false, totalBytes: 0, error: "daemon is still starting up" };
@@ -8389,6 +8874,25 @@ async function startDaemon() {
8389
8874
  listTrackedSessionIds: () => [...pidToTrackedSession.values()].map((session) => session.happySessionId).filter((sessionId) => typeof sessionId === "string"),
8390
8875
  requestShutdown: () => requestShutdown("happy-app")
8391
8876
  });
8877
+ const claudeAuthService = new ClaudeAuthService({
8878
+ happyHomeDir: persistence.configuration.happyHomeDir,
8879
+ happyLibDir: persistence.projectPath(),
8880
+ credentialSource: daemonClaudeCredentials.source,
8881
+ getCredentialStore: () => claudeCredentialStoreSetting,
8882
+ setCredentialStore: async (store) => {
8883
+ const settings = await persistence.readSettings();
8884
+ await persistence.writeSettings({ ...settings, claudeCredentialStore: store });
8885
+ claudeCredentialStoreSetting = store;
8886
+ },
8887
+ publish: (state) => apiMachine.setClaudeAuthState(state)
8888
+ });
8889
+ claudeAuthServiceRef = claudeAuthService;
8890
+ apiMachine.setClaudeAuthHandlers({
8891
+ probe: () => claudeAuthService.probe("rpc", true),
8892
+ repair: (action) => claudeAuthService.repair(action),
8893
+ setStore: (store) => claudeAuthService.setStore(store)
8894
+ });
8895
+ claudeAuthService.start();
8392
8896
  apiMachine.connect();
8393
8897
  let cliUpdateCheckRunning = false;
8394
8898
  const refreshCliUpdate = async () => {
@@ -8443,6 +8947,8 @@ async function startDaemon() {
8443
8947
  persistence.logger.debug("[DAEMON RUN] Daemon bundle replaced on disk, handing off to new daemon");
8444
8948
  clearInterval(restartOnStaleVersionAndHeartbeat);
8445
8949
  clearInterval(cliUpdateInterval);
8950
+ claudeAuthService.stop();
8951
+ claudeAuthService.stop();
8446
8952
  apiMachine.shutdown();
8447
8953
  await stopControlServer();
8448
8954
  await cleanupDaemonState();
@@ -9436,7 +9942,7 @@ const MAX_TITLE_CHARS = 60;
9436
9942
  const GENERATION_TIMEOUT_MS = 3e4;
9437
9943
  function resolveClaudeBinary() {
9438
9944
  try {
9439
- const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-uc-dtu-3.cjs', document.baseURI).href)));
9945
+ const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-BD2fHJ8o.cjs', document.baseURI).href)));
9440
9946
  const utilsPath = path.resolve(path.join(persistence.projectPath(), "scripts", "claude_version_utils.cjs"));
9441
9947
  const { getClaudeCliPath } = require$1(utilsPath);
9442
9948
  const path$1 = getClaudeCliPath();
@@ -11631,9 +12137,9 @@ function resolveLocalSignupBootstrap(configuredMode, configuredInviteCodes, gene
11631
12137
  };
11632
12138
  }
11633
12139
 
11634
- const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-uc-dtu-3.cjs', document.baseURI).href)));
12140
+ const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-BD2fHJ8o.cjs', document.baseURI).href)));
11635
12141
  const __dirname$1 = path.dirname(__filename$1);
11636
- const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-uc-dtu-3.cjs', document.baseURI).href)));
12142
+ const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-BD2fHJ8o.cjs', document.baseURI).href)));
11637
12143
  const PRISMA_QUERY_ENGINE_FILES = {
11638
12144
  "arm64-darwin": "libquery_engine-darwin-arm64.dylib.node",
11639
12145
  "x64-darwin": "libquery_engine-darwin.dylib.node",
@@ -14257,7 +14763,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14257
14763
  process.exit(0);
14258
14764
  } else if (subcommand === "install-terminal-hooks") {
14259
14765
  try {
14260
- const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-CepXxAM_.cjs'); });
14766
+ const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-H3kpFEZS.cjs'); });
14261
14767
  const command = parseTerminalHooksArgs(args.slice(1));
14262
14768
  if (command.action === "help") {
14263
14769
  console.log(TERMINAL_HOOKS_HELP);
@@ -14274,7 +14780,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14274
14780
  }
14275
14781
  } else if (subcommand === "spawn") {
14276
14782
  try {
14277
- const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-vOZA0kOi.cjs'); });
14783
+ const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-xdCsG2RT.cjs'); });
14278
14784
  await handleSpawnCommand(args.slice(1));
14279
14785
  } catch (error) {
14280
14786
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -14286,7 +14792,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14286
14792
  return;
14287
14793
  } else if (subcommand === "send") {
14288
14794
  try {
14289
- const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-6eY55o3C.cjs'); });
14795
+ const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-tyKG13xt.cjs'); });
14290
14796
  await handleSendCommand(args.slice(1));
14291
14797
  } catch (error) {
14292
14798
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -14392,9 +14898,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14392
14898
  if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
14393
14899
  const projectId = args[3];
14394
14900
  try {
14395
- const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-BjsUeQPA.cjs'); });
14396
- const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./types-okYCRlgl.cjs'); }).then(function (n) { return n.persistence; });
14397
- const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-okYCRlgl.cjs'); }).then(function (n) { return n.api; });
14901
+ const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-COq6X7U7.cjs'); });
14902
+ const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./types-DoGaKVfK.cjs'); }).then(function (n) { return n.persistence; });
14903
+ const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-DoGaKVfK.cjs'); }).then(function (n) { return n.api; });
14398
14904
  let userEmail = void 0;
14399
14905
  try {
14400
14906
  const credentials = await readCredentialsForConfiguredRelay2();
@@ -14425,7 +14931,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14425
14931
  }
14426
14932
  if (geminiSubcommand === "project" && args[2] === "get") {
14427
14933
  try {
14428
- const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-BjsUeQPA.cjs'); });
14934
+ const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-COq6X7U7.cjs'); });
14429
14935
  const config = readGeminiLocalConfig();
14430
14936
  if (config.googleCloudProject) {
14431
14937
  console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
@@ -14465,7 +14971,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14465
14971
  process.exit(0);
14466
14972
  }
14467
14973
  try {
14468
- const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-qStPY5fH.cjs'); });
14974
+ const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-w35qiFBB.cjs'); });
14469
14975
  let startedBy = void 0;
14470
14976
  for (let i = 1; i < args.length; i++) {
14471
14977
  if (args[i] === "--started-by") {
@@ -14487,7 +14993,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14487
14993
  return;
14488
14994
  } else if (subcommand === "acp") {
14489
14995
  try {
14490
- const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-DID1FV_n.cjs'); });
14996
+ const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-Dn0iOBFd.cjs'); });
14491
14997
  let startedBy = void 0;
14492
14998
  let verbose = false;
14493
14999
  const acpArgs = [];
@@ -14527,7 +15033,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14527
15033
  return;
14528
15034
  } else if (subcommand === "openclaw") {
14529
15035
  try {
14530
- const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-B8HR6GnX.cjs'); });
15036
+ const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-CkHtTCpI.cjs'); });
14531
15037
  let startedBy = void 0;
14532
15038
  let verbose = false;
14533
15039
  let gatewayUrl;
@@ -14578,7 +15084,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
14578
15084
  return;
14579
15085
  } else if (subcommand === "mcp" && args.length === 1) {
14580
15086
  try {
14581
- const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-CAtbtTXF.cjs'); });
15087
+ const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-BwNc5eRs.cjs'); });
14582
15088
  await handleMcpCommand();
14583
15089
  } catch (error) {
14584
15090
  process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}