@neta-art/cohub-cli 10.8.2 → 10.8.3
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/board-kernel.js
CHANGED
|
@@ -32153,6 +32153,10 @@ async function loadCanvasModule() {
|
|
|
32153
32153
|
throw new Error("Board image export needs the optional '@napi-rs/canvas' package. Install it with: npm i @napi-rs/canvas", { cause });
|
|
32154
32154
|
}
|
|
32155
32155
|
}
|
|
32156
|
+
function installDOMMatrix(canvasModule) {
|
|
32157
|
+
const globals = globalThis;
|
|
32158
|
+
globals.DOMMatrix ??= canvasModule.DOMMatrix;
|
|
32159
|
+
}
|
|
32156
32160
|
function installAnimationFrameShim() {
|
|
32157
32161
|
const globals = globalThis;
|
|
32158
32162
|
if (globals.requestAnimationFrame) return () => {};
|
|
@@ -32207,6 +32211,7 @@ async function createNodeBoardRenderer(options = {}) {
|
|
|
32207
32211
|
throw new Error("XML parsing is not available in Node board export.");
|
|
32208
32212
|
}
|
|
32209
32213
|
});
|
|
32214
|
+
installDOMMatrix(canvasModule);
|
|
32210
32215
|
installBoardTextMeasurement();
|
|
32211
32216
|
const restoreAnimationFrame = installAnimationFrameShim();
|
|
32212
32217
|
const renderer = new CanvasRenderer();
|
|
@@ -29,22 +29,21 @@ export async function ensureNativeSync(input, log = (line) => process.stderr.wri
|
|
|
29
29
|
return { enabled: false, harnesses: [], codexShared: false, importHistory: false, note: "unsupported" };
|
|
30
30
|
const stateRoot = runtimeStateRoot(input.spaceId);
|
|
31
31
|
const previous = await readNativeConfig(stateRoot, input.identity).catch(() => null);
|
|
32
|
-
|
|
33
|
-
await maintain(previous, log, input.executables?.pi);
|
|
34
|
-
return { enabled: true, harnesses: previous.harnesses, codexShared: previous.codexShared, importHistory: false };
|
|
35
|
-
}
|
|
32
|
+
const alreadySynced = previous && nativeSyncSatisfied(previous, input);
|
|
36
33
|
const interactive = process.stdin.isTTY === true;
|
|
37
34
|
const confirm = async (question) => input.yes ? true : interactive ? await ask(question) : false;
|
|
38
|
-
if (!
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
if (!alreadySynced) {
|
|
36
|
+
if (!input.yes && !interactive) {
|
|
37
|
+
log("Native sync off · rerun interactively or with --yes to enable\n");
|
|
38
|
+
return { enabled: false, harnesses: input.harnesses, codexShared: false, importHistory: false, note: "non-interactive" };
|
|
39
|
+
}
|
|
40
|
+
const names = input.harnesses.map((harness) => LOCAL_HARNESS_SPECS[harness].label).join(" and ");
|
|
41
|
+
if (!await confirm(`Sync ${names} chats in this folder to this Space so they continue on the web? Their history may contain secrets. [Y/n] `)) {
|
|
42
|
+
return { enabled: false, harnesses: input.harnesses, codexShared: false, importHistory: false, note: "declined" };
|
|
43
|
+
}
|
|
45
44
|
}
|
|
46
45
|
let codexShared = previous?.codexShared ?? false;
|
|
47
|
-
if (input.harnesses.includes("codex") && !codexShared) {
|
|
46
|
+
if (input.harnesses.includes("codex") && !codexShared && (input.yes || interactive)) {
|
|
48
47
|
const version = await harnessVersion(input.executables?.codex || "codex");
|
|
49
48
|
if (!sharedServerAvailable) {
|
|
50
49
|
log("Shared Codex sessions are unavailable on Windows; terminal Codex chats sync read-only\n");
|
|
@@ -56,6 +55,16 @@ export async function ensureNativeSync(input, log = (line) => process.stderr.wri
|
|
|
56
55
|
codexShared = await confirm("Let terminal Codex and the web drive the same live sessions? Cohub starts Codex's shared app-server, which keeps running in the background. [Y/n] ");
|
|
57
56
|
}
|
|
58
57
|
}
|
|
58
|
+
if (previous && alreadySynced) {
|
|
59
|
+
if (codexShared !== previous.codexShared) {
|
|
60
|
+
await writeNativeConfig(stateRoot, { ...previous, codexShared }).catch((error) => {
|
|
61
|
+
log(`Shared Codex sessions unavailable; Runtime continues without them — ${serializeDiagnosticError(error).message}\n`);
|
|
62
|
+
codexShared = previous.codexShared;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
await maintain(previous, log, input.executables?.pi);
|
|
66
|
+
return { enabled: true, harnesses: previous.harnesses, codexShared, importHistory: false };
|
|
67
|
+
}
|
|
59
68
|
const harnesses = [...new Set([...(previous?.root === input.root ? previous.harnesses : []), ...input.harnesses])];
|
|
60
69
|
const config = {
|
|
61
70
|
version: 2, identity: input.identity, spaceId: input.spaceId, root: input.root, harnesses,
|
|
@@ -158,11 +158,22 @@ async function scanCodexRollouts(signal) {
|
|
|
158
158
|
codexRolloutIndexCache = { at: Date.now(), home, index };
|
|
159
159
|
return index;
|
|
160
160
|
}
|
|
161
|
+
async function* compressedCodexRolloutBytes(path, signal) {
|
|
162
|
+
const decoder = createZstdDecompress();
|
|
163
|
+
// pipeline keeps error listeners attached, so stopping at a header or prefix cannot crash with an unhandled decoder error.
|
|
164
|
+
const pumping = pipeline(createReadStream(path), decoder, { signal }).catch(() => { });
|
|
165
|
+
try {
|
|
166
|
+
yield* decoder;
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
decoder.destroy();
|
|
170
|
+
await pumping;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
161
173
|
/** Raw JSONL bytes of a rollout, transparently decompressing `.zst` and honoring a lineage cutoff. */
|
|
162
174
|
export async function* codexRolloutBytes(path, endBytes, signal) {
|
|
163
|
-
// compose (not pipe) so a source error propagates and early exit destroys both streams.
|
|
164
175
|
const stream = path.endsWith(".zst")
|
|
165
|
-
?
|
|
176
|
+
? compressedCodexRolloutBytes(path, signal)
|
|
166
177
|
: createReadStream(path, endBytes != null ? { end: endBytes - 1, signal } : { signal });
|
|
167
178
|
let total = 0, last = -1;
|
|
168
179
|
for await (const chunk of stream) {
|
|
@@ -522,9 +533,10 @@ function parseCodexLines(lines, segment) {
|
|
|
522
533
|
calls.get(id)?.content.push({ type: "tool_result", tool_use_id: id, content: typeof payload.output === "string" ? payload.output : JSON.stringify(payload.output ?? null) });
|
|
523
534
|
}
|
|
524
535
|
}
|
|
536
|
+
// Cohub tags a Turn it starts with its own cloud Turn id (`client_id`), so the file itself records
|
|
537
|
+
// which Turns already belong to a cloud Turn and must not be ingested twice. Older Codex writes it
|
|
538
|
+
// on `item_completed`'s UserMessage, newer Codex on `user_message`.
|
|
525
539
|
if (entry.type === "event_msg" && payload.type === "item_completed") {
|
|
526
|
-
// Cohub tags a Turn it starts with its own cloud Turn id, so the file itself records which
|
|
527
|
-
// Turns already belong to a cloud Turn (and must not be ingested twice).
|
|
528
540
|
const item = record(payload.item);
|
|
529
541
|
if (item.type === "UserMessage") {
|
|
530
542
|
const clientId = text(item.client_id);
|
|
@@ -540,6 +552,9 @@ function parseCodexLines(lines, segment) {
|
|
|
540
552
|
}
|
|
541
553
|
}
|
|
542
554
|
if (entry.type === "event_msg" && payload.type === "user_message") {
|
|
555
|
+
const clientId = text(payload.client_id);
|
|
556
|
+
if (clientId)
|
|
557
|
+
current.cloudTurnId = clientId;
|
|
543
558
|
if (!userFromResponse)
|
|
544
559
|
current.userContent = [{ type: "text", text: text(payload.message) }];
|
|
545
560
|
userFromResponse = true;
|
|
@@ -152,11 +152,23 @@ export async function runRuntime(config, onState, externalSignal, onDiagnostic)
|
|
|
152
152
|
});
|
|
153
153
|
bridge.stdin?.on("error", () => undefined);
|
|
154
154
|
const closed = new Promise((resolve) => {
|
|
155
|
+
let drainTimer;
|
|
155
156
|
bridge.once("error", (error) => diagnostics.log("error", "sandboxd.process_error", { error: serializeDiagnosticError(error) }));
|
|
156
|
-
bridge.once("
|
|
157
|
+
bridge.once("exit", (code, exitSignal) => {
|
|
157
158
|
childStopped = true;
|
|
158
159
|
if (!signal.aborted)
|
|
159
160
|
diagnostics.log("warn", "sandboxd.process_exit", { code, signal: exitSignal });
|
|
161
|
+
// Descendants may still hold inherited pipes. After draining buffered
|
|
162
|
+
// output, close only our ends so supervision can continue.
|
|
163
|
+
drainTimer = setTimeout(() => {
|
|
164
|
+
diagnostics.log("warn", "sandboxd.stdio_drain_timeout");
|
|
165
|
+
for (const stream of bridge.stdio)
|
|
166
|
+
stream?.destroy();
|
|
167
|
+
}, 1000);
|
|
168
|
+
});
|
|
169
|
+
bridge.once("close", () => {
|
|
170
|
+
childStopped = true;
|
|
171
|
+
clearTimeout(drainTimer);
|
|
160
172
|
resolve();
|
|
161
173
|
});
|
|
162
174
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neta-art/cohub-cli",
|
|
3
|
-
"version": "10.8.
|
|
3
|
+
"version": "10.8.3",
|
|
4
4
|
"description": "CLI for Cohub — spaces, sessions, and agent collaboration.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"NOTICE"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@neta-art/cohub": "12.1.
|
|
21
|
+
"@neta-art/cohub": "12.1.1",
|
|
22
22
|
"@neta-art/generation": "^0.1.40",
|
|
23
23
|
"commander": "^15.0.0",
|
|
24
24
|
"sharp": "^0.35.4",
|