@surething/cockpit 1.0.270 → 1.0.272
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/.next-prod/BUILD_ID +1 -1
- package/.next-prod/app-path-routes-manifest.json +8 -8
- package/.next-prod/build-manifest.json +2 -2
- package/.next-prod/cockpit-build.json +1 -1
- package/.next-prod/prerender-manifest.json +3 -3
- package/.next-prod/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next-prod/server/app/_global-error.html +1 -1
- package/.next-prod/server/app/_global-error.rsc +1 -1
- package/.next-prod/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next-prod/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next-prod/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next-prod/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next-prod/server/app/_not-found.html +2 -2
- package/.next-prod/server/app/_not-found.rsc +3 -3
- package/.next-prod/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/.next-prod/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/.next-prod/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next-prod/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next-prod/server/app/api/session/[sessionId]/history/route.js +1 -1
- package/.next-prod/server/app/api/session-by-path/route.js +1 -1
- package/.next-prod/server/app/api/terminal/history/route.js +1 -1
- package/.next-prod/server/app/m/page.js +1 -1
- package/.next-prod/server/app/m/page_client-reference-manifest.js +1 -1
- package/.next-prod/server/app/page_client-reference-manifest.js +1 -1
- package/.next-prod/server/app/project/page_client-reference-manifest.js +1 -1
- package/.next-prod/server/app/review/[id]/page.js +1 -1
- package/.next-prod/server/app/review/[id]/page_client-reference-manifest.js +1 -1
- package/.next-prod/server/app-paths-manifest.json +8 -8
- package/.next-prod/server/chunks/516.js +1 -1
- package/.next-prod/server/chunks/5750.js +16 -14
- package/.next-prod/server/chunks/6548.js +1 -1
- package/.next-prod/server/middleware-build-manifest.js +1 -1
- package/.next-prod/server/pages/404.html +2 -2
- package/.next-prod/server/pages/500.html +1 -1
- package/.next-prod/server/server-reference-manifest.json +1 -1
- package/.next-prod/static/chunks/{2302-ebf06ca1396efcce.js → 6024-31a42934bf55e9e9.js} +20 -20
- package/.next-prod/static/chunks/7184-2a5621de437121a2.js +17 -0
- package/.next-prod/static/chunks/{6784-8e0e9ea22ff4a60f.js → 9092-f7267cbb4deb6fd5.js} +2 -2
- package/.next-prod/static/chunks/app/{layout-0782cd43a14c7ee2.js → layout-4d9685b25807b4c6.js} +1 -1
- package/.next-prod/static/chunks/app/m/page-af6600597536f9a9.js +1 -0
- package/.next-prod/static/chunks/app/{page-ca2a81ab87931cdb.js → page-af99426a6c82e466.js} +1 -1
- package/.next-prod/static/chunks/app/project/{page-ca2a81ab87931cdb.js → page-af99426a6c82e466.js} +1 -1
- package/.next-prod/static/chunks/app/review/[id]/{page-556db82704d074ab.js → page-1fe42d46b22c6482.js} +1 -1
- package/.next-prod/static/css/ea27ccfe01ce807c.css +1 -0
- package/.next-prod/trace +14 -14
- package/.next-prod/trace-build +1 -1
- package/bin/cock-browser.mjs +65 -2
- package/dist/{chunk-RZY32R7X.mjs → chunk-4EU4KZIO.mjs} +1 -0
- package/dist/{chunk-WLCT5LHX.mjs → chunk-PB4GBZQO.mjs} +191 -39
- package/dist/{chunk-VAOGZ6SO.mjs → chunk-TOA52B2X.mjs} +1 -1
- package/dist/httpApi.mjs +58 -2
- package/dist/scheduledTasks.mjs +14 -8
- package/dist/wsServer.mjs +3 -3
- package/package.json +3 -3
- package/public/html-lib/markdown.js +56 -56
- package/skills/cc/SKILL.md +26 -1
- package/.next-prod/static/chunks/7184-efdf8613e83ae823.js +0 -15
- package/.next-prod/static/chunks/app/m/page-0304eea2c0cf03f6.js +0 -1
- package/.next-prod/static/css/4e29dd2bca2bb1ac.css +0 -1
- /package/.next-prod/static/{cqNAEj5KI8Y8li81B5f7n → ZqxwSTxy2HJcALhnBemS7}/_buildManifest.js +0 -0
- /package/.next-prod/static/{cqNAEj5KI8Y8li81B5f7n → ZqxwSTxy2HJcALhnBemS7}/_ssgManifest.js +0 -0
package/.next-prod/trace-build
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"name":"run-webpack","duration":
|
|
1
|
+
[{"name":"run-webpack","duration":16432612,"timestamp":243518100,"id":14,"parentId":1,"tags":{},"startTime":1788784539677,"traceId":"a61d8bd9748a4eff"},{"name":"run-typescript","duration":5161102,"timestamp":259975966,"id":1471,"parentId":1,"tags":{},"startTime":1788784556135,"traceId":"a61d8bd9748a4eff"},{"name":"static-check","duration":1368014,"timestamp":265181806,"id":1474,"parentId":1,"tags":{},"startTime":1788784561341,"traceId":"a61d8bd9748a4eff"},{"name":"static-generation","duration":5917610,"timestamp":266672543,"id":1784,"parentId":1,"tags":{},"startTime":1788784562831,"traceId":"a61d8bd9748a4eff"},{"name":"collect-build-traces","duration":25357913,"timestamp":266550538,"id":1781,"parentId":1,"tags":{},"startTime":1788784562709,"traceId":"a61d8bd9748a4eff"},{"name":"telemetry-flush","duration":62,"timestamp":291912488,"id":1793,"parentId":1,"tags":{},"startTime":1788784588071,"traceId":"a61d8bd9748a4eff"},{"name":"next-build","duration":48581077,"timestamp":243331486,"id":1,"tags":{"buildMode":"default","version":"16.3.0","bundler":"webpack","has-custom-webpack-config":"true","use-build-worker":"false"},"startTime":1788784539490,"traceId":"a61d8bd9748a4eff"}]
|
package/bin/cock-browser.mjs
CHANGED
|
@@ -81,6 +81,16 @@ re-snapshot OR use \`click --text\` / \`click --selector\` /
|
|
|
81
81
|
|
|
82
82
|
──────────────────────────────────────────────────────
|
|
83
83
|
|
|
84
|
+
Bubbles (create / destroy — no <id> needed for open):
|
|
85
|
+
cockpit browser open <url> [--cwd PATH] [--wait-ms N]
|
|
86
|
+
Open a console browser bubble in the project that
|
|
87
|
+
owns --cwd (default: shell cwd), auto-register its
|
|
88
|
+
bridge, and print the shortId to drive it with.
|
|
89
|
+
Exit 2 if no Cockpit UI picked it up (bubble is
|
|
90
|
+
persisted, but nothing is driving it yet).
|
|
91
|
+
cockpit browser <id> close [--cwd PATH]
|
|
92
|
+
Close the bubble and remove it from the console.
|
|
93
|
+
|
|
84
94
|
Navigation:
|
|
85
95
|
navigate <url> Navigate to URL
|
|
86
96
|
reload [--noCache] Reload page
|
|
@@ -165,6 +175,13 @@ let id, action;
|
|
|
165
175
|
if (args[0] === 'list') {
|
|
166
176
|
id = null;
|
|
167
177
|
action = 'list';
|
|
178
|
+
} else if (args[0] === 'open') {
|
|
179
|
+
// `open` creates a bubble rather than addressing one, so the first token is
|
|
180
|
+
// the action, not an id. (A shortId is also four lowercase letters, so `open`
|
|
181
|
+
// and `list` are in principle collidable — the same trade-off `list` already
|
|
182
|
+
// makes; a colliding bubble is still reachable via every other action.)
|
|
183
|
+
id = null;
|
|
184
|
+
action = 'open';
|
|
168
185
|
} else {
|
|
169
186
|
id = args[0];
|
|
170
187
|
action = args[1];
|
|
@@ -213,12 +230,13 @@ function parseFlags(flagArgs) {
|
|
|
213
230
|
return params;
|
|
214
231
|
}
|
|
215
232
|
|
|
216
|
-
const params = parseFlags(args.slice(action === 'list' ? 1 : 2));
|
|
233
|
+
const params = parseFlags(args.slice(action === 'list' || action === 'open' ? 1 : 2));
|
|
217
234
|
|
|
218
235
|
// Positional argument handling: some commands treat the first positional as a special value
|
|
219
236
|
if (params._positional?.length) {
|
|
220
237
|
const pos = params._positional;
|
|
221
238
|
if (action === 'navigate' && !params.url) params.url = pos[0];
|
|
239
|
+
if (action === 'open' && !params.url) params.url = pos[0];
|
|
222
240
|
// click: positional is the ref (or text fallback for convenience if it does
|
|
223
241
|
// not look like a ref). Refs match e<N>#v<M>; anything else is treated as
|
|
224
242
|
// visible text so `click "Sign in"` Just Works.
|
|
@@ -276,6 +294,7 @@ if (params['console-no-errors']) { params.consoleNoErrors = true; delete params[
|
|
|
276
294
|
if (params['same-site']) { params.sameSite = params['same-site']; delete params['same-site']; }
|
|
277
295
|
if (params['http-only']) { params.httpOnly = true; delete params['http-only']; }
|
|
278
296
|
if (params['verify-ms'] != null) { params.verifyMs = Number(params['verify-ms']); delete params['verify-ms']; }
|
|
297
|
+
if (params['wait-ms'] != null) { params.waitMs = Number(params['wait-ms']); delete params['wait-ms']; }
|
|
279
298
|
|
|
280
299
|
// kebab → camel for flags that the extension expects camel.
|
|
281
300
|
if (params['include-hidden-text']) { params.includeHiddenText = true; delete params['include-hidden-text']; }
|
|
@@ -301,9 +320,24 @@ if (!process.env.COCKPIT_PORT) {
|
|
|
301
320
|
}
|
|
302
321
|
delete params.port;
|
|
303
322
|
const baseUrl = `http://localhost:${port}`;
|
|
304
|
-
|
|
323
|
+
// `open` blocks server-side until the bubble registers (--wait-ms); the HTTP
|
|
324
|
+
// timeout has to outlast that wait or the CLI aborts a request that was about
|
|
325
|
+
// to succeed.
|
|
326
|
+
const timeout = params.timeout
|
|
327
|
+
|| (action === 'open' && params.waitMs > 10000 ? params.waitMs + 5000 : 15000);
|
|
305
328
|
delete params.timeout;
|
|
306
329
|
|
|
330
|
+
// The CLI name to suggest in output: dev server (3456) is only reachable via
|
|
331
|
+
// `cockpit-dev`, which has no short alias.
|
|
332
|
+
const cockBin = String(port) === '3456' ? 'cockpit-dev' : 'cockpit';
|
|
333
|
+
|
|
334
|
+
// `open` / `close` address a project on disk rather than a live page, so they
|
|
335
|
+
// need a cwd. Default to where the shell is standing; the server walks up from
|
|
336
|
+
// there to the project that actually owns the console.
|
|
337
|
+
if ((action === 'open' || action === 'close') && !params.cwd) {
|
|
338
|
+
params.cwd = process.cwd();
|
|
339
|
+
}
|
|
340
|
+
|
|
307
341
|
// Quickly fetch browser url and title (2s timeout, silently return empty on failure)
|
|
308
342
|
async function fetchBrowserInfo(shortId) {
|
|
309
343
|
try {
|
|
@@ -665,6 +699,35 @@ async function formatOutput(action, data) {
|
|
|
665
699
|
|
|
666
700
|
// Special formatting
|
|
667
701
|
switch (action) {
|
|
702
|
+
case 'open':
|
|
703
|
+
console.log(
|
|
704
|
+
data.registered
|
|
705
|
+
? `${data.shortId} → registered and ready`
|
|
706
|
+
: `${data.shortId} → created, but NOT registered`
|
|
707
|
+
);
|
|
708
|
+
console.log(` url: ${data.url}`);
|
|
709
|
+
console.log(` project: ${data.projectCwd}`);
|
|
710
|
+
if (data.registered) {
|
|
711
|
+
console.log(` next: ${cockBin} browser ${data.shortId} snapshot`);
|
|
712
|
+
console.log(` close: ${cockBin} browser ${data.shortId} close`);
|
|
713
|
+
} else {
|
|
714
|
+
console.log(
|
|
715
|
+
`\n No Cockpit UI applied the bubble, so nothing is driving it.\n` +
|
|
716
|
+
` The entry is persisted — it will appear when this project is next\n` +
|
|
717
|
+
` opened in Cockpit. Open the project (or check --cwd) and retry.`
|
|
718
|
+
);
|
|
719
|
+
process.exit(2);
|
|
720
|
+
}
|
|
721
|
+
return;
|
|
722
|
+
|
|
723
|
+
case 'close':
|
|
724
|
+
console.log(
|
|
725
|
+
data.removed
|
|
726
|
+
? `closed ${data.shortId}`
|
|
727
|
+
: `closed ${data.shortId} (no persisted entry — nothing to remove)`
|
|
728
|
+
);
|
|
729
|
+
return;
|
|
730
|
+
|
|
668
731
|
case 'snapshot':
|
|
669
732
|
// a11y tree: output as plain text
|
|
670
733
|
console.log(typeof data === 'string' ? data : JSON.stringify(data, null, 2));
|
|
@@ -30851,6 +30851,7 @@ export {
|
|
|
30851
30851
|
DEEPSEEK_CREDENTIALS_FILE,
|
|
30852
30852
|
KIMI_CREDENTIALS_FILE,
|
|
30853
30853
|
GLM_CREDENTIALS_FILE,
|
|
30854
|
+
getCockpitProjectDir,
|
|
30854
30855
|
getSessionFilePath,
|
|
30855
30856
|
getTerminalHistoryPath,
|
|
30856
30857
|
getTerminalOutputPath,
|
|
@@ -9,11 +9,12 @@ import {
|
|
|
9
9
|
ensureParentDir,
|
|
10
10
|
errorToStatus,
|
|
11
11
|
getBubbleOrderPath,
|
|
12
|
+
getCockpitProjectDir,
|
|
12
13
|
getTerminalHistoryPath,
|
|
13
14
|
getTerminalOutputPath,
|
|
14
15
|
readJsonFile,
|
|
15
16
|
writeJsonFile
|
|
16
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-4EU4KZIO.mjs";
|
|
17
18
|
|
|
18
19
|
// packages/feature/console/src/server/plugins/browser/BrowserBridge.ts
|
|
19
20
|
import { WebSocket } from "ws";
|
|
@@ -75,13 +76,13 @@ function listBrowsers() {
|
|
|
75
76
|
}
|
|
76
77
|
var pendingRequests = g_browser.__cockpitBrowserPending ?? (g_browser.__cockpitBrowserPending = /* @__PURE__ */ new Map());
|
|
77
78
|
function createPendingRequest(reqId, timeout) {
|
|
78
|
-
return new Promise((
|
|
79
|
+
return new Promise((resolve2, reject) => {
|
|
79
80
|
const timer = setTimeout(() => {
|
|
80
81
|
pendingRequests.delete(reqId);
|
|
81
82
|
recordCommandResolved(reqId, false);
|
|
82
83
|
reject(new Error(`Timeout after ${timeout}ms`));
|
|
83
84
|
}, timeout);
|
|
84
|
-
pendingRequests.set(reqId, { resolve, reject, timer });
|
|
85
|
+
pendingRequests.set(reqId, { resolve: resolve2, reject, timer });
|
|
85
86
|
});
|
|
86
87
|
}
|
|
87
88
|
function resolvePendingRequest(reqId, ok2, data, error) {
|
|
@@ -154,6 +155,177 @@ function getBrowserHealth(shortId) {
|
|
|
154
155
|
};
|
|
155
156
|
}
|
|
156
157
|
|
|
158
|
+
// packages/feature/console/src/server/plugins/browser/browserBubbleControl.ts
|
|
159
|
+
import { existsSync } from "fs";
|
|
160
|
+
import { dirname, resolve } from "path";
|
|
161
|
+
|
|
162
|
+
// packages/feature/console/src/server/terminal/historyStore.ts
|
|
163
|
+
import fs from "fs/promises";
|
|
164
|
+
var OUTPUT_FILE_THRESHOLD = 4096;
|
|
165
|
+
var MAX_ENTRIES = 100;
|
|
166
|
+
async function appendHistoryEntry(cwd, tabId, entry) {
|
|
167
|
+
const historyPath = getTerminalHistoryPath(cwd, tabId);
|
|
168
|
+
await ensureParentDir(historyPath);
|
|
169
|
+
const entryToSave = { ...entry };
|
|
170
|
+
if (entry.output && entry.output.length > OUTPUT_FILE_THRESHOLD) {
|
|
171
|
+
const outputPath = getTerminalOutputPath(cwd, entry.id);
|
|
172
|
+
await fs.writeFile(outputPath, entry.output, "utf-8");
|
|
173
|
+
entryToSave.output = "";
|
|
174
|
+
entryToSave.outputFile = outputPath;
|
|
175
|
+
}
|
|
176
|
+
let existingLines = [];
|
|
177
|
+
try {
|
|
178
|
+
const content = await fs.readFile(historyPath, "utf-8");
|
|
179
|
+
existingLines = content.trim().split("\n").filter(Boolean);
|
|
180
|
+
} catch {
|
|
181
|
+
}
|
|
182
|
+
if (entry.id) {
|
|
183
|
+
const alreadyExists = existingLines.some((line) => {
|
|
184
|
+
try {
|
|
185
|
+
return JSON.parse(line).id === entry.id;
|
|
186
|
+
} catch {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
if (alreadyExists) return { success: true, skipped: true };
|
|
191
|
+
}
|
|
192
|
+
if (existingLines.length >= MAX_ENTRIES) {
|
|
193
|
+
const removedLines = existingLines.slice(
|
|
194
|
+
0,
|
|
195
|
+
existingLines.length - (MAX_ENTRIES - 1)
|
|
196
|
+
);
|
|
197
|
+
for (const line of removedLines) {
|
|
198
|
+
try {
|
|
199
|
+
const old = JSON.parse(line);
|
|
200
|
+
if (old.outputFile) await fs.unlink(old.outputFile).catch(() => {
|
|
201
|
+
});
|
|
202
|
+
} catch {
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
existingLines = existingLines.slice(-(MAX_ENTRIES - 1));
|
|
206
|
+
}
|
|
207
|
+
existingLines.push(JSON.stringify(entryToSave));
|
|
208
|
+
await fs.writeFile(historyPath, existingLines.join("\n") + "\n", "utf-8");
|
|
209
|
+
return { success: true };
|
|
210
|
+
}
|
|
211
|
+
async function removeHistoryEntry(cwd, tabId, id, onMatch) {
|
|
212
|
+
const historyPath = getTerminalHistoryPath(cwd, tabId);
|
|
213
|
+
let removed = null;
|
|
214
|
+
try {
|
|
215
|
+
const content = await fs.readFile(historyPath, "utf-8");
|
|
216
|
+
const lines = content.trim().split("\n").filter(Boolean);
|
|
217
|
+
const remaining = [];
|
|
218
|
+
for (const line of lines) {
|
|
219
|
+
try {
|
|
220
|
+
const entry = JSON.parse(line);
|
|
221
|
+
if (entry.id === id) {
|
|
222
|
+
removed = entry;
|
|
223
|
+
if (onMatch) await onMatch(entry);
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
} catch {
|
|
227
|
+
}
|
|
228
|
+
remaining.push(line);
|
|
229
|
+
}
|
|
230
|
+
if (remaining.length > 0) {
|
|
231
|
+
await fs.writeFile(historyPath, remaining.join("\n") + "\n", "utf-8");
|
|
232
|
+
} else {
|
|
233
|
+
await fs.unlink(historyPath).catch(() => {
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
} catch (e) {
|
|
237
|
+
if (e.code !== "ENOENT") throw e;
|
|
238
|
+
}
|
|
239
|
+
return removed;
|
|
240
|
+
}
|
|
241
|
+
async function readHistoryEntries(cwd, tabId) {
|
|
242
|
+
const historyPath = getTerminalHistoryPath(cwd, tabId);
|
|
243
|
+
try {
|
|
244
|
+
const content = await fs.readFile(historyPath, "utf-8");
|
|
245
|
+
return content.trim().split("\n").filter(Boolean).flatMap((line) => {
|
|
246
|
+
try {
|
|
247
|
+
return [JSON.parse(line)];
|
|
248
|
+
} catch {
|
|
249
|
+
return [];
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
} catch {
|
|
253
|
+
return [];
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// packages/feature/console/src/server/terminal/consoleBroadcast.ts
|
|
258
|
+
var WS_OPEN = 1;
|
|
259
|
+
var g = globalThis;
|
|
260
|
+
function broadcastConsoleDelta(cwd, tabId, delta, sourceId) {
|
|
261
|
+
const set = g.__cockpitGlobalStateClients;
|
|
262
|
+
if (!set || set.size === 0) return;
|
|
263
|
+
const data = JSON.stringify({
|
|
264
|
+
type: "console-delta",
|
|
265
|
+
cwd,
|
|
266
|
+
tabId,
|
|
267
|
+
sourceId,
|
|
268
|
+
...delta
|
|
269
|
+
});
|
|
270
|
+
for (const ws of set) {
|
|
271
|
+
if (ws.readyState === WS_OPEN) {
|
|
272
|
+
try {
|
|
273
|
+
ws.send(data);
|
|
274
|
+
} catch {
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// packages/feature/console/src/server/plugins/browser/browserBubbleControl.ts
|
|
281
|
+
var CONSOLE_TAB_ID = "default";
|
|
282
|
+
function resolveProjectCwd(cwd) {
|
|
283
|
+
const start = resolve(cwd);
|
|
284
|
+
let dir = start;
|
|
285
|
+
for (; ; ) {
|
|
286
|
+
if (existsSync(getCockpitProjectDir(dir))) return dir;
|
|
287
|
+
const parent = dirname(dir);
|
|
288
|
+
if (parent === dir) return start;
|
|
289
|
+
dir = parent;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
async function openBrowserBubble(opts) {
|
|
293
|
+
const projectCwd = resolveProjectCwd(opts.cwd);
|
|
294
|
+
const tabId = opts.tabId ?? CONSOLE_TAB_ID;
|
|
295
|
+
const fullId = `browser-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
296
|
+
const entry = {
|
|
297
|
+
type: "browser",
|
|
298
|
+
id: fullId,
|
|
299
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
300
|
+
url: opts.url,
|
|
301
|
+
// Base for a RELATIVE url. Deliberately the caller's raw cwd, not
|
|
302
|
+
// projectCwd: `cockpit browser open ./report.html` should resolve against
|
|
303
|
+
// the directory the user is standing in, mirroring what typing the same
|
|
304
|
+
// path into the console after a `cd` does.
|
|
305
|
+
cwd: resolve(opts.cwd),
|
|
306
|
+
autoConnect: true
|
|
307
|
+
};
|
|
308
|
+
await appendHistoryEntry(projectCwd, tabId, entry);
|
|
309
|
+
broadcastConsoleDelta(projectCwd, tabId, { op: "add", entry });
|
|
310
|
+
return { fullId, shortId: toShortId(fullId), projectCwd, tabId };
|
|
311
|
+
}
|
|
312
|
+
async function closeBrowserBubble(opts) {
|
|
313
|
+
const tabId = opts.tabId ?? CONSOLE_TAB_ID;
|
|
314
|
+
const removed = await removeHistoryEntry(opts.projectCwd, tabId, opts.fullId);
|
|
315
|
+
broadcastConsoleDelta(opts.projectCwd, tabId, {
|
|
316
|
+
op: "delete",
|
|
317
|
+
id: opts.fullId
|
|
318
|
+
});
|
|
319
|
+
return !!removed;
|
|
320
|
+
}
|
|
321
|
+
async function findBrowserBubbleByShortId(projectCwd, shortId, tabId = CONSOLE_TAB_ID) {
|
|
322
|
+
const entries = await readHistoryEntries(projectCwd, tabId);
|
|
323
|
+
for (const e of entries) {
|
|
324
|
+
if (e.type === "browser" && e.id && toShortId(e.id) === shortId) return e.id;
|
|
325
|
+
}
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
|
|
157
329
|
// packages/feature/console/src/server/terminal/TerminalBridge.ts
|
|
158
330
|
var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("terminal_bridge_registry");
|
|
159
331
|
var REVERSE_KEY = /* @__PURE__ */ Symbol.for("terminal_bridge_reverse");
|
|
@@ -257,36 +429,11 @@ function notifyExitListeners(commandId, exitCode) {
|
|
|
257
429
|
}
|
|
258
430
|
|
|
259
431
|
// packages/feature/console/src/server/terminal/RunningCommandRegistry.ts
|
|
260
|
-
import
|
|
432
|
+
import fs2 from "fs/promises";
|
|
261
433
|
import { writeFileSync, mkdirSync } from "fs";
|
|
262
|
-
import { dirname } from "path";
|
|
263
|
-
|
|
264
|
-
// packages/feature/console/src/server/terminal/consoleBroadcast.ts
|
|
265
|
-
var WS_OPEN = 1;
|
|
266
|
-
var g = globalThis;
|
|
267
|
-
function broadcastConsoleDelta(cwd, tabId, delta, sourceId) {
|
|
268
|
-
const set = g.__cockpitGlobalStateClients;
|
|
269
|
-
if (!set || set.size === 0) return;
|
|
270
|
-
const data = JSON.stringify({
|
|
271
|
-
type: "console-delta",
|
|
272
|
-
cwd,
|
|
273
|
-
tabId,
|
|
274
|
-
sourceId,
|
|
275
|
-
...delta
|
|
276
|
-
});
|
|
277
|
-
for (const ws of set) {
|
|
278
|
-
if (ws.readyState === WS_OPEN) {
|
|
279
|
-
try {
|
|
280
|
-
ws.send(data);
|
|
281
|
-
} catch {
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// packages/feature/console/src/server/terminal/RunningCommandRegistry.ts
|
|
434
|
+
import { dirname as dirname2 } from "path";
|
|
288
435
|
var MAX_OUTPUT_LINES = 5e3;
|
|
289
|
-
var
|
|
436
|
+
var OUTPUT_FILE_THRESHOLD2 = 4096;
|
|
290
437
|
var PTY_RING_BUFFER_MAX = 2 * 1024 * 1024;
|
|
291
438
|
function countNewlines(s) {
|
|
292
439
|
let n = 0;
|
|
@@ -497,7 +644,7 @@ async function writeHistoryPlaceholder(commandId, command, timestamp, cwd, proje
|
|
|
497
644
|
};
|
|
498
645
|
let existingLines = [];
|
|
499
646
|
try {
|
|
500
|
-
const content = await
|
|
647
|
+
const content = await fs2.readFile(historyPath, "utf-8");
|
|
501
648
|
existingLines = content.trim().split("\n").filter(Boolean);
|
|
502
649
|
} catch {
|
|
503
650
|
}
|
|
@@ -518,7 +665,7 @@ async function writeHistoryPlaceholder(commandId, command, timestamp, cwd, proje
|
|
|
518
665
|
for (const line of removedLines) {
|
|
519
666
|
try {
|
|
520
667
|
const old = JSON.parse(line);
|
|
521
|
-
if (old.outputFile) await
|
|
668
|
+
if (old.outputFile) await fs2.unlink(old.outputFile).catch(() => {
|
|
522
669
|
});
|
|
523
670
|
} catch {
|
|
524
671
|
}
|
|
@@ -527,7 +674,7 @@ async function writeHistoryPlaceholder(commandId, command, timestamp, cwd, proje
|
|
|
527
674
|
}
|
|
528
675
|
existingLines.push(JSON.stringify(entry));
|
|
529
676
|
}
|
|
530
|
-
await
|
|
677
|
+
await fs2.writeFile(historyPath, existingLines.join("\n") + "\n", "utf-8");
|
|
531
678
|
broadcastConsoleDelta(
|
|
532
679
|
projectCwd,
|
|
533
680
|
tabId,
|
|
@@ -562,16 +709,16 @@ async function finalizeCommand(commandId, exitCode, pid) {
|
|
|
562
709
|
};
|
|
563
710
|
const historyPath = getTerminalHistoryPath(cmd.projectCwd, cmd.tabId);
|
|
564
711
|
await ensureParentDir(historyPath);
|
|
565
|
-
if (output.length >
|
|
712
|
+
if (output.length > OUTPUT_FILE_THRESHOLD2) {
|
|
566
713
|
const outputPath = getTerminalOutputPath(cmd.projectCwd, cmd.commandId);
|
|
567
|
-
await
|
|
714
|
+
await fs2.writeFile(outputPath, output, "utf-8");
|
|
568
715
|
entry.outputFile = outputPath;
|
|
569
716
|
} else {
|
|
570
717
|
entry.output = output;
|
|
571
718
|
}
|
|
572
719
|
let existingLines = [];
|
|
573
720
|
try {
|
|
574
|
-
const content = await
|
|
721
|
+
const content = await fs2.readFile(historyPath, "utf-8");
|
|
575
722
|
existingLines = content.trim().split("\n").filter(Boolean);
|
|
576
723
|
} catch {
|
|
577
724
|
}
|
|
@@ -589,7 +736,7 @@ async function finalizeCommand(commandId, exitCode, pid) {
|
|
|
589
736
|
if (!replaced) {
|
|
590
737
|
existingLines.push(JSON.stringify(entry));
|
|
591
738
|
}
|
|
592
|
-
await
|
|
739
|
+
await fs2.writeFile(historyPath, existingLines.join("\n") + "\n", "utf-8");
|
|
593
740
|
broadcastConsoleDelta(cmd.projectCwd, cmd.tabId, {
|
|
594
741
|
op: "update",
|
|
595
742
|
id: cmd.commandId,
|
|
@@ -603,7 +750,7 @@ function flushAllRunningSync() {
|
|
|
603
750
|
if (!buf || buf.length === 0) continue;
|
|
604
751
|
try {
|
|
605
752
|
const outputPath = getTerminalOutputPath(cmd.projectCwd, cmd.commandId);
|
|
606
|
-
mkdirSync(
|
|
753
|
+
mkdirSync(dirname2(outputPath), { recursive: true });
|
|
607
754
|
writeFileSync(outputPath, buf.snapshot(), "utf-8");
|
|
608
755
|
} catch {
|
|
609
756
|
}
|
|
@@ -973,6 +1120,11 @@ export {
|
|
|
973
1120
|
resolvePendingRequest,
|
|
974
1121
|
sendCommandToBrowser,
|
|
975
1122
|
getBrowserHealth,
|
|
1123
|
+
CONSOLE_TAB_ID,
|
|
1124
|
+
resolveProjectCwd,
|
|
1125
|
+
openBrowserBubble,
|
|
1126
|
+
closeBrowserBubble,
|
|
1127
|
+
findBrowserBubbleByShortId,
|
|
976
1128
|
registerTerminal,
|
|
977
1129
|
unregisterTerminal,
|
|
978
1130
|
getTerminalByShortId,
|
package/dist/httpApi.mjs
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
+
CONSOLE_TAB_ID,
|
|
2
3
|
addExitListener,
|
|
3
4
|
addOutputListener,
|
|
5
|
+
closeBrowserBubble,
|
|
4
6
|
createPendingRequest,
|
|
7
|
+
findBrowserBubbleByShortId,
|
|
5
8
|
flushAllRunningSync,
|
|
6
9
|
getBrowserByShortId,
|
|
7
10
|
getBrowserHealth,
|
|
@@ -11,21 +14,23 @@ import {
|
|
|
11
14
|
grepOutput,
|
|
12
15
|
listBrowsers,
|
|
13
16
|
listTerminals,
|
|
17
|
+
openBrowserBubble,
|
|
14
18
|
readAround,
|
|
15
19
|
readBubbleTitles,
|
|
16
20
|
readHead,
|
|
17
21
|
readSince,
|
|
18
22
|
readTail,
|
|
19
23
|
registerTerminal,
|
|
24
|
+
resolveProjectCwd,
|
|
20
25
|
sendCommandToBrowser,
|
|
21
26
|
stripAnsi,
|
|
22
27
|
unregisterBrowser,
|
|
23
28
|
unregisterTerminal,
|
|
24
29
|
writeStdinToCommand
|
|
25
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-PB4GBZQO.mjs";
|
|
26
31
|
import {
|
|
27
32
|
getTerminalHistoryPath
|
|
28
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-4EU4KZIO.mjs";
|
|
29
34
|
import "./chunk-7P6ASYW6.mjs";
|
|
30
35
|
|
|
31
36
|
// src/lib/httpApi.ts
|
|
@@ -378,6 +383,29 @@ async function handleBrowserApi(req, res) {
|
|
|
378
383
|
sendJson(200, { ok: true, data: listBrowsers() });
|
|
379
384
|
return true;
|
|
380
385
|
}
|
|
386
|
+
if (action === "open") {
|
|
387
|
+
const p = cmdParams;
|
|
388
|
+
const url = typeof p.url === "string" ? p.url.trim() : "";
|
|
389
|
+
if (!url) {
|
|
390
|
+
sendJson(400, { ok: false, error: "Missing url" });
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
393
|
+
const cwd = typeof p.cwd === "string" && p.cwd ? p.cwd : process.cwd();
|
|
394
|
+
const waitMs = typeof p.waitMs === "number" ? p.waitMs : 8e3;
|
|
395
|
+
try {
|
|
396
|
+
const opened = await openBrowserBubble({ cwd, url });
|
|
397
|
+
const deadline = Date.now() + Math.max(0, waitMs);
|
|
398
|
+
let registered = !!getBrowserByShortId(opened.shortId);
|
|
399
|
+
while (!registered && Date.now() < deadline) {
|
|
400
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
401
|
+
registered = !!getBrowserByShortId(opened.shortId);
|
|
402
|
+
}
|
|
403
|
+
sendJson(200, { ok: true, data: { ...opened, url, registered } });
|
|
404
|
+
} catch (err) {
|
|
405
|
+
sendJson(500, { ok: false, error: err.message });
|
|
406
|
+
}
|
|
407
|
+
return true;
|
|
408
|
+
}
|
|
381
409
|
if (action === "unregister") {
|
|
382
410
|
if (!id) {
|
|
383
411
|
sendJson(400, { ok: false, error: "Missing browser id" });
|
|
@@ -405,6 +433,34 @@ async function handleBrowserApi(req, res) {
|
|
|
405
433
|
sendJson(400, { ok: false, error: "Missing browser id" });
|
|
406
434
|
return true;
|
|
407
435
|
}
|
|
436
|
+
if (action === "close") {
|
|
437
|
+
const p = cmdParams;
|
|
438
|
+
const known = getBrowserByShortId(id);
|
|
439
|
+
let projectCwd = known?.projectCwd;
|
|
440
|
+
let tabId = known?.tabId;
|
|
441
|
+
let fullId = known?.fullId ?? null;
|
|
442
|
+
if (!fullId || !projectCwd) {
|
|
443
|
+
const cwd = typeof p.cwd === "string" && p.cwd ? p.cwd : process.cwd();
|
|
444
|
+
projectCwd = resolveProjectCwd(cwd);
|
|
445
|
+
tabId = tabId ?? CONSOLE_TAB_ID;
|
|
446
|
+
fullId = await findBrowserBubbleByShortId(projectCwd, id, tabId);
|
|
447
|
+
}
|
|
448
|
+
if (!fullId || !projectCwd) {
|
|
449
|
+
sendJson(404, {
|
|
450
|
+
ok: false,
|
|
451
|
+
error: `No browser bubble "${id}" found in this project.
|
|
452
|
+
Pass --cwd if you are not standing in the project that owns it.`
|
|
453
|
+
});
|
|
454
|
+
return true;
|
|
455
|
+
}
|
|
456
|
+
try {
|
|
457
|
+
const removed = await closeBrowserBubble({ projectCwd, tabId, fullId });
|
|
458
|
+
sendJson(200, { ok: true, data: { shortId: id, fullId, removed } });
|
|
459
|
+
} catch (err) {
|
|
460
|
+
sendJson(500, { ok: false, error: err.message });
|
|
461
|
+
}
|
|
462
|
+
return true;
|
|
463
|
+
}
|
|
408
464
|
const browser = getBrowserByShortId(id);
|
|
409
465
|
if (!browser) {
|
|
410
466
|
const all = listBrowsers().map((b) => b.shortId);
|
package/dist/scheduledTasks.mjs
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
stashCodexRollout,
|
|
16
16
|
stashTranscript,
|
|
17
17
|
updateGlobalState
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-TOA52B2X.mjs";
|
|
19
19
|
import {
|
|
20
20
|
AgentError,
|
|
21
21
|
AppRuntime,
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
settlePendingRecord,
|
|
47
47
|
withFileLock,
|
|
48
48
|
writeJsonFile
|
|
49
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-4EU4KZIO.mjs";
|
|
50
50
|
import {
|
|
51
51
|
__export
|
|
52
52
|
} from "./chunk-7P6ASYW6.mjs";
|
|
@@ -15451,6 +15451,7 @@ var CODEX_MCP_NAMESPACE_PREFIX = "mcp__";
|
|
|
15451
15451
|
var codexMcpToolName = (server, tool2) => `${CODEX_MCP_NAMESPACE_PREFIX}${server}__${tool2}`;
|
|
15452
15452
|
var CODEX_SPAWN_FN_NAME = "spawn_agent";
|
|
15453
15453
|
var CODEX_SUB_AGENT_ACTIVITY_TYPE = "sub_agent_activity";
|
|
15454
|
+
var CODEX_SUB_AGENT_ACTIVITY_ITEM_TYPE = "SubAgentActivity";
|
|
15454
15455
|
var CODEX_AGENT_MESSAGE_TYPE = "agent_message";
|
|
15455
15456
|
var CODEX_PATCH_FN_NAME = "apply_patch";
|
|
15456
15457
|
var CODEX_EXEC_SCRIPT_FN_NAME = "exec";
|
|
@@ -15687,15 +15688,18 @@ function codexAgentPathName(agentPath) {
|
|
|
15687
15688
|
return segments[segments.length - 1] || agentPath;
|
|
15688
15689
|
}
|
|
15689
15690
|
function parseCodexSubAgentActivity(payload) {
|
|
15690
|
-
if (!payload
|
|
15691
|
-
const
|
|
15691
|
+
if (!payload) return null;
|
|
15692
|
+
const item = payload.item;
|
|
15693
|
+
const src = payload.type === CODEX_SUB_AGENT_ACTIVITY_TYPE ? { ...payload, callId: payload.event_id } : item && item.type === CODEX_SUB_AGENT_ACTIVITY_ITEM_TYPE ? { ...item, callId: item.id } : null;
|
|
15694
|
+
if (!src) return null;
|
|
15695
|
+
const { callId, agent_thread_id: agentThreadId } = src;
|
|
15692
15696
|
if (typeof callId !== "string" || !callId) return null;
|
|
15693
15697
|
if (typeof agentThreadId !== "string" || !agentThreadId) return null;
|
|
15694
15698
|
return {
|
|
15695
15699
|
callId,
|
|
15696
15700
|
agentThreadId,
|
|
15697
|
-
...typeof
|
|
15698
|
-
...typeof
|
|
15701
|
+
...typeof src.agent_path === "string" ? { agentPath: src.agent_path } : {},
|
|
15702
|
+
...typeof src.kind === "string" ? { kind: src.kind } : {}
|
|
15699
15703
|
};
|
|
15700
15704
|
}
|
|
15701
15705
|
function parseCodexAgentMessage(payload) {
|
|
@@ -17503,7 +17507,8 @@ var en_default2 = {
|
|
|
17503
17507
|
hidden: "{{count}} lines hidden",
|
|
17504
17508
|
more: "\xB7\xB7\xB7 more +{{count}} \xB7\xB7\xB7",
|
|
17505
17509
|
expandUp: "Expand {{count}} lines up",
|
|
17506
|
-
expandDown: "Expand {{count}} lines down"
|
|
17510
|
+
expandDown: "Expand {{count}} lines down",
|
|
17511
|
+
expandAll: "Click to expand {{count}} lines"
|
|
17507
17512
|
},
|
|
17508
17513
|
loadingSnapshots: "Loading snapshots\u2026",
|
|
17509
17514
|
noChanges: "No file changes detected in this turn",
|
|
@@ -18768,7 +18773,8 @@ var zh_default = {
|
|
|
18768
18773
|
hidden: "\u5DF2\u9690\u85CF {{count}} \u884C",
|
|
18769
18774
|
more: "\xB7\xB7\xB7 \u66F4\u591A +{{count}} \xB7\xB7\xB7",
|
|
18770
18775
|
expandUp: "\u5411\u4E0A\u5C55\u5F00 {{count}} \u884C",
|
|
18771
|
-
expandDown: "\u5411\u4E0B\u5C55\u5F00 {{count}} \u884C"
|
|
18776
|
+
expandDown: "\u5411\u4E0B\u5C55\u5F00 {{count}} \u884C",
|
|
18777
|
+
expandAll: "\u70B9\u51FB\u5C55\u5F00 {{count}} \u884C"
|
|
18772
18778
|
},
|
|
18773
18779
|
loadingSnapshots: "\u6B63\u5728\u52A0\u8F7D\u5FEB\u7167\u2026",
|
|
18774
18780
|
noChanges: "\u672C\u8F6E\u672A\u68C0\u6D4B\u5230\u6587\u4EF6\u53D8\u66F4",
|
package/dist/wsServer.mjs
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
resolvePendingRequest,
|
|
14
14
|
unregisterBrowser,
|
|
15
15
|
writeStdinToCommand
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-PB4GBZQO.mjs";
|
|
17
17
|
import {
|
|
18
18
|
addRunListener,
|
|
19
19
|
getGlobalSessionsSnapshot,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
recoverStashedCodexRollouts,
|
|
22
22
|
recoverStashedTranscripts,
|
|
23
23
|
sanitizedSpawnEnv
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-TOA52B2X.mjs";
|
|
25
25
|
import {
|
|
26
26
|
Effect_exports,
|
|
27
27
|
FSError,
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
Stream_exports,
|
|
36
36
|
ValidationError,
|
|
37
37
|
WSError
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-4EU4KZIO.mjs";
|
|
39
39
|
import "./chunk-7P6ASYW6.mjs";
|
|
40
40
|
|
|
41
41
|
// src/lib/wsServer.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@surething/cockpit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.272",
|
|
4
4
|
"description": "OpenCockpit is the open-source Claude Code GUI — an IDE-like workbench for parallel AI coding. Drive Claude (default), Codex, DeepSeek, Kimi, or local Ollama in tabs. Terminal, browser & DB bubbles, code review. Self-host on a shared dev box — a seat for every teammate. Local-first, MIT.",
|
|
5
5
|
"author": "Robert",
|
|
6
6
|
"license": "MIT",
|
|
@@ -104,9 +104,9 @@
|
|
|
104
104
|
},
|
|
105
105
|
"dependencies": {
|
|
106
106
|
"@ai-sdk/openai": "^3.0.52",
|
|
107
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.
|
|
107
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.260",
|
|
108
108
|
"@dagrejs/dagre": "^3.0.0",
|
|
109
|
-
"@openai/codex-sdk": "0.153.
|
|
109
|
+
"@openai/codex-sdk": "0.153.2",
|
|
110
110
|
"@tanstack/react-virtual": "^3.13.18",
|
|
111
111
|
"@tiptap/extension-link": "^3.19.0",
|
|
112
112
|
"@tiptap/extension-placeholder": "^3.19.0",
|