very-happy-cli 0.2.95 → 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-Cuiff4Nu.mjs → AcpBackend-CTUM4dvG.mjs} +1 -1
  2. package/dist/{AcpBackend-BXsbwTbl.cjs → AcpBackend-DrwdVSeJ.cjs} +1 -1
  3. package/dist/{AcpSessionManager-BXGmMoe8.cjs → AcpSessionManager-BieE187D.cjs} +1 -1
  4. package/dist/{AcpSessionManager-BU69q_vR.mjs → AcpSessionManager-BoBuHee3.mjs} +1 -1
  5. package/dist/{config-BVOE0pni.cjs → config-COq6X7U7.cjs} +3 -3
  6. package/dist/{config-2GD21yg_.mjs → config-DCH33LOM.mjs} +3 -3
  7. package/dist/{index-BzbaMrIa.cjs → index-BD2fHJ8o.cjs} +526 -20
  8. package/dist/{index-DVEdpWq0.mjs → index-Bcgquogx.mjs} +527 -21
  9. package/dist/{index-DZ0uw6ef.mjs → index-DkhMvofH.mjs} +6 -6
  10. package/dist/{index-CbPc1iVx.cjs → index-Dn0iOBFd.cjs} +5 -5
  11. package/dist/index.cjs +3 -3
  12. package/dist/index.mjs +3 -3
  13. package/dist/{installTerminalHooks-FiujjEvb.mjs → installTerminalHooks-DqNtW6a2.mjs} +3 -3
  14. package/dist/{installTerminalHooks-BrrsyTMd.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-0mZcHPtz.mjs → mcp-BKAuzaLX.mjs} +3 -3
  20. package/dist/{mcp-ziyMk3eS.cjs → mcp-BwNc5eRs.cjs} +3 -3
  21. package/dist/{runGemini-D_InkOhk.mjs → runGemini-Brp0UmLx.mjs} +5 -5
  22. package/dist/{runGemini-C91O1oxi.cjs → runGemini-w35qiFBB.cjs} +5 -5
  23. package/dist/{runOpenClaw-BjebGmV6.mjs → runOpenClaw-BvPRFx-L.mjs} +4 -4
  24. package/dist/{runOpenClaw-B1RRfA1V.cjs → runOpenClaw-CkHtTCpI.cjs} +4 -4
  25. package/dist/{send-CxLL0z9J.mjs → send-c-wEmh5U.mjs} +3 -3
  26. package/dist/{send-DgK6MtgT.cjs → send-tyKG13xt.cjs} +3 -3
  27. package/dist/{spawn-Dian7x_g.cjs → spawn-xdCsG2RT.cjs} +3 -3
  28. package/dist/{spawn-uTPD3qOt.mjs → spawn-yS6yY8Xi.mjs} +3 -3
  29. package/dist/{types-HRuZ13LS.cjs → types-DoGaKVfK.cjs} +88 -11
  30. package/dist/{types-BLE8Hfmh.mjs → types-xZOYW0_G.mjs} +87 -11
  31. package/package.json +7 -7
  32. package/scripts/shims/keychain-off/security +51 -0
@@ -51,7 +51,7 @@ var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
51
51
  var pty__namespace = /*#__PURE__*/_interopNamespaceDefault(pty);
52
52
 
53
53
  var name = "very-happy-cli";
54
- var version = "0.2.95";
54
+ var version = "0.2.97";
55
55
  var description = "Remote multi-agent workspace CLI with deep Claude integration, native terminal streaming, and self-hosting.";
56
56
  var author = "Kirill Dubovitskiy";
57
57
  var contributors = [
@@ -164,12 +164,12 @@ var dependencies = {
164
164
  zod: "^4.0.0"
165
165
  };
166
166
  var optionalDependencies = {
167
- "very-happy-tools-arm64-darwin": "0.2.95",
168
- "very-happy-tools-x64-darwin": "0.2.95",
169
- "very-happy-tools-arm64-linux": "0.2.95",
170
- "very-happy-tools-x64-linux": "0.2.95",
171
- "very-happy-tools-arm64-win32": "0.2.95",
172
- "very-happy-tools-x64-win32": "0.2.95"
167
+ "very-happy-tools-arm64-darwin": "0.2.97",
168
+ "very-happy-tools-x64-darwin": "0.2.97",
169
+ "very-happy-tools-arm64-linux": "0.2.97",
170
+ "very-happy-tools-x64-linux": "0.2.97",
171
+ "very-happy-tools-arm64-win32": "0.2.97",
172
+ "very-happy-tools-x64-win32": "0.2.97"
173
173
  };
174
174
  var devDependencies = {
175
175
  "@slopus/happy-wire": "workspace:*",
@@ -1002,6 +1002,22 @@ z.z.object({
1002
1002
  detectedAt: z.z.number()
1003
1003
  }).optional()
1004
1004
  });
1005
+ const ClaudeAuthStateSchema = z.z.object({
1006
+ probeVersion: z.z.number(),
1007
+ daemonPid: z.z.number(),
1008
+ status: z.z.union([z.z.enum(["ok", "not-logged-in", "unknown", "error", "claude-missing"]), z.z.string()]),
1009
+ authMethod: z.z.string().optional(),
1010
+ subscriptionType: z.z.string().optional(),
1011
+ diagnosis: z.z.string().optional(),
1012
+ detail: z.z.string().optional(),
1013
+ repairable: z.z.string().optional(),
1014
+ context: z.z.object({
1015
+ platform: z.z.string(),
1016
+ lineage: z.z.string(),
1017
+ credentialStore: z.z.string()
1018
+ }),
1019
+ checkedAt: z.z.number()
1020
+ });
1005
1021
  const CliUpdateStateSchema = z.z.object({
1006
1022
  currentVersion: z.z.string(),
1007
1023
  recommendedVersion: z.z.string().nullable(),
@@ -1096,7 +1112,15 @@ z.z.object({
1096
1112
  detectedAt: z.z.number()
1097
1113
  }).optional(),
1098
1114
  /** Relay-owned CLI compatibility/update policy last checked by this daemon. */
1099
- cliUpdate: CliUpdateStateSchema.optional()
1115
+ cliUpdate: CliUpdateStateSchema.optional(),
1116
+ /**
1117
+ * B-276: result of the daemon-context Claude auth preflight (spec
1118
+ * 2026-09-claude-auth-preflight). Trust rule for consumers:
1119
+ * `claudeAuth.daemonPid === daemonState.pid` — daemonState survives daemon
1120
+ * restarts (the server returns the existing row and connect spreads it
1121
+ * forward), so a downgraded daemon carries this field along unchanged.
1122
+ */
1123
+ claudeAuth: ClaudeAuthStateSchema.optional()
1100
1124
  });
1101
1125
  const MessageMetaSchema = z.z.object({
1102
1126
  sentFrom: z.z.string().optional(),
@@ -1545,7 +1569,7 @@ class RpcHandlerManager {
1545
1569
  }
1546
1570
  }
1547
1571
 
1548
- const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-HRuZ13LS.cjs', document.baseURI).href))));
1572
+ const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-DoGaKVfK.cjs', document.baseURI).href))));
1549
1573
  function projectPath() {
1550
1574
  const path = path$1.resolve(__dirname$1, "..");
1551
1575
  return path;
@@ -10368,8 +10392,18 @@ function resolveDefaultShell(platform, env, isExecutable = (path) => {
10368
10392
  function defaultShell() {
10369
10393
  return resolveDefaultShell(process.platform, process.env);
10370
10394
  }
10395
+ const VH_SESSION_OPTION_OVERRIDES = [
10396
+ ["session", "destroy-unattached", "off"],
10397
+ ["window", "remain-on-exit", "off"],
10398
+ ["window", "window-size", "latest"],
10399
+ ["window", "pane-border-status", "off"]
10400
+ ];
10371
10401
  function tmuxNewSessionArgs(session, cols, rows, cwd, envFlags, shell) {
10372
- return ["new-session", "-d", ...envFlags, "-s", session, "-x", String(cols), "-y", String(rows), "-c", cwd, shell];
10402
+ const args = ["new-session", "-d", ...envFlags, "-s", session, "-x", String(cols), "-y", String(rows), "-c", cwd, shell];
10403
+ for (const [scope, option, value] of VH_SESSION_OPTION_OVERRIDES) {
10404
+ args.push(";", "set-option", ...scope === "window" ? ["-w"] : [], "-q", "-t", `=${session}:`, option, value);
10405
+ }
10406
+ return args;
10373
10407
  }
10374
10408
  function shouldUseDirectPtyFallback(attachOnly, createdNew, sessionAlive) {
10375
10409
  return !attachOnly && !createdNew && !sessionAlive;
@@ -13771,6 +13805,7 @@ class ApiMachineClient {
13771
13805
  lastKnownResumeSupport = null;
13772
13806
  cliUpdateState = null;
13773
13807
  cliUpdatePushChain = Promise.resolve();
13808
+ claudeAuthState = null;
13774
13809
  rpcHandlerManager;
13775
13810
  resumeSessionHandler = null;
13776
13811
  restartSessionHandler = null;
@@ -13837,6 +13872,44 @@ class ApiMachineClient {
13837
13872
  if (!this.socket?.connected) return;
13838
13873
  this.cliUpdatePushChain = this.cliUpdatePushChain.then(() => this.updateDaemonState((current) => withCurrentCliUpdateState(current, this.cliUpdateState))).catch((error) => logger.debug("[API MACHINE] Failed to publish CLI update policy:", error));
13839
13874
  }
13875
+ /**
13876
+ * B-276: publish the daemon-context Claude auth preflight into daemonState
13877
+ * (same serialized push chain as the CLI update policy). Resolves true when
13878
+ * the server acknowledged the write with our value in it, false otherwise
13879
+ * (rate-limit `result:'error'` is swallowed by updateDaemonState, so the
13880
+ * caller checks the echoed state and re-sends on the next probe).
13881
+ */
13882
+ setClaudeAuthState(state) {
13883
+ this.claudeAuthState = state;
13884
+ if (!this.socket?.connected) return Promise.resolve(false);
13885
+ const attempt = this.cliUpdatePushChain.then(() => this.updateDaemonState((current) => ({
13886
+ ...current ?? {},
13887
+ status: current?.status ?? "running",
13888
+ claudeAuth: state
13889
+ }))).then(() => this.machine.daemonState?.claudeAuth?.checkedAt === state.checkedAt && this.machine.daemonState?.claudeAuth?.daemonPid === state.daemonPid).catch((error) => {
13890
+ logger.debug("[API MACHINE] Failed to publish Claude auth state:", error);
13891
+ return false;
13892
+ });
13893
+ this.cliUpdatePushChain = attempt.then(() => void 0);
13894
+ return attempt;
13895
+ }
13896
+ /** B-276 machine RPCs. Responses always carry `claudeAuth` so the web can refresh in place. */
13897
+ setClaudeAuthHandlers(handlers) {
13898
+ this.rpcHandlerManager.registerHandler("claude-auth-probe", async () => {
13899
+ const claudeAuth = await handlers.probe();
13900
+ return { claudeAuth };
13901
+ });
13902
+ this.rpcHandlerManager.registerHandler("claude-auth-repair", async (params) => {
13903
+ const action = typeof params?.action === "string" ? params.action : "";
13904
+ return handlers.repair(action);
13905
+ });
13906
+ this.rpcHandlerManager.registerHandler("claude-auth-set-store", async (params) => {
13907
+ const store = params?.store === "file" ? "file" : params?.store === "auto" ? "auto" : null;
13908
+ if (!store) return { error: "invalid-store", claudeAuth: this.claudeAuthState };
13909
+ const claudeAuth = await handlers.setStore(store);
13910
+ return { claudeAuth };
13911
+ });
13912
+ }
13840
13913
  setRPCHandlers({
13841
13914
  spawnSession,
13842
13915
  resumeSession,
@@ -14351,7 +14424,10 @@ class ApiMachineClient {
14351
14424
  // B-084: closed records survive daemon restarts (persisted
14352
14425
  // in closed-terminals.json), so the connect snapshot ships
14353
14426
  // them too — not just the incremental pushes.
14354
- closedTerminals: this.webTerminal.getClosedTerminals()
14427
+ closedTerminals: this.webTerminal.getClosedTerminals(),
14428
+ // B-276: re-ship the last preflight so a reconnect never
14429
+ // leaves a stale-pid value visible longer than needed.
14430
+ ...this.claudeAuthState ? { claudeAuth: this.claudeAuthState } : {}
14355
14431
  };
14356
14432
  });
14357
14433
  this.webTerminal.startListTracking((terminals) => this.pushTerminalList(terminals));
@@ -15763,3 +15839,4 @@ exports.writeCredentialsDataKey = writeCredentialsDataKey;
15763
15839
  exports.writeCredentialsLegacy = writeCredentialsLegacy;
15764
15840
  exports.writeDaemonState = writeDaemonState;
15765
15841
  exports.writePrivateFileSync = writePrivateFileSync;
15842
+ exports.writeSettings = writeSettings;
@@ -29,7 +29,7 @@ import { SandboxManager } from '@anthropic-ai/sandbox-runtime';
29
29
  import { Expo } from 'expo-server-sdk';
30
30
 
31
31
  var name = "very-happy-cli";
32
- var version = "0.2.95";
32
+ var version = "0.2.97";
33
33
  var description = "Remote multi-agent workspace CLI with deep Claude integration, native terminal streaming, and self-hosting.";
34
34
  var author = "Kirill Dubovitskiy";
35
35
  var contributors = [
@@ -142,12 +142,12 @@ var dependencies = {
142
142
  zod: "^4.0.0"
143
143
  };
144
144
  var optionalDependencies = {
145
- "very-happy-tools-arm64-darwin": "0.2.95",
146
- "very-happy-tools-x64-darwin": "0.2.95",
147
- "very-happy-tools-arm64-linux": "0.2.95",
148
- "very-happy-tools-x64-linux": "0.2.95",
149
- "very-happy-tools-arm64-win32": "0.2.95",
150
- "very-happy-tools-x64-win32": "0.2.95"
145
+ "very-happy-tools-arm64-darwin": "0.2.97",
146
+ "very-happy-tools-x64-darwin": "0.2.97",
147
+ "very-happy-tools-arm64-linux": "0.2.97",
148
+ "very-happy-tools-x64-linux": "0.2.97",
149
+ "very-happy-tools-arm64-win32": "0.2.97",
150
+ "very-happy-tools-x64-win32": "0.2.97"
151
151
  };
152
152
  var devDependencies = {
153
153
  "@slopus/happy-wire": "workspace:*",
@@ -980,6 +980,22 @@ z$1.object({
980
980
  detectedAt: z$1.number()
981
981
  }).optional()
982
982
  });
983
+ const ClaudeAuthStateSchema = z$1.object({
984
+ probeVersion: z$1.number(),
985
+ daemonPid: z$1.number(),
986
+ status: z$1.union([z$1.enum(["ok", "not-logged-in", "unknown", "error", "claude-missing"]), z$1.string()]),
987
+ authMethod: z$1.string().optional(),
988
+ subscriptionType: z$1.string().optional(),
989
+ diagnosis: z$1.string().optional(),
990
+ detail: z$1.string().optional(),
991
+ repairable: z$1.string().optional(),
992
+ context: z$1.object({
993
+ platform: z$1.string(),
994
+ lineage: z$1.string(),
995
+ credentialStore: z$1.string()
996
+ }),
997
+ checkedAt: z$1.number()
998
+ });
983
999
  const CliUpdateStateSchema = z$1.object({
984
1000
  currentVersion: z$1.string(),
985
1001
  recommendedVersion: z$1.string().nullable(),
@@ -1074,7 +1090,15 @@ z$1.object({
1074
1090
  detectedAt: z$1.number()
1075
1091
  }).optional(),
1076
1092
  /** Relay-owned CLI compatibility/update policy last checked by this daemon. */
1077
- cliUpdate: CliUpdateStateSchema.optional()
1093
+ cliUpdate: CliUpdateStateSchema.optional(),
1094
+ /**
1095
+ * B-276: result of the daemon-context Claude auth preflight (spec
1096
+ * 2026-09-claude-auth-preflight). Trust rule for consumers:
1097
+ * `claudeAuth.daemonPid === daemonState.pid` — daemonState survives daemon
1098
+ * restarts (the server returns the existing row and connect spreads it
1099
+ * forward), so a downgraded daemon carries this field along unchanged.
1100
+ */
1101
+ claudeAuth: ClaudeAuthStateSchema.optional()
1078
1102
  });
1079
1103
  const MessageMetaSchema = z$1.object({
1080
1104
  sentFrom: z$1.string().optional(),
@@ -10346,8 +10370,18 @@ function resolveDefaultShell(platform, env, isExecutable = (path) => {
10346
10370
  function defaultShell() {
10347
10371
  return resolveDefaultShell(process.platform, process.env);
10348
10372
  }
10373
+ const VH_SESSION_OPTION_OVERRIDES = [
10374
+ ["session", "destroy-unattached", "off"],
10375
+ ["window", "remain-on-exit", "off"],
10376
+ ["window", "window-size", "latest"],
10377
+ ["window", "pane-border-status", "off"]
10378
+ ];
10349
10379
  function tmuxNewSessionArgs(session, cols, rows, cwd, envFlags, shell) {
10350
- return ["new-session", "-d", ...envFlags, "-s", session, "-x", String(cols), "-y", String(rows), "-c", cwd, shell];
10380
+ const args = ["new-session", "-d", ...envFlags, "-s", session, "-x", String(cols), "-y", String(rows), "-c", cwd, shell];
10381
+ for (const [scope, option, value] of VH_SESSION_OPTION_OVERRIDES) {
10382
+ args.push(";", "set-option", ...scope === "window" ? ["-w"] : [], "-q", "-t", `=${session}:`, option, value);
10383
+ }
10384
+ return args;
10351
10385
  }
10352
10386
  function shouldUseDirectPtyFallback(attachOnly, createdNew, sessionAlive) {
10353
10387
  return !attachOnly && !createdNew && !sessionAlive;
@@ -13749,6 +13783,7 @@ class ApiMachineClient {
13749
13783
  lastKnownResumeSupport = null;
13750
13784
  cliUpdateState = null;
13751
13785
  cliUpdatePushChain = Promise.resolve();
13786
+ claudeAuthState = null;
13752
13787
  rpcHandlerManager;
13753
13788
  resumeSessionHandler = null;
13754
13789
  restartSessionHandler = null;
@@ -13815,6 +13850,44 @@ class ApiMachineClient {
13815
13850
  if (!this.socket?.connected) return;
13816
13851
  this.cliUpdatePushChain = this.cliUpdatePushChain.then(() => this.updateDaemonState((current) => withCurrentCliUpdateState(current, this.cliUpdateState))).catch((error) => logger.debug("[API MACHINE] Failed to publish CLI update policy:", error));
13817
13852
  }
13853
+ /**
13854
+ * B-276: publish the daemon-context Claude auth preflight into daemonState
13855
+ * (same serialized push chain as the CLI update policy). Resolves true when
13856
+ * the server acknowledged the write with our value in it, false otherwise
13857
+ * (rate-limit `result:'error'` is swallowed by updateDaemonState, so the
13858
+ * caller checks the echoed state and re-sends on the next probe).
13859
+ */
13860
+ setClaudeAuthState(state) {
13861
+ this.claudeAuthState = state;
13862
+ if (!this.socket?.connected) return Promise.resolve(false);
13863
+ const attempt = this.cliUpdatePushChain.then(() => this.updateDaemonState((current) => ({
13864
+ ...current ?? {},
13865
+ status: current?.status ?? "running",
13866
+ claudeAuth: state
13867
+ }))).then(() => this.machine.daemonState?.claudeAuth?.checkedAt === state.checkedAt && this.machine.daemonState?.claudeAuth?.daemonPid === state.daemonPid).catch((error) => {
13868
+ logger.debug("[API MACHINE] Failed to publish Claude auth state:", error);
13869
+ return false;
13870
+ });
13871
+ this.cliUpdatePushChain = attempt.then(() => void 0);
13872
+ return attempt;
13873
+ }
13874
+ /** B-276 machine RPCs. Responses always carry `claudeAuth` so the web can refresh in place. */
13875
+ setClaudeAuthHandlers(handlers) {
13876
+ this.rpcHandlerManager.registerHandler("claude-auth-probe", async () => {
13877
+ const claudeAuth = await handlers.probe();
13878
+ return { claudeAuth };
13879
+ });
13880
+ this.rpcHandlerManager.registerHandler("claude-auth-repair", async (params) => {
13881
+ const action = typeof params?.action === "string" ? params.action : "";
13882
+ return handlers.repair(action);
13883
+ });
13884
+ this.rpcHandlerManager.registerHandler("claude-auth-set-store", async (params) => {
13885
+ const store = params?.store === "file" ? "file" : params?.store === "auto" ? "auto" : null;
13886
+ if (!store) return { error: "invalid-store", claudeAuth: this.claudeAuthState };
13887
+ const claudeAuth = await handlers.setStore(store);
13888
+ return { claudeAuth };
13889
+ });
13890
+ }
13818
13891
  setRPCHandlers({
13819
13892
  spawnSession,
13820
13893
  resumeSession,
@@ -14329,7 +14402,10 @@ class ApiMachineClient {
14329
14402
  // B-084: closed records survive daemon restarts (persisted
14330
14403
  // in closed-terminals.json), so the connect snapshot ships
14331
14404
  // them too — not just the incremental pushes.
14332
- closedTerminals: this.webTerminal.getClosedTerminals()
14405
+ closedTerminals: this.webTerminal.getClosedTerminals(),
14406
+ // B-276: re-ship the last preflight so a reconnect never
14407
+ // leaves a stale-pid value visible longer than needed.
14408
+ ...this.claudeAuthState ? { claudeAuth: this.claudeAuthState } : {}
14333
14409
  };
14334
14410
  });
14335
14411
  this.webTerminal.startListTracking((terminals) => this.pushTerminalList(terminals));
@@ -15664,4 +15740,4 @@ const RawJSONLinesSchema = z$1.discriminatedUnion("type", [
15664
15740
  }).passthrough()
15665
15741
  ]);
15666
15742
 
15667
- export { detectResumeSupport as $, ApiClient as A, deriveLocalCliUpdateSummary as B, updateSettings as C, encodeBase64Url as D, decodeBase64 as E, writeCredentialsLegacy as F, writeCredentialsDataKey as G, readCredentialsForConfiguredRelay as H, InvalidateSync as I, encrypt as J, isClaudeSessionId as K, getLocalHappyAgentCredentialPath as L, MAX_CHAT_ATTACHMENT_SOURCE_BYTES as M, readLocalHappyAgentCredentials as N, decryptWithDataKey as O, decryptLegacy as P, extractCompleteLines as Q, RawJSONLinesSchema as R, decideBackfill as S, parseTerminalHookPayload as T, tmuxArgs as U, scrubTmuxClientEnv as V, decideMirrorBinding as W, MIRROR_BACKFILL_LINES_DEFAULT as X, persistSession as Y, mirrorLineKey as Z, mirrorLocalId as _, ApiSessionClient as a, detectCLIAvailability as a0, acquireDaemonLock as a1, summarizeSpawnSessionForLog as a2, deletePersistedSessions as a3, decrypt as a4, writeDaemonState as a5, fetchCliUpdateState as a6, resolveCliUpdateCheckInterval as a7, DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS as a8, releaseDaemonLock as a9, isValidSessionId as aa, listVhTerminals as ab, isValidTerminalId as ac, readVhTerminal as ad, sendToVhTerminal as ae, startOfflineReconnection as af, clearCredentials as ag, clearMachineId as ah, SandboxConfigSchema as ai, CodexAppServerClient as aj, getLatestDaemonLog as ak, persistence as al, api as am, createEnvelope as b, configuration as c, contentLogMetadata as d, errorLogMetadata as e, packageJson as f, delay as g, connectionState as h, readSettings as i, encodeBase64 as j, ensurePrivateDirectorySync as k, logger as l, hardenPrivateFileSync as m, readDaemonState as n, clearDaemonState as o, projectPath as p, getProjectPath as q, readPersistedSessions as r, initializeSandbox as s, wrapCommand as t, AsyncLock as u, ensurePrivateDirectory as v, writePrivateFileSync as w, hardenPrivateFile as x, readCredentials as y, credentialRelayProblem as z };
15743
+ export { detectResumeSupport as $, ApiClient as A, deriveLocalCliUpdateSummary as B, updateSettings as C, encodeBase64Url as D, decodeBase64 as E, writeCredentialsLegacy as F, writeCredentialsDataKey as G, readCredentialsForConfiguredRelay as H, InvalidateSync as I, encrypt as J, isClaudeSessionId as K, getLocalHappyAgentCredentialPath as L, MAX_CHAT_ATTACHMENT_SOURCE_BYTES as M, readLocalHappyAgentCredentials as N, decryptWithDataKey as O, decryptLegacy as P, extractCompleteLines as Q, RawJSONLinesSchema as R, decideBackfill as S, parseTerminalHookPayload as T, tmuxArgs as U, scrubTmuxClientEnv as V, decideMirrorBinding as W, MIRROR_BACKFILL_LINES_DEFAULT as X, persistSession as Y, mirrorLineKey as Z, mirrorLocalId as _, ApiSessionClient as a, detectCLIAvailability as a0, acquireDaemonLock as a1, summarizeSpawnSessionForLog as a2, deletePersistedSessions as a3, decrypt as a4, writeDaemonState as a5, writeSettings as a6, fetchCliUpdateState as a7, resolveCliUpdateCheckInterval as a8, DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS as a9, releaseDaemonLock as aa, isValidSessionId as ab, listVhTerminals as ac, isValidTerminalId as ad, readVhTerminal as ae, sendToVhTerminal as af, startOfflineReconnection as ag, clearCredentials as ah, clearMachineId as ai, SandboxConfigSchema as aj, CodexAppServerClient as ak, getLatestDaemonLog as al, persistence as am, api as an, createEnvelope as b, configuration as c, contentLogMetadata as d, errorLogMetadata as e, packageJson as f, delay as g, connectionState as h, readSettings as i, encodeBase64 as j, ensurePrivateDirectorySync as k, logger as l, hardenPrivateFileSync as m, readDaemonState as n, clearDaemonState as o, projectPath as p, getProjectPath as q, readPersistedSessions as r, initializeSandbox as s, wrapCommand as t, AsyncLock as u, ensurePrivateDirectory as v, writePrivateFileSync as w, hardenPrivateFile as x, readCredentials as y, credentialRelayProblem as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "very-happy-cli",
3
- "version": "0.2.95",
3
+ "version": "0.2.97",
4
4
  "description": "Remote multi-agent workspace CLI with deep Claude integration, native terminal streaming, and self-hosting.",
5
5
  "author": "Kirill Dubovitskiy",
6
6
  "contributors": [
@@ -113,12 +113,12 @@
113
113
  "zod": "^4.0.0"
114
114
  },
115
115
  "optionalDependencies": {
116
- "very-happy-tools-arm64-darwin": "0.2.95",
117
- "very-happy-tools-x64-darwin": "0.2.95",
118
- "very-happy-tools-arm64-linux": "0.2.95",
119
- "very-happy-tools-x64-linux": "0.2.95",
120
- "very-happy-tools-arm64-win32": "0.2.95",
121
- "very-happy-tools-x64-win32": "0.2.95"
116
+ "very-happy-tools-arm64-darwin": "0.2.97",
117
+ "very-happy-tools-x64-darwin": "0.2.97",
118
+ "very-happy-tools-arm64-linux": "0.2.97",
119
+ "very-happy-tools-x64-linux": "0.2.97",
120
+ "very-happy-tools-arm64-win32": "0.2.97",
121
+ "very-happy-tools-x64-win32": "0.2.97"
122
122
  },
123
123
  "devDependencies": {
124
124
  "@slopus/happy-wire": "workspace:*",
@@ -0,0 +1,51 @@
1
+ #!/bin/bash
2
+ # very-happy keychain-off shim for Claude Code (B-276, spec 2026-09-claude-auth-preflight D8).
3
+ #
4
+ # Placed FIRST on PATH only for the Claude Code processes very-happy spawns when
5
+ # the machine-local setting `claudeCredentialStore` is `file`. Claude Code reads
6
+ # and writes its OAuth credentials through the bare `security` CLI; an exit code
7
+ # of 36 (errSecInteractionNotAllowed) on its own keychain item makes it fall
8
+ # back to ~/.claude/.credentials.json for reads AND writes without deleting the
9
+ # file — exactly what an ssh/tmux shell sees. Everything that is not Claude
10
+ # Code's own item is passed through to the real binary untouched.
11
+ #
12
+ # Exit code MUST be 36 or 44: anything else is treated by Claude Code as a
13
+ # transient READ_FAILED (cached credentials), not as "use the file".
14
+ REAL="${HAPPY_SECURITY_BIN:-/usr/bin/security}"
15
+
16
+ is_claude_item() {
17
+ # $@ = tokens of one security command line; true when -s <value> starts with "Claude Code"
18
+ local prev="" tok
19
+ for tok in "$@"; do
20
+ if [ "$prev" = "-s" ]; then
21
+ tok="${tok%\"}"; tok="${tok#\"}"; tok="${tok%\'}"; tok="${tok#\'}"
22
+ case "$tok" in "Claude Code"*) return 0 ;; esac
23
+ return 1
24
+ fi
25
+ prev="$tok"
26
+ done
27
+ return 1
28
+ }
29
+
30
+ case "${1:-}" in
31
+ show-keychain-info)
32
+ exit 36 ;;
33
+ find-generic-password|add-generic-password|delete-generic-password)
34
+ if is_claude_item "$@"; then exit 36; fi
35
+ exec "$REAL" "$@" ;;
36
+ -i)
37
+ # Interactive form: Claude Code's normal write path feeds
38
+ # `add-generic-password -U -a <user> -s "<service>" -X <hex>` on stdin.
39
+ input="$(cat)"
40
+ first_line="$(printf '%s\n' "$input" | sed -n '1p')"
41
+ case "$first_line" in
42
+ find-generic-password*|add-generic-password*|delete-generic-password*)
43
+ if [[ "$first_line" =~ (^|[[:space:]])-s[[:space:]]+(\"([^\"]*)\"|\'([^\']*)\'|([^[:space:]]+)) ]]; then
44
+ svc="${BASH_REMATCH[3]}${BASH_REMATCH[4]}${BASH_REMATCH[5]}"
45
+ case "$svc" in "Claude Code"*) exit 36 ;; esac
46
+ fi ;;
47
+ esac
48
+ printf '%s\n' "$input" | exec "$REAL" -i ;;
49
+ *)
50
+ exec "$REAL" "$@" ;;
51
+ esac