very-happy-cli 0.2.89 → 0.2.91
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-DuxcHPyn.mjs → AcpBackend-B5RRlzLU.mjs} +1 -1
- package/dist/{AcpBackend-ClEvE-A-.cjs → AcpBackend-GqveWg8u.cjs} +1 -1
- package/dist/{AcpSessionManager-CGrA8bTm.mjs → AcpSessionManager-Ij1pI5Ex.mjs} +1 -1
- package/dist/{AcpSessionManager-DgbEf8FX.cjs → AcpSessionManager-YcrSZwvq.cjs} +1 -1
- package/dist/{config-BZNnPK1L.cjs → config-C4NCw7Dz.cjs} +2 -2
- package/dist/{config-CdoGLla8.mjs → config-ra8iKxdU.mjs} +2 -2
- package/dist/{index-Bx-UTV3I.cjs → index-C1HIm7NY.cjs} +4 -4
- package/dist/{index-BP2wylez.mjs → index-CB5H7YI6.mjs} +5 -5
- package/dist/{index-DYDAFqAN.cjs → index-FkXJNwiy.cjs} +141 -39
- package/dist/{index-vCgb7QnZ.mjs → index-UCYD5Wk3.mjs} +138 -36
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{installTerminalHooks-T4NE5fmC.cjs → installTerminalHooks-CoK5wNcA.cjs} +2 -2
- package/dist/{installTerminalHooks-C7JS6CBM.mjs → installTerminalHooks-TkkGzzbI.mjs} +2 -2
- package/dist/lib.cjs +1 -1
- package/dist/lib.d.cts +42 -0
- package/dist/lib.d.mts +42 -0
- package/dist/lib.mjs +1 -1
- package/dist/{mcp-B3EgenZh.mjs → mcp-C3MiqObi.mjs} +2 -2
- package/dist/{mcp-DgPg5mKa.cjs → mcp-DcRvswVI.cjs} +2 -2
- package/dist/{runGemini-B3iv1QRL.mjs → runGemini-BbC0uwUj.mjs} +4 -4
- package/dist/{runGemini-xZnGj7jx.cjs → runGemini-Dnvd2gWq.cjs} +4 -4
- package/dist/{runOpenClaw-CmM4ZLYi.mjs → runOpenClaw--nbqTW3K.mjs} +3 -3
- package/dist/{runOpenClaw-6ZLPeYYZ.cjs → runOpenClaw-CnuTBNQW.cjs} +3 -3
- package/dist/{send-M2ax7UGy.mjs → send-9nJxn09Y.mjs} +2 -2
- package/dist/{send-S9ibMiAt.cjs → send-DkKOPatx.cjs} +2 -2
- package/dist/{spawn-Dx_xnLlg.mjs → spawn-CRW4ioms.mjs} +2 -2
- package/dist/{spawn-ie_kfwQe.cjs → spawn-DE7WhS8Y.cjs} +2 -2
- package/dist/{types-d_104eQF.mjs → types-BKyjG23_.mjs} +304 -52
- package/dist/{types-DLI6sss2.cjs → types-ClDADuxP.cjs} +306 -52
- package/package.json +7 -7
|
@@ -51,7 +51,7 @@ var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
|
|
|
51
51
|
var pty__namespace = /*#__PURE__*/_interopNamespaceDefault(pty);
|
|
52
52
|
|
|
53
53
|
var name = "very-happy-cli";
|
|
54
|
-
var version = "0.2.
|
|
54
|
+
var version = "0.2.91";
|
|
55
55
|
var description = "Remote multi-agent workspace CLI with deep Claude integration, native terminal streaming, and self-hosting.";
|
|
56
56
|
var author = "Kirill Dubovitskiy";
|
|
57
57
|
var contributors = [
|
|
@@ -164,12 +164,12 @@ var dependencies = {
|
|
|
164
164
|
zod: "^4.0.0"
|
|
165
165
|
};
|
|
166
166
|
var optionalDependencies = {
|
|
167
|
-
"very-happy-tools-arm64-darwin": "0.2.
|
|
168
|
-
"very-happy-tools-x64-darwin": "0.2.
|
|
169
|
-
"very-happy-tools-arm64-linux": "0.2.
|
|
170
|
-
"very-happy-tools-x64-linux": "0.2.
|
|
171
|
-
"very-happy-tools-arm64-win32": "0.2.
|
|
172
|
-
"very-happy-tools-x64-win32": "0.2.
|
|
167
|
+
"very-happy-tools-arm64-darwin": "0.2.91",
|
|
168
|
+
"very-happy-tools-x64-darwin": "0.2.91",
|
|
169
|
+
"very-happy-tools-arm64-linux": "0.2.91",
|
|
170
|
+
"very-happy-tools-x64-linux": "0.2.91",
|
|
171
|
+
"very-happy-tools-arm64-win32": "0.2.91",
|
|
172
|
+
"very-happy-tools-x64-win32": "0.2.91"
|
|
173
173
|
};
|
|
174
174
|
var devDependencies = {
|
|
175
175
|
"@slopus/happy-wire": "workspace:*",
|
|
@@ -661,9 +661,27 @@ const sessionToolCallStartEventSchema = z__namespace.object({
|
|
|
661
661
|
description: z__namespace.string(),
|
|
662
662
|
args: z__namespace.record(z__namespace.string(), z__namespace.unknown())
|
|
663
663
|
});
|
|
664
|
+
const sessionSubagentResultSchema = z__namespace.object({
|
|
665
|
+
text: z__namespace.string(),
|
|
666
|
+
truncated: z__namespace.boolean().optional()
|
|
667
|
+
});
|
|
668
|
+
const sessionSubagentUsageSchema = z__namespace.object({
|
|
669
|
+
toolUses: z__namespace.number().optional(),
|
|
670
|
+
totalTokens: z__namespace.number().optional(),
|
|
671
|
+
durationMs: z__namespace.number().optional()
|
|
672
|
+
});
|
|
664
673
|
const sessionToolCallEndEventSchema = z__namespace.object({
|
|
665
674
|
t: z__namespace.literal("tool-call-end"),
|
|
666
|
-
call: z__namespace.string()
|
|
675
|
+
call: z__namespace.string(),
|
|
676
|
+
// Foreground Agent/Task completion: the sub-agent's final report + run
|
|
677
|
+
// totals (SDK `tool_use_result`). Absent for ordinary tools and for the
|
|
678
|
+
// background stub ("Async agent launched").
|
|
679
|
+
result: sessionSubagentResultSchema.extend({
|
|
680
|
+
isError: z__namespace.boolean().optional(),
|
|
681
|
+
stats: sessionSubagentUsageSchema.extend({
|
|
682
|
+
toolStats: z__namespace.record(z__namespace.string(), z__namespace.unknown()).optional()
|
|
683
|
+
}).optional()
|
|
684
|
+
}).optional()
|
|
667
685
|
});
|
|
668
686
|
const sessionFileEventSchema = z__namespace.object({
|
|
669
687
|
t: z__namespace.literal("file"),
|
|
@@ -682,7 +700,10 @@ const sessionTurnStartEventSchema = z__namespace.object({
|
|
|
682
700
|
});
|
|
683
701
|
const sessionStartEventSchema = z__namespace.object({
|
|
684
702
|
t: z__namespace.literal("start"),
|
|
685
|
-
title: z__namespace.string().optional()
|
|
703
|
+
title: z__namespace.string().optional(),
|
|
704
|
+
// B-260-P2: identity from SDK task_started / Agent tool input.
|
|
705
|
+
description: z__namespace.string().optional(),
|
|
706
|
+
subagentType: z__namespace.string().optional()
|
|
686
707
|
});
|
|
687
708
|
const sessionTurnEndStatusSchema = z__namespace.enum(["completed", "failed", "cancelled"]);
|
|
688
709
|
const sessionTurnUsageSchema = z__namespace.object({
|
|
@@ -705,7 +726,21 @@ const sessionTurnEndEventSchema = z__namespace.object({
|
|
|
705
726
|
usage: sessionTurnUsageSchema.optional()
|
|
706
727
|
});
|
|
707
728
|
const sessionStopEventSchema = z__namespace.object({
|
|
708
|
-
t: z__namespace.literal("stop")
|
|
729
|
+
t: z__namespace.literal("stop"),
|
|
730
|
+
// B-260-P2: from SDK task_notification. A second `stop` for the same
|
|
731
|
+
// subagent may follow carrying `result` once the notification user message
|
|
732
|
+
// (which holds the <result> block) arrives; consumers fold by subagent id.
|
|
733
|
+
status: z__namespace.enum(["completed", "failed", "stopped"]).optional(),
|
|
734
|
+
result: sessionSubagentResultSchema.optional(),
|
|
735
|
+
usage: sessionSubagentUsageSchema.optional()
|
|
736
|
+
});
|
|
737
|
+
const sessionProgressEventSchema = z__namespace.object({
|
|
738
|
+
t: z__namespace.literal("progress"),
|
|
739
|
+
toolUses: z__namespace.number(),
|
|
740
|
+
lastTool: z__namespace.string().optional(),
|
|
741
|
+
totalTokens: z__namespace.number().optional(),
|
|
742
|
+
durationMs: z__namespace.number().optional(),
|
|
743
|
+
summary: z__namespace.string().optional()
|
|
709
744
|
});
|
|
710
745
|
const sessionEventSchema = z__namespace.discriminatedUnion("t", [
|
|
711
746
|
sessionTextEventSchema,
|
|
@@ -716,7 +751,8 @@ const sessionEventSchema = z__namespace.discriminatedUnion("t", [
|
|
|
716
751
|
sessionTurnStartEventSchema,
|
|
717
752
|
sessionStartEventSchema,
|
|
718
753
|
sessionTurnEndEventSchema,
|
|
719
|
-
sessionStopEventSchema
|
|
754
|
+
sessionStopEventSchema,
|
|
755
|
+
sessionProgressEventSchema
|
|
720
756
|
]);
|
|
721
757
|
const sessionEnvelopeSchema = z__namespace.object({
|
|
722
758
|
id: z__namespace.string(),
|
|
@@ -747,7 +783,14 @@ const sessionEnvelopeSchema = z__namespace.object({
|
|
|
747
783
|
path: ["role"]
|
|
748
784
|
});
|
|
749
785
|
}
|
|
750
|
-
if (
|
|
786
|
+
if (envelope.ev.t === "progress" && !envelope.subagent) {
|
|
787
|
+
ctx.addIssue({
|
|
788
|
+
code: z__namespace.ZodIssueCode.custom,
|
|
789
|
+
message: "progress events must carry a subagent",
|
|
790
|
+
path: ["subagent"]
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
if ((envelope.ev.t === "start" || envelope.ev.t === "stop" || envelope.ev.t === "progress") && envelope.role !== "agent") {
|
|
751
794
|
ctx.addIssue({
|
|
752
795
|
code: z__namespace.ZodIssueCode.custom,
|
|
753
796
|
message: `${envelope.ev.t} events must use role "agent"`,
|
|
@@ -1484,7 +1527,7 @@ class RpcHandlerManager {
|
|
|
1484
1527
|
}
|
|
1485
1528
|
}
|
|
1486
1529
|
|
|
1487
|
-
const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-
|
|
1530
|
+
const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-ClDADuxP.cjs', document.baseURI).href))));
|
|
1488
1531
|
function projectPath() {
|
|
1489
1532
|
const path = path$1.resolve(__dirname$1, "..");
|
|
1490
1533
|
return path;
|
|
@@ -2171,6 +2214,69 @@ function shouldReconnect() {
|
|
|
2171
2214
|
return true;
|
|
2172
2215
|
}
|
|
2173
2216
|
|
|
2217
|
+
const SUBAGENT_RESULT_MAX_CHARS = 16384;
|
|
2218
|
+
const SUBAGENT_PROGRESS_MIN_INTERVAL_MS = 5e3;
|
|
2219
|
+
function capSubagentText(text, max = SUBAGENT_RESULT_MAX_CHARS) {
|
|
2220
|
+
const trimmed = text.trim();
|
|
2221
|
+
if (trimmed.length <= max) return { text: trimmed };
|
|
2222
|
+
return { text: trimmed.slice(0, max), truncated: true };
|
|
2223
|
+
}
|
|
2224
|
+
function toolUseResultToText(toolUseResult) {
|
|
2225
|
+
if (!toolUseResult || typeof toolUseResult !== "object") return null;
|
|
2226
|
+
const content = toolUseResult.content;
|
|
2227
|
+
if (typeof content === "string") return content;
|
|
2228
|
+
if (!Array.isArray(content)) return null;
|
|
2229
|
+
const parts = [];
|
|
2230
|
+
for (const block of content) {
|
|
2231
|
+
if (block && typeof block === "object" && block.type === "text" && typeof block.text === "string") {
|
|
2232
|
+
parts.push(block.text);
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
return parts.length > 0 ? parts.join("\n") : null;
|
|
2236
|
+
}
|
|
2237
|
+
function toolUseResultStatus(toolUseResult) {
|
|
2238
|
+
if (!toolUseResult || typeof toolUseResult !== "object") return "unknown";
|
|
2239
|
+
const status = toolUseResult.status;
|
|
2240
|
+
if (status === "async_launched") return "async_launched";
|
|
2241
|
+
if (status === "completed") return "completed";
|
|
2242
|
+
return "unknown";
|
|
2243
|
+
}
|
|
2244
|
+
function toolUseResultStats(toolUseResult) {
|
|
2245
|
+
if (!toolUseResult || typeof toolUseResult !== "object") return void 0;
|
|
2246
|
+
const r = toolUseResult;
|
|
2247
|
+
const stats = {};
|
|
2248
|
+
if (typeof r.totalToolUseCount === "number") stats.toolUses = r.totalToolUseCount;
|
|
2249
|
+
if (typeof r.totalTokens === "number") stats.totalTokens = r.totalTokens;
|
|
2250
|
+
if (typeof r.totalDurationMs === "number") stats.durationMs = r.totalDurationMs;
|
|
2251
|
+
if (r.toolStats && typeof r.toolStats === "object") stats.toolStats = r.toolStats;
|
|
2252
|
+
return Object.keys(stats).length > 0 ? stats : void 0;
|
|
2253
|
+
}
|
|
2254
|
+
function parseTaskNotificationText(text) {
|
|
2255
|
+
if (!/<task-notification>/i.test(text)) return null;
|
|
2256
|
+
const pick = (tag) => text.match(new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`, "i"))?.[1] ?? null;
|
|
2257
|
+
const rawStatus = pick("status")?.trim().toLowerCase() ?? null;
|
|
2258
|
+
const status = rawStatus === "completed" || rawStatus === "failed" || rawStatus === "stopped" ? rawStatus : null;
|
|
2259
|
+
let resultText = pick("result");
|
|
2260
|
+
let result = null;
|
|
2261
|
+
if (resultText !== null) {
|
|
2262
|
+
resultText = resultText.replace(/^\s*\[harness:[^\]]*\]\s*/i, "").replace(/<usage>[\s\S]*?<\/usage>/gi, "").trim();
|
|
2263
|
+
if (resultText.length > 0) result = capSubagentText(resultText);
|
|
2264
|
+
}
|
|
2265
|
+
return {
|
|
2266
|
+
toolUseId: pick("tool-use-id")?.trim() || null,
|
|
2267
|
+
taskId: pick("task-id")?.trim() || null,
|
|
2268
|
+
status,
|
|
2269
|
+
summary: pick("summary")?.trim() || null,
|
|
2270
|
+
result
|
|
2271
|
+
};
|
|
2272
|
+
}
|
|
2273
|
+
function shouldEmitProgress(previous, toolUses, now) {
|
|
2274
|
+
if (!previous) return true;
|
|
2275
|
+
if (previous.lastToolUses === toolUses) return false;
|
|
2276
|
+
return now - previous.lastAt >= SUBAGENT_PROGRESS_MIN_INTERVAL_MS;
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
const SUBAGENT_BUFFER_MAX_MESSAGES = 100;
|
|
2174
2280
|
function isSubagentTool(name) {
|
|
2175
2281
|
return name === "Task" || name === "Agent";
|
|
2176
2282
|
}
|
|
@@ -2239,6 +2345,7 @@ function bufferSubagentMessage(state, subagent, message) {
|
|
|
2239
2345
|
const buffer = getBufferedSubagentMessages(state);
|
|
2240
2346
|
const queue = buffer.get(subagent) ?? [];
|
|
2241
2347
|
queue.push(message);
|
|
2348
|
+
while (queue.length > SUBAGENT_BUFFER_MAX_MESSAGES) queue.shift();
|
|
2242
2349
|
buffer.set(subagent, queue);
|
|
2243
2350
|
}
|
|
2244
2351
|
function consumeBufferedSubagentMessages(state, subagent) {
|
|
@@ -2259,6 +2366,31 @@ function getActiveSubagents(state) {
|
|
|
2259
2366
|
}
|
|
2260
2367
|
return state.activeSubagents;
|
|
2261
2368
|
}
|
|
2369
|
+
function getAgentToolCalls(state) {
|
|
2370
|
+
if (!state.agentToolCalls) state.agentToolCalls = /* @__PURE__ */ new Set();
|
|
2371
|
+
return state.agentToolCalls;
|
|
2372
|
+
}
|
|
2373
|
+
function getSubagentMeta(state) {
|
|
2374
|
+
if (!state.subagentMeta) state.subagentMeta = /* @__PURE__ */ new Map();
|
|
2375
|
+
return state.subagentMeta;
|
|
2376
|
+
}
|
|
2377
|
+
function getStubSubagents(state) {
|
|
2378
|
+
if (!state.stubSubagents) state.stubSubagents = /* @__PURE__ */ new Set();
|
|
2379
|
+
return state.stubSubagents;
|
|
2380
|
+
}
|
|
2381
|
+
function getProgressThrottle(state) {
|
|
2382
|
+
if (!state.progressThrottle) state.progressThrottle = /* @__PURE__ */ new Map();
|
|
2383
|
+
return state.progressThrottle;
|
|
2384
|
+
}
|
|
2385
|
+
function nowOf(state) {
|
|
2386
|
+
return state.now ? state.now() : Date.now();
|
|
2387
|
+
}
|
|
2388
|
+
function rememberSubagentMeta(state, subagent, meta) {
|
|
2389
|
+
const existing = getSubagentMeta(state).get(subagent) ?? {};
|
|
2390
|
+
const description = typeof meta.description === "string" && meta.description.trim() ? meta.description.trim() : existing.description;
|
|
2391
|
+
const subagentType = typeof meta.subagentType === "string" && meta.subagentType.trim() ? meta.subagentType.trim() : existing.subagentType;
|
|
2392
|
+
getSubagentMeta(state).set(subagent, { ...description ? { description } : {}, ...subagentType ? { subagentType } : {} });
|
|
2393
|
+
}
|
|
2262
2394
|
function pickAssistantUsage(message) {
|
|
2263
2395
|
if (message.type !== "assistant") return void 0;
|
|
2264
2396
|
const usage = message.message?.usage;
|
|
@@ -2435,13 +2567,26 @@ function maybeEmitSubagentStart(state, turn, subagent, envelopes) {
|
|
|
2435
2567
|
return;
|
|
2436
2568
|
}
|
|
2437
2569
|
const title = getSubagentTitles(state).get(subagent);
|
|
2570
|
+
const meta = getSubagentMeta(state).get(subagent);
|
|
2438
2571
|
envelopes.push(createEnvelope("agent", {
|
|
2439
2572
|
t: "start",
|
|
2440
|
-
...title ? { title } : {}
|
|
2573
|
+
...title ? { title } : {},
|
|
2574
|
+
...meta?.description ? { description: meta.description } : {},
|
|
2575
|
+
...meta?.subagentType ? { subagentType: meta.subagentType } : {}
|
|
2441
2576
|
}, { turn, subagent }));
|
|
2442
2577
|
started.add(subagent);
|
|
2443
2578
|
getActiveSubagents(state).add(subagent);
|
|
2444
2579
|
}
|
|
2580
|
+
function emitSubagentStopWithStatus(state, turn, subagent, envelopes, payload) {
|
|
2581
|
+
envelopes.push(createEnvelope("agent", {
|
|
2582
|
+
t: "stop",
|
|
2583
|
+
...payload.status ? { status: payload.status } : {},
|
|
2584
|
+
...payload.result ? { result: payload.result } : {},
|
|
2585
|
+
...payload.usage ? { usage: payload.usage } : {}
|
|
2586
|
+
}, { ...turn ? { turn } : {}, subagent }));
|
|
2587
|
+
getActiveSubagents(state).delete(subagent);
|
|
2588
|
+
getStartedSubagents(state).delete(subagent);
|
|
2589
|
+
}
|
|
2445
2590
|
function maybeEmitSubagentStop(state, turn, subagent, envelopes) {
|
|
2446
2591
|
const active = getActiveSubagents(state);
|
|
2447
2592
|
if (!active.has(subagent)) {
|
|
@@ -2453,8 +2598,6 @@ function maybeEmitSubagentStop(state, turn, subagent, envelopes) {
|
|
|
2453
2598
|
function clearSubagentTracking(state) {
|
|
2454
2599
|
getUuidToProviderSubagent(state).clear();
|
|
2455
2600
|
getTaskPromptToSubagents(state).clear();
|
|
2456
|
-
getProviderSubagentToSessionSubagent(state).clear();
|
|
2457
|
-
getSubagentTitles(state).clear();
|
|
2458
2601
|
getBufferedSubagentMessages(state).clear();
|
|
2459
2602
|
getHiddenParentToolCalls(state).clear();
|
|
2460
2603
|
getStartedSubagents(state).clear();
|
|
@@ -2515,6 +2658,58 @@ function closeClaudeTurnWithStatus(state, status, meta) {
|
|
|
2515
2658
|
function mapClaudeLogMessageToSessionEnvelopes(message, state) {
|
|
2516
2659
|
return mapClaudeLogMessageToSessionEnvelopesInternal(message, state);
|
|
2517
2660
|
}
|
|
2661
|
+
function mapTaskLifecycleSystemMessage(message, state, envelopes) {
|
|
2662
|
+
const raw = message;
|
|
2663
|
+
const subtype = typeof raw.subtype === "string" ? raw.subtype : "";
|
|
2664
|
+
if (!subtype.startsWith("task_")) return;
|
|
2665
|
+
if (raw.skip_transcript === true) return;
|
|
2666
|
+
const toolUseId = typeof raw.tool_use_id === "string" && raw.tool_use_id.length > 0 ? raw.tool_use_id : null;
|
|
2667
|
+
if (!toolUseId || !getAgentToolCalls(state).has(toolUseId)) return;
|
|
2668
|
+
const subagent = ensureSessionSubagentIdForProviderSubagent(state, toolUseId);
|
|
2669
|
+
const usage = raw.usage && typeof raw.usage === "object" ? {
|
|
2670
|
+
...typeof raw.usage.tool_uses === "number" ? { toolUses: raw.usage.tool_uses } : {},
|
|
2671
|
+
...typeof raw.usage.total_tokens === "number" ? { totalTokens: raw.usage.total_tokens } : {},
|
|
2672
|
+
...typeof raw.usage.duration_ms === "number" ? { durationMs: raw.usage.duration_ms } : {}
|
|
2673
|
+
} : void 0;
|
|
2674
|
+
if (subtype === "task_started") {
|
|
2675
|
+
rememberSubagentMeta(state, subagent, { description: raw.description, subagentType: raw.subagent_type });
|
|
2676
|
+
const turn = ensureTurn(state, envelopes);
|
|
2677
|
+
getStartedSubagents(state).delete(subagent);
|
|
2678
|
+
maybeEmitSubagentStart(state, turn, subagent, envelopes);
|
|
2679
|
+
return;
|
|
2680
|
+
}
|
|
2681
|
+
if (subtype === "task_progress") {
|
|
2682
|
+
const toolUses = typeof raw.usage?.tool_uses === "number" ? raw.usage.tool_uses : 0;
|
|
2683
|
+
const throttle = getProgressThrottle(state);
|
|
2684
|
+
const now = nowOf(state);
|
|
2685
|
+
if (!shouldEmitProgress(throttle.get(subagent), toolUses, now)) return;
|
|
2686
|
+
throttle.set(subagent, { lastAt: now, lastToolUses: toolUses });
|
|
2687
|
+
const turn = ensureTurn(state, envelopes);
|
|
2688
|
+
maybeEmitSubagentStart(state, turn, subagent, envelopes);
|
|
2689
|
+
envelopes.push(createEnvelope("agent", {
|
|
2690
|
+
t: "progress",
|
|
2691
|
+
toolUses,
|
|
2692
|
+
...typeof raw.last_tool_name === "string" && raw.last_tool_name ? { lastTool: raw.last_tool_name } : {},
|
|
2693
|
+
...usage?.totalTokens !== void 0 ? { totalTokens: usage.totalTokens } : {},
|
|
2694
|
+
...usage?.durationMs !== void 0 ? { durationMs: usage.durationMs } : {},
|
|
2695
|
+
...typeof raw.summary === "string" && raw.summary.trim() ? { summary: raw.summary.trim() } : {}
|
|
2696
|
+
}, { turn, subagent }));
|
|
2697
|
+
return;
|
|
2698
|
+
}
|
|
2699
|
+
if (subtype === "task_notification") {
|
|
2700
|
+
const status = raw.status === "completed" || raw.status === "failed" || raw.status === "stopped" ? raw.status : "completed";
|
|
2701
|
+
emitSubagentStopWithStatus(state, state.currentTurnId ?? void 0, subagent, envelopes, {
|
|
2702
|
+
status,
|
|
2703
|
+
...usage ? { usage } : {}
|
|
2704
|
+
});
|
|
2705
|
+
getStubSubagents(state).delete(subagent);
|
|
2706
|
+
getProgressThrottle(state).delete(subagent);
|
|
2707
|
+
return;
|
|
2708
|
+
}
|
|
2709
|
+
if (subtype === "task_updated" && raw.patch?.is_backgrounded === true) {
|
|
2710
|
+
getStubSubagents(state).add(subagent);
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2518
2713
|
function mapClaudeLogMessageToSessionEnvelopesInternal(message, state) {
|
|
2519
2714
|
const envelopes = [];
|
|
2520
2715
|
const claudeUuid = pickUuid(message);
|
|
@@ -2535,6 +2730,7 @@ function mapClaudeLogMessageToSessionEnvelopesInternal(message, state) {
|
|
|
2535
2730
|
};
|
|
2536
2731
|
}
|
|
2537
2732
|
if (message.type === "system") {
|
|
2733
|
+
mapTaskLifecycleSystemMessage(message, state, envelopes);
|
|
2538
2734
|
return {
|
|
2539
2735
|
currentTurnId: state.currentTurnId,
|
|
2540
2736
|
envelopes
|
|
@@ -2576,6 +2772,9 @@ function mapClaudeLogMessageToSessionEnvelopesInternal(message, state) {
|
|
|
2576
2772
|
queueTaskPromptSubagent(state, prompt, call);
|
|
2577
2773
|
}
|
|
2578
2774
|
setSubagentTitle(state, sessionSubagentForCall, pickTaskTitle(block.input) ?? prompt);
|
|
2775
|
+
getAgentToolCalls(state).add(call);
|
|
2776
|
+
const input = block.input ?? {};
|
|
2777
|
+
rememberSubagentMeta(state, sessionSubagentForCall, { description: input.description, subagentType: input.subagent_type });
|
|
2579
2778
|
}
|
|
2580
2779
|
if (shouldHideParentToolCall(name)) {
|
|
2581
2780
|
getHiddenParentToolCalls(state).add(call);
|
|
@@ -2620,6 +2819,18 @@ function mapClaudeLogMessageToSessionEnvelopesInternal(message, state) {
|
|
|
2620
2819
|
maybeEmitSubagentStart(state, turnId2, subagent, envelopes);
|
|
2621
2820
|
envelopes.push(createEnvelope("agent", { t: "text", text: message.message.content }, { turn: turnId2, subagent, claudeUuid }));
|
|
2622
2821
|
} else {
|
|
2822
|
+
const origin = message.origin;
|
|
2823
|
+
if (origin?.kind === "task-notification" || /<task-notification>/i.test(message.message.content)) {
|
|
2824
|
+
const fields = parseTaskNotificationText(message.message.content);
|
|
2825
|
+
const providerId = fields?.toolUseId ?? null;
|
|
2826
|
+
const subagentForNotification = providerId && getAgentToolCalls(state).has(providerId) ? getSessionSubagentIdForProviderSubagent(state, providerId) : void 0;
|
|
2827
|
+
if (fields && subagentForNotification && (fields.result || fields.status)) {
|
|
2828
|
+
emitSubagentStopWithStatus(state, state.currentTurnId ?? void 0, subagentForNotification, envelopes, {
|
|
2829
|
+
...fields.status ? { status: fields.status } : {},
|
|
2830
|
+
...fields.result ? { result: fields.result } : {}
|
|
2831
|
+
});
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2623
2834
|
closeTurn(state, "completed", envelopes);
|
|
2624
2835
|
envelopes.push(createEnvelope("user", { t: "text", text: message.message.content }, { claudeUuid }));
|
|
2625
2836
|
}
|
|
@@ -2650,6 +2861,31 @@ function mapClaudeLogMessageToSessionEnvelopesInternal(message, state) {
|
|
|
2650
2861
|
getHiddenParentToolCalls(state).delete(block.tool_use_id);
|
|
2651
2862
|
continue;
|
|
2652
2863
|
}
|
|
2864
|
+
if (sessionSubagentForToolResult && getAgentToolCalls(state).has(block.tool_use_id)) {
|
|
2865
|
+
const toolUseResult = message.tool_use_result;
|
|
2866
|
+
const resultStatus = toolUseResultStatus(toolUseResult);
|
|
2867
|
+
if (resultStatus === "async_launched") {
|
|
2868
|
+
getStubSubagents(state).add(sessionSubagentForToolResult);
|
|
2869
|
+
envelopes.push(createEnvelope("agent", { t: "tool-call-end", call: block.tool_use_id }, { turn: turnId, subagent }));
|
|
2870
|
+
continue;
|
|
2871
|
+
}
|
|
2872
|
+
if (resultStatus === "completed") {
|
|
2873
|
+
const text = toolUseResultToText(toolUseResult);
|
|
2874
|
+
const stats = toolUseResultStats(toolUseResult);
|
|
2875
|
+
const result = text ? capSubagentText(text) : void 0;
|
|
2876
|
+
emitSubagentStopWithStatus(state, turnId, sessionSubagentForToolResult, envelopes, {
|
|
2877
|
+
status: "completed",
|
|
2878
|
+
...result ? { result } : {},
|
|
2879
|
+
...stats ? { usage: { toolUses: stats.toolUses, totalTokens: stats.totalTokens, durationMs: stats.durationMs } } : {}
|
|
2880
|
+
});
|
|
2881
|
+
envelopes.push(createEnvelope("agent", {
|
|
2882
|
+
t: "tool-call-end",
|
|
2883
|
+
call: block.tool_use_id,
|
|
2884
|
+
...result ? { result: { ...result, ...stats ? { stats } : {} } } : {}
|
|
2885
|
+
}, { turn: turnId, subagent }));
|
|
2886
|
+
continue;
|
|
2887
|
+
}
|
|
2888
|
+
}
|
|
2653
2889
|
if (sessionSubagentForToolResult) {
|
|
2654
2890
|
maybeEmitSubagentStop(state, turnId, sessionSubagentForToolResult, envelopes);
|
|
2655
2891
|
}
|
|
@@ -8829,6 +9065,20 @@ function previewAscii(line) {
|
|
|
8829
9065
|
return line.length > 80 ? `${out}\u2026` : out;
|
|
8830
9066
|
}
|
|
8831
9067
|
|
|
9068
|
+
const VH_TMUX_SOCKET_ENV = "VH_TMUX_SOCKET";
|
|
9069
|
+
function tmuxSocketFlags(env = process.env) {
|
|
9070
|
+
const socket = env[VH_TMUX_SOCKET_ENV];
|
|
9071
|
+
return socket ? ["-S", socket] : [];
|
|
9072
|
+
}
|
|
9073
|
+
function tmuxArgs(args, env = process.env) {
|
|
9074
|
+
return [...tmuxSocketFlags(env), ...args];
|
|
9075
|
+
}
|
|
9076
|
+
function scrubTmuxClientEnv(env) {
|
|
9077
|
+
delete env.TMUX;
|
|
9078
|
+
delete env.TMUX_PANE;
|
|
9079
|
+
return env;
|
|
9080
|
+
}
|
|
9081
|
+
|
|
8832
9082
|
const CONTROL_CLIENT_KILL_GRACE_MS = 2e3;
|
|
8833
9083
|
const CONTROL_COMMAND_TIMEOUT_MS = 1e4;
|
|
8834
9084
|
function isSafeControlCommand(command) {
|
|
@@ -8838,7 +9088,7 @@ class ControlClient {
|
|
|
8838
9088
|
constructor(tmuxSession, env, handlers) {
|
|
8839
9089
|
this.tmuxSession = tmuxSession;
|
|
8840
9090
|
this.handlers = handlers;
|
|
8841
|
-
this.child = node_child_process.spawn("tmux", ["-C", "attach-session", "-t", `=${tmuxSession}:`], {
|
|
9091
|
+
this.child = node_child_process.spawn("tmux", tmuxArgs(["-C", "attach-session", "-t", `=${tmuxSession}:`], env), {
|
|
8842
9092
|
stdio: ["pipe", "pipe", "pipe"],
|
|
8843
9093
|
env
|
|
8844
9094
|
});
|
|
@@ -9990,7 +10240,7 @@ let tmuxAvailableCache = null;
|
|
|
9990
10240
|
function isTmuxAvailable() {
|
|
9991
10241
|
if (tmuxAvailableCache !== null) return tmuxAvailableCache;
|
|
9992
10242
|
try {
|
|
9993
|
-
const r = node_child_process.spawnSync("tmux", ["-V"], { stdio: "ignore", env: ptyEnv() });
|
|
10243
|
+
const r = node_child_process.spawnSync("tmux", tmuxArgs(["-V"]), { stdio: "ignore", env: ptyEnv() });
|
|
9994
10244
|
tmuxAvailableCache = r.status === 0;
|
|
9995
10245
|
} catch {
|
|
9996
10246
|
tmuxAvailableCache = false;
|
|
@@ -10001,7 +10251,7 @@ let tmuxEnvFlagCache = null;
|
|
|
10001
10251
|
function tmuxSupportsEnvFlag() {
|
|
10002
10252
|
if (tmuxEnvFlagCache !== null) return tmuxEnvFlagCache;
|
|
10003
10253
|
try {
|
|
10004
|
-
const r = node_child_process.spawnSync("tmux", ["-V"], { encoding: "utf8", env: ptyEnv() });
|
|
10254
|
+
const r = node_child_process.spawnSync("tmux", tmuxArgs(["-V"]), { encoding: "utf8", env: ptyEnv() });
|
|
10005
10255
|
tmuxEnvFlagCache = r.status === 0 && tmuxSupportsNewSessionEnv(r.stdout || "");
|
|
10006
10256
|
} catch {
|
|
10007
10257
|
tmuxEnvFlagCache = false;
|
|
@@ -10045,6 +10295,7 @@ function ptyEnv() {
|
|
|
10045
10295
|
for (const [k, v] of Object.entries(process.env)) {
|
|
10046
10296
|
if (typeof v === "string") env[k] = v;
|
|
10047
10297
|
}
|
|
10298
|
+
scrubTmuxClientEnv(env);
|
|
10048
10299
|
const local = `${os.homedir()}/.local/bin`;
|
|
10049
10300
|
if (!(env.PATH || "").split(":").includes(local)) {
|
|
10050
10301
|
env.PATH = `${local}:${env.PATH || ""}`;
|
|
@@ -10700,7 +10951,7 @@ class WebTerminalManager {
|
|
|
10700
10951
|
const name = `vh-${plan.terminalId}`;
|
|
10701
10952
|
const exists = node_child_process.spawnSync(
|
|
10702
10953
|
"tmux",
|
|
10703
|
-
["has-session", "-t", `=${name}:`],
|
|
10954
|
+
tmuxArgs(["has-session", "-t", `=${name}:`]),
|
|
10704
10955
|
{ stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env }
|
|
10705
10956
|
).status === 0;
|
|
10706
10957
|
if (exists) return false;
|
|
@@ -10714,12 +10965,12 @@ class WebTerminalManager {
|
|
|
10714
10965
|
] : [];
|
|
10715
10966
|
const created = node_child_process.spawnSync(
|
|
10716
10967
|
"tmux",
|
|
10717
|
-
tmuxNewSessionArgs(name, 120, 30, plan.cwd, envFlags, defaultShell()),
|
|
10968
|
+
tmuxArgs(tmuxNewSessionArgs(name, 120, 30, plan.cwd, envFlags, defaultShell())),
|
|
10718
10969
|
{ stdio: "ignore", timeout: TMUX_CREATE_TIMEOUT_MS, env }
|
|
10719
10970
|
);
|
|
10720
10971
|
const live = created.status === 0 && node_child_process.spawnSync(
|
|
10721
10972
|
"tmux",
|
|
10722
|
-
["has-session", "-t", `=${name}:`],
|
|
10973
|
+
tmuxArgs(["has-session", "-t", `=${name}:`]),
|
|
10723
10974
|
{ stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env }
|
|
10724
10975
|
).status === 0;
|
|
10725
10976
|
if (!live) {
|
|
@@ -10729,12 +10980,12 @@ class WebTerminalManager {
|
|
|
10729
10980
|
if (plan.title) {
|
|
10730
10981
|
node_child_process.spawnSync(
|
|
10731
10982
|
"tmux",
|
|
10732
|
-
["set-option", "-t", `=${name}:`, "@vh_title", plan.title],
|
|
10983
|
+
tmuxArgs(["set-option", "-t", `=${name}:`, "@vh_title", plan.title]),
|
|
10733
10984
|
{ stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env }
|
|
10734
10985
|
);
|
|
10735
10986
|
}
|
|
10736
10987
|
for (const argv of startupInjectionArgs(name, plan.command)) {
|
|
10737
|
-
node_child_process.spawnSync("tmux", argv, { stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env });
|
|
10988
|
+
node_child_process.spawnSync("tmux", tmuxArgs(argv), { stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env });
|
|
10738
10989
|
}
|
|
10739
10990
|
logger.info(`[WEB TERMINAL] auto-restored ${plan.terminalId} in ${plan.cwd}`);
|
|
10740
10991
|
return true;
|
|
@@ -10866,14 +11117,14 @@ class WebTerminalManager {
|
|
|
10866
11117
|
if (opts.attachOnly || opts.resub) {
|
|
10867
11118
|
const alive = isTmuxAvailable() && node_child_process.spawnSync(
|
|
10868
11119
|
"tmux",
|
|
10869
|
-
["has-session", "-t", `=vh-${id}:`],
|
|
11120
|
+
tmuxArgs(["has-session", "-t", `=vh-${id}:`]),
|
|
10870
11121
|
{ stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env: ptyEnv() }
|
|
10871
11122
|
).status === 0;
|
|
10872
11123
|
if (!alive) throw new Error("terminal-gone");
|
|
10873
11124
|
} else if (this.tombstones[id]) {
|
|
10874
11125
|
const alive = isTmuxAvailable() && node_child_process.spawnSync(
|
|
10875
11126
|
"tmux",
|
|
10876
|
-
["has-session", "-t", `=vh-${id}:`],
|
|
11127
|
+
tmuxArgs(["has-session", "-t", `=vh-${id}:`]),
|
|
10877
11128
|
{ stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env: ptyEnv() }
|
|
10878
11129
|
).status === 0;
|
|
10879
11130
|
if (!alive) {
|
|
@@ -10902,7 +11153,7 @@ class WebTerminalManager {
|
|
|
10902
11153
|
try {
|
|
10903
11154
|
const created = node_child_process.spawnSync(
|
|
10904
11155
|
"tmux",
|
|
10905
|
-
tmuxNewSessionArgs(tmuxSession, cols, rows, cwd, envFlags, defaultShell()),
|
|
11156
|
+
tmuxArgs(tmuxNewSessionArgs(tmuxSession, cols, rows, cwd, envFlags, defaultShell())),
|
|
10906
11157
|
{ stdio: "ignore", timeout: TMUX_CREATE_TIMEOUT_MS, env }
|
|
10907
11158
|
);
|
|
10908
11159
|
createdNew = created.status === 0;
|
|
@@ -10934,7 +11185,7 @@ class WebTerminalManager {
|
|
|
10934
11185
|
];
|
|
10935
11186
|
for (const a of optArgs) {
|
|
10936
11187
|
try {
|
|
10937
|
-
node_child_process.spawnSync("tmux", a, { stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env });
|
|
11188
|
+
node_child_process.spawnSync("tmux", tmuxArgs(a), { stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env });
|
|
10938
11189
|
} catch {
|
|
10939
11190
|
}
|
|
10940
11191
|
}
|
|
@@ -10943,7 +11194,7 @@ class WebTerminalManager {
|
|
|
10943
11194
|
if (startup) {
|
|
10944
11195
|
try {
|
|
10945
11196
|
for (const a of startupInjectionArgs(tmuxSession, startup)) {
|
|
10946
|
-
node_child_process.spawnSync("tmux", a, { stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env });
|
|
11197
|
+
node_child_process.spawnSync("tmux", tmuxArgs(a), { stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env });
|
|
10947
11198
|
}
|
|
10948
11199
|
logger.debug(`[WEB TERMINAL] injected startup command into new session ${tmuxSession}`);
|
|
10949
11200
|
} catch {
|
|
@@ -10953,13 +11204,13 @@ class WebTerminalManager {
|
|
|
10953
11204
|
if (!attachOnly && !createdNew) {
|
|
10954
11205
|
const alive = node_child_process.spawnSync(
|
|
10955
11206
|
"tmux",
|
|
10956
|
-
["has-session", "-t", `=${tmuxSession}:`],
|
|
11207
|
+
tmuxArgs(["has-session", "-t", `=${tmuxSession}:`]),
|
|
10957
11208
|
{ stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env }
|
|
10958
11209
|
).status === 0;
|
|
10959
11210
|
if (shouldUseDirectPtyFallback(attachOnly, createdNew, alive)) {
|
|
10960
11211
|
const retry = node_child_process.spawnSync(
|
|
10961
11212
|
"tmux",
|
|
10962
|
-
tmuxNewSessionArgs(tmuxSession, cols, rows, cwd, envFlags, defaultShell()),
|
|
11213
|
+
tmuxArgs(tmuxNewSessionArgs(tmuxSession, cols, rows, cwd, envFlags, defaultShell())),
|
|
10963
11214
|
{ stdio: "ignore", timeout: TMUX_CREATE_TIMEOUT_MS, env }
|
|
10964
11215
|
);
|
|
10965
11216
|
createdNew = retry.status === 0;
|
|
@@ -10968,7 +11219,7 @@ class WebTerminalManager {
|
|
|
10968
11219
|
if (startup) {
|
|
10969
11220
|
for (const a of startupInjectionArgs(tmuxSession, startup)) {
|
|
10970
11221
|
try {
|
|
10971
|
-
node_child_process.spawnSync("tmux", a, { stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env });
|
|
11222
|
+
node_child_process.spawnSync("tmux", tmuxArgs(a), { stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env });
|
|
10972
11223
|
} catch {
|
|
10973
11224
|
}
|
|
10974
11225
|
}
|
|
@@ -10979,7 +11230,7 @@ class WebTerminalManager {
|
|
|
10979
11230
|
if (!attachOnly && !createdNew) {
|
|
10980
11231
|
const alive = node_child_process.spawnSync(
|
|
10981
11232
|
"tmux",
|
|
10982
|
-
["has-session", "-t", `=${tmuxSession}:`],
|
|
11233
|
+
tmuxArgs(["has-session", "-t", `=${tmuxSession}:`]),
|
|
10983
11234
|
{ stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env }
|
|
10984
11235
|
).status === 0;
|
|
10985
11236
|
if (!alive) {
|
|
@@ -11306,8 +11557,8 @@ class WebTerminalManager {
|
|
|
11306
11557
|
killSession(terminalId) {
|
|
11307
11558
|
const info = this.lastSeenInfo.get(terminalId) ?? this.listSessions().find((t) => t.id === terminalId);
|
|
11308
11559
|
const target = `=vh-${terminalId}:`;
|
|
11309
|
-
const killed = node_child_process.spawnSync("tmux", ["kill-session", "-t", target], { stdio: "ignore", env: ptyEnv() });
|
|
11310
|
-
const verified = node_child_process.spawnSync("tmux", ["has-session", "-t", target], { stdio: "ignore", env: ptyEnv() });
|
|
11560
|
+
const killed = node_child_process.spawnSync("tmux", tmuxArgs(["kill-session", "-t", target]), { stdio: "ignore", env: ptyEnv() });
|
|
11561
|
+
const verified = node_child_process.spawnSync("tmux", tmuxArgs(["has-session", "-t", target]), { stdio: "ignore", env: ptyEnv() });
|
|
11311
11562
|
if (!tmuxKillVerified(killed, verified)) {
|
|
11312
11563
|
logger.debug(`[WEB TERMINAL] failed to verify tmux session removal ${target}`);
|
|
11313
11564
|
return false;
|
|
@@ -11368,7 +11619,7 @@ class WebTerminalManager {
|
|
|
11368
11619
|
const env = ptyEnv();
|
|
11369
11620
|
const r = node_child_process.spawnSync(
|
|
11370
11621
|
"tmux",
|
|
11371
|
-
["list-sessions", "-F", LIST_SESSIONS_FORMAT],
|
|
11622
|
+
tmuxArgs(["list-sessions", "-F", LIST_SESSIONS_FORMAT]),
|
|
11372
11623
|
{ encoding: "utf8", env }
|
|
11373
11624
|
);
|
|
11374
11625
|
if (r.status !== 0 || !r.stdout) return [];
|
|
@@ -11384,7 +11635,7 @@ class WebTerminalManager {
|
|
|
11384
11635
|
try {
|
|
11385
11636
|
const w = node_child_process.spawnSync(
|
|
11386
11637
|
"tmux",
|
|
11387
|
-
["set-option", "-t", `=${s.name}:`, "@vh_title", auto],
|
|
11638
|
+
tmuxArgs(["set-option", "-t", `=${s.name}:`, "@vh_title", auto]),
|
|
11388
11639
|
{ stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env }
|
|
11389
11640
|
);
|
|
11390
11641
|
if (w.status === 0) title = auto;
|
|
@@ -11435,13 +11686,13 @@ class WebTerminalManager {
|
|
|
11435
11686
|
try {
|
|
11436
11687
|
const cmd = node_child_process.spawnSync(
|
|
11437
11688
|
"tmux",
|
|
11438
|
-
["display-message", "-p", "-t", sessionName, "#{pane_current_command}"],
|
|
11689
|
+
tmuxArgs(["display-message", "-p", "-t", sessionName, "#{pane_current_command}"]),
|
|
11439
11690
|
{ encoding: "utf8", timeout: TMUX_PROBE_TIMEOUT_MS, env: ptyEnv() }
|
|
11440
11691
|
);
|
|
11441
11692
|
if (cmd.status !== 0 || typeof cmd.stdout !== "string") return void 0;
|
|
11442
11693
|
const cap = node_child_process.spawnSync(
|
|
11443
11694
|
"tmux",
|
|
11444
|
-
["capture-pane", "-p", "-t", sessionName, "-S", "-40"],
|
|
11695
|
+
tmuxArgs(["capture-pane", "-p", "-t", sessionName, "-S", "-40"]),
|
|
11445
11696
|
{ encoding: "utf8", timeout: TMUX_PROBE_TIMEOUT_MS, env: ptyEnv() }
|
|
11446
11697
|
);
|
|
11447
11698
|
if (cap.status !== 0 || typeof cap.stdout !== "string") return void 0;
|
|
@@ -11468,7 +11719,7 @@ class WebTerminalManager {
|
|
|
11468
11719
|
try {
|
|
11469
11720
|
const probe = node_child_process.spawnSync(
|
|
11470
11721
|
"tmux",
|
|
11471
|
-
["display-message", "-p", "-t", name, "#{pane_in_mode} #{alternate_on} #{mouse_any_flag} #{pane_width} #{pane_height} #{pane_current_command}"],
|
|
11722
|
+
tmuxArgs(["display-message", "-p", "-t", name, "#{pane_in_mode} #{alternate_on} #{mouse_any_flag} #{pane_width} #{pane_height} #{pane_current_command}"]),
|
|
11472
11723
|
{ encoding: "utf8", timeout: TMUX_PROBE_TIMEOUT_MS, env: ptyEnv() }
|
|
11473
11724
|
);
|
|
11474
11725
|
if (probe.status !== 0 || typeof probe.stdout !== "string") return;
|
|
@@ -11486,7 +11737,7 @@ class WebTerminalManager {
|
|
|
11486
11737
|
const hex = sgrWheelHexBytes(action.dir, action.count, Number(paneW) || 80, Number(paneH) || 24);
|
|
11487
11738
|
node_child_process.spawnSync(
|
|
11488
11739
|
"tmux",
|
|
11489
|
-
["send-keys", "-t", name, "-H", ...hex],
|
|
11740
|
+
tmuxArgs(["send-keys", "-t", name, "-H", ...hex]),
|
|
11490
11741
|
{ stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env: ptyEnv() }
|
|
11491
11742
|
);
|
|
11492
11743
|
return;
|
|
@@ -11494,7 +11745,7 @@ class WebTerminalManager {
|
|
|
11494
11745
|
if (action.kind === "page-keys") {
|
|
11495
11746
|
node_child_process.spawnSync(
|
|
11496
11747
|
"tmux",
|
|
11497
|
-
["send-keys", "-t", name, "-N", String(action.count), action.key],
|
|
11748
|
+
tmuxArgs(["send-keys", "-t", name, "-N", String(action.count), action.key]),
|
|
11498
11749
|
{ stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env: ptyEnv() }
|
|
11499
11750
|
);
|
|
11500
11751
|
return;
|
|
@@ -11502,19 +11753,19 @@ class WebTerminalManager {
|
|
|
11502
11753
|
if (action.kind === "keys") {
|
|
11503
11754
|
node_child_process.spawnSync(
|
|
11504
11755
|
"tmux",
|
|
11505
|
-
["send-keys", "-t", name, "-N", String(action.count), action.key],
|
|
11756
|
+
tmuxArgs(["send-keys", "-t", name, "-N", String(action.count), action.key]),
|
|
11506
11757
|
{ stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env: ptyEnv() }
|
|
11507
11758
|
);
|
|
11508
11759
|
return;
|
|
11509
11760
|
}
|
|
11510
11761
|
node_child_process.spawnSync(
|
|
11511
11762
|
"tmux",
|
|
11512
|
-
["copy-mode", "-e", "-t", name],
|
|
11763
|
+
tmuxArgs(["copy-mode", "-e", "-t", name]),
|
|
11513
11764
|
{ stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env: ptyEnv() }
|
|
11514
11765
|
);
|
|
11515
11766
|
node_child_process.spawnSync(
|
|
11516
11767
|
"tmux",
|
|
11517
|
-
[
|
|
11768
|
+
tmuxArgs([
|
|
11518
11769
|
"send-keys",
|
|
11519
11770
|
"-X",
|
|
11520
11771
|
"-t",
|
|
@@ -11522,7 +11773,7 @@ class WebTerminalManager {
|
|
|
11522
11773
|
"-N",
|
|
11523
11774
|
String(action.count),
|
|
11524
11775
|
action.dir === "up" ? "scroll-up" : "scroll-down"
|
|
11525
|
-
],
|
|
11776
|
+
]),
|
|
11526
11777
|
{ stdio: "ignore", timeout: TMUX_PROBE_TIMEOUT_MS, env: ptyEnv() }
|
|
11527
11778
|
);
|
|
11528
11779
|
} catch {
|
|
@@ -11556,14 +11807,14 @@ class WebTerminalManager {
|
|
|
11556
11807
|
const name = `vh-${terminalId}`;
|
|
11557
11808
|
try {
|
|
11558
11809
|
if (ifAbsent) {
|
|
11559
|
-
const cur = node_child_process.spawnSync("tmux", ["show-options", "-t", name, "-v", "@vh_title"], { encoding: "utf8", env: ptyEnv() });
|
|
11810
|
+
const cur = node_child_process.spawnSync("tmux", tmuxArgs(["show-options", "-t", name, "-v", "@vh_title"]), { encoding: "utf8", env: ptyEnv() });
|
|
11560
11811
|
if (cur.status === 0 && cur.stdout && cur.stdout.trim()) return true;
|
|
11561
11812
|
}
|
|
11562
|
-
const r = node_child_process.spawnSync("tmux", ["set-option", "-t", name, "@vh_title", title], { stdio: "ignore", env: ptyEnv() });
|
|
11813
|
+
const r = node_child_process.spawnSync("tmux", tmuxArgs(["set-option", "-t", name, "@vh_title", title]), { stdio: "ignore", env: ptyEnv() });
|
|
11563
11814
|
if (r.status !== 0) return false;
|
|
11564
11815
|
if (!ifAbsent) {
|
|
11565
11816
|
try {
|
|
11566
|
-
node_child_process.spawnSync("tmux", ["set-option", "-t", name, "@vh_title_manual", "1"], { stdio: "ignore", env: ptyEnv() });
|
|
11817
|
+
node_child_process.spawnSync("tmux", tmuxArgs(["set-option", "-t", name, "@vh_title_manual", "1"]), { stdio: "ignore", env: ptyEnv() });
|
|
11567
11818
|
} catch {
|
|
11568
11819
|
}
|
|
11569
11820
|
}
|
|
@@ -11581,7 +11832,7 @@ class WebTerminalManager {
|
|
|
11581
11832
|
if (!valid) return false;
|
|
11582
11833
|
const name = `vh-${terminalId}`;
|
|
11583
11834
|
try {
|
|
11584
|
-
const r = node_child_process.spawnSync("tmux", ["set-option", "-t", name, "@vh_tags", JSON.stringify(valid)], {
|
|
11835
|
+
const r = node_child_process.spawnSync("tmux", tmuxArgs(["set-option", "-t", name, "@vh_tags", JSON.stringify(valid)]), {
|
|
11585
11836
|
stdio: "ignore",
|
|
11586
11837
|
env: ptyEnv()
|
|
11587
11838
|
});
|
|
@@ -11613,10 +11864,11 @@ function parseVhTerminals(stdout, hostname = os.hostname()) {
|
|
|
11613
11864
|
}
|
|
11614
11865
|
function runTmux(args, input) {
|
|
11615
11866
|
try {
|
|
11616
|
-
const r = node_child_process.spawnSync("tmux", args, {
|
|
11867
|
+
const r = node_child_process.spawnSync("tmux", tmuxArgs(args), {
|
|
11617
11868
|
encoding: "utf8",
|
|
11618
11869
|
timeout: TMUX_TIMEOUT_MS,
|
|
11619
|
-
input
|
|
11870
|
+
input,
|
|
11871
|
+
env: scrubTmuxClientEnv({ ...process.env })
|
|
11620
11872
|
});
|
|
11621
11873
|
if (r.error) return { ok: false, stdout: "", error: r.error.message };
|
|
11622
11874
|
if (r.status !== 0) return { ok: false, stdout: r.stdout ?? "", error: (r.stderr || `tmux exited with ${r.status}`).trim() };
|
|
@@ -15236,9 +15488,11 @@ exports.readSettings = readSettings;
|
|
|
15236
15488
|
exports.readVhTerminal = readVhTerminal;
|
|
15237
15489
|
exports.releaseDaemonLock = releaseDaemonLock;
|
|
15238
15490
|
exports.resolveCliUpdateCheckInterval = resolveCliUpdateCheckInterval;
|
|
15491
|
+
exports.scrubTmuxClientEnv = scrubTmuxClientEnv;
|
|
15239
15492
|
exports.sendToVhTerminal = sendToVhTerminal;
|
|
15240
15493
|
exports.startOfflineReconnection = startOfflineReconnection;
|
|
15241
15494
|
exports.summarizeSpawnSessionForLog = summarizeSpawnSessionForLog;
|
|
15495
|
+
exports.tmuxArgs = tmuxArgs;
|
|
15242
15496
|
exports.updateSettings = updateSettings;
|
|
15243
15497
|
exports.wrapCommand = wrapCommand;
|
|
15244
15498
|
exports.writeCredentialsDataKey = writeCredentialsDataKey;
|