very-happy-cli 0.2.90 → 0.2.92
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-CnYZFdd0.cjs → AcpBackend-BP7id8L6.cjs} +1 -1
- package/dist/{AcpBackend-BV4wSnJ3.mjs → AcpBackend-DDEsgc1c.mjs} +1 -1
- package/dist/{AcpSessionManager-Cyne6Rmg.mjs → AcpSessionManager-C29t6wb_.mjs} +1 -1
- package/dist/{AcpSessionManager-BPBdrrME.cjs → AcpSessionManager-Cys1Hsb8.cjs} +1 -1
- package/dist/{config-CgXitj0f.cjs → config-B77vhdwT.cjs} +2 -2
- package/dist/{config-BEdyyciP.mjs → config-CJQw0z1o.mjs} +2 -2
- package/dist/{index-an09rejO.mjs → index-8LDXVYWi.mjs} +409 -51
- package/dist/{index-4YmVbx7j.cjs → index-B63Vjt4W.cjs} +425 -67
- package/dist/{index-Dfu5uvjk.mjs → index-BP9pfzdZ.mjs} +5 -5
- package/dist/{index-B1wTVXjt.cjs → index-L3o5Gz-2.cjs} +4 -4
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{installTerminalHooks-DDpVxk8-.cjs → installTerminalHooks-BBc2nij4.cjs} +2 -2
- package/dist/{installTerminalHooks-C-OgZr5k.mjs → installTerminalHooks-DDRrUG_n.mjs} +2 -2
- package/dist/lib.cjs +1 -1
- package/dist/lib.d.cts +103 -3
- package/dist/lib.d.mts +103 -3
- package/dist/lib.mjs +1 -1
- package/dist/{mcp-Du-N0qlK.mjs → mcp-CYJAl5pk.mjs} +2 -2
- package/dist/{mcp-B6Nq-RUL.cjs → mcp-DbYXyw1U.cjs} +2 -2
- package/dist/{runGemini-ChG7cGMC.cjs → runGemini-BDSWSID6.cjs} +4 -4
- package/dist/{runGemini-DBr_TiTL.mjs → runGemini-DHYs_Beq.mjs} +4 -4
- package/dist/{runOpenClaw-D2jtVgpC.cjs → runOpenClaw-DC9gb1bd.cjs} +3 -3
- package/dist/{runOpenClaw-Cbde8t92.mjs → runOpenClaw-DTaXxvNd.mjs} +3 -3
- package/dist/{send-Bjen1TUE.cjs → send-BEdGwmA-.cjs} +2 -2
- package/dist/{send-BHliX59m.mjs → send-BQSaVz9r.mjs} +2 -2
- package/dist/{spawn-CH1Rq-LW.cjs → spawn-CK1ma_qc.cjs} +2 -2
- package/dist/{spawn-JxaPHAoP.mjs → spawn-DS-Uz_Hw.mjs} +2 -2
- package/dist/{types-DS3i_5LV.mjs → types-B_8X_rZk.mjs} +572 -93
- package/dist/{types-BNGeiP1C.cjs → types-CjlB_fKT.cjs} +573 -93
- package/package.json +7 -7
|
@@ -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-CjlB_fKT.cjs');
|
|
7
7
|
var spawn = require('cross-spawn');
|
|
8
8
|
var path = require('node:path');
|
|
9
9
|
var node_readline = require('node:readline');
|
|
@@ -46,24 +46,74 @@ var promises$1 = require('node:readline/promises');
|
|
|
46
46
|
|
|
47
47
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
48
48
|
function _interopNamespaceDefault(e) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
var n = Object.create(null);
|
|
50
|
+
if (e) {
|
|
51
|
+
Object.keys(e).forEach(function (k) {
|
|
52
|
+
if (k !== 'default') {
|
|
53
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
54
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
get: function () { return e[k]; }
|
|
57
|
+
});
|
|
58
|
+
}
|
|
57
59
|
});
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
n.default = e;
|
|
62
|
-
return Object.freeze(n);
|
|
60
|
+
}
|
|
61
|
+
n.default = e;
|
|
62
|
+
return Object.freeze(n);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
var tmp__namespace = /*#__PURE__*/_interopNamespaceDefault(tmp);
|
|
66
66
|
|
|
67
|
+
const PROCESS_IDENTITY_FIELDS = [
|
|
68
|
+
"hostPid",
|
|
69
|
+
"version",
|
|
70
|
+
"startedBy",
|
|
71
|
+
"startedFromDaemon",
|
|
72
|
+
"happyHomeDir",
|
|
73
|
+
"happyLibDir",
|
|
74
|
+
"happyToolsDir",
|
|
75
|
+
"capabilities",
|
|
76
|
+
"attachmentKinds",
|
|
77
|
+
"queueCancellation",
|
|
78
|
+
"sandbox",
|
|
79
|
+
"dangerouslySkipPermissions",
|
|
80
|
+
"os",
|
|
81
|
+
"host",
|
|
82
|
+
"homeDir",
|
|
83
|
+
"permissionMode"
|
|
84
|
+
];
|
|
85
|
+
function processIdentityFields(local) {
|
|
86
|
+
const out = {};
|
|
87
|
+
for (const key of PROCESS_IDENTITY_FIELDS) {
|
|
88
|
+
const value = local[key];
|
|
89
|
+
if (value !== void 0) out[key] = value;
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
function mergeReconnectMetadata(server, local, now) {
|
|
94
|
+
return {
|
|
95
|
+
...server,
|
|
96
|
+
...processIdentityFields(local),
|
|
97
|
+
lifecycleState: "running",
|
|
98
|
+
lifecycleStateSince: now,
|
|
99
|
+
archivedBy: void 0,
|
|
100
|
+
archiveReason: void 0
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function applyServerSnapshot(response, snapshot) {
|
|
104
|
+
return {
|
|
105
|
+
...response,
|
|
106
|
+
seq: snapshot.seq,
|
|
107
|
+
metadata: snapshot.metadata,
|
|
108
|
+
metadataVersion: snapshot.metadataVersion,
|
|
109
|
+
agentState: snapshot.agentState,
|
|
110
|
+
agentStateVersion: snapshot.agentStateVersion
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function withoutServerSnapshot(response) {
|
|
114
|
+
return { ...response, metadataVersion: 0, agentStateVersion: 0 };
|
|
115
|
+
}
|
|
116
|
+
|
|
67
117
|
function daemonControlHeaders(controlToken) {
|
|
68
118
|
return {
|
|
69
119
|
"Content-Type": "application/json",
|
|
@@ -1570,6 +1620,9 @@ function query(params) {
|
|
|
1570
1620
|
if (opts?.mcpServers && Object.keys(opts.mcpServers).length > 0) {
|
|
1571
1621
|
ensureLocalProxyBypass(env);
|
|
1572
1622
|
}
|
|
1623
|
+
if (sdkOptions.allowDangerouslySkipPermissions && typeof process.getuid === "function" && process.getuid() === 0 && env.IS_SANDBOX === void 0) {
|
|
1624
|
+
env.IS_SANDBOX = "1";
|
|
1625
|
+
}
|
|
1573
1626
|
sdkOptions.env = env;
|
|
1574
1627
|
if (opts?.canCallTool) {
|
|
1575
1628
|
const callback = opts.canCallTool;
|
|
@@ -1655,6 +1708,12 @@ function resolveRemoteClaudePermissionMode(currentMode, incomingMode, sandboxEna
|
|
|
1655
1708
|
}
|
|
1656
1709
|
return nextMode;
|
|
1657
1710
|
}
|
|
1711
|
+
function reconcilePublishedPermissionMode(input) {
|
|
1712
|
+
if (!input.effective) return null;
|
|
1713
|
+
const mismatch = input.effective !== input.intent;
|
|
1714
|
+
if (input.effective === input.published) return mismatch ? { publish: input.effective, mismatch } : null;
|
|
1715
|
+
return { publish: input.effective, mismatch };
|
|
1716
|
+
}
|
|
1658
1717
|
|
|
1659
1718
|
function parseCompact(message) {
|
|
1660
1719
|
const trimmed = message.trim();
|
|
@@ -1984,7 +2043,12 @@ async function claudeRemote(opts) {
|
|
|
1984
2043
|
mcpServers: systemInit.mcp_servers?.map((s) => ({ name: s.name, status: s.status })),
|
|
1985
2044
|
skills: systemInit.skills,
|
|
1986
2045
|
model: systemInit.model,
|
|
1987
|
-
modelIsDefault: initial.mode.model == null
|
|
2046
|
+
modelIsDefault: initial.mode.model == null,
|
|
2047
|
+
// The SDK's own verdict on the mode it will enforce —
|
|
2048
|
+
// settings (permissions.deny/ask/defaultMode/
|
|
2049
|
+
// disableBypassPermissionsMode) can override what we
|
|
2050
|
+
// asked for. runClaude publishes THIS, not our intent.
|
|
2051
|
+
permissionMode: systemInit.permissionMode
|
|
1988
2052
|
});
|
|
1989
2053
|
}
|
|
1990
2054
|
if (systemInit.session_id) {
|
|
@@ -2002,6 +2066,10 @@ async function claudeRemote(opts) {
|
|
|
2002
2066
|
if (message.type === "result") {
|
|
2003
2067
|
updateThinking(false);
|
|
2004
2068
|
persistence.logger.debug("[claudeRemote] Result received");
|
|
2069
|
+
const denials = message.permission_denials;
|
|
2070
|
+
if (denials && denials.length > 0) {
|
|
2071
|
+
persistence.logger.warn(`[claudeRemote] ${denials.length} tool call(s) auto-denied by Claude Code policy: ${denials.map((d) => d.tool_name ?? "?").join(", ")}`);
|
|
2072
|
+
}
|
|
2005
2073
|
if (isCompactCommand) {
|
|
2006
2074
|
const compactSucceeded = message.subtype === "success";
|
|
2007
2075
|
persistence.logger.debug(`[claudeRemote] Compaction ${compactSucceeded ? "completed" : "failed"}`);
|
|
@@ -2212,16 +2280,9 @@ class PermissionHandler {
|
|
|
2212
2280
|
}
|
|
2213
2281
|
} else {
|
|
2214
2282
|
if (response.approved && response.mode) {
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
this.permissionMode = response.mode;
|
|
2219
|
-
this.onModeChangedCallback?.(response.mode);
|
|
2220
|
-
} catch (err) {
|
|
2221
|
-
const reason = `Failed to switch permission mode: ${err instanceof Error ? err.message : String(err)}`;
|
|
2222
|
-
pending.resolve({ behavior: "deny", message: reason });
|
|
2223
|
-
return { ...response, approved: false, reason };
|
|
2224
|
-
}
|
|
2283
|
+
this.permissionMode = response.mode;
|
|
2284
|
+
this.deferredPermissionMode = response.mode;
|
|
2285
|
+
this.onModeChangedCallback?.(response.mode);
|
|
2225
2286
|
}
|
|
2226
2287
|
if (response.approved && !pending.suggestions?.length && response.allowTools?.length) {
|
|
2227
2288
|
response.allowTools.forEach((tool) => {
|
|
@@ -2562,6 +2623,17 @@ class PermissionHandler {
|
|
|
2562
2623
|
}
|
|
2563
2624
|
}
|
|
2564
2625
|
|
|
2626
|
+
function rewriteQueuedPermissionMode(queue, hasher, permissionMode) {
|
|
2627
|
+
let rewritten = 0;
|
|
2628
|
+
for (const item of queue) {
|
|
2629
|
+
if (item.mode.permissionMode === permissionMode) continue;
|
|
2630
|
+
item.mode = { ...item.mode, permissionMode };
|
|
2631
|
+
item.modeHash = hasher(item.mode);
|
|
2632
|
+
rewritten += 1;
|
|
2633
|
+
}
|
|
2634
|
+
return rewritten;
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2565
2637
|
function formatClaudeMessageForInk(message, messageBuffer, onAssistantResult) {
|
|
2566
2638
|
persistence.logger.debugLargeJson("[CLAUDE INK] Message from remote mode:", message);
|
|
2567
2639
|
switch (message.type) {
|
|
@@ -2816,7 +2888,13 @@ class SDKToLogConverter {
|
|
|
2816
2888
|
type: "user",
|
|
2817
2889
|
message: userMsg.message,
|
|
2818
2890
|
...userMsg.parent_tool_use_id ? { parent_tool_use_id: userMsg.parent_tool_use_id } : {},
|
|
2819
|
-
...meta ? { isMeta: true } : {}
|
|
2891
|
+
...meta ? { isMeta: true } : {},
|
|
2892
|
+
// B-260-P2: structured tool output (Agent/Task final report +
|
|
2893
|
+
// run totals, or the `async_launched` stub marker) and the
|
|
2894
|
+
// message origin (task-notification). Both are consumed by
|
|
2895
|
+
// sessionProtocolMapper; the raw-line schema is passthrough.
|
|
2896
|
+
...userMsg.tool_use_result !== void 0 ? { tool_use_result: userMsg.tool_use_result } : {},
|
|
2897
|
+
...userMsg.origin ? { origin: userMsg.origin } : {}
|
|
2820
2898
|
};
|
|
2821
2899
|
if (Array.isArray(userMsg.message.content)) {
|
|
2822
2900
|
for (const content of userMsg.message.content) {
|
|
@@ -3327,7 +3405,7 @@ function createTurnSteeringController() {
|
|
|
3327
3405
|
};
|
|
3328
3406
|
}
|
|
3329
3407
|
|
|
3330
|
-
async function claudeRemoteLauncher(session, onPermissionModeChange) {
|
|
3408
|
+
async function claudeRemoteLauncher(session, onPermissionModeChange, onEffectivePermissionMode) {
|
|
3331
3409
|
persistence.logger.debug("[claudeRemoteLauncher] Starting remote launcher");
|
|
3332
3410
|
const hasTTY = process.stdout.isTTY && process.stdin.isTTY;
|
|
3333
3411
|
persistence.logger.debug(`[claudeRemoteLauncher] TTY available: ${hasTTY}`);
|
|
@@ -3561,6 +3639,10 @@ async function claudeRemoteLauncher(session, onPermissionModeChange) {
|
|
|
3561
3639
|
mode = { ...mode, permissionMode: nextMode };
|
|
3562
3640
|
modeHash = session.queue.modeHasher(mode);
|
|
3563
3641
|
}
|
|
3642
|
+
rewriteQueuedPermissionMode(session.queue.queue, session.queue.modeHasher, nextMode);
|
|
3643
|
+
if (pending) {
|
|
3644
|
+
pending = { ...pending, mode: { ...pending.mode, permissionMode: nextMode } };
|
|
3645
|
+
}
|
|
3564
3646
|
onPermissionModeChange?.(nextMode);
|
|
3565
3647
|
return nextMode;
|
|
3566
3648
|
};
|
|
@@ -3633,6 +3715,7 @@ async function claudeRemoteLauncher(session, onPermissionModeChange) {
|
|
|
3633
3715
|
skillCount: metadata.skills?.length ?? 0
|
|
3634
3716
|
});
|
|
3635
3717
|
session.client.updateMetadata((currentMetadata) => applyClaudeSdkMetadata(currentMetadata, metadata));
|
|
3718
|
+
if (metadata.permissionMode) onEffectivePermissionMode?.(metadata.permissionMode);
|
|
3636
3719
|
},
|
|
3637
3720
|
onQueryReady: (q) => {
|
|
3638
3721
|
turnSteering.setInterrupt(q.interrupt);
|
|
@@ -3810,7 +3893,7 @@ async function loop(opts) {
|
|
|
3810
3893
|
break;
|
|
3811
3894
|
}
|
|
3812
3895
|
case "remote": {
|
|
3813
|
-
const reason = await claudeRemoteLauncher(session, opts.onPermissionModeChange);
|
|
3896
|
+
const reason = await claudeRemoteLauncher(session, opts.onPermissionModeChange, opts.onEffectivePermissionMode);
|
|
3814
3897
|
switch (reason) {
|
|
3815
3898
|
case "exit":
|
|
3816
3899
|
return 0;
|
|
@@ -5285,6 +5368,45 @@ function sanitizeSpawnPermissionMode(value) {
|
|
|
5285
5368
|
return ALLOWED_SPAWN_PERMISSION_MODES.includes(value) ? value : null;
|
|
5286
5369
|
}
|
|
5287
5370
|
|
|
5371
|
+
function resumePrecheck(metadata, fs) {
|
|
5372
|
+
const flavor = metadata.flavor ?? "claude";
|
|
5373
|
+
if (flavor !== "claude" && flavor !== "codex") {
|
|
5374
|
+
return { ok: false, reason: "unsupported-flavor", detail: `flavor "${flavor}" cannot be resumed` };
|
|
5375
|
+
}
|
|
5376
|
+
if (!metadata.path || !fs.cwdExists(metadata.path)) {
|
|
5377
|
+
return { ok: false, reason: "missing-cwd", detail: `working directory ${metadata.path ?? "(none)"} does not exist` };
|
|
5378
|
+
}
|
|
5379
|
+
if (flavor === "codex") {
|
|
5380
|
+
if (!metadata.codexThreadId) return { ok: false, reason: "no-backend-id", detail: "session has no Codex thread id" };
|
|
5381
|
+
return { ok: true };
|
|
5382
|
+
}
|
|
5383
|
+
if (!persistence.isClaudeSessionId(metadata.claudeSessionId)) {
|
|
5384
|
+
return { ok: false, reason: "no-backend-id", detail: "session has no Claude session id" };
|
|
5385
|
+
}
|
|
5386
|
+
if (!fs.conversationExists(metadata.path, metadata.claudeSessionId)) {
|
|
5387
|
+
return { ok: false, reason: "conversation-missing", detail: `conversation ${metadata.claudeSessionId} is not on disk` };
|
|
5388
|
+
}
|
|
5389
|
+
return { ok: true };
|
|
5390
|
+
}
|
|
5391
|
+
function sanitizeResumeModel(value) {
|
|
5392
|
+
if (typeof value !== "string") return null;
|
|
5393
|
+
return /^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/.test(value) ? value : null;
|
|
5394
|
+
}
|
|
5395
|
+
|
|
5396
|
+
const DEFAULT_MAX_RESTARTS = 3;
|
|
5397
|
+
function decideRestart(priorAttempts, max = DEFAULT_MAX_RESTARTS) {
|
|
5398
|
+
if (priorAttempts >= max) {
|
|
5399
|
+
return {
|
|
5400
|
+
allowed: false,
|
|
5401
|
+
reason: `restart-limit: this session has already been restarted ${priorAttempts} time(s) this daemon session (max ${max}). Start a new session instead.`
|
|
5402
|
+
};
|
|
5403
|
+
}
|
|
5404
|
+
return { allowed: true, attempt: priorAttempts + 1 };
|
|
5405
|
+
}
|
|
5406
|
+
function recordRestartAttempt(priorAttempts) {
|
|
5407
|
+
return priorAttempts + 1;
|
|
5408
|
+
}
|
|
5409
|
+
|
|
5288
5410
|
const CONTROL_TOKEN_BYTES = 32;
|
|
5289
5411
|
function createDaemonControlToken() {
|
|
5290
5412
|
return node_crypto.randomBytes(CONTROL_TOKEN_BYTES).toString("base64url");
|
|
@@ -7102,6 +7224,7 @@ async function startDaemon() {
|
|
|
7102
7224
|
tracked.pid = livePid;
|
|
7103
7225
|
tracked.startedBy = "recovered after daemon restart";
|
|
7104
7226
|
pidToTrackedSession.set(livePid, tracked);
|
|
7227
|
+
persistence.persistSession(id, { ...s, savedAt: Date.now() });
|
|
7105
7228
|
} else {
|
|
7106
7229
|
sessionIdToFinishedSession.set(id, tracked);
|
|
7107
7230
|
}
|
|
@@ -7530,6 +7653,13 @@ async function startDaemon() {
|
|
|
7530
7653
|
const timeout = setTimeout(() => {
|
|
7531
7654
|
pidToAwaiter.delete(happyProcess.pid);
|
|
7532
7655
|
persistence.logger.debug(`[DAEMON RUN] Session webhook timeout for PID ${happyProcess.pid}`);
|
|
7656
|
+
if (happyProcess.pid) {
|
|
7657
|
+
try {
|
|
7658
|
+
terminateProcess(happyProcess.pid, () => {
|
|
7659
|
+
});
|
|
7660
|
+
} catch {
|
|
7661
|
+
}
|
|
7662
|
+
}
|
|
7533
7663
|
resolve({
|
|
7534
7664
|
type: "error",
|
|
7535
7665
|
errorMessage: `Session webhook timeout for PID ${happyProcess.pid}`
|
|
@@ -7552,6 +7682,19 @@ async function startDaemon() {
|
|
|
7552
7682
|
return sessionIdToFinishedSession.get(happySessionId);
|
|
7553
7683
|
};
|
|
7554
7684
|
const fetchServerSessionMetadata = async (sessionId, encryptionKey, encryptionVariant) => {
|
|
7685
|
+
try {
|
|
7686
|
+
const byId = await axios.get(`${persistence.configuration.serverUrl}/v1/sessions/${encodeURIComponent(sessionId)}`, {
|
|
7687
|
+
headers: { Authorization: `Bearer ${credentials.token}` },
|
|
7688
|
+
timeout: 1e4,
|
|
7689
|
+
validateStatus: (status) => status >= 200 && status < 300 || status === 404
|
|
7690
|
+
});
|
|
7691
|
+
if (byId.status !== 404) {
|
|
7692
|
+
const row = byId.data.session;
|
|
7693
|
+
if (row?.metadata) return persistence.decrypt(encryptionKey, encryptionVariant, persistence.decodeBase64(row.metadata));
|
|
7694
|
+
}
|
|
7695
|
+
} catch (error) {
|
|
7696
|
+
persistence.logger.debug(`[DAEMON RUN] by-id session metadata fetch failed, falling back to list: ${error instanceof Error ? error.message : error}`);
|
|
7697
|
+
}
|
|
7555
7698
|
try {
|
|
7556
7699
|
const response = await axios.get(`${persistence.configuration.serverUrl}/v1/sessions`, {
|
|
7557
7700
|
headers: { Authorization: `Bearer ${credentials.token}` },
|
|
@@ -7567,17 +7710,38 @@ async function startDaemon() {
|
|
|
7567
7710
|
return null;
|
|
7568
7711
|
}
|
|
7569
7712
|
};
|
|
7713
|
+
const resumeGates = /* @__PURE__ */ new Map();
|
|
7570
7714
|
const resumeSession = async (happySessionId, options) => {
|
|
7715
|
+
let gate = resumeGates.get(happySessionId);
|
|
7716
|
+
if (!gate) {
|
|
7717
|
+
gate = createSpawnGate();
|
|
7718
|
+
resumeGates.set(happySessionId, gate);
|
|
7719
|
+
}
|
|
7571
7720
|
try {
|
|
7721
|
+
return await gate.join(() => resumeSessionImpl(happySessionId, options));
|
|
7722
|
+
} finally {
|
|
7723
|
+
if (!gate.inFlight()) resumeGates.delete(happySessionId);
|
|
7724
|
+
}
|
|
7725
|
+
};
|
|
7726
|
+
const resumeSessionImpl = async (happySessionId, options) => {
|
|
7727
|
+
try {
|
|
7728
|
+
for (const [pid, live] of pidToTrackedSession.entries()) {
|
|
7729
|
+
if (live.happySessionId !== happySessionId) continue;
|
|
7730
|
+
if (isPidAlive(pid)) {
|
|
7731
|
+
persistence.logger.debug(`[DAEMON RUN] resume ${happySessionId}: process ${pid} already alive \u2014 idempotent success`);
|
|
7732
|
+
return { type: "success", sessionId: happySessionId };
|
|
7733
|
+
}
|
|
7734
|
+
onChildExited(pid);
|
|
7735
|
+
}
|
|
7572
7736
|
const tracked = findTrackedSessionById(happySessionId);
|
|
7573
7737
|
if (!tracked) {
|
|
7574
|
-
return { type: "error", errorMessage: `Session ${happySessionId} is not tracked by this daemon. It may have been started before the daemon or on another machine.` };
|
|
7738
|
+
return { type: "error", errorMessage: `resume-precheck:not-tracked: Session ${happySessionId} is not tracked by this daemon. It may have been started before the daemon, more than 14 days ago, or on another machine.` };
|
|
7575
7739
|
}
|
|
7576
7740
|
if (!tracked.happySessionMetadataFromLocalWebhook) {
|
|
7577
|
-
return { type: "error", errorMessage: `Session ${happySessionId} has no metadata. Cannot resume.` };
|
|
7741
|
+
return { type: "error", errorMessage: `resume-precheck:no-metadata: Session ${happySessionId} has no metadata. Cannot resume.` };
|
|
7578
7742
|
}
|
|
7579
7743
|
if (!tracked.encryption) {
|
|
7580
|
-
return { type: "error", errorMessage: `Session ${happySessionId} has no stored encryption data. It was likely started before this feature was available. Restart the daemon and start a new session to enable resume.` };
|
|
7744
|
+
return { type: "error", errorMessage: `resume-precheck:no-encryption: Session ${happySessionId} has no stored encryption data. It was likely started before this feature was available. Restart the daemon and start a new session to enable resume.` };
|
|
7581
7745
|
}
|
|
7582
7746
|
let metadata = tracked.happySessionMetadataFromLocalWebhook;
|
|
7583
7747
|
const needsFetch = !metadata.claudeSessionId && (!metadata.flavor || metadata.flavor === "claude") || !metadata.codexThreadId && metadata.flavor === "codex";
|
|
@@ -7589,18 +7753,24 @@ async function startDaemon() {
|
|
|
7589
7753
|
tracked.happySessionMetadataFromLocalWebhook = serverMetadata;
|
|
7590
7754
|
}
|
|
7591
7755
|
}
|
|
7756
|
+
const precheck = resumePrecheck(metadata, {
|
|
7757
|
+
cwdExists: (p) => fs$1.existsSync(p),
|
|
7758
|
+
conversationExists: (cwd, claudeSessionId) => fs$1.existsSync(path$1.join(persistence.getProjectPath(cwd), `${claudeSessionId}.jsonl`))
|
|
7759
|
+
});
|
|
7760
|
+
if (!precheck.ok) {
|
|
7761
|
+
return { type: "error", errorMessage: `resume-precheck:${precheck.reason}: ${precheck.detail}` };
|
|
7762
|
+
}
|
|
7592
7763
|
const launch = buildResumeLaunch(
|
|
7593
7764
|
{ id: happySessionId, active: true, metadata },
|
|
7594
7765
|
{ startedBy: "daemon", claudeStartingMode: "remote" }
|
|
7595
7766
|
);
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
}
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
}
|
|
7602
|
-
await
|
|
7603
|
-
return spawnTrackedHappyProcess({
|
|
7767
|
+
const model = sanitizeResumeModel(options?.model);
|
|
7768
|
+
if (model) launch.args.push("--model", model);
|
|
7769
|
+
else if (options?.model !== void 0) persistence.logger.debug(`[DAEMON RUN] resume: ignoring invalid model ${JSON.stringify(options.model)}`);
|
|
7770
|
+
const permissionMode = sanitizeSpawnPermissionMode(options?.permissionMode);
|
|
7771
|
+
if (permissionMode) launch.args.push("--permission-mode", permissionMode);
|
|
7772
|
+
else if (options?.permissionMode !== void 0) persistence.logger.debug(`[DAEMON RUN] resume: ignoring invalid permission mode ${JSON.stringify(options.permissionMode)}`);
|
|
7773
|
+
const result = await spawnTrackedHappyProcess({
|
|
7604
7774
|
args: launch.args,
|
|
7605
7775
|
cwd: launch.cwd,
|
|
7606
7776
|
env: {
|
|
@@ -7613,6 +7783,18 @@ async function startDaemon() {
|
|
|
7613
7783
|
HAPPY_RECONNECT_AGENT_STATE_VERSION: String(tracked.encryption.agentStateVersion)
|
|
7614
7784
|
}
|
|
7615
7785
|
});
|
|
7786
|
+
if (result.type === "success") {
|
|
7787
|
+
persistence.persistSession(happySessionId, {
|
|
7788
|
+
encryptionKey: persistence.encodeBase64(tracked.encryption.encryptionKey),
|
|
7789
|
+
encryptionVariant: tracked.encryption.encryptionVariant,
|
|
7790
|
+
seq: tracked.encryption.seq,
|
|
7791
|
+
metadataVersion: tracked.encryption.metadataVersion,
|
|
7792
|
+
agentStateVersion: tracked.encryption.agentStateVersion,
|
|
7793
|
+
metadata,
|
|
7794
|
+
savedAt: Date.now()
|
|
7795
|
+
});
|
|
7796
|
+
}
|
|
7797
|
+
return result;
|
|
7616
7798
|
} catch (error) {
|
|
7617
7799
|
const errorMessage = error instanceof Error ? error.message : error && typeof error === "object" ? JSON.stringify(error) : String(error);
|
|
7618
7800
|
persistence.logger.debug(`[DAEMON RUN] Failed to resume session: ${errorMessage}`, error instanceof Error ? error.stack : void 0);
|
|
@@ -7622,6 +7804,136 @@ async function startDaemon() {
|
|
|
7622
7804
|
};
|
|
7623
7805
|
}
|
|
7624
7806
|
};
|
|
7807
|
+
const restartCounts = /* @__PURE__ */ new Map();
|
|
7808
|
+
const stopSessionAndWait = (happySessionId, timeoutMs = 8e3) => {
|
|
7809
|
+
let targetPid = null;
|
|
7810
|
+
for (const [pid2, s] of pidToTrackedSession.entries()) {
|
|
7811
|
+
if (s.happySessionId === happySessionId && isPidAlive(pid2)) {
|
|
7812
|
+
targetPid = pid2;
|
|
7813
|
+
break;
|
|
7814
|
+
}
|
|
7815
|
+
}
|
|
7816
|
+
if (targetPid === null) return Promise.resolve();
|
|
7817
|
+
const pid = targetPid;
|
|
7818
|
+
return new Promise((resolve) => {
|
|
7819
|
+
let settled = false;
|
|
7820
|
+
const done = () => {
|
|
7821
|
+
if (!settled) {
|
|
7822
|
+
settled = true;
|
|
7823
|
+
resolve();
|
|
7824
|
+
}
|
|
7825
|
+
};
|
|
7826
|
+
const requested = terminateProcess(pid, () => {
|
|
7827
|
+
const tracked = pidToTrackedSession.get(pid);
|
|
7828
|
+
if (tracked) {
|
|
7829
|
+
if (tracked.happySessionId && tracked.encryption) {
|
|
7830
|
+
sessionIdToFinishedSession.set(tracked.happySessionId, tracked);
|
|
7831
|
+
}
|
|
7832
|
+
pidToTrackedSession.delete(pid);
|
|
7833
|
+
}
|
|
7834
|
+
done();
|
|
7835
|
+
});
|
|
7836
|
+
if (!requested) done();
|
|
7837
|
+
setTimeout(done, timeoutMs).unref?.();
|
|
7838
|
+
});
|
|
7839
|
+
};
|
|
7840
|
+
const restartSession = async (happySessionId, options) => {
|
|
7841
|
+
let gate = resumeGates.get(happySessionId);
|
|
7842
|
+
if (!gate) {
|
|
7843
|
+
gate = createSpawnGate();
|
|
7844
|
+
resumeGates.set(happySessionId, gate);
|
|
7845
|
+
}
|
|
7846
|
+
try {
|
|
7847
|
+
return await gate.replace(() => restartSessionImpl(happySessionId, options));
|
|
7848
|
+
} finally {
|
|
7849
|
+
if (!gate.inFlight()) resumeGates.delete(happySessionId);
|
|
7850
|
+
}
|
|
7851
|
+
};
|
|
7852
|
+
const restartSessionImpl = async (happySessionId, options) => {
|
|
7853
|
+
try {
|
|
7854
|
+
const prior = restartCounts.get(happySessionId) ?? 0;
|
|
7855
|
+
const decision = decideRestart(prior, DEFAULT_MAX_RESTARTS);
|
|
7856
|
+
if (!decision.allowed) {
|
|
7857
|
+
return { type: "error", errorMessage: `restart:${decision.reason}` };
|
|
7858
|
+
}
|
|
7859
|
+
await stopSessionAndWait(happySessionId);
|
|
7860
|
+
const tracked = findTrackedSessionById(happySessionId);
|
|
7861
|
+
if (!tracked) {
|
|
7862
|
+
return { type: "error", errorMessage: `restart-precheck:not-tracked: Session ${happySessionId} is not tracked by this daemon.` };
|
|
7863
|
+
}
|
|
7864
|
+
if (!tracked.happySessionMetadataFromLocalWebhook) {
|
|
7865
|
+
return { type: "error", errorMessage: `restart-precheck:no-metadata: Session ${happySessionId} has no metadata. Cannot restart.` };
|
|
7866
|
+
}
|
|
7867
|
+
if (!tracked.encryption) {
|
|
7868
|
+
return { type: "error", errorMessage: `restart-precheck:no-encryption: Session ${happySessionId} has no stored encryption data. Restart the daemon and start a new session.` };
|
|
7869
|
+
}
|
|
7870
|
+
let metadata = tracked.happySessionMetadataFromLocalWebhook;
|
|
7871
|
+
const needsFetch = !metadata.claudeSessionId && (!metadata.flavor || metadata.flavor === "claude") || !metadata.codexThreadId && metadata.flavor === "codex";
|
|
7872
|
+
if (needsFetch) {
|
|
7873
|
+
const serverMetadata = await fetchServerSessionMetadata(happySessionId, tracked.encryption.encryptionKey, tracked.encryption.encryptionVariant);
|
|
7874
|
+
if (serverMetadata) {
|
|
7875
|
+
metadata = serverMetadata;
|
|
7876
|
+
tracked.happySessionMetadataFromLocalWebhook = serverMetadata;
|
|
7877
|
+
}
|
|
7878
|
+
}
|
|
7879
|
+
const precheck = resumePrecheck(metadata, {
|
|
7880
|
+
cwdExists: (p) => fs$1.existsSync(p),
|
|
7881
|
+
conversationExists: (cwd2, claudeSessionId) => fs$1.existsSync(path$1.join(persistence.getProjectPath(cwd2), `${claudeSessionId}.jsonl`))
|
|
7882
|
+
});
|
|
7883
|
+
let args;
|
|
7884
|
+
let cwd;
|
|
7885
|
+
if (precheck.ok) {
|
|
7886
|
+
const launch = buildResumeLaunch(
|
|
7887
|
+
{ id: happySessionId, active: true, metadata },
|
|
7888
|
+
{ startedBy: "daemon", claudeStartingMode: "remote" }
|
|
7889
|
+
);
|
|
7890
|
+
args = launch.args;
|
|
7891
|
+
cwd = launch.cwd;
|
|
7892
|
+
} else if ((metadata.flavor ?? "claude") === "claude" && typeof metadata.path === "string" && metadata.path.length > 0) {
|
|
7893
|
+
cwd = metadata.path;
|
|
7894
|
+
if (!fs$1.existsSync(cwd)) {
|
|
7895
|
+
return { type: "error", errorMessage: `restart-precheck:cwd-missing: ${cwd}` };
|
|
7896
|
+
}
|
|
7897
|
+
args = ["claude", "--happy-starting-mode", "remote", "--started-by", "daemon"];
|
|
7898
|
+
} else {
|
|
7899
|
+
return { type: "error", errorMessage: `restart-precheck:${precheck.ok ? "unknown" : precheck.reason}: ${precheck.ok ? "" : precheck.detail}` };
|
|
7900
|
+
}
|
|
7901
|
+
const model = sanitizeResumeModel(options?.model);
|
|
7902
|
+
if (model) args.push("--model", model);
|
|
7903
|
+
const permissionMode = sanitizeSpawnPermissionMode(options?.permissionMode);
|
|
7904
|
+
if (permissionMode) args.push("--permission-mode", permissionMode);
|
|
7905
|
+
restartCounts.set(happySessionId, recordRestartAttempt(prior));
|
|
7906
|
+
const result = await spawnTrackedHappyProcess({
|
|
7907
|
+
args,
|
|
7908
|
+
cwd,
|
|
7909
|
+
env: {
|
|
7910
|
+
...process.env,
|
|
7911
|
+
HAPPY_RECONNECT_SESSION_ID: happySessionId,
|
|
7912
|
+
HAPPY_RECONNECT_ENCRYPTION_KEY: persistence.encodeBase64(tracked.encryption.encryptionKey),
|
|
7913
|
+
HAPPY_RECONNECT_ENCRYPTION_VARIANT: tracked.encryption.encryptionVariant,
|
|
7914
|
+
HAPPY_RECONNECT_SEQ: String(tracked.encryption.seq),
|
|
7915
|
+
HAPPY_RECONNECT_METADATA_VERSION: String(tracked.encryption.metadataVersion),
|
|
7916
|
+
HAPPY_RECONNECT_AGENT_STATE_VERSION: String(tracked.encryption.agentStateVersion)
|
|
7917
|
+
}
|
|
7918
|
+
});
|
|
7919
|
+
if (result.type === "success") {
|
|
7920
|
+
persistence.persistSession(happySessionId, {
|
|
7921
|
+
encryptionKey: persistence.encodeBase64(tracked.encryption.encryptionKey),
|
|
7922
|
+
encryptionVariant: tracked.encryption.encryptionVariant,
|
|
7923
|
+
seq: tracked.encryption.seq,
|
|
7924
|
+
metadataVersion: tracked.encryption.metadataVersion,
|
|
7925
|
+
agentStateVersion: tracked.encryption.agentStateVersion,
|
|
7926
|
+
metadata,
|
|
7927
|
+
savedAt: Date.now()
|
|
7928
|
+
});
|
|
7929
|
+
}
|
|
7930
|
+
return result;
|
|
7931
|
+
} catch (error) {
|
|
7932
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
7933
|
+
persistence.logger.debug(`[DAEMON RUN] Failed to restart session: ${errorMessage}`, error instanceof Error ? error.stack : void 0);
|
|
7934
|
+
return { type: "error", errorMessage: `Failed to restart session: ${errorMessage}` };
|
|
7935
|
+
}
|
|
7936
|
+
};
|
|
7625
7937
|
const stopSession = (sessionId) => {
|
|
7626
7938
|
persistence.logger.debug(`[DAEMON RUN] Attempting to stop session ${sessionId}`);
|
|
7627
7939
|
for (const [pid, session] of pidToTrackedSession.entries()) {
|
|
@@ -7792,6 +8104,7 @@ async function startDaemon() {
|
|
|
7792
8104
|
apiMachine.setRPCHandlers({
|
|
7793
8105
|
spawnSession,
|
|
7794
8106
|
resumeSession,
|
|
8107
|
+
restartSession,
|
|
7795
8108
|
stopSession,
|
|
7796
8109
|
listTrackedSessionIds: () => [...pidToTrackedSession.values()].map((session) => session.happySessionId).filter((sessionId) => typeof sessionId === "string"),
|
|
7797
8110
|
requestShutdown: () => requestShutdown("happy-app")
|
|
@@ -8843,7 +9156,7 @@ const MAX_TITLE_CHARS = 60;
|
|
|
8843
9156
|
const GENERATION_TIMEOUT_MS = 3e4;
|
|
8844
9157
|
function resolveClaudeBinary() {
|
|
8845
9158
|
try {
|
|
8846
|
-
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-
|
|
9159
|
+
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-B63Vjt4W.cjs', document.baseURI).href)));
|
|
8847
9160
|
const utilsPath = path.resolve(path.join(persistence.projectPath(), "scripts", "claude_version_utils.cjs"));
|
|
8848
9161
|
const { getClaudeCliPath } = require$1(utilsPath);
|
|
8849
9162
|
const path$1 = getClaudeCliPath();
|
|
@@ -9383,6 +9696,18 @@ async function runClaude(credentials, options = {}) {
|
|
|
9383
9696
|
if (reconnectSessionId && !await api.reactivateSession(response.id)) {
|
|
9384
9697
|
throw new Error(`Failed to reactivate archived session ${response.id}`);
|
|
9385
9698
|
}
|
|
9699
|
+
let reconnectSeeded = false;
|
|
9700
|
+
if (reconnectSessionId) {
|
|
9701
|
+
const snapshot = await api.getSession(response.id, response.encryptionKey, response.encryptionVariant);
|
|
9702
|
+
if (snapshot.ok) {
|
|
9703
|
+
response = applyServerSnapshot(response, snapshot.session);
|
|
9704
|
+
reconnectSeeded = true;
|
|
9705
|
+
persistence.logger.debug(`[START] Reconnect seeded from server: seq=${snapshot.session.seq} metadataVersion=${snapshot.session.metadataVersion}`);
|
|
9706
|
+
} else {
|
|
9707
|
+
response = withoutServerSnapshot(response);
|
|
9708
|
+
persistence.logger.debug(`[START] Reconnect without server snapshot (${snapshot.reason}); skipping existing messages`);
|
|
9709
|
+
}
|
|
9710
|
+
}
|
|
9386
9711
|
try {
|
|
9387
9712
|
persistence.logger.debug(`[START] Reporting session ${response.id} to daemon`);
|
|
9388
9713
|
const result = await notifyDaemonSessionStarted(response.id, metadata, {
|
|
@@ -9400,15 +9725,17 @@ async function runClaude(credentials, options = {}) {
|
|
|
9400
9725
|
} catch (error) {
|
|
9401
9726
|
persistence.logger.debug("[START] Failed to report to daemon (may not be running):", error);
|
|
9402
9727
|
}
|
|
9403
|
-
const session = api.sessionSyncClient(response);
|
|
9728
|
+
const session = api.sessionSyncClient(response, reconnectSeeded ? { initialSeq: response.seq } : void 0);
|
|
9404
9729
|
if (reconnectSessionId) {
|
|
9405
9730
|
session.suppressNextArchiveSignal();
|
|
9406
|
-
session.skipExistingMessages();
|
|
9731
|
+
if (!reconnectSeeded) session.skipExistingMessages();
|
|
9407
9732
|
session.updateMetadata((meta) => ({
|
|
9408
|
-
...meta,
|
|
9409
|
-
|
|
9410
|
-
|
|
9411
|
-
|
|
9733
|
+
...mergeReconnectMetadata(meta, metadata, Date.now()),
|
|
9734
|
+
queueCancellation: true,
|
|
9735
|
+
// B-262 batch 2 (B5): a reconnected process re-publishes the mode
|
|
9736
|
+
// IT enforces; the server copy may still carry the previous
|
|
9737
|
+
// process's value.
|
|
9738
|
+
permissionMode: mapToClaudeMode(initialPermissionMode ?? "default")
|
|
9412
9739
|
}));
|
|
9413
9740
|
}
|
|
9414
9741
|
const forkClaudeSessionId = process.env.HAPPY_FORK_CLAUDE_SESSION_ID;
|
|
@@ -9548,6 +9875,22 @@ async function runClaude(credentials, options = {}) {
|
|
|
9548
9875
|
publishedPermissionMode = published;
|
|
9549
9876
|
session.updateMetadata((meta) => ({ ...meta, permissionMode: published }));
|
|
9550
9877
|
};
|
|
9878
|
+
const publishEffectivePermissionMode = (effective) => {
|
|
9879
|
+
const decision = reconcilePublishedPermissionMode({
|
|
9880
|
+
intent: mapToClaudeMode(currentPermissionMode ?? "default"),
|
|
9881
|
+
published: publishedPermissionMode,
|
|
9882
|
+
effective
|
|
9883
|
+
});
|
|
9884
|
+
if (!decision) return;
|
|
9885
|
+
if (decision.mismatch) {
|
|
9886
|
+
persistence.logger.warn(`[loop] Claude Code enforces permission mode '${effective}' but this process asked for '${mapToClaudeMode(currentPermissionMode ?? "default")}' \u2014 check ~/.claude settings (permissions.deny/ask/defaultMode/disableBypassPermissionsMode). Publishing the effective mode.`);
|
|
9887
|
+
}
|
|
9888
|
+
if (decision.publish !== publishedPermissionMode) {
|
|
9889
|
+
publishedPermissionMode = decision.publish;
|
|
9890
|
+
session.updateMetadata((meta) => ({ ...meta, permissionMode: decision.publish }));
|
|
9891
|
+
}
|
|
9892
|
+
};
|
|
9893
|
+
let lastExplicitModeSwitchAt = 0;
|
|
9551
9894
|
let currentModel = options.model ?? DEFAULT_CLAUDE_MODEL;
|
|
9552
9895
|
let currentFallbackModel = void 0;
|
|
9553
9896
|
let currentCustomSystemPrompt = void 0;
|
|
@@ -9592,7 +9935,11 @@ async function runClaude(credentials, options = {}) {
|
|
|
9592
9935
|
}
|
|
9593
9936
|
const attachmentsForThisMessage = await session.drainAttachmentsForUserMessage();
|
|
9594
9937
|
let messagePermissionMode = currentPermissionMode;
|
|
9595
|
-
|
|
9938
|
+
const messageCreatedAt = message.createdAt;
|
|
9939
|
+
const staleModeSnapshot = message.meta?.permissionMode !== void 0 && typeof messageCreatedAt === "number" && messageCreatedAt < lastExplicitModeSwitchAt;
|
|
9940
|
+
if (staleModeSnapshot) {
|
|
9941
|
+
persistence.logger.debug(`[loop] Ignoring stale meta.permissionMode=${message.meta?.permissionMode} (message ${messageCreatedAt} predates explicit switch ${lastExplicitModeSwitchAt}); keeping ${currentPermissionMode}`);
|
|
9942
|
+
} else if (message.meta?.permissionMode) {
|
|
9596
9943
|
const previousPermissionMode = currentPermissionMode;
|
|
9597
9944
|
messagePermissionMode = resolveRemoteClaudePermissionMode(
|
|
9598
9945
|
currentPermissionMode,
|
|
@@ -9856,9 +10203,11 @@ async function runClaude(credentials, options = {}) {
|
|
|
9856
10203
|
},
|
|
9857
10204
|
onAbort: resetCurrentModeDefaults,
|
|
9858
10205
|
onPermissionModeChange: (mode) => {
|
|
10206
|
+
lastExplicitModeSwitchAt = Date.now();
|
|
9859
10207
|
publishPermissionMode(mode);
|
|
9860
10208
|
persistence.logger.debug(`[loop] Permission mode updated from session RPC / approval to: ${mode}`);
|
|
9861
10209
|
},
|
|
10210
|
+
onEffectivePermissionMode: (mode) => publishEffectivePermissionMode(mode),
|
|
9862
10211
|
mcpServers: {
|
|
9863
10212
|
"happy": {
|
|
9864
10213
|
type: "http",
|
|
@@ -11001,9 +11350,9 @@ function resolveLocalSignupBootstrap(configuredMode, configuredInviteCodes, gene
|
|
|
11001
11350
|
};
|
|
11002
11351
|
}
|
|
11003
11352
|
|
|
11004
|
-
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-
|
|
11353
|
+
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-B63Vjt4W.cjs', document.baseURI).href)));
|
|
11005
11354
|
const __dirname$1 = path.dirname(__filename$1);
|
|
11006
|
-
const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-
|
|
11355
|
+
const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-B63Vjt4W.cjs', document.baseURI).href)));
|
|
11007
11356
|
const PRISMA_QUERY_ENGINE_FILES = {
|
|
11008
11357
|
"arm64-darwin": "libquery_engine-darwin-arm64.dylib.node",
|
|
11009
11358
|
"x64-darwin": "libquery_engine-darwin.dylib.node",
|
|
@@ -12092,7 +12441,7 @@ function setupOfflineReconnection(opts) {
|
|
|
12092
12441
|
});
|
|
12093
12442
|
return { session, reconnectionHandle, isOffline: true };
|
|
12094
12443
|
} else {
|
|
12095
|
-
session = api.sessionSyncClient(response);
|
|
12444
|
+
session = api.sessionSyncClient(response, opts.sessionClientOptions);
|
|
12096
12445
|
return { session, reconnectionHandle: null, isOffline: false };
|
|
12097
12446
|
}
|
|
12098
12447
|
}
|
|
@@ -12861,6 +13210,18 @@ async function runCodex(opts) {
|
|
|
12861
13210
|
if (reconnectSessionId && response && !await api.reactivateSession(response.id)) {
|
|
12862
13211
|
throw new Error(`Failed to reactivate archived session ${response.id}`);
|
|
12863
13212
|
}
|
|
13213
|
+
let reconnectSeeded = false;
|
|
13214
|
+
if (reconnectSessionId && response) {
|
|
13215
|
+
const snapshot = await api.getSession(response.id, response.encryptionKey, response.encryptionVariant);
|
|
13216
|
+
if (snapshot.ok) {
|
|
13217
|
+
response = applyServerSnapshot(response, snapshot.session);
|
|
13218
|
+
reconnectSeeded = true;
|
|
13219
|
+
persistence.logger.debug(`[START] Reconnect seeded from server: seq=${snapshot.session.seq} metadataVersion=${snapshot.session.metadataVersion}`);
|
|
13220
|
+
} else {
|
|
13221
|
+
response = withoutServerSnapshot(response);
|
|
13222
|
+
persistence.logger.debug(`[START] Reconnect without server snapshot (${snapshot.reason}); skipping existing messages`);
|
|
13223
|
+
}
|
|
13224
|
+
}
|
|
12864
13225
|
let session;
|
|
12865
13226
|
let permissionHandler;
|
|
12866
13227
|
let client;
|
|
@@ -12872,6 +13233,7 @@ async function runCodex(opts) {
|
|
|
12872
13233
|
metadata,
|
|
12873
13234
|
state,
|
|
12874
13235
|
response,
|
|
13236
|
+
sessionClientOptions: reconnectSeeded && response ? { initialSeq: response.seq } : void 0,
|
|
12875
13237
|
onSessionSwap: (newSession) => {
|
|
12876
13238
|
session = newSession;
|
|
12877
13239
|
if (permissionHandler) {
|
|
@@ -12882,12 +13244,8 @@ async function runCodex(opts) {
|
|
|
12882
13244
|
session = initialSession;
|
|
12883
13245
|
if (reconnectSessionId) {
|
|
12884
13246
|
session.suppressNextArchiveSignal();
|
|
12885
|
-
session.skipExistingMessages();
|
|
12886
|
-
session.updateMetadata((meta) => (
|
|
12887
|
-
...meta,
|
|
12888
|
-
lifecycleState: "running",
|
|
12889
|
-
archivedBy: void 0
|
|
12890
|
-
}));
|
|
13247
|
+
if (!reconnectSeeded) session.skipExistingMessages();
|
|
13248
|
+
session.updateMetadata((meta) => mergeReconnectMetadata(meta, metadata, Date.now()));
|
|
12891
13249
|
}
|
|
12892
13250
|
if (response) {
|
|
12893
13251
|
try {
|
|
@@ -13615,7 +13973,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
13615
13973
|
process.exit(0);
|
|
13616
13974
|
} else if (subcommand === "install-terminal-hooks") {
|
|
13617
13975
|
try {
|
|
13618
|
-
const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-
|
|
13976
|
+
const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-BBc2nij4.cjs'); });
|
|
13619
13977
|
const command = parseTerminalHooksArgs(args.slice(1));
|
|
13620
13978
|
if (command.action === "help") {
|
|
13621
13979
|
console.log(TERMINAL_HOOKS_HELP);
|
|
@@ -13632,7 +13990,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
13632
13990
|
}
|
|
13633
13991
|
} else if (subcommand === "spawn") {
|
|
13634
13992
|
try {
|
|
13635
|
-
const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-
|
|
13993
|
+
const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-CK1ma_qc.cjs'); });
|
|
13636
13994
|
await handleSpawnCommand(args.slice(1));
|
|
13637
13995
|
} catch (error) {
|
|
13638
13996
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -13644,7 +14002,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
13644
14002
|
return;
|
|
13645
14003
|
} else if (subcommand === "send") {
|
|
13646
14004
|
try {
|
|
13647
|
-
const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-
|
|
14005
|
+
const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-BEdGwmA-.cjs'); });
|
|
13648
14006
|
await handleSendCommand(args.slice(1));
|
|
13649
14007
|
} catch (error) {
|
|
13650
14008
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -13750,9 +14108,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
13750
14108
|
if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
|
|
13751
14109
|
const projectId = args[3];
|
|
13752
14110
|
try {
|
|
13753
|
-
const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-
|
|
13754
|
-
const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./types-
|
|
13755
|
-
const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-
|
|
14111
|
+
const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-B77vhdwT.cjs'); });
|
|
14112
|
+
const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./types-CjlB_fKT.cjs'); }).then(function (n) { return n.persistence; });
|
|
14113
|
+
const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-CjlB_fKT.cjs'); }).then(function (n) { return n.api; });
|
|
13756
14114
|
let userEmail = void 0;
|
|
13757
14115
|
try {
|
|
13758
14116
|
const credentials = await readCredentialsForConfiguredRelay2();
|
|
@@ -13783,7 +14141,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
13783
14141
|
}
|
|
13784
14142
|
if (geminiSubcommand === "project" && args[2] === "get") {
|
|
13785
14143
|
try {
|
|
13786
|
-
const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-
|
|
14144
|
+
const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-B77vhdwT.cjs'); });
|
|
13787
14145
|
const config = readGeminiLocalConfig();
|
|
13788
14146
|
if (config.googleCloudProject) {
|
|
13789
14147
|
console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
|
|
@@ -13823,7 +14181,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
13823
14181
|
process.exit(0);
|
|
13824
14182
|
}
|
|
13825
14183
|
try {
|
|
13826
|
-
const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-
|
|
14184
|
+
const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-BDSWSID6.cjs'); });
|
|
13827
14185
|
let startedBy = void 0;
|
|
13828
14186
|
for (let i = 1; i < args.length; i++) {
|
|
13829
14187
|
if (args[i] === "--started-by") {
|
|
@@ -13845,7 +14203,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
13845
14203
|
return;
|
|
13846
14204
|
} else if (subcommand === "acp") {
|
|
13847
14205
|
try {
|
|
13848
|
-
const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-
|
|
14206
|
+
const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-L3o5Gz-2.cjs'); });
|
|
13849
14207
|
let startedBy = void 0;
|
|
13850
14208
|
let verbose = false;
|
|
13851
14209
|
const acpArgs = [];
|
|
@@ -13885,7 +14243,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
13885
14243
|
return;
|
|
13886
14244
|
} else if (subcommand === "openclaw") {
|
|
13887
14245
|
try {
|
|
13888
|
-
const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-
|
|
14246
|
+
const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-DC9gb1bd.cjs'); });
|
|
13889
14247
|
let startedBy = void 0;
|
|
13890
14248
|
let verbose = false;
|
|
13891
14249
|
let gatewayUrl;
|
|
@@ -13936,7 +14294,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
13936
14294
|
return;
|
|
13937
14295
|
} else if (subcommand === "mcp" && args.length === 1) {
|
|
13938
14296
|
try {
|
|
13939
|
-
const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-
|
|
14297
|
+
const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-DbYXyw1U.cjs'); });
|
|
13940
14298
|
await handleMcpCommand();
|
|
13941
14299
|
} catch (error) {
|
|
13942
14300
|
process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
|