very-happy-cli 0.2.142 → 0.2.144
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-D2LqY2to.mjs → AcpBackend-DLsPpWnc.mjs} +2 -2
- package/dist/{AcpBackend-DJsqfgjD.cjs → AcpBackend-DssrjZDS.cjs} +30 -30
- package/dist/{AcpSessionManager-CdeM5KD9.mjs → AcpSessionManager-1pAH8SdV.mjs} +1 -1
- package/dist/{AcpSessionManager-CTfDxziP.cjs → AcpSessionManager-DkBV80Rr.cjs} +9 -9
- package/dist/{agentGuidance-Cz8QVcX3.mjs → agentGuidance-CupQ9Lve.mjs} +1 -1
- package/dist/{agentGuidance-Bi8iBjy3.cjs → agentGuidance-D1PDVswF.cjs} +1 -1
- package/dist/agentHome-BaSxP7lQ.mjs +107 -0
- package/dist/agentHome-uf1zs2Fi.cjs +113 -0
- package/dist/codex/happyMcpStdioBridge.cjs +2 -2
- package/dist/codex/happyMcpStdioBridge.mjs +2 -2
- package/dist/{config-ZsBeq10u.mjs → config-CxHoQo52.mjs} +4 -4
- package/dist/{config-BIbYBmTd.cjs → config-kx4y9oAI.cjs} +4 -4
- package/dist/{index-Bom8mTuS.cjs → index-DIoSNgtt.cjs} +4 -4
- package/dist/{index-CYFendNf.mjs → index-Diu81aSC.mjs} +77 -28
- package/dist/{index-CSQZhQ0C.cjs → index-Dn0JMM8l.cjs} +250 -201
- package/dist/{index-BPTPrjhL.cjs → index-Dox9iD5R.cjs} +31 -31
- package/dist/{index-CNARLBax.mjs → index-DxEaiVzX.mjs} +4 -4
- package/dist/{index-CY0zmhIp.mjs → index-J6a8OHS6.mjs} +8 -8
- package/dist/index.cjs +4 -4
- package/dist/index.mjs +4 -4
- package/dist/{installTerminalHooks-BPJu2WVz.mjs → installTerminalHooks-BBMGk3q5.mjs} +4 -4
- package/dist/{installTerminalHooks-DA7SyFYW.cjs → installTerminalHooks-De7_iOOC.cjs} +4 -4
- package/dist/lib.cjs +5 -5
- package/dist/lib.mjs +2 -2
- package/dist/{limits-B3hngubn.cjs → limits-C_Sklt--.cjs} +7 -7
- package/dist/{limits-CHsz3Ba-.mjs → limits-DxArdmkZ.mjs} +8 -8
- package/dist/{mcp-BkWBRWFe.mjs → mcp-C1oNnlw5.mjs} +4 -4
- package/dist/{mcp-ySrfNOYl.cjs → mcp-xyb8dYIQ.cjs} +9 -9
- package/dist/{piRuntime-uX0WHVr4.cjs → piRuntime-3Vbdgv6X.cjs} +2 -2
- package/dist/{piRuntime-DBLUyXFr.mjs → piRuntime-CzJdE4z4.mjs} +2 -2
- package/dist/{piTerminal-DNr3hkzY.cjs → piTerminal-BFpwVGWr.cjs} +6 -6
- package/dist/{piTerminal-Bc3jSCnY.mjs → piTerminal-Do2GiKMN.mjs} +6 -6
- package/dist/{runGemini-eJ08cXk7.cjs → runGemini-CCdGxTF2.cjs} +24 -24
- package/dist/{runGemini-rgFHTnG7.mjs → runGemini-De5NRMT9.mjs} +6 -6
- package/dist/{runOpenClaw-GjLWwjas.mjs → runOpenClaw-C2t4DRyi.mjs} +5 -5
- package/dist/{runOpenClaw-D0LVzxqM.cjs → runOpenClaw-CRMUfrWk.cjs} +26 -26
- package/dist/{send-Bg2oqt7f.cjs → send-BA1Dgpgn.cjs} +4 -4
- package/dist/{send-DV8liaRN.mjs → send-l6Rj09c0.mjs} +4 -4
- package/dist/{sessions-DPimBZ8H.cjs → sessions-CtVcoXvG.cjs} +5 -5
- package/dist/{sessions-JiL4aJkC.mjs → sessions-MWLDqQk-.mjs} +4 -4
- package/dist/{spawn-COOcUwkG.cjs → spawn-Be4nsNuQ.cjs} +6 -6
- package/dist/{spawn-CnMk3LFG.mjs → spawn-DKWR-6Qc.mjs} +4 -4
- package/dist/{teams-DSQgHBLE.cjs → teams-CcjjNLi8.cjs} +4 -4
- package/dist/{teams-uHZcdX9j.mjs → teams-DMf9GNGE.mjs} +4 -4
- package/dist/{todo-oHWNpEx_.mjs → todo-BEXZRm1A.mjs} +3 -3
- package/dist/{todo-DeauuUd6.cjs → todo-EffYAnre.cjs} +5 -5
- package/dist/{types-Dnoxgb7G.mjs → types-D6YKR7wo.mjs} +372 -15
- package/dist/{types-Xd_LJRJN.cjs → types-DZ5c-9f3.cjs} +379 -13
- package/package.json +7 -7
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
var chalk = require('chalk');
|
|
4
4
|
var os = require('node:os');
|
|
5
5
|
var node_crypto = require('node:crypto');
|
|
6
|
-
var
|
|
7
|
-
var persistence = require('./limits-
|
|
6
|
+
var index = require('./types-DZ5c-9f3.cjs');
|
|
7
|
+
var persistence = require('./limits-C_Sklt--.cjs');
|
|
8
8
|
var spawn = require('cross-spawn');
|
|
9
9
|
var path = require('node:path');
|
|
10
10
|
var node_readline = require('node:readline');
|
|
11
11
|
var node_fs = require('node:fs');
|
|
12
12
|
var projectPath = require('./projectPath-ChLhdOyt.cjs');
|
|
13
|
-
var agentGuidance = require('./agentGuidance-
|
|
13
|
+
var agentGuidance = require('./agentGuidance-D1PDVswF.cjs');
|
|
14
14
|
var promises = require('node:fs/promises');
|
|
15
15
|
var fs = require('fs/promises');
|
|
16
16
|
var ink = require('ink');
|
|
@@ -288,7 +288,7 @@ class Session {
|
|
|
288
288
|
reportEventToDaemon = (event) => {
|
|
289
289
|
const spawnedBy = process.env.HAPPY_SPAWNED_BY;
|
|
290
290
|
if (!spawnedBy) return;
|
|
291
|
-
void
|
|
291
|
+
void index.notifyDaemonSessionEvent(this.client.sessionId, event, spawnedBy).catch((error) => persistence.logger.debug("[Session] Failed to report session event to daemon:", error));
|
|
292
292
|
};
|
|
293
293
|
/** Produce an `error` notification for an unexpected session failure. */
|
|
294
294
|
onSessionError = (message) => {
|
|
@@ -398,7 +398,7 @@ function pinSmallFastModel(env) {
|
|
|
398
398
|
}
|
|
399
399
|
|
|
400
400
|
function claudeCheckSession(sessionId, path$1) {
|
|
401
|
-
const projectDir =
|
|
401
|
+
const projectDir = index.getProjectPath(path$1);
|
|
402
402
|
const sessionFile = path.join(projectDir, `${sessionId}.jsonl`);
|
|
403
403
|
const sessionExists = node_fs.existsSync(sessionFile);
|
|
404
404
|
if (!sessionExists) {
|
|
@@ -424,7 +424,7 @@ function claudeCheckSession(sessionId, path$1) {
|
|
|
424
424
|
|
|
425
425
|
function claudeFindLastSession(workingDirectory) {
|
|
426
426
|
try {
|
|
427
|
-
const projectDir =
|
|
427
|
+
const projectDir = index.getProjectPath(workingDirectory);
|
|
428
428
|
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
429
429
|
const files = node_fs.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).map((f) => {
|
|
430
430
|
const sessionId = f.replace(".jsonl", "");
|
|
@@ -478,7 +478,7 @@ function shouldIncludeCoAuthoredBy() {
|
|
|
478
478
|
|
|
479
479
|
const BASE_SYSTEM_PROMPT = (() => agentGuidance.trimIdent(`
|
|
480
480
|
ALWAYS when you start a new chat - you must call a tool "mcp__happy__change_title" to set a chat title. When you think chat title is not relevant anymore - call the tool again to change it. When chat name is too generic and you have a change to make it more specific - call the tool again to change it. This title is needed to easily find the chat in the future. Help human.
|
|
481
|
-
`))() + "\n\n" + agentGuidance.AGENT_GUIDANCE + "\n\n" +
|
|
481
|
+
`))() + "\n\n" + agentGuidance.AGENT_GUIDANCE + "\n\n" + index.BUILTIN_TODO_DISCOVERY;
|
|
482
482
|
const CO_AUTHORED_CREDITS = (() => agentGuidance.trimIdent(`
|
|
483
483
|
When making commit messages, instead of just giving co-credit to Claude, also give credit to Happy like so:
|
|
484
484
|
|
|
@@ -511,7 +511,7 @@ function quoteShellArg(value) {
|
|
|
511
511
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
512
512
|
}
|
|
513
513
|
async function claudeLocal(opts) {
|
|
514
|
-
const projectDir =
|
|
514
|
+
const projectDir = index.getProjectPath(opts.path);
|
|
515
515
|
node_fs.mkdirSync(projectDir, { recursive: true });
|
|
516
516
|
const hasContinueFlag = opts.claudeArgs?.includes("--continue");
|
|
517
517
|
const hasResumeFlag = opts.claudeArgs?.includes("--resume");
|
|
@@ -667,7 +667,7 @@ async function claudeLocal(opts) {
|
|
|
667
667
|
persistence.logger.warn("[ClaudeLocal] Sandbox is not supported on Windows; continuing without sandbox.");
|
|
668
668
|
} else {
|
|
669
669
|
try {
|
|
670
|
-
cleanupSandbox = await
|
|
670
|
+
cleanupSandbox = await index.initializeSandbox(opts.sandboxConfig, opts.path);
|
|
671
671
|
if (!spawnArgs.includes("--dangerously-skip-permissions")) {
|
|
672
672
|
spawnArgs = [...spawnArgs, "--dangerously-skip-permissions"];
|
|
673
673
|
}
|
|
@@ -675,7 +675,7 @@ async function claudeLocal(opts) {
|
|
|
675
675
|
"node",
|
|
676
676
|
...spawnArgs.map((arg) => quoteShellArg(arg))
|
|
677
677
|
].join(" ");
|
|
678
|
-
spawnCommand = await
|
|
678
|
+
spawnCommand = await index.wrapCommand(fullCommand);
|
|
679
679
|
spawnWithShell = true;
|
|
680
680
|
persistence.logger.info(
|
|
681
681
|
`[ClaudeLocal] Sandbox enabled: workspace=${opts.sandboxConfig.workspaceRoot ?? opts.path}, network=${opts.sandboxConfig.networkMode}`
|
|
@@ -738,7 +738,7 @@ async function claudeLocal(opts) {
|
|
|
738
738
|
persistence.logger.debug(`[ClaudeLocal] Unknown message type: ${message.type}`);
|
|
739
739
|
}
|
|
740
740
|
} catch (e) {
|
|
741
|
-
persistence.logger.debug("[ClaudeLocal] Non-JSON line from fd3:",
|
|
741
|
+
persistence.logger.debug("[ClaudeLocal] Non-JSON line from fd3:", index.contentLogMetadata(line));
|
|
742
742
|
}
|
|
743
743
|
});
|
|
744
744
|
rl.on("error", (err) => {
|
|
@@ -876,7 +876,7 @@ const INTERNAL_CLAUDE_EVENT_TYPES$1 = /* @__PURE__ */ new Set([
|
|
|
876
876
|
"queue-operation"
|
|
877
877
|
]);
|
|
878
878
|
async function createSessionScanner(opts) {
|
|
879
|
-
const projectDir =
|
|
879
|
+
const projectDir = index.getProjectPath(opts.workingDirectory);
|
|
880
880
|
let finishedSessions = /* @__PURE__ */ new Set();
|
|
881
881
|
let pendingSessions = /* @__PURE__ */ new Set();
|
|
882
882
|
let currentSessionId = null;
|
|
@@ -891,7 +891,7 @@ async function createSessionScanner(opts) {
|
|
|
891
891
|
}
|
|
892
892
|
currentSessionId = opts.sessionId;
|
|
893
893
|
}
|
|
894
|
-
const sync = new
|
|
894
|
+
const sync = new index.InvalidateSync(async () => {
|
|
895
895
|
let sessions = [];
|
|
896
896
|
for (let p of pendingSessions) {
|
|
897
897
|
if (!deadSessions.has(p)) {
|
|
@@ -1033,7 +1033,7 @@ async function readSessionLog(projectDir, sessionId) {
|
|
|
1033
1033
|
if (message.type && INTERNAL_CLAUDE_EVENT_TYPES$1.has(message.type)) {
|
|
1034
1034
|
continue;
|
|
1035
1035
|
}
|
|
1036
|
-
let parsed =
|
|
1036
|
+
let parsed = index.RawJSONLinesSchema.safeParse(message);
|
|
1037
1037
|
if (!parsed.success) {
|
|
1038
1038
|
continue;
|
|
1039
1039
|
}
|
|
@@ -1912,7 +1912,7 @@ async function awaitFileExist(file, timeout = 1e4) {
|
|
|
1912
1912
|
await fs.access(file);
|
|
1913
1913
|
return true;
|
|
1914
1914
|
} catch (e) {
|
|
1915
|
-
await
|
|
1915
|
+
await index.delay(1e3);
|
|
1916
1916
|
}
|
|
1917
1917
|
}
|
|
1918
1918
|
return false;
|
|
@@ -2107,7 +2107,7 @@ async function claudeRemote(opts) {
|
|
|
2107
2107
|
}
|
|
2108
2108
|
continue;
|
|
2109
2109
|
}
|
|
2110
|
-
persistence.logger.debug(`[claudeRemote] Message ${message.type}`,
|
|
2110
|
+
persistence.logger.debug(`[claudeRemote] Message ${message.type}`, index.contentLogMetadata(message));
|
|
2111
2111
|
if (message.type === "assistant" && message.error) {
|
|
2112
2112
|
lastAssistantError = message.error;
|
|
2113
2113
|
}
|
|
@@ -2147,7 +2147,7 @@ async function claudeRemote(opts) {
|
|
|
2147
2147
|
}
|
|
2148
2148
|
if (systemInit.session_id) {
|
|
2149
2149
|
persistence.logger.debug(`[claudeRemote] Waiting for session file to be written to disk: ${systemInit.session_id}`);
|
|
2150
|
-
const projectDir =
|
|
2150
|
+
const projectDir = index.getProjectPath(opts.path);
|
|
2151
2151
|
const found = await awaitFileExist(path.join(projectDir, `${systemInit.session_id}.jsonl`), 3e4);
|
|
2152
2152
|
persistence.logger.debug(`[claudeRemote] Session file found: ${systemInit.session_id} ${found}`);
|
|
2153
2153
|
if (!found) {
|
|
@@ -2378,9 +2378,9 @@ class PermissionHandler {
|
|
|
2378
2378
|
persistence.logger.debug("Plan mode result received", {
|
|
2379
2379
|
approved: response.approved,
|
|
2380
2380
|
mode: response.mode,
|
|
2381
|
-
reason:
|
|
2381
|
+
reason: index.contentLogMetadata(response.reason),
|
|
2382
2382
|
allowToolCount: response.allowTools?.length ?? 0,
|
|
2383
|
-
updatedInput:
|
|
2383
|
+
updatedInput: index.contentLogMetadata(response.updatedInput)
|
|
2384
2384
|
});
|
|
2385
2385
|
if (response.approved) {
|
|
2386
2386
|
const newMode = response.mode && ["default", "acceptEdits", "bypassPermissions"].includes(response.mode) ? response.mode : "bypassPermissions";
|
|
@@ -2704,9 +2704,9 @@ class PermissionHandler {
|
|
|
2704
2704
|
id: message.id,
|
|
2705
2705
|
approved: message.approved,
|
|
2706
2706
|
mode: message.mode,
|
|
2707
|
-
reason:
|
|
2707
|
+
reason: index.contentLogMetadata(message.reason),
|
|
2708
2708
|
allowToolCount: message.allowTools?.length ?? 0,
|
|
2709
|
-
updatedInput:
|
|
2709
|
+
updatedInput: index.contentLogMetadata(message.updatedInput)
|
|
2710
2710
|
});
|
|
2711
2711
|
const id = message.id;
|
|
2712
2712
|
const pending = this.pendingRequests.get(id);
|
|
@@ -3191,7 +3191,7 @@ class OutgoingMessageQueue {
|
|
|
3191
3191
|
}
|
|
3192
3192
|
queue = [];
|
|
3193
3193
|
nextId = 1;
|
|
3194
|
-
lock = new
|
|
3194
|
+
lock = new index.AsyncLock();
|
|
3195
3195
|
processTimer;
|
|
3196
3196
|
delayTimers = /* @__PURE__ */ new Map();
|
|
3197
3197
|
/**
|
|
@@ -3483,7 +3483,7 @@ class StreamRelay {
|
|
|
3483
3483
|
}
|
|
3484
3484
|
this.pending.text += text;
|
|
3485
3485
|
this.pending.bytes += Buffer.byteLength(text, "utf8");
|
|
3486
|
-
if (this.pending.bytes >= STREAM_FLUSH_MAX_BYTES || this.pending.text.length >=
|
|
3486
|
+
if (this.pending.bytes >= STREAM_FLUSH_MAX_BYTES || this.pending.text.length >= index.STREAM_DELTA_MAX_CHARS) {
|
|
3487
3487
|
this.flushPending();
|
|
3488
3488
|
return;
|
|
3489
3489
|
}
|
|
@@ -3663,8 +3663,8 @@ async function stageClaudeAttachments(attachments, options) {
|
|
|
3663
3663
|
await persistence.ensurePrivateDirectory(sessionDir);
|
|
3664
3664
|
const staged = [];
|
|
3665
3665
|
for (const attachment of attachments) {
|
|
3666
|
-
if (attachment.data.length >
|
|
3667
|
-
throw new Error(`Attachment exceeds the ${
|
|
3666
|
+
if (attachment.data.length > index.MAX_CHAT_ATTACHMENT_SOURCE_BYTES) {
|
|
3667
|
+
throw new Error(`Attachment exceeds the ${index.MAX_CHAT_ATTACHMENT_SOURCE_BYTES / 1024 / 1024} MB limit`);
|
|
3668
3668
|
}
|
|
3669
3669
|
const name = safeFileName(attachment.name || "file");
|
|
3670
3670
|
const targetPath = path.join(sessionDir, uniqueFileName(name));
|
|
@@ -4265,12 +4265,12 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
|
|
|
4265
4265
|
claudeArgs: session.claudeArgs,
|
|
4266
4266
|
onMessage,
|
|
4267
4267
|
onCompletionEvent: (message) => {
|
|
4268
|
-
persistence.logger.debug("[remote]: Completion event received:",
|
|
4268
|
+
persistence.logger.debug("[remote]: Completion event received:", index.contentLogMetadata(message));
|
|
4269
4269
|
session.client.sendSessionEvent({ type: "message", message });
|
|
4270
4270
|
},
|
|
4271
4271
|
onAuthFailure: (reason) => {
|
|
4272
4272
|
session.client.sendSessionEvent({ type: "message", message: `Claude Code auth: ${reason}`, kind: "claude-auth-failed" });
|
|
4273
|
-
void
|
|
4273
|
+
void index.notifyDaemonClaudeAuthFailed(session.client.sessionId).catch((error) => persistence.logger.debug("[remote]: auth_failed report to daemon failed:", error));
|
|
4274
4274
|
},
|
|
4275
4275
|
onSessionReset: () => {
|
|
4276
4276
|
persistence.logger.debug("[remote]: Session reset");
|
|
@@ -5062,7 +5062,7 @@ function daemonReadiness(authenticated, running, hasState) {
|
|
|
5062
5062
|
message: "\u26A0\uFE0F Daemon is not running \u2014 run `very-happy daemon start`"
|
|
5063
5063
|
};
|
|
5064
5064
|
}
|
|
5065
|
-
function collectRuntimeReadiness(run = node_child_process.spawnSync, currentNodeVersion = process.version, onPath =
|
|
5065
|
+
function collectRuntimeReadiness(run = node_child_process.spawnSync, currentNodeVersion = process.version, onPath = index.commandOnPath) {
|
|
5066
5066
|
const tmux = probe("tmux", run);
|
|
5067
5067
|
return {
|
|
5068
5068
|
node: {
|
|
@@ -5111,7 +5111,7 @@ function shareSafeEnvironmentInfo(env = process.env, runtime = process) {
|
|
|
5111
5111
|
function printCliUpdateStatus(state) {
|
|
5112
5112
|
const installed = persistence.configuration.currentCliVersion;
|
|
5113
5113
|
const running = state?.startedWithCliVersion ?? null;
|
|
5114
|
-
const summary =
|
|
5114
|
+
const summary = index.deriveLocalCliUpdateSummary(installed, running, state?.cliUpdate);
|
|
5115
5115
|
console.log(` Installed CLI: ${installed}`);
|
|
5116
5116
|
console.log(` Running daemon: ${running ?? "not running"}`);
|
|
5117
5117
|
if (state?.cliUpdate?.recommendedVersion) console.log(` Recommended: ${state.cliUpdate.recommendedVersion}`);
|
|
@@ -5146,7 +5146,7 @@ function getLogFiles(logDir) {
|
|
|
5146
5146
|
async function runDoctorDaemon() {
|
|
5147
5147
|
console.log(chalk.bold("\n\u{1F916} Daemon Status"));
|
|
5148
5148
|
try {
|
|
5149
|
-
const isRunning = await
|
|
5149
|
+
const isRunning = await index.checkIfDaemonRunningAndCleanupStaleState();
|
|
5150
5150
|
const state = await persistence.readDaemonState();
|
|
5151
5151
|
if (isRunning && state) {
|
|
5152
5152
|
console.log(chalk.green("\u2713 Daemon is running"));
|
|
@@ -5316,6 +5316,16 @@ ${typeLabels[type] || type}:`));
|
|
|
5316
5316
|
console.log(chalk.gray(" OS-keychain credentials cannot be verified here; see /docs/configuration#claude-credentials."));
|
|
5317
5317
|
}
|
|
5318
5318
|
console.log(chalk.gray(" An external claude command is only needed for native terminal/mirror use."));
|
|
5319
|
+
try {
|
|
5320
|
+
const { resolveAgentHomesForCli } = await Promise.resolve().then(function () { return require('./agentHome-uf1zs2Fi.cjs'); });
|
|
5321
|
+
const { describeAgentHome } = await Promise.resolve().then(function () { return require('./types-DZ5c-9f3.cjs'); }).then(function (n) { return n.index; });
|
|
5322
|
+
const homes = await resolveAgentHomesForCli();
|
|
5323
|
+
console.log(chalk.green(`\u2713 Claude config dir: ${describeAgentHome(homes.claudeConfigDir)}`));
|
|
5324
|
+
console.log(chalk.green(`\u2713 Codex home: ${describeAgentHome(homes.codexHome)}`));
|
|
5325
|
+
console.log(chalk.gray(" Resolved from settings.json, then your login shell, then the daemon environment; pin with `very-happy agent-home`."));
|
|
5326
|
+
} catch {
|
|
5327
|
+
console.log(chalk.yellow("\u25CB Could not resolve the Claude/Codex home directories"));
|
|
5328
|
+
}
|
|
5319
5329
|
if (availableAgents.length === 0) {
|
|
5320
5330
|
console.log(chalk.yellow("\u25CB No external agent command found on this daemon PATH"));
|
|
5321
5331
|
console.log(chalk.gray(" Codex, Gemini, OpenCode, OpenClaw, and native Claude terminal paths need their local command or gateway."));
|
|
@@ -5349,7 +5359,7 @@ ${typeLabels[type] || type}:`));
|
|
|
5349
5359
|
}
|
|
5350
5360
|
console.log(chalk.bold("\n\u{1F916} Daemon Status"));
|
|
5351
5361
|
try {
|
|
5352
|
-
const isRunning = await
|
|
5362
|
+
const isRunning = await index.checkIfDaemonRunningAndCleanupStaleState();
|
|
5353
5363
|
const state = await persistence.readDaemonState();
|
|
5354
5364
|
const summary = daemonReadiness(authenticated, isRunning, Boolean(state));
|
|
5355
5365
|
if (summary.level === "ready" && state) {
|
|
@@ -5419,7 +5429,7 @@ async function registryVersion(name) {
|
|
|
5419
5429
|
return typeof data.version === "string" ? stableVersion(data.version) : null;
|
|
5420
5430
|
}
|
|
5421
5431
|
async function detectAgentVersions(deps = { probe: probeAgentVersion, registryVersion }, now = Date.now()) {
|
|
5422
|
-
const agents = await Promise.all(
|
|
5432
|
+
const agents = await Promise.all(index.AGENT_VERSION_SOURCES.map(async (source) => {
|
|
5423
5433
|
const local = source.command ? await deps.probe(source.command).catch(() => ({ version: null, missing: false })) : { version: stableVersion(persistence.packageJson.dependencies["@anthropic-ai/claude-agent-sdk"]), missing: false };
|
|
5424
5434
|
if (local.missing) return { id: source.id, installed: null, latest: null, status: "not-installed" };
|
|
5425
5435
|
const latest = await deps.registryVersion(source.package).catch(() => null);
|
|
@@ -5678,7 +5688,7 @@ async function waitForAuthentication(keypair, claimSecret) {
|
|
|
5678
5688
|
}
|
|
5679
5689
|
process.stdout.write("\rWaiting for authentication" + ".".repeat(dots % 3 + 1) + " ");
|
|
5680
5690
|
dots++;
|
|
5681
|
-
await
|
|
5691
|
+
await index.delay(1e3);
|
|
5682
5692
|
}
|
|
5683
5693
|
} finally {
|
|
5684
5694
|
process.off("SIGINT", handleInterrupt);
|
|
@@ -6003,7 +6013,7 @@ async function waitForSessionKey(sessionId, timeoutMs) {
|
|
|
6003
6013
|
`Session ${sessionId} has no encryption key in ${persistence.configuration.sessionsFile}. Either it was not spawned by this machine's daemon, or the daemon is too old to persist session keys.`
|
|
6004
6014
|
);
|
|
6005
6015
|
}
|
|
6006
|
-
await
|
|
6016
|
+
await index.delay(200);
|
|
6007
6017
|
}
|
|
6008
6018
|
}
|
|
6009
6019
|
async function sendUserMessage(sessionId, persisted, text, client, options = {}) {
|
|
@@ -6065,7 +6075,7 @@ function resumePrecheck(metadata, fs) {
|
|
|
6065
6075
|
if (!metadata.codexThreadId) return { ok: false, reason: "no-backend-id", detail: "session has no Codex thread id" };
|
|
6066
6076
|
return { ok: true };
|
|
6067
6077
|
}
|
|
6068
|
-
if (!
|
|
6078
|
+
if (!index.isClaudeSessionId(metadata.claudeSessionId)) {
|
|
6069
6079
|
return { ok: false, reason: "no-backend-id", detail: "session has no Claude session id" };
|
|
6070
6080
|
}
|
|
6071
6081
|
if (!fs.conversationExists(metadata.path, metadata.claudeSessionId)) {
|
|
@@ -7377,8 +7387,8 @@ function decryptBoxBundle(bundle, recipientSecretKey) {
|
|
|
7377
7387
|
return decrypted ? new Uint8Array(decrypted) : null;
|
|
7378
7388
|
}
|
|
7379
7389
|
function readAgentCredentials() {
|
|
7380
|
-
const credentialPath =
|
|
7381
|
-
const credentials =
|
|
7390
|
+
const credentialPath = index.getLocalHappyAgentCredentialPath();
|
|
7391
|
+
const credentials = index.readLocalHappyAgentCredentials();
|
|
7382
7392
|
if (!credentials) {
|
|
7383
7393
|
throw new Error(
|
|
7384
7394
|
`Cannot use the legacy CLI resume path without ${credentialPath}. This credential is produced only by the source-only internal control-plane prototype; do not install the unrelated npm package named happy-agent. Use the Web session controls instead.`
|
|
@@ -7678,7 +7688,7 @@ function ownedCliLink(link, target, packageDir) {
|
|
|
7678
7688
|
return resolved.startsWith(path.join(packageDir, "bin") + path.sep);
|
|
7679
7689
|
}
|
|
7680
7690
|
async function installCliSafely(version, deps = defaults) {
|
|
7681
|
-
const parsed =
|
|
7691
|
+
const parsed = index.parseExactVersion(version);
|
|
7682
7692
|
if (!parsed) throw new Error("Invalid exact CLI version");
|
|
7683
7693
|
const args = autoUpdateInstallArgs(parsed.exact);
|
|
7684
7694
|
if (deps.platform === "win32") {
|
|
@@ -7769,7 +7779,7 @@ function createUpdateController(deps) {
|
|
|
7769
7779
|
let lastPublished = "";
|
|
7770
7780
|
const now = deps.now ?? Date.now;
|
|
7771
7781
|
function validManualTarget(next, version) {
|
|
7772
|
-
return version === next.recommendedVersion && Number.isFinite(next.checkedAt) && now() - next.checkedAt <= 65 * 6e4 && next.checkedAt <= now() + 6e4 &&
|
|
7782
|
+
return version === next.recommendedVersion && Number.isFinite(next.checkedAt) && now() - next.checkedAt <= 65 * 6e4 && next.checkedAt <= now() + 6e4 && index.compareExactVersions(next.currentVersion, version) === -1 && (!next.minimumVersion || [0, 1].includes(index.compareExactVersions(version, next.minimumVersion) ?? -1));
|
|
7773
7783
|
}
|
|
7774
7784
|
function publish(state, version, detail) {
|
|
7775
7785
|
if (!policy) return;
|
|
@@ -7807,7 +7817,7 @@ function createUpdateController(deps) {
|
|
|
7807
7817
|
publish("unapproved", null);
|
|
7808
7818
|
return;
|
|
7809
7819
|
}
|
|
7810
|
-
const order =
|
|
7820
|
+
const order = index.compareExactVersions(policy.currentVersion, target);
|
|
7811
7821
|
if (order !== -1) {
|
|
7812
7822
|
publish(order === null ? "policy_stale" : "current", target);
|
|
7813
7823
|
return;
|
|
@@ -7988,7 +7998,7 @@ function parseJsonObject(text) {
|
|
|
7988
7998
|
return null;
|
|
7989
7999
|
}
|
|
7990
8000
|
}
|
|
7991
|
-
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-
|
|
8001
|
+
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-Dn0JMM8l.cjs', document.baseURI).href))).resolve(s)) {
|
|
7992
8002
|
const platformArch = `${platform}-${arch}`;
|
|
7993
8003
|
const candidates = [
|
|
7994
8004
|
`@anthropic-ai/claude-agent-sdk-${platformArch}/claude`,
|
|
@@ -8378,7 +8388,7 @@ function parseLines(lines) {
|
|
|
8378
8388
|
try {
|
|
8379
8389
|
const parsed = JSON.parse(line);
|
|
8380
8390
|
if (parsed?.type && INTERNAL_CLAUDE_EVENT_TYPES.has(parsed.type)) continue;
|
|
8381
|
-
const result =
|
|
8391
|
+
const result = index.RawJSONLinesSchema.safeParse(parsed);
|
|
8382
8392
|
if (!result.success) continue;
|
|
8383
8393
|
out.push(result.data);
|
|
8384
8394
|
} catch {
|
|
@@ -8422,19 +8432,19 @@ function createMirrorScanner(opts) {
|
|
|
8422
8432
|
} finally {
|
|
8423
8433
|
await handle.close();
|
|
8424
8434
|
}
|
|
8425
|
-
const { lines, consumedBytes } =
|
|
8435
|
+
const { lines, consumedBytes } = index.extractCompleteLines(buf);
|
|
8426
8436
|
tail.offset += consumedBytes;
|
|
8427
8437
|
if (lines.length === 0) return;
|
|
8428
8438
|
let messages = parseLines(lines);
|
|
8429
8439
|
if (isFirstBackfillRead) {
|
|
8430
|
-
const decision =
|
|
8440
|
+
const decision = index.decideBackfill(messages, opts.backfillLines);
|
|
8431
8441
|
messages = decision.replay;
|
|
8432
8442
|
if (decision.truncated) opts.events.onBackfillTruncated?.();
|
|
8433
8443
|
tail.mode = "from-eof";
|
|
8434
8444
|
}
|
|
8435
8445
|
if (messages.length > 0) opts.events.onMessages(messages);
|
|
8436
8446
|
};
|
|
8437
|
-
const sync = new
|
|
8447
|
+
const sync = new index.InvalidateSync(async () => {
|
|
8438
8448
|
for (const tail of files.values()) {
|
|
8439
8449
|
try {
|
|
8440
8450
|
await readTail(tail);
|
|
@@ -8518,7 +8528,7 @@ function pendingCreateSupersededBy(pending, event) {
|
|
|
8518
8528
|
const TERMINAL_MIRROR_FLAVOR = "terminal-mirror";
|
|
8519
8529
|
const RECONCILE_HYSTERESIS_MS = 2e4;
|
|
8520
8530
|
function createMirrorManager(deps) {
|
|
8521
|
-
const backfillLines = deps.backfillLines ??
|
|
8531
|
+
const backfillLines = deps.backfillLines ?? index.MIRROR_BACKFILL_LINES_DEFAULT;
|
|
8522
8532
|
const bindings = /* @__PURE__ */ new Map();
|
|
8523
8533
|
const lastEndedAt = /* @__PURE__ */ new Map();
|
|
8524
8534
|
const pendingCreates = /* @__PURE__ */ new Map();
|
|
@@ -8533,7 +8543,7 @@ function createMirrorManager(deps) {
|
|
|
8533
8543
|
};
|
|
8534
8544
|
const isTerminalAlive = deps.isTerminalAlive ?? ((terminalId) => {
|
|
8535
8545
|
try {
|
|
8536
|
-
return node_child_process.spawnSync("tmux",
|
|
8546
|
+
return node_child_process.spawnSync("tmux", index.tmuxArgs(["has-session", "-t", `=vh-${terminalId}:`]), { stdio: "ignore", timeout: 3e3, env: index.scrubTmuxClientEnv({ ...process.env }) }).status === 0;
|
|
8537
8547
|
} catch {
|
|
8538
8548
|
return false;
|
|
8539
8549
|
}
|
|
@@ -8541,7 +8551,7 @@ function createMirrorManager(deps) {
|
|
|
8541
8551
|
const transcriptPathFor = (event) => {
|
|
8542
8552
|
if (event.transcriptPath) return event.transcriptPath;
|
|
8543
8553
|
if (!event.cwd) return null;
|
|
8544
|
-
return path.join(
|
|
8554
|
+
return path.join(index.getProjectPath(event.cwd), `${event.claudeSessionId}.jsonl`);
|
|
8545
8555
|
};
|
|
8546
8556
|
const persistBinding = (binding) => {
|
|
8547
8557
|
persistence.persistSession(binding.happySessionId, {
|
|
@@ -8557,8 +8567,8 @@ function createMirrorManager(deps) {
|
|
|
8557
8567
|
};
|
|
8558
8568
|
const sendMessages = (binding, messages) => {
|
|
8559
8569
|
for (const message of messages) {
|
|
8560
|
-
const key =
|
|
8561
|
-
binding.client.sendClaudeSessionMessage(message, key ? { localIdFor: (envelopeIndex) =>
|
|
8570
|
+
const key = index.mirrorLineKey(message);
|
|
8571
|
+
binding.client.sendClaudeSessionMessage(message, key ? { localIdFor: (envelopeIndex) => index.mirrorLocalId(key, envelopeIndex) } : void 0);
|
|
8562
8572
|
}
|
|
8563
8573
|
};
|
|
8564
8574
|
const attachScanner = (binding, opts) => {
|
|
@@ -8662,7 +8672,7 @@ function createMirrorManager(deps) {
|
|
|
8662
8672
|
archiveReason: void 0
|
|
8663
8673
|
});
|
|
8664
8674
|
const scanner = attachScanner(binding, { withTruncationNotice: false });
|
|
8665
|
-
scanner.addFile(path.join(
|
|
8675
|
+
scanner.addFile(path.join(index.getProjectPath(meta.path), `${meta.claudeSessionId}.jsonl`), "backfill-tail");
|
|
8666
8676
|
persistence.logger.debug(`[MIRROR] reconcile adopted terminal ${terminalId} \u2192 ${sessionId}`);
|
|
8667
8677
|
deps.onBindingsChanged?.();
|
|
8668
8678
|
};
|
|
@@ -8677,7 +8687,7 @@ function createMirrorManager(deps) {
|
|
|
8677
8687
|
archiveReason: void 0
|
|
8678
8688
|
});
|
|
8679
8689
|
const scanner = binding.scanner ?? attachScanner(binding, { withTruncationNotice: false });
|
|
8680
|
-
scanner.addFile(path.join(
|
|
8690
|
+
scanner.addFile(path.join(index.getProjectPath(binding.metadata.path), `${binding.claudeSessionId}.jsonl`), "backfill-tail");
|
|
8681
8691
|
persistence.logger.debug(`[MIRROR] reconcile reactivated (in place) terminal ${binding.terminalId}`);
|
|
8682
8692
|
deps.onBindingsChanged?.();
|
|
8683
8693
|
};
|
|
@@ -8780,7 +8790,7 @@ function createMirrorManager(deps) {
|
|
|
8780
8790
|
const parked = pendingCreates.get(event.terminalId);
|
|
8781
8791
|
if (parked && pendingCreateSupersededBy(parked, event)) pendingCreates.delete(event.terminalId);
|
|
8782
8792
|
const binding = bindings.get(event.terminalId) ?? null;
|
|
8783
|
-
const decision =
|
|
8793
|
+
const decision = index.decideMirrorBinding(
|
|
8784
8794
|
event,
|
|
8785
8795
|
binding ? { status: binding.status, claudeSessionId: binding.claudeSessionId } : null
|
|
8786
8796
|
);
|
|
@@ -8801,7 +8811,7 @@ function createMirrorManager(deps) {
|
|
|
8801
8811
|
};
|
|
8802
8812
|
return {
|
|
8803
8813
|
handleHookPayload(body) {
|
|
8804
|
-
const event =
|
|
8814
|
+
const event = index.parseTerminalHookPayload(body);
|
|
8805
8815
|
if (!event) {
|
|
8806
8816
|
persistence.logger.debug("[MIRROR] unparseable /terminal-hook payload dropped");
|
|
8807
8817
|
return;
|
|
@@ -8929,7 +8939,7 @@ function createMirrorManager(deps) {
|
|
|
8929
8939
|
};
|
|
8930
8940
|
bindings.set(terminalId, binding);
|
|
8931
8941
|
const scanner = attachScanner(binding, { withTruncationNotice: false });
|
|
8932
|
-
scanner.addFile(path.join(
|
|
8942
|
+
scanner.addFile(path.join(index.getProjectPath(meta.path), `${meta.claudeSessionId}.jsonl`), "backfill-tail");
|
|
8933
8943
|
persistence.logger.debug(`[MIRROR] restored binding terminal ${terminalId} \u2192 ${sessionId}`);
|
|
8934
8944
|
deps.onBindingsChanged?.();
|
|
8935
8945
|
}
|
|
@@ -9608,7 +9618,7 @@ function toSummary(id, persisted, extra) {
|
|
|
9608
9618
|
};
|
|
9609
9619
|
}
|
|
9610
9620
|
async function listSessions(options = {}) {
|
|
9611
|
-
const live = await
|
|
9621
|
+
const live = await index.listDaemonSessions();
|
|
9612
9622
|
return mergeSessionSummaries(live, persistence.readPersistedSessions(), options);
|
|
9613
9623
|
}
|
|
9614
9624
|
function summarizeAccountSession(row, persisted, liveIds, now) {
|
|
@@ -9678,7 +9688,7 @@ async function listAccountSessions(options = {}) {
|
|
|
9678
9688
|
});
|
|
9679
9689
|
const rows = Array.isArray(response.data?.sessions) ? response.data.sessions : [];
|
|
9680
9690
|
const persisted = persistence.readPersistedSessions();
|
|
9681
|
-
const live = await
|
|
9691
|
+
const live = await index.listDaemonSessions();
|
|
9682
9692
|
const liveIds = new Set(live.map((child) => child.happySessionId).filter((id) => typeof id === "string"));
|
|
9683
9693
|
const now = Date.now();
|
|
9684
9694
|
const summaries = rows.filter((row) => typeof row?.id === "string").map((row) => summarizeAccountSession(row, persisted[row.id], liveIds, now)).filter((summary) => options.includeArchived || !summary.archived);
|
|
@@ -9712,7 +9722,7 @@ async function readSessionTranscript(sessionId, limit) {
|
|
|
9712
9722
|
const messages = Array.isArray(response.data?.messages) ? response.data.messages : [];
|
|
9713
9723
|
messages.reverse();
|
|
9714
9724
|
const key = persistence.decodeBase64(persisted.encryptionKey);
|
|
9715
|
-
const live = await
|
|
9725
|
+
const live = await index.listDaemonSessions();
|
|
9716
9726
|
const bodies = messages.map((message) => {
|
|
9717
9727
|
if (message.content?.t !== "encrypted") return null;
|
|
9718
9728
|
try {
|
|
@@ -9728,7 +9738,7 @@ async function readSessionTranscript(sessionId, limit) {
|
|
|
9728
9738
|
};
|
|
9729
9739
|
}
|
|
9730
9740
|
async function stopSession(sessionId) {
|
|
9731
|
-
return await
|
|
9741
|
+
return await index.stopDaemonSession(sessionId);
|
|
9732
9742
|
}
|
|
9733
9743
|
async function archiveSession(sessionId) {
|
|
9734
9744
|
const token = await bearerToken();
|
|
@@ -10038,6 +10048,10 @@ Use the teams tools to inspect current task state before acting. This message is
|
|
|
10038
10048
|
} };
|
|
10039
10049
|
}
|
|
10040
10050
|
|
|
10051
|
+
function daemonExitCode(source) {
|
|
10052
|
+
return source === "exception" ? 1 : 0;
|
|
10053
|
+
}
|
|
10054
|
+
|
|
10041
10055
|
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
10042
10056
|
function sanitizeImportTitle(value) {
|
|
10043
10057
|
if (typeof value !== "string") return null;
|
|
@@ -10046,7 +10060,7 @@ function sanitizeImportTitle(value) {
|
|
|
10046
10060
|
return collapsed.length > 200 ? `${collapsed.slice(0, 199)}\u2026` : collapsed;
|
|
10047
10061
|
}
|
|
10048
10062
|
const hostSuffix = process.env.HAPPY_VARIANT === "dev" ? "-dev" : "";
|
|
10049
|
-
const startupCliAvailability =
|
|
10063
|
+
const startupCliAvailability = index.detectCLIAvailability();
|
|
10050
10064
|
const initialMachineMetadata = {
|
|
10051
10065
|
teamsVersion: 1,
|
|
10052
10066
|
teamLaunchVersion: 1,
|
|
@@ -10057,7 +10071,7 @@ const initialMachineMetadata = {
|
|
|
10057
10071
|
happyHomeDir: persistence.configuration.happyHomeDir,
|
|
10058
10072
|
happyLibDir: projectPath.projectPath(),
|
|
10059
10073
|
cliAvailability: startupCliAvailability,
|
|
10060
|
-
resumeSupport: { ...
|
|
10074
|
+
resumeSupport: { ...index.detectResumeSupport(), rpcAvailable: true }
|
|
10061
10075
|
};
|
|
10062
10076
|
async function preflightNewBundle(bundlePath) {
|
|
10063
10077
|
const home = fs$1.mkdtempSync(path$1.join(os.tmpdir(), "vh-preflight-"));
|
|
@@ -10112,14 +10126,20 @@ async function startDaemon() {
|
|
|
10112
10126
|
let cliUpdateStateRef = null;
|
|
10113
10127
|
let lastHandoverHold = null;
|
|
10114
10128
|
let claudeCredentialStoreSetting = (await persistence.readSettings()).claudeCredentialStore === "file" ? "file" : "auto";
|
|
10129
|
+
try {
|
|
10130
|
+
const homes = await index.refreshAgentHomes();
|
|
10131
|
+
persistence.logger.debug(`[DAEMON RUN] Claude config dir: ${index.describeAgentHome(homes.claudeConfigDir)}; Codex home: ${index.describeAgentHome(homes.codexHome)}`);
|
|
10132
|
+
} catch (error) {
|
|
10133
|
+
persistence.logger.debug("[DAEMON RUN] agent home resolution failed; using the daemon environment as-is", error);
|
|
10134
|
+
}
|
|
10115
10135
|
let requestShutdown;
|
|
10116
10136
|
let resolvesWhenShutdownRequested = new Promise((resolve) => {
|
|
10117
10137
|
requestShutdown = (source, errorMessage) => {
|
|
10118
10138
|
persistence.logger.debug(`[DAEMON RUN] Requesting shutdown (source: ${source}, errorMessage: ${errorMessage})`);
|
|
10119
10139
|
setTimeout(async () => {
|
|
10120
|
-
persistence.logger.debug(
|
|
10140
|
+
persistence.logger.debug(`[DAEMON RUN] Shutdown did not complete in time, forcing exit with code ${daemonExitCode(source)}`);
|
|
10121
10141
|
await new Promise((resolve2) => setTimeout(resolve2, 100));
|
|
10122
|
-
process.exit(
|
|
10142
|
+
process.exit(daemonExitCode(source));
|
|
10123
10143
|
}, 1e3);
|
|
10124
10144
|
resolve({ source, errorMessage });
|
|
10125
10145
|
};
|
|
@@ -10156,7 +10176,7 @@ async function startDaemon() {
|
|
|
10156
10176
|
});
|
|
10157
10177
|
persistence.logger.debug("[DAEMON RUN] Starting daemon process...");
|
|
10158
10178
|
persistence.logger.debugLargeJson("[DAEMON RUN] Environment", getEnvironmentInfo());
|
|
10159
|
-
const runningDaemonVersionMatches = await
|
|
10179
|
+
const runningDaemonVersionMatches = await index.isDaemonRunningCurrentlyInstalledHappyVersion();
|
|
10160
10180
|
const runningDaemonState = await persistence.readDaemonState();
|
|
10161
10181
|
const runningDaemonEndpointsMatch = Boolean(runningDaemonState) && daemonEndpointsMatch(
|
|
10162
10182
|
runningDaemonState?.serverUrl,
|
|
@@ -10166,7 +10186,7 @@ async function startDaemon() {
|
|
|
10166
10186
|
);
|
|
10167
10187
|
if (!runningDaemonVersionMatches || !runningDaemonEndpointsMatch) {
|
|
10168
10188
|
persistence.logger.debug("[DAEMON RUN] Daemon version or endpoint mismatch detected, restarting daemon");
|
|
10169
|
-
await
|
|
10189
|
+
await index.stopDaemon();
|
|
10170
10190
|
} else {
|
|
10171
10191
|
persistence.logger.debug("[DAEMON RUN] Daemon version matches, keeping existing daemon");
|
|
10172
10192
|
console.log("Daemon already running with matching version");
|
|
@@ -10185,7 +10205,7 @@ async function startDaemon() {
|
|
|
10185
10205
|
const { credentials, machineId } = await authAndSetupMachineIfNeeded();
|
|
10186
10206
|
persistence.logger.debug("[DAEMON RUN] Auth and machine setup complete");
|
|
10187
10207
|
const pidToTrackedSession = /* @__PURE__ */ new Map();
|
|
10188
|
-
const turnActivity = new
|
|
10208
|
+
const turnActivity = new index.TurnActivityTracker();
|
|
10189
10209
|
const sessionIdToFinishedSession = /* @__PURE__ */ new Map();
|
|
10190
10210
|
let teamWorker;
|
|
10191
10211
|
const persisted = persistence.readPersistedSessions();
|
|
@@ -10277,7 +10297,8 @@ async function startDaemon() {
|
|
|
10277
10297
|
}
|
|
10278
10298
|
};
|
|
10279
10299
|
const assistantSpawnGate = createSpawnGate();
|
|
10280
|
-
const spawnSession = (options) => {
|
|
10300
|
+
const spawnSession = async (options) => {
|
|
10301
|
+
await index.refreshAgentHomes();
|
|
10281
10302
|
if (assistantSpawnMode(options) !== "claude-singleton") {
|
|
10282
10303
|
return spawnSessionImpl(options);
|
|
10283
10304
|
}
|
|
@@ -10285,7 +10306,7 @@ async function startDaemon() {
|
|
|
10285
10306
|
};
|
|
10286
10307
|
const currentCliAvailability = () => apiMachineRef?.getCLIAvailability() ?? startupCliAvailability;
|
|
10287
10308
|
const spawnSessionImpl = async (options) => {
|
|
10288
|
-
persistence.logger.debugLargeJson("[DAEMON RUN] Spawning session",
|
|
10309
|
+
persistence.logger.debugLargeJson("[DAEMON RUN] Spawning session", index.summarizeSpawnSessionForLog(options));
|
|
10289
10310
|
const spawnModel = options.agent === "pi" ? sanitizeSpawnModel(options.model) : null;
|
|
10290
10311
|
const spawnPermissionMode = sanitizeSpawnPermissionMode(options.permissionMode);
|
|
10291
10312
|
if (options.permissionMode !== void 0 && spawnPermissionMode === null) {
|
|
@@ -10350,7 +10371,7 @@ async function startDaemon() {
|
|
|
10350
10371
|
s.encryptionVariant
|
|
10351
10372
|
);
|
|
10352
10373
|
const claudeSessionId = resolveAssistantClaudeSessionId(s.metadata, serverMetadata);
|
|
10353
|
-
const canResumeClaude = !!claudeSessionId &&
|
|
10374
|
+
const canResumeClaude = !!claudeSessionId && index.locateClaudeConversation(assistantHome(), claudeSessionId) !== null;
|
|
10354
10375
|
return spawnTrackedHappyProcess({
|
|
10355
10376
|
args: [
|
|
10356
10377
|
"claude",
|
|
@@ -10369,6 +10390,8 @@ async function startDaemon() {
|
|
|
10369
10390
|
// B-297: see the resume/restart paths — every spawn carries the
|
|
10370
10391
|
// credentialStore=file shim, not just fresh sessions (B-276 D8).
|
|
10371
10392
|
...claudeAuthServiceRef?.claudeProcessEnvOverrides() ?? {},
|
|
10393
|
+
// B-478: point Claude at the directory the transcript was found in.
|
|
10394
|
+
...canResumeClaude ? index.agentHomeSpawnEnv({ workingDirectory: assistantHome(), claudeSessionId }) : {},
|
|
10372
10395
|
HAPPY_SESSION_VARIANT: "assistant",
|
|
10373
10396
|
HAPPY_RECONNECT_SESSION_ID: assistantSessionId,
|
|
10374
10397
|
HAPPY_RECONNECT_ENCRYPTION_KEY: s.encryptionKey,
|
|
@@ -10512,9 +10535,9 @@ async function startDaemon() {
|
|
|
10512
10535
|
};
|
|
10513
10536
|
}
|
|
10514
10537
|
const resumeId = agent === "claude" ? options.resumeClaudeSessionId : agent === "codex" ? options.resumeCodexThreadId : void 0;
|
|
10515
|
-
const resumeFragment = resumeId ? ` --resume ${
|
|
10516
|
-
const permissionModeFragment = spawnPermissionMode ? ` --permission-mode ${
|
|
10517
|
-
const modelFragment = spawnModel ? ` --model ${
|
|
10538
|
+
const resumeFragment = resumeId ? ` --resume ${index.shellescape(resumeId)}` : "";
|
|
10539
|
+
const permissionModeFragment = spawnPermissionMode ? ` --permission-mode ${index.shellescape(spawnPermissionMode)}` : "";
|
|
10540
|
+
const modelFragment = spawnModel ? ` --model ${index.shellescape(spawnModel)}` : "";
|
|
10518
10541
|
const fullCommand = `node --no-warnings --no-deprecation ${cliPath} ${agent} --happy-starting-mode remote --started-by daemon${resumeFragment}${permissionModeFragment}${modelFragment}`;
|
|
10519
10542
|
const windowName = `happy-${Date.now()}-${agent}`;
|
|
10520
10543
|
const tmuxEnv = {};
|
|
@@ -10523,6 +10546,7 @@ async function startDaemon() {
|
|
|
10523
10546
|
tmuxEnv[key] = value;
|
|
10524
10547
|
}
|
|
10525
10548
|
}
|
|
10549
|
+
Object.assign(tmuxEnv, index.agentHomeSpawnEnv({ workingDirectory: directory, claudeSessionId: options.resumeClaudeSessionId, codexThreadId: options.resumeCodexThreadId }));
|
|
10526
10550
|
Object.assign(tmuxEnv, extraEnv);
|
|
10527
10551
|
const tmuxResult = await tmux.spawnInTmux([fullCommand], {
|
|
10528
10552
|
sessionName: tmuxSessionName,
|
|
@@ -10617,6 +10641,9 @@ async function startDaemon() {
|
|
|
10617
10641
|
cwd: directory,
|
|
10618
10642
|
env: {
|
|
10619
10643
|
...process.env,
|
|
10644
|
+
// B-478: a fork/duplicate resumes a transcript that may live in
|
|
10645
|
+
// a moved config dir. Explicit environmentVariables still win.
|
|
10646
|
+
...index.agentHomeSpawnEnv({ workingDirectory: directory, claudeSessionId: options.resumeClaudeSessionId, codexThreadId: options.resumeCodexThreadId }),
|
|
10620
10647
|
...extraEnv
|
|
10621
10648
|
},
|
|
10622
10649
|
directoryCreated,
|
|
@@ -10767,6 +10794,7 @@ async function startDaemon() {
|
|
|
10767
10794
|
gate = createSpawnGate();
|
|
10768
10795
|
resumeGates.set(happySessionId, gate);
|
|
10769
10796
|
}
|
|
10797
|
+
await index.refreshAgentHomes();
|
|
10770
10798
|
try {
|
|
10771
10799
|
return await gate.join(() => resumeSessionImpl(happySessionId, options));
|
|
10772
10800
|
} finally {
|
|
@@ -10813,7 +10841,9 @@ async function startDaemon() {
|
|
|
10813
10841
|
}
|
|
10814
10842
|
const precheck = resumePrecheck(metadata, {
|
|
10815
10843
|
cwdExists: (p) => fs$1.existsSync(p),
|
|
10816
|
-
|
|
10844
|
+
// B-478: also looks in every other Claude config dir the user's shell
|
|
10845
|
+
// or settings point at, not just the one the daemon was started with.
|
|
10846
|
+
conversationExists: (cwd, claudeSessionId) => index.locateClaudeConversation(cwd, claudeSessionId) !== null
|
|
10817
10847
|
});
|
|
10818
10848
|
let freshConversation = false;
|
|
10819
10849
|
if (!precheck.ok) {
|
|
@@ -10844,6 +10874,9 @@ async function startDaemon() {
|
|
|
10844
10874
|
// fell back to `auto` reads a different credential store than the
|
|
10845
10875
|
// fresh one next to it (B-276 D8).
|
|
10846
10876
|
...claudeAuthServiceRef?.claudeProcessEnvOverrides() ?? {},
|
|
10877
|
+
// B-478: if the transcript lives in a Claude/Codex home other than
|
|
10878
|
+
// the resolved one, this spawn is pointed there.
|
|
10879
|
+
...freshConversation ? {} : index.agentHomeSpawnEnv({ workingDirectory: launch.cwd, claudeSessionId: metadata.claudeSessionId, codexThreadId: metadata.codexThreadId }),
|
|
10847
10880
|
HAPPY_RECONNECT_SESSION_ID: happySessionId,
|
|
10848
10881
|
HAPPY_RECONNECT_ENCRYPTION_KEY: persistence.encodeBase64(tracked.encryption.encryptionKey),
|
|
10849
10882
|
HAPPY_RECONNECT_ENCRYPTION_VARIANT: tracked.encryption.encryptionVariant,
|
|
@@ -10905,6 +10938,7 @@ async function startDaemon() {
|
|
|
10905
10938
|
gate = createSpawnGate();
|
|
10906
10939
|
resumeGates.set(happySessionId, gate);
|
|
10907
10940
|
}
|
|
10941
|
+
await index.refreshAgentHomes();
|
|
10908
10942
|
try {
|
|
10909
10943
|
return await gate.replace(() => restartSessionImpl(happySessionId, options));
|
|
10910
10944
|
} finally {
|
|
@@ -10940,7 +10974,9 @@ async function startDaemon() {
|
|
|
10940
10974
|
}
|
|
10941
10975
|
const precheck = resumePrecheck(metadata, {
|
|
10942
10976
|
cwdExists: (p) => fs$1.existsSync(p),
|
|
10943
|
-
|
|
10977
|
+
// B-478: also looks in every other Claude config dir the user's shell
|
|
10978
|
+
// or settings point at, not just the one the daemon was started with.
|
|
10979
|
+
conversationExists: (cwd2, claudeSessionId) => index.locateClaudeConversation(cwd2, claudeSessionId) !== null
|
|
10944
10980
|
});
|
|
10945
10981
|
let args;
|
|
10946
10982
|
let cwd;
|
|
@@ -10975,6 +11011,8 @@ async function startDaemon() {
|
|
|
10975
11011
|
// fell back to `auto` reads a different credential store than the
|
|
10976
11012
|
// fresh one next to it (B-276 D8).
|
|
10977
11013
|
...claudeAuthServiceRef?.claudeProcessEnvOverrides() ?? {},
|
|
11014
|
+
// B-478: see resumeSession.
|
|
11015
|
+
...precheck.ok ? index.agentHomeSpawnEnv({ workingDirectory: cwd, claudeSessionId: metadata.claudeSessionId, codexThreadId: metadata.codexThreadId }) : {},
|
|
10978
11016
|
HAPPY_RECONNECT_SESSION_ID: happySessionId,
|
|
10979
11017
|
HAPPY_RECONNECT_ENCRYPTION_KEY: persistence.encodeBase64(tracked.encryption.encryptionKey),
|
|
10980
11018
|
HAPPY_RECONNECT_ENCRYPTION_VARIANT: tracked.encryption.encryptionVariant,
|
|
@@ -11152,8 +11190,8 @@ async function startDaemon() {
|
|
|
11152
11190
|
httpPort: controlPort,
|
|
11153
11191
|
startedAt: Date.now()
|
|
11154
11192
|
};
|
|
11155
|
-
const api
|
|
11156
|
-
const machine = await api
|
|
11193
|
+
const api = await index.ApiClient.create(credentials);
|
|
11194
|
+
const machine = await api.getOrCreateMachine({
|
|
11157
11195
|
machineId,
|
|
11158
11196
|
metadata: initialMachineMetadata,
|
|
11159
11197
|
daemonState: initialDaemonState
|
|
@@ -11167,10 +11205,10 @@ async function startDaemon() {
|
|
|
11167
11205
|
if (identityConflict) {
|
|
11168
11206
|
persistence.logger.warn(`[DAEMON RUN] machine identity conflict (${identityConflict.confidence}): ${describeMachineIdentityConflict(identityConflict)}`);
|
|
11169
11207
|
}
|
|
11170
|
-
const apiMachine = api
|
|
11208
|
+
const apiMachine = api.machineSyncClient(machine);
|
|
11171
11209
|
apiMachineRef = apiMachine;
|
|
11172
11210
|
const mirrorManager = createMirrorManager({
|
|
11173
|
-
api
|
|
11211
|
+
api,
|
|
11174
11212
|
machineId,
|
|
11175
11213
|
onBindingsChanged: () => apiMachine.requestTerminalListRefresh()
|
|
11176
11214
|
});
|
|
@@ -11221,7 +11259,7 @@ async function startDaemon() {
|
|
|
11221
11259
|
}
|
|
11222
11260
|
let lastUpdateLog = "";
|
|
11223
11261
|
const updateController = createUpdateController({
|
|
11224
|
-
policy: () =>
|
|
11262
|
+
policy: () => index.fetchCliUpdateState(persistence.configuration.serverUrl, persistence.packageJson.version),
|
|
11225
11263
|
enabled: async () => ((await persistence.readSettings()).cliAutoUpdate ?? "idle") !== "off",
|
|
11226
11264
|
// B-466: "idle" = no agent turn in flight. Idle wrappers survive a
|
|
11227
11265
|
// handover (they talk to the server themselves) and web terminals live
|
|
@@ -11248,9 +11286,9 @@ async function startDaemon() {
|
|
|
11248
11286
|
persistence.logger.debug("[DAEMON RUN] CLI update policy check failed:", error);
|
|
11249
11287
|
});
|
|
11250
11288
|
void refreshCliUpdate();
|
|
11251
|
-
const cliUpdateIntervalMs =
|
|
11252
|
-
if (process.env.HAPPY_CLI_UPDATE_CHECK_INTERVAL && cliUpdateIntervalMs ===
|
|
11253
|
-
persistence.logger.warn(`[DAEMON RUN] Ignoring invalid HAPPY_CLI_UPDATE_CHECK_INTERVAL; using ${
|
|
11289
|
+
const cliUpdateIntervalMs = index.resolveCliUpdateCheckInterval(process.env.HAPPY_CLI_UPDATE_CHECK_INTERVAL);
|
|
11290
|
+
if (process.env.HAPPY_CLI_UPDATE_CHECK_INTERVAL && cliUpdateIntervalMs === index.DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS && process.env.HAPPY_CLI_UPDATE_CHECK_INTERVAL.trim() !== String(index.DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS)) {
|
|
11291
|
+
persistence.logger.warn(`[DAEMON RUN] Ignoring invalid HAPPY_CLI_UPDATE_CHECK_INTERVAL; using ${index.DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS}ms`);
|
|
11254
11292
|
}
|
|
11255
11293
|
const cliUpdateInterval = setInterval(() => void refreshCliUpdate(), cliUpdateIntervalMs);
|
|
11256
11294
|
const stopAgentVersionChecks = startAgentVersionChecks(
|
|
@@ -11301,7 +11339,7 @@ async function startDaemon() {
|
|
|
11301
11339
|
claudeAuthService.stop();
|
|
11302
11340
|
apiMachine.shutdown();
|
|
11303
11341
|
await stopControlServer();
|
|
11304
|
-
await
|
|
11342
|
+
await index.cleanupDaemonState();
|
|
11305
11343
|
await persistence.releaseDaemonLock(daemonLockHandle);
|
|
11306
11344
|
await stopCaffeinate();
|
|
11307
11345
|
try {
|
|
@@ -11374,11 +11412,11 @@ async function startDaemon() {
|
|
|
11374
11412
|
}
|
|
11375
11413
|
apiMachine.shutdown();
|
|
11376
11414
|
await stopControlServer();
|
|
11377
|
-
await
|
|
11415
|
+
await index.cleanupDaemonState();
|
|
11378
11416
|
await stopCaffeinate();
|
|
11379
11417
|
await persistence.releaseDaemonLock(daemonLockHandle);
|
|
11380
|
-
persistence.logger.debug(
|
|
11381
|
-
process.exit(
|
|
11418
|
+
persistence.logger.debug(`[DAEMON RUN] Cleanup completed, exiting process with code ${daemonExitCode(source)}`);
|
|
11419
|
+
process.exit(daemonExitCode(source));
|
|
11382
11420
|
};
|
|
11383
11421
|
persistence.logger.debug("[DAEMON RUN] Daemon started successfully, waiting for shutdown request");
|
|
11384
11422
|
const shutdownRequest = await resolvesWhenShutdownRequested;
|
|
@@ -11641,7 +11679,7 @@ ${sessions.map(describeSummary).join("\n")}`);
|
|
|
11641
11679
|
limit: z.z.number().optional().describe("How many recent messages to fetch (default 20, max 100)")
|
|
11642
11680
|
}
|
|
11643
11681
|
}, async (args) => {
|
|
11644
|
-
if (!
|
|
11682
|
+
if (!index.isValidSessionId(args.sessionId)) return fail("Invalid sessionId");
|
|
11645
11683
|
try {
|
|
11646
11684
|
const result = await readSessionTranscript(args.sessionId, args.limit ?? 20);
|
|
11647
11685
|
const body = result.transcript.length > 0 ? result.transcript : "(no readable conversation content in this range)";
|
|
@@ -11660,7 +11698,7 @@ ${body}`);
|
|
|
11660
11698
|
text: z.z.string().describe("The message text to send")
|
|
11661
11699
|
}
|
|
11662
11700
|
}, async (args) => {
|
|
11663
|
-
if (!
|
|
11701
|
+
if (!index.isValidSessionId(args.sessionId)) return fail("Invalid sessionId");
|
|
11664
11702
|
if (typeof args.text !== "string" || args.text.trim().length === 0) return fail("text must be non-empty");
|
|
11665
11703
|
try {
|
|
11666
11704
|
const persisted = await waitForSessionKey(args.sessionId, 0);
|
|
@@ -11682,7 +11720,7 @@ ${body}`);
|
|
|
11682
11720
|
if (!normalized.ok) return fail(normalized.error);
|
|
11683
11721
|
const directory = normalized.directory;
|
|
11684
11722
|
try {
|
|
11685
|
-
const result = await
|
|
11723
|
+
const result = await index.spawnDaemonSession(directory, void 0, { spawnedBy: "assistant" });
|
|
11686
11724
|
if (result?.error || !result?.sessionId) {
|
|
11687
11725
|
return fail(`Failed to spawn session: ${result?.error ?? "daemon returned no session id"}`);
|
|
11688
11726
|
}
|
|
@@ -11709,7 +11747,7 @@ ${body}`);
|
|
|
11709
11747
|
sessionId: z.z.string().describe("The Happy session id to stop")
|
|
11710
11748
|
}
|
|
11711
11749
|
}, async (args) => {
|
|
11712
|
-
if (!
|
|
11750
|
+
if (!index.isValidSessionId(args.sessionId)) return fail("Invalid sessionId");
|
|
11713
11751
|
try {
|
|
11714
11752
|
const persisted = persistence.readPersistedSessions()[args.sessionId];
|
|
11715
11753
|
const success = await stopSession(args.sessionId);
|
|
@@ -11726,7 +11764,7 @@ ${body}`);
|
|
|
11726
11764
|
sessionId: z.z.string().describe("The Happy session id to archive")
|
|
11727
11765
|
}
|
|
11728
11766
|
}, async (args) => {
|
|
11729
|
-
if (!
|
|
11767
|
+
if (!index.isValidSessionId(args.sessionId)) return fail("Invalid sessionId");
|
|
11730
11768
|
try {
|
|
11731
11769
|
await archiveSession(args.sessionId);
|
|
11732
11770
|
const persisted = persistence.readPersistedSessions()[args.sessionId];
|
|
@@ -11742,7 +11780,7 @@ function registerAssistantMachineTools(mcp) {
|
|
|
11742
11780
|
title: "List Terminals",
|
|
11743
11781
|
inputSchema: {}
|
|
11744
11782
|
}, async () => {
|
|
11745
|
-
const r =
|
|
11783
|
+
const r = index.listVhTerminals();
|
|
11746
11784
|
if (!r.ok) return fail(`Failed to list terminals: ${r.error}`);
|
|
11747
11785
|
if (r.terminals.length === 0) return ok("No web terminals are open on this machine.");
|
|
11748
11786
|
const lines = r.terminals.map((t) => {
|
|
@@ -11762,8 +11800,8 @@ ${lines.join("\n")}`);
|
|
|
11762
11800
|
lines: z.z.number().optional().describe("How many history lines to read (default 80, max 2000)")
|
|
11763
11801
|
}
|
|
11764
11802
|
}, async (args) => {
|
|
11765
|
-
if (!
|
|
11766
|
-
const r =
|
|
11803
|
+
if (!index.isValidTerminalId(args.terminalId)) return fail("Invalid terminalId");
|
|
11804
|
+
const r = index.readVhTerminal(args.terminalId, args.lines ?? 80);
|
|
11767
11805
|
if (!r.ok) return fail(`Failed to read terminal ${args.terminalId}: ${r.error}`);
|
|
11768
11806
|
return ok(`terminal ${args.terminalId} \u2014 last output:
|
|
11769
11807
|
${r.text}`);
|
|
@@ -11777,10 +11815,10 @@ ${r.text}`);
|
|
|
11777
11815
|
submit: z.z.boolean().optional().describe("Also press Enter after pasting (default false)")
|
|
11778
11816
|
}
|
|
11779
11817
|
}, async (args) => {
|
|
11780
|
-
if (!
|
|
11818
|
+
if (!index.isValidTerminalId(args.terminalId)) return fail("Invalid terminalId");
|
|
11781
11819
|
if (typeof args.text !== "string" || args.text.length === 0) return fail("text must be non-empty");
|
|
11782
11820
|
const submit = args.submit === true;
|
|
11783
|
-
const r =
|
|
11821
|
+
const r = index.sendToVhTerminal(args.terminalId, args.text, submit);
|
|
11784
11822
|
if (!r.ok) return fail(`Failed to send to terminal ${args.terminalId}: ${r.error}`);
|
|
11785
11823
|
return ok(submit ? `Pasted and submitted (Enter sent) in terminal ${args.terminalId}.` : `Pasted into terminal ${args.terminalId} WITHOUT pressing Enter \u2014 the user (or a follow-up terminal_send with submit=true) decides whether it runs.`);
|
|
11786
11824
|
});
|
|
@@ -12052,7 +12090,7 @@ async function startHappyServer(client, options) {
|
|
|
12052
12090
|
return;
|
|
12053
12091
|
}
|
|
12054
12092
|
}
|
|
12055
|
-
const usage =
|
|
12093
|
+
const usage = index.ContextUsageSchema.parse({ ...JSON.parse(body), updatedAt: Date.now() });
|
|
12056
12094
|
options.onContextUsage(usage);
|
|
12057
12095
|
res.writeHead(204).end();
|
|
12058
12096
|
} catch {
|
|
@@ -12372,7 +12410,7 @@ function registerSideQuestionHandler(rpc, deps) {
|
|
|
12372
12410
|
const retainMs = deps.retainMs ?? SIDE_QUESTION_RETAIN_MS;
|
|
12373
12411
|
const maxRunMs = deps.maxRunMs ?? SIDE_QUESTION_MAX_RUN_MS;
|
|
12374
12412
|
const run = deps.run ?? (async (input) => {
|
|
12375
|
-
const { query } = await Promise.resolve().then(function () { return require('./index-
|
|
12413
|
+
const { query } = await Promise.resolve().then(function () { return require('./index-DIoSNgtt.cjs'); });
|
|
12376
12414
|
return runSideQuestion(query, input);
|
|
12377
12415
|
});
|
|
12378
12416
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -12474,7 +12512,7 @@ const MAX_TITLE_CHARS = 60;
|
|
|
12474
12512
|
const GENERATION_TIMEOUT_MS = 3e4;
|
|
12475
12513
|
function resolveClaudeBinary() {
|
|
12476
12514
|
try {
|
|
12477
|
-
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-
|
|
12515
|
+
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-Dn0JMM8l.cjs', document.baseURI).href)));
|
|
12478
12516
|
const utilsPath = path.resolve(path.join(projectPath.projectPath(), "scripts", "claude_version_utils.cjs"));
|
|
12479
12517
|
const { getClaudeCliPath } = require$1(utilsPath);
|
|
12480
12518
|
const path$1 = getClaudeCliPath();
|
|
@@ -12486,7 +12524,7 @@ function resolveClaudeBinary() {
|
|
|
12486
12524
|
}
|
|
12487
12525
|
function buildPrompt(firstUserMessage) {
|
|
12488
12526
|
const sample = firstUserMessage.slice(0, MAX_PROMPT_SAMPLE_CHARS);
|
|
12489
|
-
return `${
|
|
12527
|
+
return `${index.TITLE_PROMPT_PREFIX} (match the message's language). Be concrete \u2014 name the actual task/subject. Do NOT output generic placeholders like "\u65B0\u5BF9\u8BDD"/"New chat"/"Conversation"/"Untitled". No quotes, no trailing punctuation. Reply with ONLY the title.
|
|
12490
12528
|
|
|
12491
12529
|
Message: "${sample}"`;
|
|
12492
12530
|
}
|
|
@@ -12682,7 +12720,7 @@ function buildBoardPrompt(input) {
|
|
|
12682
12720
|
const taskLines = tasks.length > 0 ? tasks.map((t) => `- ${t.id}: ${t.title}`).join("\n") : "(no tasks defined)";
|
|
12683
12721
|
const todoBlock = input.todos.length > 0 ? input.todos.join("\n") : "(none)";
|
|
12684
12722
|
return [
|
|
12685
|
-
`${
|
|
12723
|
+
`${index.BOARD_ANALYZER_PROMPT_PREFIX} Analyze this session snapshot and reply with ONLY a strict JSON object, no markdown, no explanations:`,
|
|
12686
12724
|
'{"taskId": string|null, "attention": "none"|"review"|"blocked", "progress": string}',
|
|
12687
12725
|
"",
|
|
12688
12726
|
"Rules:",
|
|
@@ -12886,8 +12924,8 @@ async function runClaude(credentials, options = {}) {
|
|
|
12886
12924
|
if (options.startedBy === "daemon" && options.startingMode === "local") {
|
|
12887
12925
|
throw new Error("Daemon-spawned sessions cannot use local/interactive mode. Use --happy-starting-mode remote or spawn sessions directly from terminal.");
|
|
12888
12926
|
}
|
|
12889
|
-
|
|
12890
|
-
const api
|
|
12927
|
+
index.connectionState.setBackend("Claude");
|
|
12928
|
+
const api = await index.ApiClient.create(credentials);
|
|
12891
12929
|
let state = {};
|
|
12892
12930
|
const settings = await persistence.readSettings();
|
|
12893
12931
|
let machineId = settings?.machineId;
|
|
@@ -12904,7 +12942,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
12904
12942
|
}
|
|
12905
12943
|
persistence.logger.debug(`Using machineId: ${machineId}`);
|
|
12906
12944
|
const sessionTag = node_crypto.randomUUID();
|
|
12907
|
-
await api
|
|
12945
|
+
await api.getOrCreateMachine({
|
|
12908
12946
|
machineId,
|
|
12909
12947
|
metadata: initialMachineMetadata
|
|
12910
12948
|
});
|
|
@@ -12974,16 +13012,16 @@ async function runClaude(credentials, options = {}) {
|
|
|
12974
13012
|
agentStateVersion: parseInt(reconnectAgentStateVersion || "0", 10)
|
|
12975
13013
|
};
|
|
12976
13014
|
} else {
|
|
12977
|
-
response = await api
|
|
13015
|
+
response = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
12978
13016
|
}
|
|
12979
13017
|
if (!response) {
|
|
12980
13018
|
let offlineSessionId = null;
|
|
12981
|
-
const reconnection =
|
|
13019
|
+
const reconnection = index.startOfflineReconnection({
|
|
12982
13020
|
serverUrl: persistence.configuration.serverUrl,
|
|
12983
13021
|
onReconnected: async () => {
|
|
12984
|
-
const resp = await api
|
|
13022
|
+
const resp = await api.getOrCreateSession({ tag: node_crypto.randomUUID(), metadata, state });
|
|
12985
13023
|
if (!resp) throw new Error("Server unavailable");
|
|
12986
|
-
const session2 = api
|
|
13024
|
+
const session2 = api.sessionSyncClient(resp);
|
|
12987
13025
|
const scanner = await createSessionScanner({
|
|
12988
13026
|
sessionId: null,
|
|
12989
13027
|
workingDirectory,
|
|
@@ -13019,12 +13057,12 @@ async function runClaude(credentials, options = {}) {
|
|
|
13019
13057
|
}
|
|
13020
13058
|
persistence.logger.debug(`Session created: ${response.id}`);
|
|
13021
13059
|
await claimSessionOrExit(response.id, { takeover: !!reconnectSessionId, flavor: "claude" });
|
|
13022
|
-
if (reconnectSessionId && !await api
|
|
13060
|
+
if (reconnectSessionId && !await api.reactivateSession(response.id)) {
|
|
13023
13061
|
throw new Error(`Failed to reactivate archived session ${response.id}`);
|
|
13024
13062
|
}
|
|
13025
13063
|
let reconnectSeeded = false;
|
|
13026
13064
|
if (reconnectSessionId) {
|
|
13027
|
-
const snapshot = await api
|
|
13065
|
+
const snapshot = await api.getSession(response.id, response.encryptionKey, response.encryptionVariant);
|
|
13028
13066
|
if (snapshot.ok) {
|
|
13029
13067
|
response = applyServerSnapshot(response, snapshot.session);
|
|
13030
13068
|
reconnectSeeded = true;
|
|
@@ -13036,7 +13074,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
13036
13074
|
}
|
|
13037
13075
|
try {
|
|
13038
13076
|
persistence.logger.debug(`[START] Reporting session ${response.id} to daemon`);
|
|
13039
|
-
const result = await
|
|
13077
|
+
const result = await index.notifyDaemonSessionStarted(response.id, metadata, {
|
|
13040
13078
|
encryptionKey: persistence.encodeBase64(response.encryptionKey),
|
|
13041
13079
|
encryptionVariant: response.encryptionVariant,
|
|
13042
13080
|
seq: response.seq,
|
|
@@ -13051,7 +13089,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
13051
13089
|
} catch (error) {
|
|
13052
13090
|
persistence.logger.debug("[START] Failed to report to daemon (may not be running):", error);
|
|
13053
13091
|
}
|
|
13054
|
-
const session = api
|
|
13092
|
+
const session = api.sessionSyncClient(response, reconnectSeeded ? { initialSeq: response.seq } : void 0);
|
|
13055
13093
|
if (reconnectSessionId) {
|
|
13056
13094
|
session.suppressNextArchiveSignal();
|
|
13057
13095
|
if (!reconnectSeeded) session.skipExistingMessages();
|
|
@@ -13067,7 +13105,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
13067
13105
|
}
|
|
13068
13106
|
const forkClaudeSessionId = process.env.HAPPY_FORK_CLAUDE_SESSION_ID;
|
|
13069
13107
|
if (!reconnectSessionId && forkClaudeSessionId) {
|
|
13070
|
-
const jsonlPath = path.join(
|
|
13108
|
+
const jsonlPath = path.join(index.getProjectPath(workingDirectory), `${forkClaudeSessionId}.jsonl`);
|
|
13071
13109
|
try {
|
|
13072
13110
|
const file = await promises.readFile(jsonlPath, "utf-8");
|
|
13073
13111
|
const lines = file.split("\n");
|
|
@@ -13080,7 +13118,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
13080
13118
|
} catch {
|
|
13081
13119
|
continue;
|
|
13082
13120
|
}
|
|
13083
|
-
const result =
|
|
13121
|
+
const result = index.RawJSONLinesSchema.safeParse(parsed);
|
|
13084
13122
|
if (!result.success) continue;
|
|
13085
13123
|
session.sendClaudeSessionMessage(result.data);
|
|
13086
13124
|
backfilled += 1;
|
|
@@ -13122,7 +13160,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
13122
13160
|
enabled: settings?.boardLlm === true,
|
|
13123
13161
|
selfReportState: boardSelfReport,
|
|
13124
13162
|
fetchTasks: async () => {
|
|
13125
|
-
const item = await api
|
|
13163
|
+
const item = await api.kvGet("vh.board-tasks.v1");
|
|
13126
13164
|
if (!item) return null;
|
|
13127
13165
|
try {
|
|
13128
13166
|
const parsed = JSON.parse(Buffer.from(item.value, "base64").toString("utf8"));
|
|
@@ -13158,7 +13196,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
13158
13196
|
let currentSession = null;
|
|
13159
13197
|
const hookServer = await startHookServer({
|
|
13160
13198
|
onSessionHook: (sessionId, data) => {
|
|
13161
|
-
persistence.logger.debug(`[START] Session hook received: ${sessionId}`,
|
|
13199
|
+
persistence.logger.debug(`[START] Session hook received: ${sessionId}`, index.contentLogMetadata(data));
|
|
13162
13200
|
remoteScanner.onNewSession(sessionId, { treatExistingAsProcessed: true });
|
|
13163
13201
|
if (currentSession) {
|
|
13164
13202
|
const previousSessionId = currentSession.sessionId;
|
|
@@ -13376,7 +13414,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
13376
13414
|
};
|
|
13377
13415
|
messageQueue.pushIsolateAndClear(specialCommand.originalMessage || message.content.text, enhancedMode2, attachmentsForThisMessage, message.localKey);
|
|
13378
13416
|
persistence.logger.debug("[start] /compact command pushed to queue:", {
|
|
13379
|
-
...
|
|
13417
|
+
...index.contentLogMetadata(message.content.text),
|
|
13380
13418
|
attachmentCount: attachmentsForThisMessage?.length ?? 0,
|
|
13381
13419
|
hasMetadata: Boolean(message.meta)
|
|
13382
13420
|
});
|
|
@@ -13396,7 +13434,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
13396
13434
|
};
|
|
13397
13435
|
messageQueue.pushIsolateAndClear(specialCommand.originalMessage || message.content.text, enhancedMode2, attachmentsForThisMessage, message.localKey);
|
|
13398
13436
|
persistence.logger.debug("[start] /clear command pushed to queue:", {
|
|
13399
|
-
...
|
|
13437
|
+
...index.contentLogMetadata(message.content.text),
|
|
13400
13438
|
attachmentCount: attachmentsForThisMessage?.length ?? 0,
|
|
13401
13439
|
hasMetadata: Boolean(message.meta)
|
|
13402
13440
|
});
|
|
@@ -13458,7 +13496,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
13458
13496
|
}) === true;
|
|
13459
13497
|
if (accepted) {
|
|
13460
13498
|
persistence.logger.debug("User message steered into current turn:", {
|
|
13461
|
-
...
|
|
13499
|
+
...index.contentLogMetadata(message.content.text),
|
|
13462
13500
|
attachmentCount: attachmentsForThisMessage?.length ?? 0
|
|
13463
13501
|
});
|
|
13464
13502
|
return;
|
|
@@ -13467,7 +13505,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
13467
13505
|
}
|
|
13468
13506
|
messageQueue.push(message.content.text, enhancedMode, attachmentsForThisMessage, message.localKey);
|
|
13469
13507
|
persistence.logger.debug("User message pushed to queue:", {
|
|
13470
|
-
...
|
|
13508
|
+
...index.contentLogMetadata(message.content.text),
|
|
13471
13509
|
attachmentCount: attachmentsForThisMessage?.length ?? 0,
|
|
13472
13510
|
hasMetadata: Boolean(message.meta)
|
|
13473
13511
|
});
|
|
@@ -13488,7 +13526,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
13488
13526
|
currentSession?.cleanup();
|
|
13489
13527
|
session.sendSessionDeath();
|
|
13490
13528
|
try {
|
|
13491
|
-
await api
|
|
13529
|
+
await api.deactivateSession(session.sessionId);
|
|
13492
13530
|
} catch (err) {
|
|
13493
13531
|
persistence.logger.debug("[START] deactivateSession during cleanup failed:", err);
|
|
13494
13532
|
}
|
|
@@ -13535,7 +13573,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
13535
13573
|
permissionMode: initialPermissionMode,
|
|
13536
13574
|
startingMode: options.startingMode,
|
|
13537
13575
|
messageQueue,
|
|
13538
|
-
api
|
|
13576
|
+
api,
|
|
13539
13577
|
allowedTools: happyServer.toolNames.map((toolName) => `mcp__happy__${toolName}`),
|
|
13540
13578
|
onModeChange: (newMode) => {
|
|
13541
13579
|
currentRunMode = newMode;
|
|
@@ -13764,7 +13802,7 @@ async function handleAuthLogin(args) {
|
|
|
13764
13802
|
console.log(chalk.gray(" \u2022 Re-authenticate and register machine\n"));
|
|
13765
13803
|
try {
|
|
13766
13804
|
persistence.logger.debug("Stopping daemon for force auth...");
|
|
13767
|
-
await
|
|
13805
|
+
await index.stopDaemon();
|
|
13768
13806
|
console.log(chalk.gray("\u2713 Stopped daemon"));
|
|
13769
13807
|
} catch (error) {
|
|
13770
13808
|
persistence.logger.debug("Daemon was not running or failed to stop:", error);
|
|
@@ -13829,7 +13867,7 @@ async function handleAuthLogout() {
|
|
|
13829
13867
|
if (answer.toLowerCase() === "y" || answer.toLowerCase() === "yes") {
|
|
13830
13868
|
try {
|
|
13831
13869
|
try {
|
|
13832
|
-
await
|
|
13870
|
+
await index.stopDaemon();
|
|
13833
13871
|
console.log(chalk.gray("Stopped daemon"));
|
|
13834
13872
|
} catch {
|
|
13835
13873
|
}
|
|
@@ -13874,7 +13912,7 @@ async function handleAuthStatus() {
|
|
|
13874
13912
|
console.log(chalk.gray(`
|
|
13875
13913
|
Data directory: ${persistence.configuration.happyHomeDir}`));
|
|
13876
13914
|
try {
|
|
13877
|
-
const running = await
|
|
13915
|
+
const running = await index.checkIfDaemonRunningAndCleanupStaleState();
|
|
13878
13916
|
if (running) {
|
|
13879
13917
|
console.log(chalk.green("\u2713 Daemon running"));
|
|
13880
13918
|
} else {
|
|
@@ -14436,23 +14474,23 @@ async function handleConnectVendor(vendor, displayName) {
|
|
|
14436
14474
|
console.log(chalk.gray(' Please run "very-happy auth login" first'));
|
|
14437
14475
|
process.exit(1);
|
|
14438
14476
|
}
|
|
14439
|
-
const api
|
|
14477
|
+
const api = await index.ApiClient.create(credentials);
|
|
14440
14478
|
if (vendor === "codex") {
|
|
14441
14479
|
console.log("\u{1F680} Registering Codex token with server");
|
|
14442
14480
|
const codexAuthTokens = await authenticateCodex();
|
|
14443
|
-
await api
|
|
14481
|
+
await api.registerVendorToken("openai", { oauth: codexAuthTokens });
|
|
14444
14482
|
console.log("\u2705 Codex token registered with server");
|
|
14445
14483
|
process.exit(0);
|
|
14446
14484
|
} else if (vendor === "claude") {
|
|
14447
14485
|
console.log("\u{1F680} Registering Anthropic token with server");
|
|
14448
14486
|
const anthropicAuthTokens = await authenticateClaude();
|
|
14449
|
-
await api
|
|
14487
|
+
await api.registerVendorToken("anthropic", { oauth: anthropicAuthTokens });
|
|
14450
14488
|
console.log("\u2705 Anthropic token registered with server");
|
|
14451
14489
|
process.exit(0);
|
|
14452
14490
|
} else if (vendor === "gemini") {
|
|
14453
14491
|
console.log("\u{1F680} Registering Gemini token with server");
|
|
14454
14492
|
const geminiAuthTokens = await authenticateGemini();
|
|
14455
|
-
await api
|
|
14493
|
+
await api.registerVendorToken("gemini", { oauth: geminiAuthTokens });
|
|
14456
14494
|
console.log("\u2705 Gemini token registered with server");
|
|
14457
14495
|
updateLocalGeminiCredentials(geminiAuthTokens);
|
|
14458
14496
|
process.exit(0);
|
|
@@ -14468,7 +14506,7 @@ async function handleConnectStatus() {
|
|
|
14468
14506
|
console.log(chalk.gray(' Please run "very-happy auth login" first'));
|
|
14469
14507
|
process.exit(1);
|
|
14470
14508
|
}
|
|
14471
|
-
const api
|
|
14509
|
+
const api = await index.ApiClient.create(credentials);
|
|
14472
14510
|
const vendors = [
|
|
14473
14511
|
{ key: "gemini", name: "Gemini", display: "Google Gemini" },
|
|
14474
14512
|
{ key: "openai", name: "Codex", display: "OpenAI Codex" },
|
|
@@ -14476,7 +14514,7 @@ async function handleConnectStatus() {
|
|
|
14476
14514
|
];
|
|
14477
14515
|
for (const vendor of vendors) {
|
|
14478
14516
|
try {
|
|
14479
|
-
const token = await api
|
|
14517
|
+
const token = await api.getVendorToken(vendor.key);
|
|
14480
14518
|
if (token?.oauth) {
|
|
14481
14519
|
let userInfo = "";
|
|
14482
14520
|
if (token.oauth.id_token) {
|
|
@@ -14700,9 +14738,9 @@ function resolveLocalSignupBootstrap(configuredMode, configuredInviteCodes, gene
|
|
|
14700
14738
|
};
|
|
14701
14739
|
}
|
|
14702
14740
|
|
|
14703
|
-
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-
|
|
14741
|
+
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-Dn0JMM8l.cjs', document.baseURI).href)));
|
|
14704
14742
|
const __dirname$1 = path.dirname(__filename$1);
|
|
14705
|
-
const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-
|
|
14743
|
+
const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-Dn0JMM8l.cjs', document.baseURI).href)));
|
|
14706
14744
|
const PRISMA_QUERY_ENGINE_FILES = {
|
|
14707
14745
|
"arm64-darwin": "libquery_engine-darwin-arm64.dylib.node",
|
|
14708
14746
|
"x64-darwin": "libquery_engine-darwin.dylib.node",
|
|
@@ -15091,7 +15129,7 @@ const DAEMON_READY_TIMEOUT_MS = 5e3;
|
|
|
15091
15129
|
const DAEMON_READY_POLL_INTERVAL_MS = 100;
|
|
15092
15130
|
async function ensureDaemonRunning() {
|
|
15093
15131
|
persistence.logger.debug("Ensuring Happy background service is running & matches our version...");
|
|
15094
|
-
const versionMatches = await
|
|
15132
|
+
const versionMatches = await index.isDaemonRunningCurrentlyInstalledHappyVersion();
|
|
15095
15133
|
const state = await persistence.readDaemonState();
|
|
15096
15134
|
const endpointsMatch = Boolean(state) && daemonEndpointsMatch(
|
|
15097
15135
|
state?.serverUrl,
|
|
@@ -15102,9 +15140,9 @@ async function ensureDaemonRunning() {
|
|
|
15102
15140
|
if (versionMatches && endpointsMatch) {
|
|
15103
15141
|
return;
|
|
15104
15142
|
}
|
|
15105
|
-
if (await
|
|
15143
|
+
if (await index.checkIfDaemonRunningAndCleanupStaleState()) {
|
|
15106
15144
|
persistence.logger.debug("Stopping daemon whose version or configured relay no longer matches...");
|
|
15107
|
-
await
|
|
15145
|
+
await index.stopDaemon();
|
|
15108
15146
|
}
|
|
15109
15147
|
persistence.logger.debug("Starting Happy background service...");
|
|
15110
15148
|
const daemonProcess = spawnHappyCLI(["daemon", "start-sync"], {
|
|
@@ -15115,7 +15153,7 @@ async function ensureDaemonRunning() {
|
|
|
15115
15153
|
daemonProcess.unref();
|
|
15116
15154
|
const deadline = Date.now() + DAEMON_READY_TIMEOUT_MS;
|
|
15117
15155
|
while (Date.now() < deadline) {
|
|
15118
|
-
if (await
|
|
15156
|
+
if (await index.checkIfDaemonRunningAndCleanupStaleState()) {
|
|
15119
15157
|
persistence.logger.debug("Happy background service is ready");
|
|
15120
15158
|
return;
|
|
15121
15159
|
}
|
|
@@ -15137,14 +15175,14 @@ function maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagent
|
|
|
15137
15175
|
if (!subagent || startedSubagents.has(subagent)) {
|
|
15138
15176
|
return;
|
|
15139
15177
|
}
|
|
15140
|
-
envelopes.push(
|
|
15178
|
+
envelopes.push(index.createEnvelope("agent", { t: "start" }, { ...opts, subagent }));
|
|
15141
15179
|
startedSubagents.add(subagent);
|
|
15142
15180
|
activeSubagents.add(subagent);
|
|
15143
15181
|
}
|
|
15144
15182
|
function emitSubagentStops(opts, startedSubagents, activeSubagents) {
|
|
15145
15183
|
const envelopes = [];
|
|
15146
15184
|
for (const subagent of activeSubagents) {
|
|
15147
|
-
envelopes.push(
|
|
15185
|
+
envelopes.push(index.createEnvelope("agent", { t: "stop" }, { ...opts, subagent }));
|
|
15148
15186
|
}
|
|
15149
15187
|
activeSubagents.clear();
|
|
15150
15188
|
startedSubagents.clear();
|
|
@@ -15240,7 +15278,7 @@ function turnStatus(turn) {
|
|
|
15240
15278
|
function emitHistoricalToolCall(envelopes, turn, item, name, title, args, output) {
|
|
15241
15279
|
const time = turnTimestampMs(turn);
|
|
15242
15280
|
const opts = { turn: turn.id, time, codexItemId: item.id };
|
|
15243
|
-
envelopes.push(
|
|
15281
|
+
envelopes.push(index.createEnvelope("agent", {
|
|
15244
15282
|
t: "tool-call-start",
|
|
15245
15283
|
call: item.id,
|
|
15246
15284
|
name,
|
|
@@ -15252,7 +15290,7 @@ function emitHistoricalToolCall(envelopes, turn, item, name, title, args, output
|
|
|
15252
15290
|
id: `${item.id}:start`
|
|
15253
15291
|
}));
|
|
15254
15292
|
if (output && output.trim().length > 0) {
|
|
15255
|
-
envelopes.push(
|
|
15293
|
+
envelopes.push(index.createEnvelope("agent", {
|
|
15256
15294
|
t: "text",
|
|
15257
15295
|
text: output,
|
|
15258
15296
|
thinking: true
|
|
@@ -15262,7 +15300,7 @@ function emitHistoricalToolCall(envelopes, turn, item, name, title, args, output
|
|
|
15262
15300
|
}));
|
|
15263
15301
|
}
|
|
15264
15302
|
if ("status" in item && (item.status === "inProgress" || item.status === "running")) return;
|
|
15265
|
-
envelopes.push(
|
|
15303
|
+
envelopes.push(index.createEnvelope("agent", {
|
|
15266
15304
|
t: "tool-call-end",
|
|
15267
15305
|
call: item.id
|
|
15268
15306
|
}, {
|
|
@@ -15284,7 +15322,7 @@ function mapCodexCollaborationItem(item, opts = {}, source = "history") {
|
|
|
15284
15322
|
agentsStates: item.agentsStates ?? {}
|
|
15285
15323
|
};
|
|
15286
15324
|
const startId = source === "live" ? `${item.id}:${item.status ?? "unknown"}:start` : `${item.id}:start`;
|
|
15287
|
-
const envelopes = [
|
|
15325
|
+
const envelopes = [index.createEnvelope("agent", {
|
|
15288
15326
|
t: "tool-call-start",
|
|
15289
15327
|
call: item.id,
|
|
15290
15328
|
name: "CodexCollaboration",
|
|
@@ -15293,7 +15331,7 @@ function mapCodexCollaborationItem(item, opts = {}, source = "history") {
|
|
|
15293
15331
|
args
|
|
15294
15332
|
}, { ...opts, id: startId })];
|
|
15295
15333
|
if (item.status === "completed" || item.status === "failed" || item.status === "interrupted") {
|
|
15296
|
-
envelopes.push(
|
|
15334
|
+
envelopes.push(index.createEnvelope("agent", {
|
|
15297
15335
|
t: "tool-call-end",
|
|
15298
15336
|
call: item.id,
|
|
15299
15337
|
result: { text: JSON.stringify(args, null, 2), isError: item.status !== "completed" }
|
|
@@ -15306,7 +15344,7 @@ function mapCodexThreadToSessionEnvelopes(thread) {
|
|
|
15306
15344
|
for (const turn of thread.turns ?? []) {
|
|
15307
15345
|
const startedAt = turnTimestampMs(turn);
|
|
15308
15346
|
const completedAt = completedTimestampMs(turn);
|
|
15309
|
-
envelopes.push(
|
|
15347
|
+
envelopes.push(index.createEnvelope("agent", { t: "turn-start" }, {
|
|
15310
15348
|
id: `${turn.id}:start`,
|
|
15311
15349
|
turn: turn.id,
|
|
15312
15350
|
time: startedAt
|
|
@@ -15321,7 +15359,7 @@ function mapCodexThreadToSessionEnvelopes(thread) {
|
|
|
15321
15359
|
case "userMessage": {
|
|
15322
15360
|
const text = textFromInputItems(item.content);
|
|
15323
15361
|
if (text) {
|
|
15324
|
-
envelopes.push(
|
|
15362
|
+
envelopes.push(index.createEnvelope("user", { t: "text", text }, {
|
|
15325
15363
|
id: item.id,
|
|
15326
15364
|
time: startedAt,
|
|
15327
15365
|
codexItemId: item.id
|
|
@@ -15332,7 +15370,7 @@ function mapCodexThreadToSessionEnvelopes(thread) {
|
|
|
15332
15370
|
case "agentMessage": {
|
|
15333
15371
|
const text = typeof item.text === "string" ? item.text.trim() : "";
|
|
15334
15372
|
if (text.length > 0) {
|
|
15335
|
-
envelopes.push(
|
|
15373
|
+
envelopes.push(index.createEnvelope("agent", { t: "text", text }, {
|
|
15336
15374
|
id: item.id,
|
|
15337
15375
|
turn: turn.id,
|
|
15338
15376
|
time: completedAt,
|
|
@@ -15344,7 +15382,7 @@ function mapCodexThreadToSessionEnvelopes(thread) {
|
|
|
15344
15382
|
case "reasoning": {
|
|
15345
15383
|
const text = reasoningText(item);
|
|
15346
15384
|
if (text) {
|
|
15347
|
-
envelopes.push(
|
|
15385
|
+
envelopes.push(index.createEnvelope("agent", { t: "text", text, thinking: true }, {
|
|
15348
15386
|
id: item.id,
|
|
15349
15387
|
turn: turn.id,
|
|
15350
15388
|
time: startedAt,
|
|
@@ -15399,7 +15437,7 @@ function mapCodexThreadToSessionEnvelopes(thread) {
|
|
|
15399
15437
|
}
|
|
15400
15438
|
}
|
|
15401
15439
|
}
|
|
15402
|
-
envelopes.push(
|
|
15440
|
+
envelopes.push(index.createEnvelope("agent", { t: "turn-end", status: turnStatus(turn) }, {
|
|
15403
15441
|
id: `${turn.id}:end`,
|
|
15404
15442
|
turn: turn.id,
|
|
15405
15443
|
time: completedAt
|
|
@@ -15454,7 +15492,7 @@ function mapCodexMcpMessageToSessionEnvelopes(message, state) {
|
|
|
15454
15492
|
}
|
|
15455
15493
|
if (type === "task_started") {
|
|
15456
15494
|
const turnId = cuid2.createId();
|
|
15457
|
-
const turnStart =
|
|
15495
|
+
const turnStart = index.createEnvelope("agent", { t: "turn-start" }, { turn: turnId });
|
|
15458
15496
|
startedSubagents.clear();
|
|
15459
15497
|
activeSubagents.clear();
|
|
15460
15498
|
providerSubagentToSessionSubagent.clear();
|
|
@@ -15485,7 +15523,7 @@ function mapCodexMcpMessageToSessionEnvelopes(message, state) {
|
|
|
15485
15523
|
providerSubagentToSessionSubagent,
|
|
15486
15524
|
envelopes: [
|
|
15487
15525
|
...emitSubagentStops(lifecycleOpts, startedSubagents, activeSubagents),
|
|
15488
|
-
|
|
15526
|
+
index.createEnvelope("agent", {
|
|
15489
15527
|
t: "turn-end",
|
|
15490
15528
|
status: pickTurnEndStatus(message, type)
|
|
15491
15529
|
}, lifecycleOpts)
|
|
@@ -15515,7 +15553,7 @@ function mapCodexMcpMessageToSessionEnvelopes(message, state) {
|
|
|
15515
15553
|
}
|
|
15516
15554
|
const envelopes = [];
|
|
15517
15555
|
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15518
|
-
envelopes.push(
|
|
15556
|
+
envelopes.push(index.createEnvelope("agent", { t: "text", text: message.message }, opts));
|
|
15519
15557
|
return {
|
|
15520
15558
|
currentTurnId: state.currentTurnId,
|
|
15521
15559
|
startedSubagents,
|
|
@@ -15537,7 +15575,7 @@ function mapCodexMcpMessageToSessionEnvelopes(message, state) {
|
|
|
15537
15575
|
}
|
|
15538
15576
|
const envelopes = [];
|
|
15539
15577
|
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15540
|
-
envelopes.push(
|
|
15578
|
+
envelopes.push(index.createEnvelope("agent", { t: "text", text, thinking: true }, opts));
|
|
15541
15579
|
return {
|
|
15542
15580
|
currentTurnId: state.currentTurnId,
|
|
15543
15581
|
startedSubagents,
|
|
@@ -15554,7 +15592,7 @@ function mapCodexMcpMessageToSessionEnvelopes(message, state) {
|
|
|
15554
15592
|
const envelopes = [];
|
|
15555
15593
|
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15556
15594
|
envelopes.push(
|
|
15557
|
-
|
|
15595
|
+
index.createEnvelope("agent", {
|
|
15558
15596
|
t: "tool-call-start",
|
|
15559
15597
|
call,
|
|
15560
15598
|
name: "CodexBash",
|
|
@@ -15575,7 +15613,7 @@ function mapCodexMcpMessageToSessionEnvelopes(message, state) {
|
|
|
15575
15613
|
const call = pickCallId(message);
|
|
15576
15614
|
const envelopes = [];
|
|
15577
15615
|
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15578
|
-
envelopes.push(
|
|
15616
|
+
envelopes.push(index.createEnvelope("agent", { t: "tool-call-end", call }, opts));
|
|
15579
15617
|
return {
|
|
15580
15618
|
currentTurnId: state.currentTurnId,
|
|
15581
15619
|
startedSubagents,
|
|
@@ -15591,7 +15629,7 @@ function mapCodexMcpMessageToSessionEnvelopes(message, state) {
|
|
|
15591
15629
|
const envelopes = [];
|
|
15592
15630
|
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15593
15631
|
envelopes.push(
|
|
15594
|
-
|
|
15632
|
+
index.createEnvelope("agent", {
|
|
15595
15633
|
t: "tool-call-start",
|
|
15596
15634
|
call,
|
|
15597
15635
|
name: "CodexPatch",
|
|
@@ -15615,7 +15653,7 @@ function mapCodexMcpMessageToSessionEnvelopes(message, state) {
|
|
|
15615
15653
|
const call = pickCallId(message);
|
|
15616
15654
|
const envelopes = [];
|
|
15617
15655
|
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15618
|
-
envelopes.push(
|
|
15656
|
+
envelopes.push(index.createEnvelope("agent", { t: "tool-call-end", call }, opts));
|
|
15619
15657
|
return {
|
|
15620
15658
|
currentTurnId: state.currentTurnId,
|
|
15621
15659
|
startedSubagents,
|
|
@@ -15636,7 +15674,7 @@ function mapCodexProcessorMessageToSessionEnvelopes(message, state) {
|
|
|
15636
15674
|
const toolLikeMessage = message;
|
|
15637
15675
|
const opts = buildEnvelopeOptions(state.currentTurnId);
|
|
15638
15676
|
if (message.type === "reasoning") {
|
|
15639
|
-
return [
|
|
15677
|
+
return [index.createEnvelope("agent", {
|
|
15640
15678
|
t: "text",
|
|
15641
15679
|
text: message.message,
|
|
15642
15680
|
thinking: true
|
|
@@ -15644,7 +15682,7 @@ function mapCodexProcessorMessageToSessionEnvelopes(message, state) {
|
|
|
15644
15682
|
}
|
|
15645
15683
|
if (message.type === "tool-call") {
|
|
15646
15684
|
const title = typeof toolLikeMessage.input?.title === "string" ? toolLikeMessage.input.title : `${toolLikeMessage.name || "Tool"} call`;
|
|
15647
|
-
return [
|
|
15685
|
+
return [index.createEnvelope("agent", {
|
|
15648
15686
|
t: "tool-call-start",
|
|
15649
15687
|
call: toolLikeMessage.callId,
|
|
15650
15688
|
name: toolLikeMessage.name || "unknown",
|
|
@@ -15657,13 +15695,13 @@ function mapCodexProcessorMessageToSessionEnvelopes(message, state) {
|
|
|
15657
15695
|
const envelopes = [];
|
|
15658
15696
|
const content = toolLikeMessage.output?.content;
|
|
15659
15697
|
if (typeof content === "string" && content.trim().length > 0) {
|
|
15660
|
-
envelopes.push(
|
|
15698
|
+
envelopes.push(index.createEnvelope("agent", {
|
|
15661
15699
|
t: "text",
|
|
15662
15700
|
text: content,
|
|
15663
15701
|
thinking: true
|
|
15664
15702
|
}, opts));
|
|
15665
15703
|
}
|
|
15666
|
-
envelopes.push(
|
|
15704
|
+
envelopes.push(index.createEnvelope("agent", {
|
|
15667
15705
|
t: "tool-call-end",
|
|
15668
15706
|
call: toolLikeMessage.callId
|
|
15669
15707
|
}, opts));
|
|
@@ -16352,17 +16390,17 @@ function createOfflineSessionStub(sessionTag) {
|
|
|
16352
16390
|
}
|
|
16353
16391
|
|
|
16354
16392
|
function setupOfflineReconnection(opts) {
|
|
16355
|
-
const { api
|
|
16393
|
+
const { api, sessionTag, metadata, state, response, onSessionSwap } = opts;
|
|
16356
16394
|
let session;
|
|
16357
16395
|
let reconnectionHandle = null;
|
|
16358
16396
|
if (!response) {
|
|
16359
16397
|
session = createOfflineSessionStub(sessionTag);
|
|
16360
|
-
reconnectionHandle =
|
|
16398
|
+
reconnectionHandle = index.startOfflineReconnection({
|
|
16361
16399
|
serverUrl: persistence.configuration.serverUrl,
|
|
16362
16400
|
onReconnected: async () => {
|
|
16363
|
-
const resp = await api
|
|
16401
|
+
const resp = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
16364
16402
|
if (!resp) throw new Error("Server unavailable");
|
|
16365
|
-
const realSession = api
|
|
16403
|
+
const realSession = api.sessionSyncClient(resp);
|
|
16366
16404
|
onSessionSwap(realSession);
|
|
16367
16405
|
return realSession;
|
|
16368
16406
|
},
|
|
@@ -16372,7 +16410,7 @@ function setupOfflineReconnection(opts) {
|
|
|
16372
16410
|
});
|
|
16373
16411
|
return { session, reconnectionHandle, isOffline: true };
|
|
16374
16412
|
} else {
|
|
16375
|
-
session = api
|
|
16413
|
+
session = api.sessionSyncClient(response, opts.sessionClientOptions);
|
|
16376
16414
|
return { session, reconnectionHandle: null, isOffline: false };
|
|
16377
16415
|
}
|
|
16378
16416
|
}
|
|
@@ -16622,7 +16660,7 @@ function buildCodexTurnPrompt(opts) {
|
|
|
16622
16660
|
parts.push(opts.message);
|
|
16623
16661
|
if (opts.includeTitleInstruction) {
|
|
16624
16662
|
parts.push(CHANGE_TITLE_INSTRUCTION);
|
|
16625
|
-
parts.push(
|
|
16663
|
+
parts.push(index.BUILTIN_TODO_DISCOVERY);
|
|
16626
16664
|
}
|
|
16627
16665
|
return parts.join("\n\n");
|
|
16628
16666
|
}
|
|
@@ -16690,8 +16728,8 @@ async function runCodex(opts) {
|
|
|
16690
16728
|
process.exit(1);
|
|
16691
16729
|
}
|
|
16692
16730
|
const sessionTag = node_crypto.randomUUID();
|
|
16693
|
-
|
|
16694
|
-
const api
|
|
16731
|
+
index.connectionState.setBackend("Codex");
|
|
16732
|
+
const api = await index.ApiClient.create(opts.credentials);
|
|
16695
16733
|
persistence.logger.debug(`[codex] Starting with options: startedBy=${opts.startedBy || "terminal"}`);
|
|
16696
16734
|
const settings = await persistence.readSettings();
|
|
16697
16735
|
let machineId = settings?.machineId;
|
|
@@ -16701,7 +16739,7 @@ async function runCodex(opts) {
|
|
|
16701
16739
|
process.exit(1);
|
|
16702
16740
|
}
|
|
16703
16741
|
persistence.logger.debug(`Using machineId: ${machineId}`);
|
|
16704
|
-
await api
|
|
16742
|
+
await api.getOrCreateMachine({
|
|
16705
16743
|
machineId,
|
|
16706
16744
|
metadata: initialMachineMetadata
|
|
16707
16745
|
});
|
|
@@ -16745,17 +16783,17 @@ async function runCodex(opts) {
|
|
|
16745
16783
|
agentStateVersion: parseInt(reconnectAgentStateVersion || "0", 10)
|
|
16746
16784
|
};
|
|
16747
16785
|
} else {
|
|
16748
|
-
response = await api
|
|
16786
|
+
response = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
16749
16787
|
}
|
|
16750
16788
|
if (response) {
|
|
16751
16789
|
await claimSessionOrExit(response.id, { takeover: !!reconnectSessionId, flavor: "codex" });
|
|
16752
16790
|
}
|
|
16753
|
-
if (reconnectSessionId && response && !await api
|
|
16791
|
+
if (reconnectSessionId && response && !await api.reactivateSession(response.id)) {
|
|
16754
16792
|
throw new Error(`Failed to reactivate archived session ${response.id}`);
|
|
16755
16793
|
}
|
|
16756
16794
|
let reconnectSeeded = false;
|
|
16757
16795
|
if (reconnectSessionId && response) {
|
|
16758
|
-
const snapshot = await api
|
|
16796
|
+
const snapshot = await api.getSession(response.id, response.encryptionKey, response.encryptionVariant);
|
|
16759
16797
|
if (snapshot.ok) {
|
|
16760
16798
|
response = applyServerSnapshot(response, snapshot.session);
|
|
16761
16799
|
reconnectSeeded = true;
|
|
@@ -16772,7 +16810,7 @@ async function runCodex(opts) {
|
|
|
16772
16810
|
let abortInProgress = null;
|
|
16773
16811
|
let turnActive = false;
|
|
16774
16812
|
const { session: initialSession, reconnectionHandle } = setupOfflineReconnection({
|
|
16775
|
-
api
|
|
16813
|
+
api,
|
|
16776
16814
|
sessionTag,
|
|
16777
16815
|
metadata,
|
|
16778
16816
|
state,
|
|
@@ -16795,7 +16833,7 @@ async function runCodex(opts) {
|
|
|
16795
16833
|
if (response) {
|
|
16796
16834
|
try {
|
|
16797
16835
|
persistence.logger.debug(`[START] Reporting session ${response.id} to daemon`);
|
|
16798
|
-
const result = await
|
|
16836
|
+
const result = await index.notifyDaemonSessionStarted(response.id, metadata, {
|
|
16799
16837
|
encryptionKey: persistence.encodeBase64(response.encryptionKey),
|
|
16800
16838
|
encryptionVariant: response.encryptionVariant,
|
|
16801
16839
|
seq: response.seq,
|
|
@@ -16928,7 +16966,7 @@ async function runCodex(opts) {
|
|
|
16928
16966
|
const sendReady = () => {
|
|
16929
16967
|
session.sendSessionEvent({ type: "ready" });
|
|
16930
16968
|
try {
|
|
16931
|
-
api
|
|
16969
|
+
api.push().sendSessionNotification({
|
|
16932
16970
|
kind: "done",
|
|
16933
16971
|
metadata: session.getMetadata(),
|
|
16934
16972
|
data: {
|
|
@@ -17058,7 +17096,7 @@ async function runCodex(opts) {
|
|
|
17058
17096
|
}
|
|
17059
17097
|
process.stdin.setEncoding("utf8");
|
|
17060
17098
|
}
|
|
17061
|
-
client = new
|
|
17099
|
+
client = new index.CodexAppServerClient(sandboxConfig);
|
|
17062
17100
|
const idleRelease = new CodexIdleReleaseTimer({
|
|
17063
17101
|
delayMs: resolveCodexIdleReleaseMs(process.env[CODEX_IDLE_RELEASE_ENV]),
|
|
17064
17102
|
isIdle: () => shouldReleaseIdleCodex({
|
|
@@ -17617,7 +17655,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17617
17655
|
return;
|
|
17618
17656
|
} else if (subcommand === "install-terminal-hooks") {
|
|
17619
17657
|
try {
|
|
17620
|
-
const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-
|
|
17658
|
+
const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-De7_iOOC.cjs'); });
|
|
17621
17659
|
const command = parseTerminalHooksArgs(args.slice(1));
|
|
17622
17660
|
if (command.action === "help") {
|
|
17623
17661
|
console.log(TERMINAL_HOOKS_HELP);
|
|
@@ -17632,9 +17670,18 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17632
17670
|
}
|
|
17633
17671
|
process.exit(1);
|
|
17634
17672
|
}
|
|
17673
|
+
} else if (subcommand === "agent-home") {
|
|
17674
|
+
try {
|
|
17675
|
+
const { parseAgentHomeArgs, runAgentHomeCommand } = await Promise.resolve().then(function () { return require('./agentHome-uf1zs2Fi.cjs'); });
|
|
17676
|
+
await runAgentHomeCommand(parseAgentHomeArgs(args.slice(1)));
|
|
17677
|
+
process.exit(0);
|
|
17678
|
+
} catch (error) {
|
|
17679
|
+
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
17680
|
+
process.exit(1);
|
|
17681
|
+
}
|
|
17635
17682
|
} else if (subcommand === "spawn") {
|
|
17636
17683
|
try {
|
|
17637
|
-
const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-
|
|
17684
|
+
const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-Be4nsNuQ.cjs'); });
|
|
17638
17685
|
await handleSpawnCommand(args.slice(1));
|
|
17639
17686
|
} catch (error) {
|
|
17640
17687
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -17646,7 +17693,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17646
17693
|
return;
|
|
17647
17694
|
} else if (subcommand === "sessions") {
|
|
17648
17695
|
try {
|
|
17649
|
-
const { handleSessionsCommand } = await Promise.resolve().then(function () { return require('./sessions-
|
|
17696
|
+
const { handleSessionsCommand } = await Promise.resolve().then(function () { return require('./sessions-CtVcoXvG.cjs'); });
|
|
17650
17697
|
await handleSessionsCommand(args.slice(1));
|
|
17651
17698
|
} catch (error) {
|
|
17652
17699
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -17658,7 +17705,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17658
17705
|
return;
|
|
17659
17706
|
} else if (subcommand === "send") {
|
|
17660
17707
|
try {
|
|
17661
|
-
const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-
|
|
17708
|
+
const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-BA1Dgpgn.cjs'); });
|
|
17662
17709
|
await handleSendCommand(args.slice(1));
|
|
17663
17710
|
} catch (error) {
|
|
17664
17711
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -17764,9 +17811,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17764
17811
|
if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
|
|
17765
17812
|
const projectId = args[3];
|
|
17766
17813
|
try {
|
|
17767
|
-
const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-
|
|
17768
|
-
const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./limits-
|
|
17769
|
-
const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-
|
|
17814
|
+
const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-kx4y9oAI.cjs'); });
|
|
17815
|
+
const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./limits-C_Sklt--.cjs'); }).then(function (n) { return n.persistence; });
|
|
17816
|
+
const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-DZ5c-9f3.cjs'); }).then(function (n) { return n.api; });
|
|
17770
17817
|
let userEmail = void 0;
|
|
17771
17818
|
try {
|
|
17772
17819
|
const credentials = await readCredentialsForConfiguredRelay2();
|
|
@@ -17797,7 +17844,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17797
17844
|
}
|
|
17798
17845
|
if (geminiSubcommand === "project" && args[2] === "get") {
|
|
17799
17846
|
try {
|
|
17800
|
-
const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-
|
|
17847
|
+
const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-kx4y9oAI.cjs'); });
|
|
17801
17848
|
const config = readGeminiLocalConfig();
|
|
17802
17849
|
if (config.googleCloudProject) {
|
|
17803
17850
|
console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
|
|
@@ -17837,7 +17884,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17837
17884
|
process.exit(0);
|
|
17838
17885
|
}
|
|
17839
17886
|
try {
|
|
17840
|
-
const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-
|
|
17887
|
+
const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-CCdGxTF2.cjs'); });
|
|
17841
17888
|
let startedBy = void 0;
|
|
17842
17889
|
for (let i = 1; i < args.length; i++) {
|
|
17843
17890
|
if (args[i] === "--started-by") {
|
|
@@ -17860,7 +17907,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17860
17907
|
} else if (subcommand === "pi") {
|
|
17861
17908
|
if (args[1] === "--terminal") {
|
|
17862
17909
|
try {
|
|
17863
|
-
const { runPiTerminal } = await Promise.resolve().then(function () { return require('./piTerminal-
|
|
17910
|
+
const { runPiTerminal } = await Promise.resolve().then(function () { return require('./piTerminal-BFpwVGWr.cjs'); });
|
|
17864
17911
|
process.exitCode = await runPiTerminal(args.slice(2));
|
|
17865
17912
|
} catch (error) {
|
|
17866
17913
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -17877,7 +17924,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17877
17924
|
}
|
|
17878
17925
|
};
|
|
17879
17926
|
try {
|
|
17880
|
-
const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-
|
|
17927
|
+
const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-Dox9iD5R.cjs'); });
|
|
17881
17928
|
const parsed = parsePiRunnerArgs(args.slice(1));
|
|
17882
17929
|
const resolved = resolveAcpAgentConfig(["pi", ...parsed.passthrough]);
|
|
17883
17930
|
const { credentials } = await authAndSetupMachineIfNeeded();
|
|
@@ -17905,7 +17952,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17905
17952
|
return;
|
|
17906
17953
|
} else if (subcommand === "acp") {
|
|
17907
17954
|
try {
|
|
17908
|
-
const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-
|
|
17955
|
+
const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-Dox9iD5R.cjs'); });
|
|
17909
17956
|
let startedBy = void 0;
|
|
17910
17957
|
let verbose = false;
|
|
17911
17958
|
const acpArgs = [];
|
|
@@ -17945,7 +17992,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17945
17992
|
return;
|
|
17946
17993
|
} else if (subcommand === "openclaw") {
|
|
17947
17994
|
try {
|
|
17948
|
-
const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-
|
|
17995
|
+
const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-CRMUfrWk.cjs'); });
|
|
17949
17996
|
let startedBy = void 0;
|
|
17950
17997
|
let verbose = false;
|
|
17951
17998
|
let gatewayUrl;
|
|
@@ -17996,7 +18043,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17996
18043
|
return;
|
|
17997
18044
|
} else if (subcommand === "todo") {
|
|
17998
18045
|
try {
|
|
17999
|
-
const { handleTodoCommand } = await Promise.resolve().then(function () { return require('./todo-
|
|
18046
|
+
const { handleTodoCommand } = await Promise.resolve().then(function () { return require('./todo-EffYAnre.cjs'); });
|
|
18000
18047
|
await handleTodoCommand(args.slice(1));
|
|
18001
18048
|
} catch (error) {
|
|
18002
18049
|
console.error(JSON.stringify({ error: error instanceof Error ? error.message : "Todo command failed" }));
|
|
@@ -18005,7 +18052,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18005
18052
|
return;
|
|
18006
18053
|
} else if (subcommand === "teams") {
|
|
18007
18054
|
try {
|
|
18008
|
-
const { handleTeamsCommand } = await Promise.resolve().then(function () { return require('./teams-
|
|
18055
|
+
const { handleTeamsCommand } = await Promise.resolve().then(function () { return require('./teams-CcjjNLi8.cjs'); });
|
|
18009
18056
|
await handleTeamsCommand(args.slice(1));
|
|
18010
18057
|
} catch (error) {
|
|
18011
18058
|
console.error(error instanceof Error ? error.message : "Teams command failed");
|
|
@@ -18014,7 +18061,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18014
18061
|
return;
|
|
18015
18062
|
} else if (subcommand === "mcp" && (args.length === 1 || args.length === 2 && args[1] === "--terminal-tools")) {
|
|
18016
18063
|
try {
|
|
18017
|
-
const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-
|
|
18064
|
+
const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-xyb8dYIQ.cjs'); });
|
|
18018
18065
|
await handleMcpCommand(args[1] === "--terminal-tools");
|
|
18019
18066
|
} catch (error) {
|
|
18020
18067
|
process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
|
|
@@ -18037,7 +18084,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18037
18084
|
const daemonSubcommand = args[1];
|
|
18038
18085
|
if (daemonSubcommand === "list") {
|
|
18039
18086
|
try {
|
|
18040
|
-
const sessions = await
|
|
18087
|
+
const sessions = await index.listDaemonSessions();
|
|
18041
18088
|
if (sessions.length === 0) {
|
|
18042
18089
|
console.log("No active sessions this daemon is aware of (they might have been started by a previous version of the daemon)");
|
|
18043
18090
|
} else {
|
|
@@ -18055,7 +18102,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18055
18102
|
process.exit(1);
|
|
18056
18103
|
}
|
|
18057
18104
|
try {
|
|
18058
|
-
const success = await
|
|
18105
|
+
const success = await index.stopDaemonSession(sessionId);
|
|
18059
18106
|
console.log(success ? "Session stopped" : "Failed to stop session");
|
|
18060
18107
|
} catch (error) {
|
|
18061
18108
|
console.log("No daemon running");
|
|
@@ -18063,7 +18110,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18063
18110
|
return;
|
|
18064
18111
|
} else if (daemonSubcommand === "start") {
|
|
18065
18112
|
const currentState = await persistence.readDaemonState();
|
|
18066
|
-
const running = await
|
|
18113
|
+
const running = await index.checkIfDaemonRunningAndCleanupStaleState();
|
|
18067
18114
|
const currentDaemonMatches = currentState && currentState.startedWithCliVersion === persistence.configuration.currentCliVersion && daemonEndpointsMatch(
|
|
18068
18115
|
currentState.serverUrl,
|
|
18069
18116
|
currentState.webappUrl,
|
|
@@ -18072,7 +18119,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18072
18119
|
);
|
|
18073
18120
|
if (running && !currentDaemonMatches) {
|
|
18074
18121
|
console.log("Configured relay or CLI version changed; restarting the existing daemon");
|
|
18075
|
-
await
|
|
18122
|
+
await index.stopDaemon();
|
|
18076
18123
|
}
|
|
18077
18124
|
const child = spawnHappyCLI(["daemon", "start-sync"], {
|
|
18078
18125
|
detached: true,
|
|
@@ -18082,7 +18129,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18082
18129
|
child.unref();
|
|
18083
18130
|
let started = false;
|
|
18084
18131
|
for (let i = 0; i < 50; i++) {
|
|
18085
|
-
if (await
|
|
18132
|
+
if (await index.checkIfDaemonRunningAndCleanupStaleState()) {
|
|
18086
18133
|
started = true;
|
|
18087
18134
|
break;
|
|
18088
18135
|
}
|
|
@@ -18099,7 +18146,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18099
18146
|
await startDaemon();
|
|
18100
18147
|
process.exit(0);
|
|
18101
18148
|
} else if (daemonSubcommand === "stop") {
|
|
18102
|
-
await
|
|
18149
|
+
await index.stopDaemon();
|
|
18103
18150
|
process.exit(0);
|
|
18104
18151
|
} else if (daemonSubcommand === "status") {
|
|
18105
18152
|
await runDoctorDaemon();
|
|
@@ -18244,6 +18291,8 @@ ${chalk.bold("Usage:")}
|
|
|
18244
18291
|
very-happy install-terminal-hooks
|
|
18245
18292
|
Install optional Claude terminal mirror hooks
|
|
18246
18293
|
(add --remove to uninstall them)
|
|
18294
|
+
very-happy agent-home Show or pin where Claude Code / Codex keep their
|
|
18295
|
+
conversations on this machine (agent-home --help)
|
|
18247
18296
|
very-happy connect Connect AI vendor API keys
|
|
18248
18297
|
very-happy todo Built-in Todos and official agent skill (todo --help)
|
|
18249
18298
|
very-happy sandbox Configure and manage OS-level sandboxing
|
|
@@ -18359,9 +18408,9 @@ ${chalk.bold("Examples:")}
|
|
|
18359
18408
|
}
|
|
18360
18409
|
console.log(chalk.blue("\u{1F4F1} Sending push notification..."));
|
|
18361
18410
|
try {
|
|
18362
|
-
const api
|
|
18411
|
+
const api = await index.ApiClient.create(credentials);
|
|
18363
18412
|
const notificationTitle = title || "Happy";
|
|
18364
|
-
api
|
|
18413
|
+
api.push().sendToAllDevices(
|
|
18365
18414
|
notificationTitle,
|
|
18366
18415
|
message,
|
|
18367
18416
|
{
|