very-happy-cli 0.2.115 → 0.2.117
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-DEZTWZZu.mjs → AcpBackend-C4RMHt0I.mjs} +1 -1
- package/dist/{AcpBackend-BrZN8KM-.cjs → AcpBackend-CrbXvcgQ.cjs} +1 -1
- package/dist/{AcpSessionManager-DjulpKY0.cjs → AcpSessionManager-CjAVO4RX.cjs} +1 -1
- package/dist/{AcpSessionManager-BzP3eiOG.mjs → AcpSessionManager-Cnc8Jatl.mjs} +1 -1
- package/dist/{config-CMgRBQMS.mjs → config-CnA3JIUn.mjs} +2 -2
- package/dist/{config-BNAsx9Wg.cjs → config-O9quMfxg.cjs} +2 -2
- package/dist/{index-B2KfhNku.mjs → index-B0o3H6_x.mjs} +2 -2
- package/dist/{index-BHNEb4bc.mjs → index-BYZKuQoy.mjs} +590 -41
- package/dist/{index-tPXwlc_t.cjs → index-DcESl4cI.cjs} +601 -43
- package/dist/{index-CpGR7rIw.mjs → index-DiRN0Rv8.mjs} +78 -8
- package/dist/{index-B3UkbonP.cjs → index-DqmVH6R5.cjs} +2 -2
- package/dist/{index-ClR0jhjm.cjs → index-W-O4xR_O.cjs} +77 -7
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{installTerminalHooks-DD6QuHfT.mjs → installTerminalHooks-DeYqyjCB.mjs} +2 -2
- package/dist/{installTerminalHooks-CWfCF68p.cjs → installTerminalHooks-zfsWSotO.cjs} +2 -2
- package/dist/lib.cjs +1 -1
- package/dist/lib.d.cts +66 -1
- package/dist/lib.d.mts +66 -1
- package/dist/lib.mjs +1 -1
- package/dist/{mcp-CiNrjYox.mjs → mcp-D_5aOK0I.mjs} +62 -17
- package/dist/{mcp-CqjiDRnG.cjs → mcp-nYqC4FYm.cjs} +62 -16
- package/dist/{runGemini-DdJqpywr.mjs → runGemini-CEURRmM4.mjs} +4 -4
- package/dist/{runGemini-UN5IznJp.cjs → runGemini-DYf3ntib.cjs} +4 -4
- package/dist/{runOpenClaw-CM5UrVBy.mjs → runOpenClaw-BozfKWng.mjs} +3 -3
- package/dist/{runOpenClaw-9hhfGllZ.cjs → runOpenClaw-CNKjAw-H.cjs} +3 -3
- package/dist/{send-CnVtXOj0.cjs → send-BZLhRZb-.cjs} +2 -2
- package/dist/{send-C6G2jsQp.mjs → send-CYznZGrp.mjs} +2 -2
- package/dist/sessions-DYPB3Peg.mjs +317 -0
- package/dist/sessions-YWt9YEN8.cjs +322 -0
- package/dist/{spawn-qb344Y5E.mjs → spawn-CsrHZd3y.mjs} +3 -4
- package/dist/{spawn-CfYddkS_.cjs → spawn-tSvo3stN.cjs} +6 -7
- package/dist/{types-CpnzfHHS.cjs → types-DD3AK6Nb.cjs} +189 -26
- package/dist/{types-B3qx8Ga1.mjs → types-jSfU_0o1.mjs} +187 -26
- package/package.json +7 -7
- package/dist/sessions-CGdcF05T.cjs +0 -204
- package/dist/sessions-CmabJzYS.mjs +0 -200
|
@@ -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.117";
|
|
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.117",
|
|
168
|
+
"very-happy-tools-x64-darwin": "0.2.117",
|
|
169
|
+
"very-happy-tools-arm64-linux": "0.2.117",
|
|
170
|
+
"very-happy-tools-x64-linux": "0.2.117",
|
|
171
|
+
"very-happy-tools-arm64-win32": "0.2.117",
|
|
172
|
+
"very-happy-tools-x64-win32": "0.2.117"
|
|
173
173
|
};
|
|
174
174
|
var devDependencies = {
|
|
175
175
|
"@slopus/happy-wire": "workspace:*",
|
|
@@ -1039,6 +1039,8 @@ z.z.object({
|
|
|
1039
1039
|
codex: z.z.boolean(),
|
|
1040
1040
|
gemini: z.z.boolean(),
|
|
1041
1041
|
openclaw: z.z.boolean(),
|
|
1042
|
+
pi: z.z.boolean().optional(),
|
|
1043
|
+
// absent on daemons that predate the pi runner
|
|
1042
1044
|
detectedAt: z.z.number()
|
|
1043
1045
|
}).optional(),
|
|
1044
1046
|
resumeSupport: z.z.object({
|
|
@@ -1076,7 +1078,14 @@ const CliUpdateStateSchema = z.z.object({
|
|
|
1076
1078
|
* serving the old code. Present only while that is true. Optional and additive:
|
|
1077
1079
|
* old web builds ignore it, old daemons never send it (iron rule 4).
|
|
1078
1080
|
*/
|
|
1079
|
-
handoverHold: z.z.object({ reason: z.z.string(), at: z.z.number() }).nullable().optional()
|
|
1081
|
+
handoverHold: z.z.object({ reason: z.z.string(), at: z.z.number() }).nullable().optional(),
|
|
1082
|
+
/** B-327: the last thing the machine's auto-update did, or why it did nothing. */
|
|
1083
|
+
autoUpdate: z.z.object({
|
|
1084
|
+
state: z.z.union([z.z.enum(["installing", "installed", "failed", "skipped"]), z.z.string()]),
|
|
1085
|
+
version: z.z.string().nullable(),
|
|
1086
|
+
detail: z.z.string().optional(),
|
|
1087
|
+
at: z.z.number()
|
|
1088
|
+
}).nullable().optional()
|
|
1080
1089
|
});
|
|
1081
1090
|
const WebTerminalListItemSchema = z.z.object({
|
|
1082
1091
|
id: z.z.string(),
|
|
@@ -1673,7 +1682,7 @@ class RpcHandlerManager {
|
|
|
1673
1682
|
}
|
|
1674
1683
|
}
|
|
1675
1684
|
|
|
1676
|
-
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-
|
|
1685
|
+
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-DD3AK6Nb.cjs', document.baseURI).href))));
|
|
1677
1686
|
function projectPath() {
|
|
1678
1687
|
const path = path$1.resolve(__dirname$1, "..");
|
|
1679
1688
|
return path;
|
|
@@ -9856,6 +9865,49 @@ class SnapshotStore {
|
|
|
9856
9865
|
}
|
|
9857
9866
|
}
|
|
9858
9867
|
|
|
9868
|
+
const OUTPUT_COALESCE_MS = 16;
|
|
9869
|
+
const OUTPUT_COALESCE_MAX_BYTES = 64 * 1024;
|
|
9870
|
+
function createOutputCoalescer({ maxDelayMs, maxBytes } = {
|
|
9871
|
+
maxDelayMs: OUTPUT_COALESCE_MS,
|
|
9872
|
+
maxBytes: OUTPUT_COALESCE_MAX_BYTES
|
|
9873
|
+
}) {
|
|
9874
|
+
let buffered = [];
|
|
9875
|
+
let bufferedBytes = 0;
|
|
9876
|
+
let firstBufferedAt = 0;
|
|
9877
|
+
let lastEmitAt = Number.NEGATIVE_INFINITY;
|
|
9878
|
+
const drain = (now) => {
|
|
9879
|
+
if (bufferedBytes === 0) return null;
|
|
9880
|
+
const out = buffered.length === 1 ? buffered[0] : Buffer.concat(buffered, bufferedBytes);
|
|
9881
|
+
buffered = [];
|
|
9882
|
+
bufferedBytes = 0;
|
|
9883
|
+
firstBufferedAt = 0;
|
|
9884
|
+
lastEmitAt = now;
|
|
9885
|
+
return out;
|
|
9886
|
+
};
|
|
9887
|
+
return {
|
|
9888
|
+
push(data, now) {
|
|
9889
|
+
if (data.length === 0) return null;
|
|
9890
|
+
if (bufferedBytes === 0 && now - lastEmitAt >= maxDelayMs) {
|
|
9891
|
+
lastEmitAt = now;
|
|
9892
|
+
return data;
|
|
9893
|
+
}
|
|
9894
|
+
if (bufferedBytes === 0) firstBufferedAt = now;
|
|
9895
|
+
buffered.push(data);
|
|
9896
|
+
bufferedBytes += data.length;
|
|
9897
|
+
return bufferedBytes >= maxBytes ? drain(now) : null;
|
|
9898
|
+
},
|
|
9899
|
+
flush(now) {
|
|
9900
|
+
return drain(now);
|
|
9901
|
+
},
|
|
9902
|
+
dueAt() {
|
|
9903
|
+
return bufferedBytes === 0 ? null : firstBufferedAt + maxDelayMs;
|
|
9904
|
+
},
|
|
9905
|
+
pendingBytes() {
|
|
9906
|
+
return bufferedBytes;
|
|
9907
|
+
}
|
|
9908
|
+
};
|
|
9909
|
+
}
|
|
9910
|
+
|
|
9859
9911
|
const MAX_SEND_KEYS_PAYLOAD_BYTES = 1e3;
|
|
9860
9912
|
function tmuxSingleQuote(text) {
|
|
9861
9913
|
return `'${text.split("'").join("'\\''")}'`;
|
|
@@ -10766,6 +10818,18 @@ class TerminalSession {
|
|
|
10766
10818
|
lastOutputAt;
|
|
10767
10819
|
cols;
|
|
10768
10820
|
rows;
|
|
10821
|
+
/**
|
|
10822
|
+
* B-334: `%output` arrives as one message per producer write — pi's startup
|
|
10823
|
+
* frame measured 1029 chunks of a median 9 bytes. Merging them before they
|
|
10824
|
+
* are given a seq is what keeps the wire (and the web's write chain) from
|
|
10825
|
+
* carrying a thousand frames for 12 KB. See outputCoalescer.ts.
|
|
10826
|
+
*/
|
|
10827
|
+
coalescer = createOutputCoalescer();
|
|
10828
|
+
flushTimer = null;
|
|
10829
|
+
/** Set by the manager right after construction: how a merged chunk reaches
|
|
10830
|
+
* the subscribers. Left undefined ⇒ the session buffers and drops nothing,
|
|
10831
|
+
* it just has nobody to tell. */
|
|
10832
|
+
onOutputChunk;
|
|
10769
10833
|
constructor(id, transport, tmuxSession, cols, rows) {
|
|
10770
10834
|
this.id = id;
|
|
10771
10835
|
this.transport = transport;
|
|
@@ -10812,6 +10876,61 @@ class TerminalSession {
|
|
|
10812
10876
|
}
|
|
10813
10877
|
return chunk;
|
|
10814
10878
|
}
|
|
10879
|
+
/**
|
|
10880
|
+
* The live-output entry point (B-334). Every `%output` / pty chunk goes
|
|
10881
|
+
* through here instead of straight to `ingest`: the coalescer decides
|
|
10882
|
+
* whether this byte run is emitted now (the common interactive case — an
|
|
10883
|
+
* echo after an idle window pays zero extra latency) or merged into the
|
|
10884
|
+
* frame currently forming. Merging is byte-exact concatenation, so one seq
|
|
10885
|
+
* covering the merged run is indistinguishable from tmux having handed us
|
|
10886
|
+
* one bigger read — the ring/replay/gap protocol is untouched.
|
|
10887
|
+
*/
|
|
10888
|
+
pushOutput(data) {
|
|
10889
|
+
const ready = this.coalescer.push(data, Date.now());
|
|
10890
|
+
if (ready) {
|
|
10891
|
+
this.clearFlushTimer();
|
|
10892
|
+
this.emitOutput(ready);
|
|
10893
|
+
}
|
|
10894
|
+
this.armFlushTimer();
|
|
10895
|
+
}
|
|
10896
|
+
/**
|
|
10897
|
+
* Emit whatever is buffered right now. MUST be called before anything that
|
|
10898
|
+
* reads or changes the screen's identity, because buffered bytes have not
|
|
10899
|
+
* been ingested yet and therefore own no seq:
|
|
10900
|
+
* - the capture anchor (`runCaptureBatch`) — pre-anchor output is already
|
|
10901
|
+
* inside the capture, so it has to own a seq <= `seqAtAnchor` or the
|
|
10902
|
+
* client applies it a second time on top of the restore;
|
|
10903
|
+
* - `resizeHeadless` — those bytes were produced at the OLD size;
|
|
10904
|
+
* - transport exit — otherwise the last frame before a shell dies is lost.
|
|
10905
|
+
*/
|
|
10906
|
+
flushOutput() {
|
|
10907
|
+
this.clearFlushTimer();
|
|
10908
|
+
const ready = this.coalescer.flush(Date.now());
|
|
10909
|
+
if (ready) this.emitOutput(ready);
|
|
10910
|
+
}
|
|
10911
|
+
emitOutput(data) {
|
|
10912
|
+
const chunk = this.ingest(data);
|
|
10913
|
+
this.onOutputChunk?.(chunk);
|
|
10914
|
+
}
|
|
10915
|
+
armFlushTimer() {
|
|
10916
|
+
const due = this.coalescer.dueAt();
|
|
10917
|
+
if (due === null) {
|
|
10918
|
+
this.clearFlushTimer();
|
|
10919
|
+
return;
|
|
10920
|
+
}
|
|
10921
|
+
if (this.flushTimer) return;
|
|
10922
|
+
const timer = setTimeout(() => {
|
|
10923
|
+
this.flushTimer = null;
|
|
10924
|
+
this.flushOutput();
|
|
10925
|
+
}, Math.max(0, due - Date.now()));
|
|
10926
|
+
timer.unref?.();
|
|
10927
|
+
this.flushTimer = timer;
|
|
10928
|
+
}
|
|
10929
|
+
clearFlushTimer() {
|
|
10930
|
+
if (!this.flushTimer) return;
|
|
10931
|
+
clearTimeout(this.flushTimer);
|
|
10932
|
+
this.flushTimer = null;
|
|
10933
|
+
}
|
|
10815
10934
|
/**
|
|
10816
10935
|
* Write a RESTORE payload (the open capture) into the authoritative screen
|
|
10817
10936
|
* WITHOUT giving it a seq: it is not a live chunk, so it must not enter the
|
|
@@ -10831,6 +10950,7 @@ class TerminalSession {
|
|
|
10831
10950
|
/** Keep the authoritative screen's dimensions in lockstep with the terminal
|
|
10832
10951
|
* so a later snapshot serialize() reflects the real geometry. */
|
|
10833
10952
|
resizeHeadless(cols, rows) {
|
|
10953
|
+
this.flushOutput();
|
|
10834
10954
|
this.cols = cols;
|
|
10835
10955
|
this.rows = rows;
|
|
10836
10956
|
try {
|
|
@@ -10910,6 +11030,7 @@ class TerminalSession {
|
|
|
10910
11030
|
} catch {
|
|
10911
11031
|
}
|
|
10912
11032
|
}
|
|
11033
|
+
this.clearFlushTimer();
|
|
10913
11034
|
try {
|
|
10914
11035
|
this.headless.dispose();
|
|
10915
11036
|
} catch {
|
|
@@ -11761,14 +11882,16 @@ class WebTerminalManager {
|
|
|
11761
11882
|
client: void 0
|
|
11762
11883
|
// replaced below
|
|
11763
11884
|
}, tmuxSession, cols, rows);
|
|
11885
|
+
created.onOutputChunk = (chunk) => {
|
|
11886
|
+
this.emit("terminal-output", { terminalId: id, data: chunk.data, seq: chunk.seq });
|
|
11887
|
+
this.noteActivity();
|
|
11888
|
+
};
|
|
11764
11889
|
const client = new ControlClient(tmuxSession, env, {
|
|
11765
11890
|
onOutput: (pane, data) => {
|
|
11766
11891
|
if (this.terminals.get(id) !== created) return;
|
|
11767
11892
|
if (!created.ingesting) return;
|
|
11768
11893
|
if (created.paneId && pane !== created.paneId) return;
|
|
11769
|
-
|
|
11770
|
-
this.emit("terminal-output", { terminalId: id, data: chunk.data, seq: chunk.seq });
|
|
11771
|
-
this.noteActivity();
|
|
11894
|
+
created.pushOutput(data);
|
|
11772
11895
|
},
|
|
11773
11896
|
onNotification: (name, args2) => {
|
|
11774
11897
|
if (this.terminals.get(id) !== created) return;
|
|
@@ -11790,6 +11913,7 @@ class WebTerminalManager {
|
|
|
11790
11913
|
},
|
|
11791
11914
|
onExit: (code) => {
|
|
11792
11915
|
if (this.terminals.get(id) !== created) return;
|
|
11916
|
+
created.flushOutput();
|
|
11793
11917
|
this.terminals.delete(id);
|
|
11794
11918
|
this.snapshots.drop(id);
|
|
11795
11919
|
created.dispose();
|
|
@@ -11810,14 +11934,17 @@ class WebTerminalManager {
|
|
|
11810
11934
|
}
|
|
11811
11935
|
}
|
|
11812
11936
|
const created = new TerminalSession(id, { kind: "pty", pty: proc }, void 0, cols, rows);
|
|
11813
|
-
|
|
11814
|
-
if (this.terminals.get(id) !== created) return;
|
|
11815
|
-
const chunk = created.ingest(Buffer.from(data, "utf8"));
|
|
11937
|
+
created.onOutputChunk = (chunk) => {
|
|
11816
11938
|
this.emit("terminal-output", { terminalId: id, data: chunk.data, seq: chunk.seq });
|
|
11817
11939
|
this.noteActivity();
|
|
11940
|
+
};
|
|
11941
|
+
proc.onData((data) => {
|
|
11942
|
+
if (this.terminals.get(id) !== created) return;
|
|
11943
|
+
created.pushOutput(Buffer.from(data, "utf8"));
|
|
11818
11944
|
});
|
|
11819
11945
|
proc.onExit(({ exitCode }) => {
|
|
11820
11946
|
if (this.terminals.get(id) !== created) return;
|
|
11947
|
+
created.flushOutput();
|
|
11821
11948
|
this.terminals.delete(id);
|
|
11822
11949
|
this.snapshots.drop(id);
|
|
11823
11950
|
created.dispose();
|
|
@@ -11961,6 +12088,7 @@ class WebTerminalManager {
|
|
|
11961
12088
|
command: c.command,
|
|
11962
12089
|
label: c.key,
|
|
11963
12090
|
onBlock: c.key === "anchor" ? () => {
|
|
12091
|
+
session.flushOutput();
|
|
11964
12092
|
seqAtAnchor = session.seq;
|
|
11965
12093
|
if (fresh) session.ingesting = true;
|
|
11966
12094
|
} : void 0
|
|
@@ -12627,6 +12755,19 @@ function commandExists(command) {
|
|
|
12627
12755
|
return false;
|
|
12628
12756
|
}
|
|
12629
12757
|
}
|
|
12758
|
+
function commandExistsWindows(name) {
|
|
12759
|
+
try {
|
|
12760
|
+
child_process.execSync(`powershell -NoProfile -Command "Get-Command ${name} -ErrorAction SilentlyContinue"`, { stdio: "ignore", windowsHide: true });
|
|
12761
|
+
return true;
|
|
12762
|
+
} catch {
|
|
12763
|
+
return false;
|
|
12764
|
+
}
|
|
12765
|
+
}
|
|
12766
|
+
const SAFE_COMMAND_NAME = /^[A-Za-z0-9._-]+$/;
|
|
12767
|
+
function commandOnPath(name) {
|
|
12768
|
+
if (!SAFE_COMMAND_NAME.test(name)) return false;
|
|
12769
|
+
return os$1.platform() === "win32" ? commandExistsWindows(name) : commandExists(name);
|
|
12770
|
+
}
|
|
12630
12771
|
function detectPosix() {
|
|
12631
12772
|
const claude = commandExists("claude");
|
|
12632
12773
|
const codex = commandExists("codex");
|
|
@@ -12635,17 +12776,11 @@ function detectPosix() {
|
|
|
12635
12776
|
const openclawConfig = fs$1.existsSync(path$1.join(os$1.homedir(), ".openclaw", "openclaw.json"));
|
|
12636
12777
|
const openclawEnv = !!process.env.OPENCLAW_GATEWAY_URL;
|
|
12637
12778
|
const openclaw = openclawCommand || openclawConfig || openclawEnv;
|
|
12638
|
-
|
|
12779
|
+
const pi = commandExists("pi") && commandExists("pi-acp");
|
|
12780
|
+
return { claude, codex, gemini, openclaw, pi, detectedAt: Date.now() };
|
|
12639
12781
|
}
|
|
12640
12782
|
function detectWindows() {
|
|
12641
|
-
const checkCommand =
|
|
12642
|
-
try {
|
|
12643
|
-
child_process.execSync(`powershell -NoProfile -Command "Get-Command ${name} -ErrorAction SilentlyContinue"`, { stdio: "ignore", windowsHide: true });
|
|
12644
|
-
return true;
|
|
12645
|
-
} catch {
|
|
12646
|
-
return false;
|
|
12647
|
-
}
|
|
12648
|
-
};
|
|
12783
|
+
const checkCommand = commandExistsWindows;
|
|
12649
12784
|
const claude = checkCommand("claude");
|
|
12650
12785
|
const codex = checkCommand("codex");
|
|
12651
12786
|
const gemini = checkCommand("gemini");
|
|
@@ -12653,7 +12788,8 @@ function detectWindows() {
|
|
|
12653
12788
|
const openclawConfig = fs$1.existsSync(path$1.join(process.env.USERPROFILE || os$1.homedir(), ".openclaw", "openclaw.json"));
|
|
12654
12789
|
const openclawEnv = !!process.env.OPENCLAW_GATEWAY_URL;
|
|
12655
12790
|
const openclaw = openclawCommand || openclawConfig || openclawEnv;
|
|
12656
|
-
|
|
12791
|
+
const pi = checkCommand("pi") && checkCommand("pi-acp");
|
|
12792
|
+
return { claude, codex, gemini, openclaw, pi, detectedAt: Date.now() };
|
|
12657
12793
|
}
|
|
12658
12794
|
|
|
12659
12795
|
const AgentCredentialsSchema = z.z.object({
|
|
@@ -14431,6 +14567,15 @@ class ApiMachineClient {
|
|
|
14431
14567
|
// recover account material or impersonate a Web client. (Declared before
|
|
14432
14568
|
// webTerminal so the emit closure can read it.)
|
|
14433
14569
|
encTerminals = /* @__PURE__ */ new Set();
|
|
14570
|
+
/** B-327: an auto-update swaps the process that owns these terminals, so it
|
|
14571
|
+
* waits until there are none. */
|
|
14572
|
+
hasLiveTerminals() {
|
|
14573
|
+
try {
|
|
14574
|
+
return this.webTerminal.buildTerminalList().length > 0;
|
|
14575
|
+
} catch {
|
|
14576
|
+
return true;
|
|
14577
|
+
}
|
|
14578
|
+
}
|
|
14434
14579
|
webTerminal = new WebTerminalManager((event, payload) => {
|
|
14435
14580
|
let out = payload;
|
|
14436
14581
|
if (event === "terminal-output" && this.encTerminals.has(payload.terminalId)) {
|
|
@@ -14453,6 +14598,22 @@ class ApiMachineClient {
|
|
|
14453
14598
|
event: n.event
|
|
14454
14599
|
});
|
|
14455
14600
|
});
|
|
14601
|
+
/**
|
|
14602
|
+
* The CLI availability last advertised in machine metadata (re-probed by
|
|
14603
|
+
* the keep-alive). Null until the first keep-alive tick; the daemon falls
|
|
14604
|
+
* back to its startup probe then.
|
|
14605
|
+
*/
|
|
14606
|
+
getCLIAvailability() {
|
|
14607
|
+
return this.lastKnownCLIAvailability;
|
|
14608
|
+
}
|
|
14609
|
+
/**
|
|
14610
|
+
* Title a web terminal from inside it (`very-happy mcp` change_title →
|
|
14611
|
+
* daemon /terminal-title → here). Same tmux truthfulness as the
|
|
14612
|
+
* `set-terminal-title` RPC.
|
|
14613
|
+
*/
|
|
14614
|
+
setTerminalTitle(terminalId, title, ifAbsent) {
|
|
14615
|
+
return this.webTerminal.setTitle(terminalId, title, ifAbsent);
|
|
14616
|
+
}
|
|
14456
14617
|
/**
|
|
14457
14618
|
* Push text to the clipboard of every web client the user has open
|
|
14458
14619
|
* (terminal-path claude → `very-happy mcp` → daemon /clipboard → here).
|
|
@@ -15261,7 +15422,7 @@ class ApiMachineClient {
|
|
|
15261
15422
|
const prev = this.lastKnownCLIAvailability;
|
|
15262
15423
|
const newResumeSupport = detectResumeSupport();
|
|
15263
15424
|
const prevResume = this.lastKnownResumeSupport;
|
|
15264
|
-
const cliAvailabilityChanged = !prev || prev.claude !== newAvailability.claude || prev.codex !== newAvailability.codex || prev.gemini !== newAvailability.gemini || prev.openclaw !== newAvailability.openclaw;
|
|
15425
|
+
const cliAvailabilityChanged = !prev || prev.claude !== newAvailability.claude || prev.codex !== newAvailability.codex || prev.gemini !== newAvailability.gemini || prev.openclaw !== newAvailability.openclaw || prev.pi !== newAvailability.pi;
|
|
15265
15426
|
const resumeSupportChanged = !prevResume || prevResume.rpcAvailable !== newResumeSupport.rpcAvailable || prevResume.happyAgentAuthenticated !== newResumeSupport.happyAgentAuthenticated;
|
|
15266
15427
|
if (cliAvailabilityChanged || resumeSupportChanged) {
|
|
15267
15428
|
this.lastKnownCLIAvailability = newAvailability;
|
|
@@ -16502,6 +16663,8 @@ exports.api = api;
|
|
|
16502
16663
|
exports.clearCredentials = clearCredentials;
|
|
16503
16664
|
exports.clearDaemonState = clearDaemonState;
|
|
16504
16665
|
exports.clearMachineId = clearMachineId;
|
|
16666
|
+
exports.commandOnPath = commandOnPath;
|
|
16667
|
+
exports.compareExactVersions = compareExactVersions;
|
|
16505
16668
|
exports.configuration = configuration;
|
|
16506
16669
|
exports.connectionState = connectionState;
|
|
16507
16670
|
exports.contentLogMetadata = contentLogMetadata;
|