very-happy-cli 0.2.155 → 0.2.157
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-DmFcRh54.cjs → AcpBackend-BymWX-LI.cjs} +2 -2
- package/dist/{AcpBackend-DVB0nzgR.mjs → AcpBackend-Cy18U7yw.mjs} +2 -2
- package/dist/{AcpSessionManager-CWaSYTnT.cjs → AcpSessionManager-BF7zBGAi.cjs} +1 -1
- package/dist/{AcpSessionManager-dGDgNb-p.mjs → AcpSessionManager-Ds8rcp95.mjs} +1 -1
- package/dist/{agentGuidance-BWxFC6UL.mjs → agentGuidance-CU6YD_Ms.mjs} +560 -29
- package/dist/{agentGuidance-un7YPryB.cjs → agentGuidance-Db76O1kw.cjs} +579 -28
- package/dist/{agentHome-aucT8BHw.cjs → agentHome-B0CLy0Qx.cjs} +2 -2
- package/dist/{agentHome-ByLb2HFg.mjs → agentHome-BaJ9xtxB.mjs} +2 -2
- package/dist/{auto-BQnD6gVx.mjs → auto-B1YAwaeU.mjs} +6 -6
- package/dist/{auto-P9RoJaY0.cjs → auto-DqKGFq8U.cjs} +6 -6
- package/dist/codex/happyMcpStdioBridge.cjs +2 -2
- package/dist/codex/happyMcpStdioBridge.mjs +2 -2
- package/dist/{config-BoePh9PX.cjs → config-CzkBjZnV.cjs} +4 -4
- package/dist/{config-BPZ2Y6o8.mjs → config-aAbhJllb.mjs} +4 -4
- package/dist/{index-BjzdXb9x.mjs → index-BVu8Cufk.mjs} +8 -8
- package/dist/{index-B4oXnbYw.mjs → index-BYU1e81k.mjs} +372 -65
- package/dist/{index-D_fYUxVg.cjs → index-C9QzZsUQ.cjs} +375 -68
- package/dist/{index-DRrLaljt.cjs → index-CTbGqVFY.cjs} +7 -7
- package/dist/{index--KCpVs1c.cjs → index-Cz-uqnJk.cjs} +4 -4
- package/dist/{index-DVVRqaVG.mjs → index-DQcRkI9r.mjs} +4 -4
- package/dist/index.cjs +4 -4
- package/dist/index.mjs +4 -4
- package/dist/{install-CGigiocs.cjs → install-BMlV0Tnr.cjs} +1 -1
- package/dist/{install-DP5aPNEX.mjs → install-BuYnqtVa.mjs} +1 -1
- package/dist/{installTerminalHooks-XrcPvfBs.cjs → installTerminalHooks-BVVOEGhG.cjs} +4 -4
- package/dist/{installTerminalHooks-tIg7mANc.mjs → installTerminalHooks-ELDoqh0A.mjs} +4 -4
- package/dist/lib.cjs +2 -2
- package/dist/lib.d.cts +101 -9
- package/dist/lib.d.mts +101 -9
- package/dist/lib.mjs +2 -2
- package/dist/{limits-C_DW0M0q.mjs → limits-A2c-3M-_.mjs} +162 -11
- package/dist/{limits-DkfHJ3nS.cjs → limits-CyuIt-Vl.cjs} +169 -10
- package/dist/{mcp-o7QglAQM.mjs → mcp-Bo934Kpy.mjs} +4 -4
- package/dist/{mcp-BqlXl10F.cjs → mcp-CXkvnztT.cjs} +4 -4
- package/dist/{piRuntime-BxP4B_zY.cjs → piRuntime-CJjA26oD.cjs} +2 -2
- package/dist/{piRuntime-MjiJI-nV.mjs → piRuntime-DdEY2mE9.mjs} +2 -2
- package/dist/{piTerminal-DYzRcwgb.cjs → piTerminal-CpU3hzrX.cjs} +6 -6
- package/dist/{piTerminal-Dpq6yqKU.mjs → piTerminal-DwWmgumi.mjs} +6 -6
- package/dist/{runGemini-CDlcQ-OA.mjs → runGemini-Cj6oJQ-I.mjs} +6 -6
- package/dist/{runGemini-8Pxh94Fm.cjs → runGemini-DS-0qm0L.cjs} +6 -6
- package/dist/{runOpenClaw-B5FSZIbK.cjs → runOpenClaw-CvSm8oTc.cjs} +5 -5
- package/dist/{runOpenClaw-YkhsgPs0.mjs → runOpenClaw-DUCQxkI-.mjs} +5 -5
- package/dist/{send-CwrYXTPr.cjs → send-CHxobaoI.cjs} +43 -31
- package/dist/{send-DJStmLBv.mjs → send-D5CyRyZ_.mjs} +43 -31
- package/dist/{sessions-MX21NJXd.cjs → sessions-BFlIrKCY.cjs} +133 -49
- package/dist/{sessions-JaVXlSqj.mjs → sessions-DsE01xKc.mjs} +133 -49
- package/dist/{spawn-BaPnjClT.mjs → spawn-CdihhwHs.mjs} +4 -4
- package/dist/{spawn-cIoglKVf.cjs → spawn-HV345RN-.cjs} +4 -4
- package/dist/{teams-DXV5Pwwt.mjs → teams-BE8nMB6O.mjs} +5 -5
- package/dist/{teams-Dqk7F3D-.cjs → teams-BahinMnH.cjs} +5 -5
- package/dist/{todo-Buuqn9gm.cjs → todo-CMMQ6yhU.cjs} +2 -2
- package/dist/{todo-2Z1REhfx.mjs → todo-CuQAkSp2.mjs} +2 -2
- package/dist/{types-a2xsH2UI.cjs → types-B0sSi6eM.cjs} +125 -13
- package/dist/{types-CkbfdRzq.mjs → types-BrGJ7PJz.mjs} +125 -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 index = require('./types-
|
|
7
|
-
var persistence = require('./limits-
|
|
6
|
+
var index = require('./types-B0sSi6eM.cjs');
|
|
7
|
+
var persistence = require('./limits-CyuIt-Vl.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 terminalTitleSuggest = require('./terminalTitleSuggest-Dji8I0Jy.cjs');
|
|
13
|
-
var agentGuidance = require('./agentGuidance-
|
|
13
|
+
var agentGuidance = require('./agentGuidance-Db76O1kw.cjs');
|
|
14
14
|
var promises = require('node:fs/promises');
|
|
15
15
|
var fs = require('fs/promises');
|
|
16
16
|
var ink = require('ink');
|
|
@@ -137,6 +137,11 @@ class Session {
|
|
|
137
137
|
sessionId;
|
|
138
138
|
mode = "local";
|
|
139
139
|
thinking = false;
|
|
140
|
+
/** B-507: background tasks still in flight (async sub-agents, backgrounded
|
|
141
|
+
* commands, monitors) — published with every keepAlive. Always an array
|
|
142
|
+
* for the Claude runner: an empty one says "nothing running", which is a
|
|
143
|
+
* different statement from a runner that has no such notion (undefined). */
|
|
144
|
+
backgroundTasks = [];
|
|
140
145
|
/**
|
|
141
146
|
* Window after a user-initiated abort during which stray promise rejections
|
|
142
147
|
* from tearing down the SDK query (MCP transports, in-flight tool calls,
|
|
@@ -198,11 +203,21 @@ class Session {
|
|
|
198
203
|
persistence.logger.debug("[Session] Failed to create notification producer:", err);
|
|
199
204
|
this.notificationProducer = null;
|
|
200
205
|
}
|
|
201
|
-
this.client.keepAlive(this.thinking, this.mode);
|
|
206
|
+
this.client.keepAlive(this.thinking, this.mode, this.backgroundTasks);
|
|
202
207
|
this.keepAliveInterval = setInterval(() => {
|
|
203
|
-
this.client.keepAlive(this.thinking, this.mode);
|
|
208
|
+
this.client.keepAlive(this.thinking, this.mode, this.backgroundTasks);
|
|
204
209
|
}, 2e3);
|
|
205
210
|
}
|
|
211
|
+
/**
|
|
212
|
+
* B-507: the tracker's current set (`claude/backgroundTasks.ts`). A change
|
|
213
|
+
* beats at once so the daemon, agentState and the web see the edge without
|
|
214
|
+
* waiting for the 2s tick; an unchanged set is left to the interval.
|
|
215
|
+
*/
|
|
216
|
+
setBackgroundTasks = (tasks) => {
|
|
217
|
+
if (persistence.sameBackgroundTasks(this.backgroundTasks, tasks)) return;
|
|
218
|
+
this.backgroundTasks = tasks;
|
|
219
|
+
this.client.keepAlive(this.thinking, this.mode, this.backgroundTasks);
|
|
220
|
+
};
|
|
206
221
|
/**
|
|
207
222
|
* Cleanup resources (call when session is no longer needed)
|
|
208
223
|
*/
|
|
@@ -237,7 +252,7 @@ class Session {
|
|
|
237
252
|
this.lastAssistantSnippet = void 0;
|
|
238
253
|
}
|
|
239
254
|
this.thinking = thinking;
|
|
240
|
-
this.client.keepAlive(thinking, this.mode);
|
|
255
|
+
this.client.keepAlive(thinking, this.mode, this.backgroundTasks);
|
|
241
256
|
};
|
|
242
257
|
/**
|
|
243
258
|
* Record that Claude emitted an assistant text reply during this turn.
|
|
@@ -304,7 +319,7 @@ class Session {
|
|
|
304
319
|
};
|
|
305
320
|
onModeChange = (mode) => {
|
|
306
321
|
this.mode = mode;
|
|
307
|
-
this.client.keepAlive(this.thinking, mode);
|
|
322
|
+
this.client.keepAlive(this.thinking, mode, this.backgroundTasks);
|
|
308
323
|
this._onModeChange(mode);
|
|
309
324
|
};
|
|
310
325
|
onAbort = () => {
|
|
@@ -3948,6 +3963,7 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
|
|
|
3948
3963
|
const turnSteering = createTurnSteeringController();
|
|
3949
3964
|
const runtimeControls = createRuntimeControls(() => session.thinking);
|
|
3950
3965
|
session.client.rpcHandlerManager.registerHandler("claude-runtime-control", async (input) => runtimeControls.request(input));
|
|
3966
|
+
const backgroundTasks = persistence.createBackgroundTaskTracker();
|
|
3951
3967
|
async function abort() {
|
|
3952
3968
|
if (abortController && !abortController.signal.aborted) {
|
|
3953
3969
|
abortController.abort();
|
|
@@ -4033,6 +4049,8 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
|
|
|
4033
4049
|
let notifiedQuestionToolCalls = /* @__PURE__ */ new Set();
|
|
4034
4050
|
function onMessage(message) {
|
|
4035
4051
|
runtimeControls.observe(message);
|
|
4052
|
+
backgroundTasks.observe(message);
|
|
4053
|
+
session.setBackgroundTasks(backgroundTasks.list());
|
|
4036
4054
|
if (isRuntimeCheckpointReplay(message)) return;
|
|
4037
4055
|
if (message.type === "user" && isClaudeInterruptSentinelContent(message.message.content)) {
|
|
4038
4056
|
sdkToLogConverter.convert(message);
|
|
@@ -4257,6 +4275,8 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
|
|
|
4257
4275
|
},
|
|
4258
4276
|
onQueryReady: (q) => {
|
|
4259
4277
|
runtimeControls.setQuery(q);
|
|
4278
|
+
backgroundTasks.reset();
|
|
4279
|
+
session.setBackgroundTasks([]);
|
|
4260
4280
|
turnSteering.setInterrupt(q.interrupt);
|
|
4261
4281
|
session.setSideQuestionLive({ ask: q.sideQuestion, canControl: q.canControl });
|
|
4262
4282
|
session.setSteerHandler(async (input) => {
|
|
@@ -4353,6 +4373,8 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
|
|
|
4353
4373
|
}
|
|
4354
4374
|
} finally {
|
|
4355
4375
|
runtimeControls.setQuery(null);
|
|
4376
|
+
backgroundTasks.reset();
|
|
4377
|
+
session.setBackgroundTasks([]);
|
|
4356
4378
|
turnSteering.reset();
|
|
4357
4379
|
session.setSteerHandler(null);
|
|
4358
4380
|
session.setSideQuestionLive(null);
|
|
@@ -5402,8 +5424,8 @@ ${typeLabels[type] || type}:`));
|
|
|
5402
5424
|
}
|
|
5403
5425
|
console.log(chalk.gray(" An external claude command is only needed for native terminal/mirror use."));
|
|
5404
5426
|
try {
|
|
5405
|
-
const { resolveAgentHomesForCli } = await Promise.resolve().then(function () { return require('./agentHome-
|
|
5406
|
-
const { describeAgentHome } = await Promise.resolve().then(function () { return require('./types-
|
|
5427
|
+
const { resolveAgentHomesForCli } = await Promise.resolve().then(function () { return require('./agentHome-B0CLy0Qx.cjs'); });
|
|
5428
|
+
const { describeAgentHome } = await Promise.resolve().then(function () { return require('./types-B0sSi6eM.cjs'); }).then(function (n) { return n.index; });
|
|
5407
5429
|
const homes = await resolveAgentHomesForCli();
|
|
5408
5430
|
console.log(chalk.green(`\u2713 Claude config dir: ${describeAgentHome(homes.claudeConfigDir)}`));
|
|
5409
5431
|
console.log(chalk.green(`\u2713 Codex home: ${describeAgentHome(homes.codexHome)}`));
|
|
@@ -6226,6 +6248,18 @@ function checkPreviewPath(input, opts) {
|
|
|
6226
6248
|
return { resolved, deniedReason: null };
|
|
6227
6249
|
}
|
|
6228
6250
|
|
|
6251
|
+
const BackgroundTaskInfoSchema = z.z.object({
|
|
6252
|
+
id: z.z.string().min(1).max(200),
|
|
6253
|
+
type: z.z.string().max(64),
|
|
6254
|
+
description: z.z.string().max(persistence.BACKGROUND_TASK_DESCRIPTION_MAX + 1),
|
|
6255
|
+
startedAt: z.z.number()
|
|
6256
|
+
});
|
|
6257
|
+
const BackgroundTasksReportSchema = z.z.object({
|
|
6258
|
+
count: z.z.number().int().nonnegative(),
|
|
6259
|
+
tasks: z.z.array(BackgroundTaskInfoSchema),
|
|
6260
|
+
reportedAt: z.z.number().optional(),
|
|
6261
|
+
stale: z.z.boolean().optional()
|
|
6262
|
+
});
|
|
6229
6263
|
function startDaemonControlServer({
|
|
6230
6264
|
controlToken,
|
|
6231
6265
|
getChildren,
|
|
@@ -6237,12 +6271,15 @@ function startDaemonControlServer({
|
|
|
6237
6271
|
onSessionStateEvent,
|
|
6238
6272
|
onClaudeAuthFailed,
|
|
6239
6273
|
onSessionTurnEvent,
|
|
6274
|
+
onSessionBackgroundTasks,
|
|
6275
|
+
getBackgroundTasks,
|
|
6240
6276
|
pushClipboard,
|
|
6241
6277
|
pushFilePreview,
|
|
6242
6278
|
onTerminalHook,
|
|
6243
6279
|
setTerminalTitle,
|
|
6244
6280
|
onSessionEdit,
|
|
6245
|
-
listPeers
|
|
6281
|
+
listPeers,
|
|
6282
|
+
isTurnActive
|
|
6246
6283
|
}) {
|
|
6247
6284
|
return new Promise((resolve) => {
|
|
6248
6285
|
const app = fastify({
|
|
@@ -6296,8 +6333,10 @@ function startDaemonControlServer({
|
|
|
6296
6333
|
schema: {
|
|
6297
6334
|
body: z.z.object({
|
|
6298
6335
|
sessionId: z.z.string(),
|
|
6299
|
-
event: z.z.enum(["completed", "needs_input", "auth_failed", "turn_started", "turn_ended"]),
|
|
6300
|
-
spawnedBy: z.z.string().optional()
|
|
6336
|
+
event: z.z.enum(["completed", "needs_input", "auth_failed", "turn_started", "turn_ended", "background_tasks"]),
|
|
6337
|
+
spawnedBy: z.z.string().optional(),
|
|
6338
|
+
// B-507: only with event 'background_tasks' — the wrapper's full set.
|
|
6339
|
+
backgroundTasks: z.z.array(BackgroundTaskInfoSchema).max(persistence.BACKGROUND_TASKS_MAX).optional()
|
|
6301
6340
|
}),
|
|
6302
6341
|
response: {
|
|
6303
6342
|
200: z.z.object({
|
|
@@ -6308,6 +6347,10 @@ function startDaemonControlServer({
|
|
|
6308
6347
|
}, async (request) => {
|
|
6309
6348
|
const { sessionId, event, spawnedBy } = request.body;
|
|
6310
6349
|
persistence.logger.debug(`[CONTROL SERVER] Session event: ${sessionId} ${event} (spawnedBy=${spawnedBy ?? "unset"})`);
|
|
6350
|
+
if (event === "background_tasks") {
|
|
6351
|
+
onSessionBackgroundTasks?.(sessionId, request.body.backgroundTasks ?? []);
|
|
6352
|
+
return { status: "ok" };
|
|
6353
|
+
}
|
|
6311
6354
|
if (event === "auth_failed") {
|
|
6312
6355
|
onClaudeAuthFailed?.(sessionId);
|
|
6313
6356
|
return { status: "ok" };
|
|
@@ -6326,7 +6369,10 @@ function startDaemonControlServer({
|
|
|
6326
6369
|
children: z.z.array(z.z.object({
|
|
6327
6370
|
startedBy: z.z.string(),
|
|
6328
6371
|
happySessionId: z.z.string(),
|
|
6329
|
-
pid: z.z.number()
|
|
6372
|
+
pid: z.z.number(),
|
|
6373
|
+
turnActive: z.z.boolean(),
|
|
6374
|
+
// B-507: in-flight background tasks per the wrapper's last report (lease-expired = count 0).
|
|
6375
|
+
backgroundTasks: BackgroundTasksReportSchema.optional()
|
|
6330
6376
|
}))
|
|
6331
6377
|
})
|
|
6332
6378
|
}
|
|
@@ -6338,7 +6384,9 @@ function startDaemonControlServer({
|
|
|
6338
6384
|
children: children.filter((child) => child.happySessionId !== void 0).map((child) => ({
|
|
6339
6385
|
startedBy: child.startedBy,
|
|
6340
6386
|
happySessionId: child.happySessionId,
|
|
6341
|
-
pid: child.pid
|
|
6387
|
+
pid: child.pid,
|
|
6388
|
+
turnActive: isTurnActive ? isTurnActive(child.happySessionId) : false,
|
|
6389
|
+
...getBackgroundTasks ? { backgroundTasks: getBackgroundTasks(child.happySessionId) } : {}
|
|
6342
6390
|
}))
|
|
6343
6391
|
};
|
|
6344
6392
|
});
|
|
@@ -6906,6 +6954,170 @@ function createPeerCoordinator(deps) {
|
|
|
6906
6954
|
};
|
|
6907
6955
|
}
|
|
6908
6956
|
|
|
6957
|
+
const WRITE_METHODS = /* @__PURE__ */ new Set(["sessions.send", "sessions.message"]);
|
|
6958
|
+
const REMOTE_CLIENT_TAG = "cli-send-remote";
|
|
6959
|
+
function defaultDeps(machineId) {
|
|
6960
|
+
return {
|
|
6961
|
+
machineId,
|
|
6962
|
+
host: os.hostname(),
|
|
6963
|
+
enabled: async () => (await persistence.readSettings()).remoteSessionOps !== "off",
|
|
6964
|
+
readPersisted: persistence.readPersistedSessions,
|
|
6965
|
+
listLocal: (options) => agentGuidance.listSessions(options),
|
|
6966
|
+
listAccount: (options) => agentGuidance.listAccountSessions(options),
|
|
6967
|
+
readTranscript: (sessionId, limit, options) => agentGuidance.readSessionTranscript(sessionId, limit, options),
|
|
6968
|
+
deliver: (sessionId, persisted, text, client, options, deps) => agentGuidance.deliverToSession(sessionId, persisted, text, client, options, deps),
|
|
6969
|
+
listPeers: (context, scope) => agentGuidance.listPeerSessions(context, scope),
|
|
6970
|
+
sendPeer: (context, args) => agentGuidance.sendPeerMessage(context, args),
|
|
6971
|
+
log: (line) => persistence.logger.info(line),
|
|
6972
|
+
now: () => Date.now()
|
|
6973
|
+
};
|
|
6974
|
+
}
|
|
6975
|
+
function createRemoteSessionOpsHandlers(machineId, overrides = {}) {
|
|
6976
|
+
const deps = { ...defaultDeps(machineId), ...overrides };
|
|
6977
|
+
const readBudget = deps.budget ?? new agentGuidance.RemoteCallBudget(void 0, deps.now);
|
|
6978
|
+
const writeBudget = deps.writeBudget ?? new agentGuidance.RemoteCallBudget(agentGuidance.REMOTE_WRITE_CALLS_PER_MINUTE, deps.now);
|
|
6979
|
+
const deadlineMs = deps.deadlineMs ?? agentGuidance.REMOTE_OP_DEADLINE_MS;
|
|
6980
|
+
const sendCommitDeadlineMs = deps.sendCommitDeadlineMs ?? agentGuidance.REMOTE_SEND_COMMIT_DEADLINE_MS;
|
|
6981
|
+
const resumeWaitMs = deps.resumeWaitMs ?? agentGuidance.REMOTE_RESUME_WAIT_MS;
|
|
6982
|
+
const run = (method, op, targetOf) => async (params) => {
|
|
6983
|
+
const started = deps.now();
|
|
6984
|
+
let from = null;
|
|
6985
|
+
let sessionId;
|
|
6986
|
+
const finish = (response) => {
|
|
6987
|
+
const outcome = response.ok ? "ok" : response.error.code;
|
|
6988
|
+
deps.log(agentGuidance.formatRemoteAuditLine({ method, from, sessionId, outcome, durationMs: deps.now() - started }));
|
|
6989
|
+
return response;
|
|
6990
|
+
};
|
|
6991
|
+
let enabled = false;
|
|
6992
|
+
try {
|
|
6993
|
+
enabled = await deps.enabled();
|
|
6994
|
+
} catch {
|
|
6995
|
+
enabled = false;
|
|
6996
|
+
}
|
|
6997
|
+
const guard = agentGuidance.guardRemoteSessionOpsRequest(method, params, { enabled });
|
|
6998
|
+
if (!guard.ok) return finish(guard);
|
|
6999
|
+
from = guard.request.from;
|
|
7000
|
+
sessionId = targetOf(guard.request.args);
|
|
7001
|
+
const budget = WRITE_METHODS.has(method) ? writeBudget : readBudget;
|
|
7002
|
+
const token = budget.take();
|
|
7003
|
+
if (!token.ok) {
|
|
7004
|
+
return finish(agentGuidance.remoteError("rate_limited", `This machine accepts at most ${budget.perMinute} remote ${WRITE_METHODS.has(method) ? "send/message" : "list/read/peers"} calls per minute; retry in ${Math.ceil(token.retryAfterMs / 1e3)}s`));
|
|
7005
|
+
}
|
|
7006
|
+
let timer;
|
|
7007
|
+
const deadline = new Promise((_, reject) => {
|
|
7008
|
+
timer = setTimeout(() => reject(new RemoteOpFailure("timeout", `${method} did not finish within ${Math.round(deadlineMs / 1e3)}s on ${deps.host}`)), deadlineMs);
|
|
7009
|
+
timer.unref?.();
|
|
7010
|
+
});
|
|
7011
|
+
try {
|
|
7012
|
+
return finish({ ok: true, result: await Promise.race([op(guard.request.args, from, started), deadline]) });
|
|
7013
|
+
} catch (error) {
|
|
7014
|
+
const message = error instanceof Error ? error.message : "Remote session operation failed";
|
|
7015
|
+
if (error instanceof RemoteOpFailure) return finish(agentGuidance.remoteError(error.code, message));
|
|
7016
|
+
return finish(agentGuidance.remoteError("internal", message));
|
|
7017
|
+
} finally {
|
|
7018
|
+
if (timer) clearTimeout(timer);
|
|
7019
|
+
}
|
|
7020
|
+
};
|
|
7021
|
+
const requirePersisted = (id) => {
|
|
7022
|
+
const persisted = deps.readPersisted()[id];
|
|
7023
|
+
if (!persisted) throw new RemoteOpFailure("no_local_key", `Session ${id} is not on ${deps.host} (no local key there either)`);
|
|
7024
|
+
return persisted;
|
|
7025
|
+
};
|
|
7026
|
+
return {
|
|
7027
|
+
"sessions.list": run("sessions.list", async (args) => {
|
|
7028
|
+
const wanted = args.ids ? new Set(args.ids) : null;
|
|
7029
|
+
let sessions;
|
|
7030
|
+
if (args.all) {
|
|
7031
|
+
sessions = (await deps.listAccount({ tag: args.tag, recentLimit: wanted ? 1e4 : args.limit, includeArchived: true })).filter((row) => row.decryptable);
|
|
7032
|
+
} else if (wanted) {
|
|
7033
|
+
const persisted = deps.readPersisted();
|
|
7034
|
+
const live = await deps.listLocal({ recentLimit: 1e4 });
|
|
7035
|
+
const liveById = new Map(live.map((row) => [row.id, row]));
|
|
7036
|
+
sessions = [...wanted].filter((id) => persisted[id] !== void 0 || liveById.has(id)).map((id) => liveById.get(id) ?? summaryFromPersisted(id, persisted[id]));
|
|
7037
|
+
} else {
|
|
7038
|
+
sessions = await deps.listLocal({ tag: args.tag, recentLimit: args.limit });
|
|
7039
|
+
}
|
|
7040
|
+
if (wanted) sessions = sessions.filter((row) => wanted.has(row.id));
|
|
7041
|
+
const result = { machineId: deps.machineId, host: deps.host, sessions };
|
|
7042
|
+
return result;
|
|
7043
|
+
}, () => void 0),
|
|
7044
|
+
"sessions.read": run("sessions.read", async (args) => {
|
|
7045
|
+
requirePersisted(args.sessionId);
|
|
7046
|
+
const limit = Math.max(1, Math.min(agentGuidance.MAX_READ_LIMIT, args.limit ?? 20));
|
|
7047
|
+
const transcript = await deps.readTranscript(args.sessionId, limit, { full: args.full === true });
|
|
7048
|
+
const capped = agentGuidance.capRemoteTranscript(transcript.transcript);
|
|
7049
|
+
const result = {
|
|
7050
|
+
...transcript,
|
|
7051
|
+
summary: {
|
|
7052
|
+
...transcript.summary,
|
|
7053
|
+
...transcript.summary.title !== void 0 ? { title: agentGuidance.capRemoteText(transcript.summary.title, agentGuidance.REMOTE_TITLE_MAX_BYTES) } : {}
|
|
7054
|
+
},
|
|
7055
|
+
turn: { ...transcript.turn, answer: agentGuidance.capRemoteText(transcript.turn.answer, agentGuidance.REMOTE_ANSWER_MAX_BYTES, "tail") },
|
|
7056
|
+
transcript: capped.transcript,
|
|
7057
|
+
...capped.truncated ? { truncated: true } : {},
|
|
7058
|
+
machineId: deps.machineId,
|
|
7059
|
+
host: deps.host
|
|
7060
|
+
};
|
|
7061
|
+
return result;
|
|
7062
|
+
}, (args) => args.sessionId),
|
|
7063
|
+
"sessions.send": run("sessions.send", async (args, _from, started) => {
|
|
7064
|
+
const persisted = requirePersisted(args.sessionId);
|
|
7065
|
+
const send = (sessionId, key, text, client, options) => {
|
|
7066
|
+
if (deps.now() - started > sendCommitDeadlineMs) {
|
|
7067
|
+
throw new RemoteOpFailure("timeout", `Session ${sessionId} was not live within ${Math.round(sendCommitDeadlineMs / 1e3)}s on ${deps.host}; nothing was sent \u2014 retry (the same localId cannot double-deliver)`);
|
|
7068
|
+
}
|
|
7069
|
+
return agentGuidance.sendUserMessage(sessionId, key, text, client, { ...options, ...args.localId ? { localId: args.localId } : {} });
|
|
7070
|
+
};
|
|
7071
|
+
return deps.deliver(args.sessionId, persisted, args.text, REMOTE_CLIENT_TAG, {
|
|
7072
|
+
resume: args.resume === true,
|
|
7073
|
+
waitMs: resumeWaitMs,
|
|
7074
|
+
pollMs: 1e3,
|
|
7075
|
+
...args.model !== void 0 ? { model: args.model } : {},
|
|
7076
|
+
...args.sentFrom !== void 0 ? { sentFrom: args.sentFrom } : {}
|
|
7077
|
+
}, { send });
|
|
7078
|
+
}, (args) => args.sessionId),
|
|
7079
|
+
"sessions.peers": run("sessions.peers", async (args, from) => {
|
|
7080
|
+
const scope = args.cwd ? args.scope ?? "machine" : "machine";
|
|
7081
|
+
const context = {
|
|
7082
|
+
self: () => ({ sessionId: from.sessionId ?? agentGuidance.CLI_PEER_SENDER_ID, cwd: args.cwd ?? "/", machine: from.host }),
|
|
7083
|
+
readPersisted: deps.readPersisted
|
|
7084
|
+
};
|
|
7085
|
+
const listing = await deps.listPeers(context, scope);
|
|
7086
|
+
return { ...listing, machineId: deps.machineId, host: deps.host };
|
|
7087
|
+
}, () => void 0),
|
|
7088
|
+
"sessions.message": run("sessions.message", async (args) => {
|
|
7089
|
+
requirePersisted(args.to);
|
|
7090
|
+
const context = {
|
|
7091
|
+
self: () => ({ ...args.from, cwd: args.from.cwd ?? "/" }),
|
|
7092
|
+
readPersisted: deps.readPersisted,
|
|
7093
|
+
// The target must be HERE; never bounce a remote request onward.
|
|
7094
|
+
remoteMessage: null
|
|
7095
|
+
};
|
|
7096
|
+
return deps.sendPeer(context, { to: args.to, body: args.body, ...args.replyTo ? { replyTo: args.replyTo } : {} });
|
|
7097
|
+
}, (args) => args.to)
|
|
7098
|
+
};
|
|
7099
|
+
}
|
|
7100
|
+
class RemoteOpFailure extends Error {
|
|
7101
|
+
constructor(code, message) {
|
|
7102
|
+
super(message);
|
|
7103
|
+
this.code = code;
|
|
7104
|
+
}
|
|
7105
|
+
}
|
|
7106
|
+
function summaryFromPersisted(id, persisted) {
|
|
7107
|
+
const meta = persisted?.metadata;
|
|
7108
|
+
return {
|
|
7109
|
+
id,
|
|
7110
|
+
live: false,
|
|
7111
|
+
...meta?.summary?.text ? { title: meta.summary.text } : {},
|
|
7112
|
+
...meta?.path ? { cwd: meta.path } : {},
|
|
7113
|
+
...meta?.flavor ? { flavor: meta.flavor } : {},
|
|
7114
|
+
...meta?.tags?.length ? { tags: [...meta.tags] } : {},
|
|
7115
|
+
...meta?.variant ? { variant: meta.variant } : {},
|
|
7116
|
+
...persisted?.savedAt !== void 0 ? { savedAt: persisted.savedAt } : {},
|
|
7117
|
+
url: agentGuidance.sessionWebUrl(id)
|
|
7118
|
+
};
|
|
7119
|
+
}
|
|
7120
|
+
|
|
6909
7121
|
const ASSISTANT_CLAUDE_MD = `# very-happy \u8C03\u5EA6\u4E2D\u5FC3\uFF08\u8BED\u97F3\u52A9\u624B\uFF09
|
|
6910
7122
|
|
|
6911
7123
|
\u4F60\u662F very-happy \u7684\u8C03\u5EA6\u4E2D\u5FC3\uFF0C\u8DD1\u5728\u7528\u6237\u81EA\u5DF1\u7684\u673A\u5668\u4E0A\u3002\u7528\u6237\u4E3B\u8981\u901A\u8FC7\u8BED\u97F3\u8DDF\u4F60\u8BF4\u8BDD\uFF0C
|
|
@@ -8442,7 +8654,7 @@ function parseJsonObject(text) {
|
|
|
8442
8654
|
return null;
|
|
8443
8655
|
}
|
|
8444
8656
|
}
|
|
8445
|
-
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-
|
|
8657
|
+
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-C9QzZsUQ.cjs', document.baseURI).href))).resolve(s)) {
|
|
8446
8658
|
const platformArch = `${platform}-${arch}`;
|
|
8447
8659
|
const candidates = [
|
|
8448
8660
|
`@anthropic-ai/claude-agent-sdk-${platformArch}/claude`,
|
|
@@ -9132,9 +9344,9 @@ function createMirrorManager(deps) {
|
|
|
9132
9344
|
archiveReason: reason
|
|
9133
9345
|
});
|
|
9134
9346
|
try {
|
|
9135
|
-
await deps.api.
|
|
9347
|
+
await deps.api.archiveSession(binding.happySessionId);
|
|
9136
9348
|
} catch (error) {
|
|
9137
|
-
persistence.logger.debug(`[MIRROR]
|
|
9349
|
+
persistence.logger.debug(`[MIRROR] archiveSession failed for ${binding.happySessionId}:`, error);
|
|
9138
9350
|
}
|
|
9139
9351
|
deps.onBindingsChanged?.();
|
|
9140
9352
|
};
|
|
@@ -10614,6 +10826,13 @@ ${action.prompt}`, { localId: `automation-${run.id}`, ...meta });
|
|
|
10614
10826
|
if (edgeFell) item.sawTurn = false;
|
|
10615
10827
|
const turn = await readTurn(sessionId, item.runId).catch(() => null);
|
|
10616
10828
|
if (!turn?.ended) continue;
|
|
10829
|
+
const background = deps.backgroundTasks?.(sessionId) ?? 0;
|
|
10830
|
+
if (background > 0 && turn.status !== "failed" && turn.status !== "cancelled") {
|
|
10831
|
+
if (!item.waitingOnBackground) deps.log(`Automation run ${item.runId}: turn ended but ${background} background task(s) still running; not done yet`);
|
|
10832
|
+
item.waitingOnBackground = true;
|
|
10833
|
+
continue;
|
|
10834
|
+
}
|
|
10835
|
+
item.waitingOnBackground = false;
|
|
10617
10836
|
if (turn.status === "failed" || turn.status === "cancelled") await finish(item, { claimId: item.claimId, status: "failed", sessionId, error: turn.error ?? `Turn ${turn.status}`, needsAttention: true, attentionReason: `turn_${turn.status}` });
|
|
10618
10837
|
else await finish(item, { claimId: item.claimId, status: "done", sessionId, summary: clipText(turn.answer, persistence.AUTOMATION_SUMMARY_MAX_CHARS) });
|
|
10619
10838
|
}
|
|
@@ -10743,6 +10962,16 @@ ${action.prompt}`, { localId: `automation-${run.id}`, ...meta });
|
|
|
10743
10962
|
function daemonExitCode(source) {
|
|
10744
10963
|
return source === "exception" ? 1 : 0;
|
|
10745
10964
|
}
|
|
10965
|
+
const HANDOVER_EXIT_CODE = 75;
|
|
10966
|
+
|
|
10967
|
+
function detectDaemonSupervisor(env, platform = process.platform) {
|
|
10968
|
+
const explicit = env.HAPPY_DAEMON_SUPERVISOR?.trim().toLowerCase();
|
|
10969
|
+
if (explicit === "systemd") return "systemd";
|
|
10970
|
+
if (explicit === "none") return "none";
|
|
10971
|
+
if (platform === "linux" && typeof env.INVOCATION_ID === "string" && env.INVOCATION_ID.trim() !== "") return "systemd";
|
|
10972
|
+
return "none";
|
|
10973
|
+
}
|
|
10974
|
+
const SYSTEMD_RESTART_HINT = "systemctl --user restart very-happy-daemon";
|
|
10746
10975
|
|
|
10747
10976
|
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
10748
10977
|
function sanitizeImportTitle(value) {
|
|
@@ -10898,6 +11127,7 @@ async function startDaemon() {
|
|
|
10898
11127
|
persistence.logger.debug("[DAEMON RUN] Auth and machine setup complete");
|
|
10899
11128
|
const pidToTrackedSession = /* @__PURE__ */ new Map();
|
|
10900
11129
|
const turnActivity = new index.TurnActivityTracker();
|
|
11130
|
+
const backgroundTasks = new persistence.BackgroundTaskTracker();
|
|
10901
11131
|
const peerCoordinator = createPeerCoordinator({ getChildren: () => Array.from(pidToTrackedSession.values()) });
|
|
10902
11132
|
const sessionIdToFinishedSession = /* @__PURE__ */ new Map();
|
|
10903
11133
|
let teamWorker;
|
|
@@ -11758,6 +11988,7 @@ async function startDaemon() {
|
|
|
11758
11988
|
if (session?.happySessionId && (session.spawnedBy === "teams" || teamWorker?.hasSession(session.happySessionId))) teamWorker?.report(session.happySessionId, "exited");
|
|
11759
11989
|
if (session?.happySessionId && automationRunner?.hasSession(session.happySessionId)) automationRunner.report(session.happySessionId, "exited");
|
|
11760
11990
|
if (session?.happySessionId) turnActivity.forget(session.happySessionId);
|
|
11991
|
+
if (session?.happySessionId) backgroundTasks.forget(session.happySessionId);
|
|
11761
11992
|
if (session?.happySessionId) peerCoordinator.forget(session.happySessionId);
|
|
11762
11993
|
if (session?.happySessionId && session.encryption) {
|
|
11763
11994
|
sessionIdToFinishedSession.set(session.happySessionId, session);
|
|
@@ -11844,10 +12075,15 @@ async function startDaemon() {
|
|
|
11844
12075
|
onSessionStateEvent,
|
|
11845
12076
|
onClaudeAuthFailed: (sessionId) => claudeAuthServiceRef?.signalAuthFailed(sessionId),
|
|
11846
12077
|
onSessionTurnEvent: (sessionId, event) => turnActivity.apply(sessionId, event),
|
|
12078
|
+
onSessionBackgroundTasks: (sessionId, tasks) => backgroundTasks.apply(sessionId, tasks),
|
|
12079
|
+
getBackgroundTasks: (sessionId) => backgroundTasks.report(sessionId),
|
|
11847
12080
|
onSessionEdit: (edit) => {
|
|
11848
12081
|
peerCoordinator.onEdit(edit);
|
|
11849
12082
|
},
|
|
11850
12083
|
listPeers: () => peerCoordinator.list(),
|
|
12084
|
+
// B-505: `daemon list` shows which sessions have a turn in flight, so an
|
|
12085
|
+
// operator can check the WHOLE machine before a supervised restart.
|
|
12086
|
+
isTurnActive: (sessionId) => turnActivity.activeSessions().includes(sessionId),
|
|
11851
12087
|
pushClipboard: (text, terminalId) => {
|
|
11852
12088
|
if (!apiMachineRef) {
|
|
11853
12089
|
return { delivered: false, truncated: false, totalBytes: 0, error: "daemon is still starting up" };
|
|
@@ -11867,6 +12103,8 @@ async function startDaemon() {
|
|
|
11867
12103
|
}
|
|
11868
12104
|
});
|
|
11869
12105
|
const daemonClaudeCredentials = resolveClaudeCredentialReadiness();
|
|
12106
|
+
const daemonSupervisor = detectDaemonSupervisor(process.env);
|
|
12107
|
+
persistence.logger.debug(`[DAEMON RUN] Supervisor: ${daemonSupervisor}`);
|
|
11870
12108
|
let fileState = {
|
|
11871
12109
|
pid: process.pid,
|
|
11872
12110
|
httpPort: controlPort,
|
|
@@ -11876,7 +12114,8 @@ async function startDaemon() {
|
|
|
11876
12114
|
serverUrl: persistence.configuration.serverUrl,
|
|
11877
12115
|
webappUrl: persistence.configuration.webappUrl,
|
|
11878
12116
|
daemonLogPath: persistence.logger.logFilePath,
|
|
11879
|
-
claudeCredentialSource: daemonClaudeCredentials.source
|
|
12117
|
+
claudeCredentialSource: daemonClaudeCredentials.source,
|
|
12118
|
+
supervisor: daemonSupervisor
|
|
11880
12119
|
};
|
|
11881
12120
|
persistence.writeDaemonState(fileState);
|
|
11882
12121
|
persistence.logger.debug("[DAEMON RUN] Daemon state written");
|
|
@@ -11937,6 +12176,7 @@ async function startDaemon() {
|
|
|
11937
12176
|
listTrackedSessionIds: () => [...pidToTrackedSession.values()].map((session) => session.happySessionId).filter((sessionId) => typeof sessionId === "string"),
|
|
11938
12177
|
requestShutdown: () => requestShutdown("happy-app")
|
|
11939
12178
|
});
|
|
12179
|
+
apiMachine.setRemoteSessionOpsHandlers(createRemoteSessionOpsHandlers(machineId));
|
|
11940
12180
|
const claudeAuthService = new ClaudeAuthService({
|
|
11941
12181
|
happyHomeDir: persistence.configuration.happyHomeDir,
|
|
11942
12182
|
happyLibDir: terminalTitleSuggest.projectPath(),
|
|
@@ -11969,8 +12209,9 @@ async function startDaemon() {
|
|
|
11969
12209
|
enabled: async () => ((await persistence.readSettings()).cliAutoUpdate ?? "idle") !== "off",
|
|
11970
12210
|
// B-466: "idle" = no agent turn in flight. Idle wrappers survive a
|
|
11971
12211
|
// handover (they talk to the server themselves) and web terminals live
|
|
11972
|
-
// in tmux, so neither is a reason to hold an update.
|
|
11973
|
-
|
|
12212
|
+
// in tmux, so neither is a reason to hold an update. B-507: a session
|
|
12213
|
+
// whose turn ended but still has background tasks is busy too.
|
|
12214
|
+
idle: () => !turnActivity.hasActiveTurn() && !backgroundTasks.hasAny(),
|
|
11974
12215
|
install: installCliSafely,
|
|
11975
12216
|
publish: (state) => {
|
|
11976
12217
|
cliUpdateStateRef = state;
|
|
@@ -12025,7 +12266,7 @@ async function startDaemon() {
|
|
|
12025
12266
|
} catch {
|
|
12026
12267
|
}
|
|
12027
12268
|
}
|
|
12028
|
-
if (bundleReplaced && !teamWorker?.busy && !automationRunner?.busy && !updateController.isRunning() && !turnActivity.hasActiveTurn()) {
|
|
12269
|
+
if (bundleReplaced && !teamWorker?.busy && !automationRunner?.busy && !updateController.isRunning() && !turnActivity.hasActiveTurn() && !backgroundTasks.hasAny()) {
|
|
12029
12270
|
const preflight = await preflightNewBundle(bundlePath);
|
|
12030
12271
|
if (preflight.action === "hold") {
|
|
12031
12272
|
if (lastHandoverHold !== preflight.reason) {
|
|
@@ -12035,7 +12276,7 @@ async function startDaemon() {
|
|
|
12035
12276
|
updateController.holdHandover(preflight.reason);
|
|
12036
12277
|
return;
|
|
12037
12278
|
}
|
|
12038
|
-
if (teamWorker?.busy || automationRunner?.busy || updateController.isRunning() || turnActivity.hasActiveTurn()) return;
|
|
12279
|
+
if (teamWorker?.busy || automationRunner?.busy || updateController.isRunning() || turnActivity.hasActiveTurn() || backgroundTasks.hasAny()) return;
|
|
12039
12280
|
lastHandoverHold = null;
|
|
12040
12281
|
persistence.logger.debug("[DAEMON RUN] Daemon bundle replaced on disk and verified, handing off to new daemon");
|
|
12041
12282
|
teamWorker?.stop();
|
|
@@ -12049,6 +12290,10 @@ async function startDaemon() {
|
|
|
12049
12290
|
await persistence.cleanupDaemonState();
|
|
12050
12291
|
await persistence.releaseDaemonLock(daemonLockHandle);
|
|
12051
12292
|
await stopCaffeinate();
|
|
12293
|
+
if (daemonSupervisor === "systemd") {
|
|
12294
|
+
persistence.logger.debug(`[DAEMON RUN] systemd-supervised: exiting ${HANDOVER_EXIT_CODE} for the unit to restart on the new bundle`);
|
|
12295
|
+
process.exit(HANDOVER_EXIT_CODE);
|
|
12296
|
+
}
|
|
12052
12297
|
try {
|
|
12053
12298
|
spawnHappyCLI(["daemon", "start"], {
|
|
12054
12299
|
detached: true,
|
|
@@ -12097,6 +12342,7 @@ async function startDaemon() {
|
|
|
12097
12342
|
spawn: spawnSession,
|
|
12098
12343
|
live: (id) => [...pidToTrackedSession.values()].some((s) => s.happySessionId === id && isPidAlive(s.pid)),
|
|
12099
12344
|
turnActive: (id) => turnActivity.activeSessions().includes(id),
|
|
12345
|
+
backgroundTasks: (id) => backgroundTasks.count(id),
|
|
12100
12346
|
log: (message) => persistence.logger.debug(`[DAEMON RUN] ${message}`)
|
|
12101
12347
|
});
|
|
12102
12348
|
void apiMachine.updateMachineMetadata((current) => ({
|
|
@@ -12390,36 +12636,54 @@ ${sessions.map(describeSummary).join("\n")}`);
|
|
|
12390
12636
|
}
|
|
12391
12637
|
});
|
|
12392
12638
|
mcp.registerTool("session_read", {
|
|
12393
|
-
description: "Read the latest messages of a session as a compact role-tagged transcript (user / assistant / tool summaries; large payloads truncated).
|
|
12639
|
+
description: "Read the latest messages of a session as a compact role-tagged transcript (user / assistant / tool summaries; large payloads truncated). Sessions spawned by this machine are read directly; a session spawned by another machine of this account is read through that machine's daemon (it must be online).",
|
|
12394
12640
|
title: "Read Session Transcript",
|
|
12395
12641
|
inputSchema: {
|
|
12396
12642
|
sessionId: z.z.string().describe("The Happy session id to read"),
|
|
12397
|
-
limit: z.z.number().optional().describe("How many recent messages to fetch (default 20, max 100)")
|
|
12643
|
+
limit: z.z.number().optional().describe("How many recent messages to fetch (default 20, max 100)"),
|
|
12644
|
+
machineId: z.z.string().optional().describe("Machine id the session runs on, when known (skips the lookup across the account's machines)")
|
|
12398
12645
|
}
|
|
12399
12646
|
}, async (args) => {
|
|
12400
12647
|
if (!persistence.isValidSessionId(args.sessionId)) return fail("Invalid sessionId");
|
|
12401
12648
|
try {
|
|
12402
|
-
const
|
|
12649
|
+
const local = persistence.readPersistedSessions()[args.sessionId];
|
|
12650
|
+
if (local && !args.machineId) {
|
|
12651
|
+
const result2 = await agentGuidance.readSessionTranscript(args.sessionId, args.limit ?? 20);
|
|
12652
|
+
const body2 = result2.transcript.length > 0 ? result2.transcript : "(no readable conversation content in this range)";
|
|
12653
|
+
return ok(`${describeSummary(result2.summary)}
|
|
12654
|
+
--- last ${result2.messageCount} message(s) ---
|
|
12655
|
+
${body2}`);
|
|
12656
|
+
}
|
|
12657
|
+
const result = await agentGuidance.readRemoteTranscript(args.sessionId, { limit: args.limit ?? 20, ...args.machineId ? { machineId: args.machineId } : {} });
|
|
12403
12658
|
const body = result.transcript.length > 0 ? result.transcript : "(no readable conversation content in this range)";
|
|
12404
|
-
return ok(`${describeSummary(result.summary)}
|
|
12405
|
-
--- last ${result.messageCount} message(s) ---
|
|
12659
|
+
return ok(`${describeSummary(result.summary)} machine=${result.host} (${result.machineId})
|
|
12660
|
+
--- last ${result.messageCount} message(s)${result.truncated ? ", truncated to fit" : ""} ---
|
|
12406
12661
|
${body}`);
|
|
12407
12662
|
} catch (error) {
|
|
12408
12663
|
return fail(`Failed to read session: ${error instanceof Error ? error.message : String(error)}`);
|
|
12409
12664
|
}
|
|
12410
12665
|
});
|
|
12411
12666
|
mcp.registerTool("session_send", {
|
|
12412
|
-
description: "Send a user message into an existing session
|
|
12667
|
+
description: "Send a user message into an existing session. Only delivers when a live wrapper will read it: an archived / offline session is refused (the server would store the message unread) unless resume:true brings it back on its machine first. A session spawned by another machine of this account is delivered through that machine's daemon (it must be online). Returns immediately after delivery \u2014 it does NOT wait for the session to respond; use session_read later to check progress.",
|
|
12413
12668
|
title: "Send Message to Session",
|
|
12414
12669
|
inputSchema: {
|
|
12415
12670
|
sessionId: z.z.string().describe("The Happy session id to message"),
|
|
12416
12671
|
text: z.z.string().describe("The message text to send"),
|
|
12417
|
-
resume: z.z.boolean().optional().describe("If the session is archived or offline, resume it on
|
|
12672
|
+
resume: z.z.boolean().optional().describe("If the session is archived or offline, resume it on its machine (like the web Restore button) and wait until it is live before sending"),
|
|
12673
|
+
machineId: z.z.string().optional().describe("Machine id the session runs on, when known (skips the lookup across the account's machines)")
|
|
12418
12674
|
}
|
|
12419
12675
|
}, async (args) => {
|
|
12420
12676
|
if (!persistence.isValidSessionId(args.sessionId)) return fail("Invalid sessionId");
|
|
12421
12677
|
if (typeof args.text !== "string" || args.text.trim().length === 0) return fail("text must be non-empty");
|
|
12422
12678
|
try {
|
|
12679
|
+
if (!persistence.readPersistedSessions()[args.sessionId] || args.machineId) {
|
|
12680
|
+
const remote = await agentGuidance.sendRemoteMessage(args.sessionId, args.text, { resume: args.resume === true, sentFrom: "assistant", ...args.machineId ? { machineId: args.machineId } : {} });
|
|
12681
|
+
if (!remote.delivered) {
|
|
12682
|
+
const detail = remote.error ?? `session is ${remote.status}`;
|
|
12683
|
+
return fail(remote.stored ? `Not delivered (via ${remote.machine.host}): ${detail}` : `Session ${args.sessionId} on ${remote.machine.host} is ${remote.status}: ${detail}`);
|
|
12684
|
+
}
|
|
12685
|
+
return ok(`Message delivered${remote.resumed ? ` (session resumed on ${remote.machine.host})` : ""} to ${args.sessionId} on machine ${remote.machine.host} (${remote.machine.id}) ${agentGuidance.sessionWebUrl(args.sessionId)}`);
|
|
12686
|
+
}
|
|
12423
12687
|
const persisted = await agentGuidance.waitForSessionKey(args.sessionId, 0);
|
|
12424
12688
|
const result = await agentGuidance.deliverToSession(args.sessionId, persisted, args.text, MCP_CLIENT_TAG, {
|
|
12425
12689
|
resume: args.resume === true,
|
|
@@ -12431,6 +12695,7 @@ ${body}`);
|
|
|
12431
12695
|
}
|
|
12432
12696
|
return ok(`Message delivered${result.resumed ? " (session resumed on this machine)" : ""} to ${describeSession(args.sessionId, persisted, { live: true })}`);
|
|
12433
12697
|
} catch (error) {
|
|
12698
|
+
if (error instanceof agentGuidance.RemoteSessionOpsError) return fail(`Failed to send (${error.code}): ${error.message}`);
|
|
12434
12699
|
return fail(`Failed to send: ${error instanceof Error ? error.message : String(error)}`);
|
|
12435
12700
|
}
|
|
12436
12701
|
});
|
|
@@ -13028,6 +13293,40 @@ function registerKillSessionHandler(rpcHandlerManager, killThisHappy, archiveEve
|
|
|
13028
13293
|
};
|
|
13029
13294
|
}
|
|
13030
13295
|
|
|
13296
|
+
async function settleSessionOnExit(sessionId, intent, deps) {
|
|
13297
|
+
if (intent === "archive") {
|
|
13298
|
+
deps.updateMetadata((currentMetadata) => ({
|
|
13299
|
+
...currentMetadata,
|
|
13300
|
+
lifecycleState: "archived",
|
|
13301
|
+
lifecycleStateSince: Date.now(),
|
|
13302
|
+
archivedBy: "cli",
|
|
13303
|
+
archiveReason: "User terminated"
|
|
13304
|
+
}));
|
|
13305
|
+
}
|
|
13306
|
+
deps.sendSessionDeath();
|
|
13307
|
+
try {
|
|
13308
|
+
if (intent === "archive") await deps.archiveSession(sessionId);
|
|
13309
|
+
else await deps.deactivateSession(sessionId);
|
|
13310
|
+
} catch (error) {
|
|
13311
|
+
deps.log?.(`[START] ${intent === "archive" ? "archiveSession" : "deactivateSession"} during cleanup failed:`, error);
|
|
13312
|
+
}
|
|
13313
|
+
}
|
|
13314
|
+
class SessionExitGate {
|
|
13315
|
+
decided = null;
|
|
13316
|
+
/** Returns the intent to act on, or null when cleanup already started. */
|
|
13317
|
+
claim(intent) {
|
|
13318
|
+
if (this.decided !== null) return null;
|
|
13319
|
+
this.decided = intent;
|
|
13320
|
+
return intent;
|
|
13321
|
+
}
|
|
13322
|
+
get current() {
|
|
13323
|
+
return this.decided;
|
|
13324
|
+
}
|
|
13325
|
+
}
|
|
13326
|
+
function exitIntentFromArchiveFlag(archive) {
|
|
13327
|
+
return archive ?? true ? "archive" : "offline";
|
|
13328
|
+
}
|
|
13329
|
+
|
|
13031
13330
|
function isUnsupportedSideQuestionError(error) {
|
|
13032
13331
|
const message = error instanceof Error ? error.message : String(error);
|
|
13033
13332
|
return /unknown|unsupported|not supported|unrecognized|invalid.*subtype/i.test(message);
|
|
@@ -13204,7 +13503,7 @@ function registerSideQuestionHandler(rpc, deps) {
|
|
|
13204
13503
|
const retainMs = deps.retainMs ?? SIDE_QUESTION_RETAIN_MS;
|
|
13205
13504
|
const maxRunMs = deps.maxRunMs ?? SIDE_QUESTION_MAX_RUN_MS;
|
|
13206
13505
|
const fork = deps.run ?? (async (input) => {
|
|
13207
|
-
const { query } = await Promise.resolve().then(function () { return require('./index
|
|
13506
|
+
const { query } = await Promise.resolve().then(function () { return require('./index-Cz-uqnJk.cjs'); });
|
|
13208
13507
|
return runSideQuestion(query, input);
|
|
13209
13508
|
});
|
|
13210
13509
|
const run = async (input, live) => {
|
|
@@ -13323,7 +13622,7 @@ const MAX_TITLE_CHARS = 60;
|
|
|
13323
13622
|
const GENERATION_TIMEOUT_MS = 3e4;
|
|
13324
13623
|
function resolveClaudeBinary() {
|
|
13325
13624
|
try {
|
|
13326
|
-
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-
|
|
13625
|
+
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-C9QzZsUQ.cjs', document.baseURI).href)));
|
|
13327
13626
|
const utilsPath = path.resolve(path.join(terminalTitleSuggest.projectPath(), "scripts", "claude_version_utils.cjs"));
|
|
13328
13627
|
const { getClaudeCliPath } = require$1(utilsPath);
|
|
13329
13628
|
const path$1 = getClaudeCliPath();
|
|
@@ -14341,26 +14640,24 @@ async function runClaude(credentials, options = {}) {
|
|
|
14341
14640
|
hasMetadata: Boolean(message.meta)
|
|
14342
14641
|
});
|
|
14343
14642
|
});
|
|
14643
|
+
const exitGate = new SessionExitGate();
|
|
14344
14644
|
const cleanup = async (opts = { archive: true }) => {
|
|
14345
|
-
|
|
14645
|
+
const intent = exitGate.claim(exitIntentFromArchiveFlag(opts.archive));
|
|
14646
|
+
if (intent === null) {
|
|
14647
|
+
persistence.logger.debug(`[START] Termination (archive=${opts.archive ?? true}) ignored: cleanup already running as ${exitGate.current}`);
|
|
14648
|
+
return;
|
|
14649
|
+
}
|
|
14650
|
+
persistence.logger.debug(`[START] Received termination signal, cleaning up (archive=${intent === "archive"})...`);
|
|
14346
14651
|
try {
|
|
14347
14652
|
if (session) {
|
|
14348
|
-
if (opts.archive ?? true) {
|
|
14349
|
-
session.updateMetadata((currentMetadata) => ({
|
|
14350
|
-
...currentMetadata,
|
|
14351
|
-
lifecycleState: "archived",
|
|
14352
|
-
lifecycleStateSince: Date.now(),
|
|
14353
|
-
archivedBy: "cli",
|
|
14354
|
-
archiveReason: "User terminated"
|
|
14355
|
-
}));
|
|
14356
|
-
}
|
|
14357
14653
|
currentSession?.cleanup();
|
|
14358
|
-
session.
|
|
14359
|
-
|
|
14360
|
-
|
|
14361
|
-
|
|
14362
|
-
|
|
14363
|
-
|
|
14654
|
+
await settleSessionOnExit(session.sessionId, intent, {
|
|
14655
|
+
updateMetadata: (handler) => session.updateMetadata(handler),
|
|
14656
|
+
sendSessionDeath: () => session.sendSessionDeath(),
|
|
14657
|
+
archiveSession: (id) => api.archiveSession(id),
|
|
14658
|
+
deactivateSession: (id) => api.deactivateSession(id),
|
|
14659
|
+
log: (message, ...args) => persistence.logger.debug(message, ...args)
|
|
14660
|
+
});
|
|
14364
14661
|
await session.flush();
|
|
14365
14662
|
await session.close();
|
|
14366
14663
|
}
|
|
@@ -15569,9 +15866,9 @@ function resolveLocalSignupBootstrap(configuredMode, configuredInviteCodes, gene
|
|
|
15569
15866
|
};
|
|
15570
15867
|
}
|
|
15571
15868
|
|
|
15572
|
-
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-
|
|
15869
|
+
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-C9QzZsUQ.cjs', document.baseURI).href)));
|
|
15573
15870
|
const __dirname$1 = path.dirname(__filename$1);
|
|
15574
|
-
const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-
|
|
15871
|
+
const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-C9QzZsUQ.cjs', document.baseURI).href)));
|
|
15575
15872
|
const PRISMA_QUERY_ENGINE_FILES = {
|
|
15576
15873
|
"arm64-darwin": "libquery_engine-darwin-arm64.dylib.node",
|
|
15577
15874
|
"x64-darwin": "libquery_engine-darwin.dylib.node",
|
|
@@ -18514,7 +18811,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18514
18811
|
return;
|
|
18515
18812
|
} else if (subcommand === "install-terminal-hooks") {
|
|
18516
18813
|
try {
|
|
18517
|
-
const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-
|
|
18814
|
+
const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-BVVOEGhG.cjs'); });
|
|
18518
18815
|
const command = parseTerminalHooksArgs(args.slice(1));
|
|
18519
18816
|
if (command.action === "help") {
|
|
18520
18817
|
console.log(TERMINAL_HOOKS_HELP);
|
|
@@ -18531,7 +18828,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18531
18828
|
}
|
|
18532
18829
|
} else if (subcommand === "agent-home") {
|
|
18533
18830
|
try {
|
|
18534
|
-
const { parseAgentHomeArgs, runAgentHomeCommand } = await Promise.resolve().then(function () { return require('./agentHome-
|
|
18831
|
+
const { parseAgentHomeArgs, runAgentHomeCommand } = await Promise.resolve().then(function () { return require('./agentHome-B0CLy0Qx.cjs'); });
|
|
18535
18832
|
await runAgentHomeCommand(parseAgentHomeArgs(args.slice(1)));
|
|
18536
18833
|
process.exit(0);
|
|
18537
18834
|
} catch (error) {
|
|
@@ -18540,7 +18837,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18540
18837
|
}
|
|
18541
18838
|
} else if (subcommand === "spawn") {
|
|
18542
18839
|
try {
|
|
18543
|
-
const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-
|
|
18840
|
+
const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-HV345RN-.cjs'); });
|
|
18544
18841
|
await handleSpawnCommand(args.slice(1));
|
|
18545
18842
|
} catch (error) {
|
|
18546
18843
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -18552,7 +18849,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18552
18849
|
return;
|
|
18553
18850
|
} else if (subcommand === "sessions") {
|
|
18554
18851
|
try {
|
|
18555
|
-
const { handleSessionsCommand } = await Promise.resolve().then(function () { return require('./sessions-
|
|
18852
|
+
const { handleSessionsCommand } = await Promise.resolve().then(function () { return require('./sessions-BFlIrKCY.cjs'); });
|
|
18556
18853
|
await handleSessionsCommand(args.slice(1));
|
|
18557
18854
|
} catch (error) {
|
|
18558
18855
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -18564,7 +18861,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18564
18861
|
return;
|
|
18565
18862
|
} else if (subcommand === "send") {
|
|
18566
18863
|
try {
|
|
18567
|
-
const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-
|
|
18864
|
+
const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-CHxobaoI.cjs'); });
|
|
18568
18865
|
await handleSendCommand(args.slice(1));
|
|
18569
18866
|
} catch (error) {
|
|
18570
18867
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -18670,9 +18967,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18670
18967
|
if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
|
|
18671
18968
|
const projectId = args[3];
|
|
18672
18969
|
try {
|
|
18673
|
-
const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-
|
|
18674
|
-
const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./limits-
|
|
18675
|
-
const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-
|
|
18970
|
+
const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-CzkBjZnV.cjs'); });
|
|
18971
|
+
const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./limits-CyuIt-Vl.cjs'); }).then(function (n) { return n.persistence; });
|
|
18972
|
+
const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-B0sSi6eM.cjs'); }).then(function (n) { return n.api; });
|
|
18676
18973
|
let userEmail = void 0;
|
|
18677
18974
|
try {
|
|
18678
18975
|
const credentials = await readCredentialsForConfiguredRelay2();
|
|
@@ -18703,7 +19000,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18703
19000
|
}
|
|
18704
19001
|
if (geminiSubcommand === "project" && args[2] === "get") {
|
|
18705
19002
|
try {
|
|
18706
|
-
const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-
|
|
19003
|
+
const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-CzkBjZnV.cjs'); });
|
|
18707
19004
|
const config = readGeminiLocalConfig();
|
|
18708
19005
|
if (config.googleCloudProject) {
|
|
18709
19006
|
console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
|
|
@@ -18743,7 +19040,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18743
19040
|
process.exit(0);
|
|
18744
19041
|
}
|
|
18745
19042
|
try {
|
|
18746
|
-
const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-
|
|
19043
|
+
const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-DS-0qm0L.cjs'); });
|
|
18747
19044
|
let startedBy = void 0;
|
|
18748
19045
|
for (let i = 1; i < args.length; i++) {
|
|
18749
19046
|
if (args[i] === "--started-by") {
|
|
@@ -18766,7 +19063,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18766
19063
|
} else if (subcommand === "pi") {
|
|
18767
19064
|
if (args[1] === "--terminal") {
|
|
18768
19065
|
try {
|
|
18769
|
-
const { runPiTerminal } = await Promise.resolve().then(function () { return require('./piTerminal-
|
|
19066
|
+
const { runPiTerminal } = await Promise.resolve().then(function () { return require('./piTerminal-CpU3hzrX.cjs'); });
|
|
18770
19067
|
process.exitCode = await runPiTerminal(args.slice(2));
|
|
18771
19068
|
} catch (error) {
|
|
18772
19069
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -18783,7 +19080,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18783
19080
|
}
|
|
18784
19081
|
};
|
|
18785
19082
|
try {
|
|
18786
|
-
const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-
|
|
19083
|
+
const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-CTbGqVFY.cjs'); });
|
|
18787
19084
|
const parsed = parsePiRunnerArgs(args.slice(1));
|
|
18788
19085
|
const resolved = resolveAcpAgentConfig(["pi", ...parsed.passthrough]);
|
|
18789
19086
|
const { credentials } = await authAndSetupMachineIfNeeded();
|
|
@@ -18811,7 +19108,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18811
19108
|
return;
|
|
18812
19109
|
} else if (subcommand === "acp") {
|
|
18813
19110
|
try {
|
|
18814
|
-
const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-
|
|
19111
|
+
const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-CTbGqVFY.cjs'); });
|
|
18815
19112
|
let startedBy = void 0;
|
|
18816
19113
|
let verbose = false;
|
|
18817
19114
|
const acpArgs = [];
|
|
@@ -18851,7 +19148,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18851
19148
|
return;
|
|
18852
19149
|
} else if (subcommand === "openclaw") {
|
|
18853
19150
|
try {
|
|
18854
|
-
const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-
|
|
19151
|
+
const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-CvSm8oTc.cjs'); });
|
|
18855
19152
|
let startedBy = void 0;
|
|
18856
19153
|
let verbose = false;
|
|
18857
19154
|
let gatewayUrl;
|
|
@@ -18902,7 +19199,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18902
19199
|
return;
|
|
18903
19200
|
} else if (subcommand === "todo") {
|
|
18904
19201
|
try {
|
|
18905
|
-
const { handleTodoCommand } = await Promise.resolve().then(function () { return require('./todo-
|
|
19202
|
+
const { handleTodoCommand } = await Promise.resolve().then(function () { return require('./todo-CMMQ6yhU.cjs'); });
|
|
18906
19203
|
await handleTodoCommand(args.slice(1));
|
|
18907
19204
|
} catch (error) {
|
|
18908
19205
|
console.error(JSON.stringify({ error: error instanceof Error ? error.message : "Todo command failed" }));
|
|
@@ -18911,7 +19208,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18911
19208
|
return;
|
|
18912
19209
|
} else if (subcommand === "teams") {
|
|
18913
19210
|
try {
|
|
18914
|
-
const { handleTeamsCommand } = await Promise.resolve().then(function () { return require('./teams-
|
|
19211
|
+
const { handleTeamsCommand } = await Promise.resolve().then(function () { return require('./teams-BahinMnH.cjs'); });
|
|
18915
19212
|
await handleTeamsCommand(args.slice(1));
|
|
18916
19213
|
} catch (error) {
|
|
18917
19214
|
console.error(error instanceof Error ? error.message : "Teams command failed");
|
|
@@ -18920,7 +19217,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18920
19217
|
return;
|
|
18921
19218
|
} else if (subcommand === "auto") {
|
|
18922
19219
|
try {
|
|
18923
|
-
const { handleAutoCommand } = await Promise.resolve().then(function () { return require('./auto-
|
|
19220
|
+
const { handleAutoCommand } = await Promise.resolve().then(function () { return require('./auto-DqKGFq8U.cjs'); });
|
|
18924
19221
|
await handleAutoCommand(args.slice(1));
|
|
18925
19222
|
} catch (error) {
|
|
18926
19223
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Automation command failed");
|
|
@@ -18932,7 +19229,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18932
19229
|
return;
|
|
18933
19230
|
} else if (subcommand === "mcp" && (args.length === 1 || args.length === 2 && args[1] === "--terminal-tools")) {
|
|
18934
19231
|
try {
|
|
18935
|
-
const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-
|
|
19232
|
+
const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-CXkvnztT.cjs'); });
|
|
18936
19233
|
await handleMcpCommand(args[1] === "--terminal-tools");
|
|
18937
19234
|
} catch (error) {
|
|
18938
19235
|
process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
|
|
@@ -18961,6 +19258,10 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18961
19258
|
} else {
|
|
18962
19259
|
console.log("Active sessions:");
|
|
18963
19260
|
console.log(JSON.stringify(sessions, null, 2));
|
|
19261
|
+
const busy = sessions.filter((s) => s.turnActive === true);
|
|
19262
|
+
console.log(busy.length === 0 ? "No turn in flight on this machine (wrappers older than 0.2.139 do not report turns)." : `${busy.length} session(s) with a turn in flight: ${busy.map((s) => s.happySessionId).join(", ")}`);
|
|
19263
|
+
const background = sessions.filter((s) => (s.backgroundTasks?.count ?? 0) > 0);
|
|
19264
|
+
console.log(background.length === 0 ? "No background tasks in flight (wrappers older than 0.2.157 do not report them)." : `${background.length} session(s) with background tasks in flight: ${background.map((s) => `${s.happySessionId} (${s.backgroundTasks?.count})`).join(", ")}`);
|
|
18964
19265
|
}
|
|
18965
19266
|
} catch (error) {
|
|
18966
19267
|
console.log("No daemon running");
|
|
@@ -18989,13 +19290,19 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
18989
19290
|
persistence.configuration.webappUrl
|
|
18990
19291
|
);
|
|
18991
19292
|
if (running && !currentDaemonMatches) {
|
|
19293
|
+
if (currentState?.supervisor === "systemd") {
|
|
19294
|
+
console.error(`The running daemon is supervised by systemd; hand over through the unit instead:
|
|
19295
|
+
${SYSTEMD_RESTART_HINT}`);
|
|
19296
|
+
process.exit(1);
|
|
19297
|
+
}
|
|
18992
19298
|
console.log("Configured relay or CLI version changed; restarting the existing daemon");
|
|
18993
19299
|
await persistence.stopDaemon();
|
|
18994
19300
|
}
|
|
19301
|
+
const { HAPPY_DAEMON_SUPERVISOR: _supervisor, INVOCATION_ID: _invocation, ...detachedEnv } = process.env;
|
|
18995
19302
|
const child = spawnHappyCLI(["daemon", "start-sync"], {
|
|
18996
19303
|
detached: true,
|
|
18997
19304
|
stdio: "ignore",
|
|
18998
|
-
env:
|
|
19305
|
+
env: detachedEnv
|
|
18999
19306
|
});
|
|
19000
19307
|
child.unref();
|
|
19001
19308
|
let started = false;
|