very-happy-cli 0.2.96 → 0.2.98
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.
- package/dist/{AcpBackend-B5Eh8G3W.mjs → AcpBackend-BXiGiFC7.mjs} +1 -1
- package/dist/{AcpBackend-BaCt4_zS.cjs → AcpBackend-DhR8ml8L.cjs} +1 -1
- package/dist/{AcpSessionManager-grr_aJEI.mjs → AcpSessionManager-CDnrxAfQ.mjs} +1 -1
- package/dist/{AcpSessionManager-CvgmPlXB.cjs → AcpSessionManager-Ckc0NFmf.cjs} +1 -1
- package/dist/{config-B69TZlJj.mjs → config-B3pA9YsN.mjs} +3 -3
- package/dist/{config-BjsUeQPA.cjs → config-GJQc_kpD.cjs} +3 -3
- package/dist/{index-DID1FV_n.cjs → index-BBm2b34F.cjs} +5 -5
- package/dist/{index-C-uJXSm3.mjs → index-Bh5Rcy0s.mjs} +6 -6
- package/dist/{index-uc-dtu-3.cjs → index-CO1gNtuP.cjs} +528 -25
- package/dist/{index-BMmbxCTq.mjs → index-CuUVSZnK.mjs} +527 -24
- package/dist/index.cjs +3 -3
- package/dist/index.mjs +3 -3
- package/dist/{installTerminalHooks-CepXxAM_.cjs → installTerminalHooks-Cp9JVxQ-.cjs} +3 -3
- package/dist/{installTerminalHooks-CBHjEQ-a.mjs → installTerminalHooks-Ru0dn_zF.mjs} +3 -3
- package/dist/lib.cjs +1 -1
- package/dist/lib.d.cts +77 -0
- package/dist/lib.d.mts +77 -0
- package/dist/lib.mjs +1 -1
- package/dist/{mcp-CAtbtTXF.cjs → mcp-B5HMF24K.cjs} +3 -3
- package/dist/{mcp-BdSHqi2d.mjs → mcp-CQoVN0u2.mjs} +3 -3
- package/dist/{runGemini-qStPY5fH.cjs → runGemini-BBzPVzuc.cjs} +5 -5
- package/dist/{runGemini-cMZ3_CRf.mjs → runGemini-CwZXQsgu.mjs} +5 -5
- package/dist/{runOpenClaw-B8HR6GnX.cjs → runOpenClaw-B4nC6XGL.cjs} +4 -4
- package/dist/{runOpenClaw-BJ36wEbk.mjs → runOpenClaw-C-jz4rWr.mjs} +4 -4
- package/dist/{send-6eY55o3C.cjs → send-CWgaINHC.cjs} +3 -3
- package/dist/{send-TX13v8Xe.mjs → send-DN-nVBEI.mjs} +3 -3
- package/dist/{spawn-vOZA0kOi.cjs → spawn-C0NSP84Y.cjs} +3 -3
- package/dist/{spawn-CfCE6JAv.mjs → spawn-CqcfbOnk.mjs} +3 -3
- package/dist/{types-okYCRlgl.cjs → types-BP-4phS_.cjs} +358 -72
- package/dist/{types-CLRl0ET3.mjs → types-Cl4vWuDY.mjs} +356 -72
- package/package.json +7 -7
- 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-
|
|
6
|
+
var persistence = require('./types-BP-4phS_.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
|
|
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-CO1gNtuP.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 = [];
|
|
@@ -7372,9 +7850,6 @@ async function claimSessionOrExit(happySessionId, options) {
|
|
|
7372
7850
|
process.on("exit", () => releaseSessionLock(happySessionId));
|
|
7373
7851
|
}
|
|
7374
7852
|
|
|
7375
|
-
function shellescape(s) {
|
|
7376
|
-
return "'" + s.replace(/'/g, "'\\''") + "'";
|
|
7377
|
-
}
|
|
7378
7853
|
const hostSuffix = process.env.HAPPY_VARIANT === "dev" ? "-dev" : "";
|
|
7379
7854
|
const initialMachineMetadata = {
|
|
7380
7855
|
host: os$1.hostname() + hostSuffix,
|
|
@@ -7387,6 +7862,8 @@ const initialMachineMetadata = {
|
|
|
7387
7862
|
resumeSupport: { ...persistence.detectResumeSupport(), rpcAvailable: true }
|
|
7388
7863
|
};
|
|
7389
7864
|
async function startDaemon() {
|
|
7865
|
+
let claudeAuthServiceRef = null;
|
|
7866
|
+
let claudeCredentialStoreSetting = (await persistence.readSettings()).claudeCredentialStore === "file" ? "file" : "auto";
|
|
7390
7867
|
let requestShutdown;
|
|
7391
7868
|
let resolvesWhenShutdownRequested = new Promise((resolve) => {
|
|
7392
7869
|
requestShutdown = (source, errorMessage) => {
|
|
@@ -7693,7 +8170,11 @@ async function startDaemon() {
|
|
|
7693
8170
|
}
|
|
7694
8171
|
let extraEnv = {
|
|
7695
8172
|
...authEnv,
|
|
7696
|
-
...options.environmentVariables ?? {}
|
|
8173
|
+
...options.environmentVariables ?? {},
|
|
8174
|
+
// B-276 D8: credentialStore=file pins the spawned Claude Code (SDK
|
|
8175
|
+
// Query, title/board one-shots — all inside this wrapper) to
|
|
8176
|
+
// ~/.claude/.credentials.json via the keychain-off `security` shim.
|
|
8177
|
+
...claudeAuthServiceRef?.claudeProcessEnvOverrides() ?? {}
|
|
7697
8178
|
};
|
|
7698
8179
|
if (options.parentSessionId) {
|
|
7699
8180
|
extraEnv.HAPPY_FORKED_FROM_SESSION_ID = options.parentSessionId;
|
|
@@ -7753,8 +8234,8 @@ async function startDaemon() {
|
|
|
7753
8234
|
const cliPath = path$1.join(persistence.projectPath(), "dist", "index.mjs");
|
|
7754
8235
|
const agent = options.agent === "gemini" ? "gemini" : options.agent === "codex" ? "codex" : options.agent === "openclaw" ? "openclaw" : "claude";
|
|
7755
8236
|
const resumeId = agent === "claude" ? options.resumeClaudeSessionId : agent === "codex" ? options.resumeCodexThreadId : void 0;
|
|
7756
|
-
const resumeFragment = resumeId ? ` --resume ${shellescape(resumeId)}` : "";
|
|
7757
|
-
const permissionModeFragment = spawnPermissionMode ? ` --permission-mode ${shellescape(spawnPermissionMode)}` : "";
|
|
8237
|
+
const resumeFragment = resumeId ? ` --resume ${persistence.shellescape(resumeId)}` : "";
|
|
8238
|
+
const permissionModeFragment = spawnPermissionMode ? ` --permission-mode ${persistence.shellescape(spawnPermissionMode)}` : "";
|
|
7758
8239
|
const fullCommand = `node --no-warnings --no-deprecation ${cliPath} ${agent} --happy-starting-mode remote --started-by daemon${resumeFragment}${permissionModeFragment}`;
|
|
7759
8240
|
const windowName = `happy-${Date.now()}-${agent}`;
|
|
7760
8241
|
const tmuxEnv = {};
|
|
@@ -8319,6 +8800,7 @@ async function startDaemon() {
|
|
|
8319
8800
|
requestShutdown: () => requestShutdown("happy-cli"),
|
|
8320
8801
|
onHappySessionWebhook,
|
|
8321
8802
|
onSessionStateEvent,
|
|
8803
|
+
onClaudeAuthFailed: (sessionId) => claudeAuthServiceRef?.signalAuthFailed(sessionId),
|
|
8322
8804
|
pushClipboard: (text) => {
|
|
8323
8805
|
if (!apiMachineRef) {
|
|
8324
8806
|
return { delivered: false, truncated: false, totalBytes: 0, error: "daemon is still starting up" };
|
|
@@ -8389,6 +8871,25 @@ async function startDaemon() {
|
|
|
8389
8871
|
listTrackedSessionIds: () => [...pidToTrackedSession.values()].map((session) => session.happySessionId).filter((sessionId) => typeof sessionId === "string"),
|
|
8390
8872
|
requestShutdown: () => requestShutdown("happy-app")
|
|
8391
8873
|
});
|
|
8874
|
+
const claudeAuthService = new ClaudeAuthService({
|
|
8875
|
+
happyHomeDir: persistence.configuration.happyHomeDir,
|
|
8876
|
+
happyLibDir: persistence.projectPath(),
|
|
8877
|
+
credentialSource: daemonClaudeCredentials.source,
|
|
8878
|
+
getCredentialStore: () => claudeCredentialStoreSetting,
|
|
8879
|
+
setCredentialStore: async (store) => {
|
|
8880
|
+
const settings = await persistence.readSettings();
|
|
8881
|
+
await persistence.writeSettings({ ...settings, claudeCredentialStore: store });
|
|
8882
|
+
claudeCredentialStoreSetting = store;
|
|
8883
|
+
},
|
|
8884
|
+
publish: (state) => apiMachine.setClaudeAuthState(state)
|
|
8885
|
+
});
|
|
8886
|
+
claudeAuthServiceRef = claudeAuthService;
|
|
8887
|
+
apiMachine.setClaudeAuthHandlers({
|
|
8888
|
+
probe: () => claudeAuthService.probe("rpc", true),
|
|
8889
|
+
repair: (action) => claudeAuthService.repair(action),
|
|
8890
|
+
setStore: (store) => claudeAuthService.setStore(store)
|
|
8891
|
+
});
|
|
8892
|
+
claudeAuthService.start();
|
|
8392
8893
|
apiMachine.connect();
|
|
8393
8894
|
let cliUpdateCheckRunning = false;
|
|
8394
8895
|
const refreshCliUpdate = async () => {
|
|
@@ -8443,6 +8944,8 @@ async function startDaemon() {
|
|
|
8443
8944
|
persistence.logger.debug("[DAEMON RUN] Daemon bundle replaced on disk, handing off to new daemon");
|
|
8444
8945
|
clearInterval(restartOnStaleVersionAndHeartbeat);
|
|
8445
8946
|
clearInterval(cliUpdateInterval);
|
|
8947
|
+
claudeAuthService.stop();
|
|
8948
|
+
claudeAuthService.stop();
|
|
8446
8949
|
apiMachine.shutdown();
|
|
8447
8950
|
await stopControlServer();
|
|
8448
8951
|
await cleanupDaemonState();
|
|
@@ -9436,7 +9939,7 @@ const MAX_TITLE_CHARS = 60;
|
|
|
9436
9939
|
const GENERATION_TIMEOUT_MS = 3e4;
|
|
9437
9940
|
function resolveClaudeBinary() {
|
|
9438
9941
|
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-
|
|
9942
|
+
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-CO1gNtuP.cjs', document.baseURI).href)));
|
|
9440
9943
|
const utilsPath = path.resolve(path.join(persistence.projectPath(), "scripts", "claude_version_utils.cjs"));
|
|
9441
9944
|
const { getClaudeCliPath } = require$1(utilsPath);
|
|
9442
9945
|
const path$1 = getClaudeCliPath();
|
|
@@ -11631,9 +12134,9 @@ function resolveLocalSignupBootstrap(configuredMode, configuredInviteCodes, gene
|
|
|
11631
12134
|
};
|
|
11632
12135
|
}
|
|
11633
12136
|
|
|
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-
|
|
12137
|
+
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-CO1gNtuP.cjs', document.baseURI).href)));
|
|
11635
12138
|
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-
|
|
12139
|
+
const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-CO1gNtuP.cjs', document.baseURI).href)));
|
|
11637
12140
|
const PRISMA_QUERY_ENGINE_FILES = {
|
|
11638
12141
|
"arm64-darwin": "libquery_engine-darwin-arm64.dylib.node",
|
|
11639
12142
|
"x64-darwin": "libquery_engine-darwin.dylib.node",
|
|
@@ -14257,7 +14760,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
14257
14760
|
process.exit(0);
|
|
14258
14761
|
} else if (subcommand === "install-terminal-hooks") {
|
|
14259
14762
|
try {
|
|
14260
|
-
const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-
|
|
14763
|
+
const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-Cp9JVxQ-.cjs'); });
|
|
14261
14764
|
const command = parseTerminalHooksArgs(args.slice(1));
|
|
14262
14765
|
if (command.action === "help") {
|
|
14263
14766
|
console.log(TERMINAL_HOOKS_HELP);
|
|
@@ -14274,7 +14777,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
14274
14777
|
}
|
|
14275
14778
|
} else if (subcommand === "spawn") {
|
|
14276
14779
|
try {
|
|
14277
|
-
const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-
|
|
14780
|
+
const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-C0NSP84Y.cjs'); });
|
|
14278
14781
|
await handleSpawnCommand(args.slice(1));
|
|
14279
14782
|
} catch (error) {
|
|
14280
14783
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -14286,7 +14789,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
14286
14789
|
return;
|
|
14287
14790
|
} else if (subcommand === "send") {
|
|
14288
14791
|
try {
|
|
14289
|
-
const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-
|
|
14792
|
+
const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-CWgaINHC.cjs'); });
|
|
14290
14793
|
await handleSendCommand(args.slice(1));
|
|
14291
14794
|
} catch (error) {
|
|
14292
14795
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -14392,9 +14895,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
14392
14895
|
if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
|
|
14393
14896
|
const projectId = args[3];
|
|
14394
14897
|
try {
|
|
14395
|
-
const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-
|
|
14396
|
-
const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./types-
|
|
14397
|
-
const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-
|
|
14898
|
+
const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-GJQc_kpD.cjs'); });
|
|
14899
|
+
const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./types-BP-4phS_.cjs'); }).then(function (n) { return n.persistence; });
|
|
14900
|
+
const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-BP-4phS_.cjs'); }).then(function (n) { return n.api; });
|
|
14398
14901
|
let userEmail = void 0;
|
|
14399
14902
|
try {
|
|
14400
14903
|
const credentials = await readCredentialsForConfiguredRelay2();
|
|
@@ -14425,7 +14928,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
14425
14928
|
}
|
|
14426
14929
|
if (geminiSubcommand === "project" && args[2] === "get") {
|
|
14427
14930
|
try {
|
|
14428
|
-
const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-
|
|
14931
|
+
const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-GJQc_kpD.cjs'); });
|
|
14429
14932
|
const config = readGeminiLocalConfig();
|
|
14430
14933
|
if (config.googleCloudProject) {
|
|
14431
14934
|
console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
|
|
@@ -14465,7 +14968,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
14465
14968
|
process.exit(0);
|
|
14466
14969
|
}
|
|
14467
14970
|
try {
|
|
14468
|
-
const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-
|
|
14971
|
+
const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-BBzPVzuc.cjs'); });
|
|
14469
14972
|
let startedBy = void 0;
|
|
14470
14973
|
for (let i = 1; i < args.length; i++) {
|
|
14471
14974
|
if (args[i] === "--started-by") {
|
|
@@ -14487,7 +14990,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
14487
14990
|
return;
|
|
14488
14991
|
} else if (subcommand === "acp") {
|
|
14489
14992
|
try {
|
|
14490
|
-
const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-
|
|
14993
|
+
const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-BBm2b34F.cjs'); });
|
|
14491
14994
|
let startedBy = void 0;
|
|
14492
14995
|
let verbose = false;
|
|
14493
14996
|
const acpArgs = [];
|
|
@@ -14527,7 +15030,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
14527
15030
|
return;
|
|
14528
15031
|
} else if (subcommand === "openclaw") {
|
|
14529
15032
|
try {
|
|
14530
|
-
const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-
|
|
15033
|
+
const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-B4nC6XGL.cjs'); });
|
|
14531
15034
|
let startedBy = void 0;
|
|
14532
15035
|
let verbose = false;
|
|
14533
15036
|
let gatewayUrl;
|
|
@@ -14578,7 +15081,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
14578
15081
|
return;
|
|
14579
15082
|
} else if (subcommand === "mcp" && args.length === 1) {
|
|
14580
15083
|
try {
|
|
14581
|
-
const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-
|
|
15084
|
+
const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-B5HMF24K.cjs'); });
|
|
14582
15085
|
await handleMcpCommand();
|
|
14583
15086
|
} catch (error) {
|
|
14584
15087
|
process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
|