@surething/cockpit 1.0.216 → 1.0.218

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.
Files changed (75) hide show
  1. package/.next-prod/BUILD_ID +1 -1
  2. package/.next-prod/app-path-routes-manifest.json +2 -2
  3. package/.next-prod/build-manifest.json +2 -2
  4. package/.next-prod/prerender-manifest.json +3 -3
  5. package/.next-prod/server/app/_global-error/page_client-reference-manifest.js +1 -1
  6. package/.next-prod/server/app/_global-error.html +1 -1
  7. package/.next-prod/server/app/_global-error.rsc +1 -1
  8. package/.next-prod/server/app/_global-error.segments/_full.segment.rsc +1 -1
  9. package/.next-prod/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  10. package/.next-prod/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  11. package/.next-prod/server/app/_global-error.segments/_head.segment.rsc +1 -1
  12. package/.next-prod/server/app/_global-error.segments/_index.segment.rsc +1 -1
  13. package/.next-prod/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next-prod/server/app/_not-found/page_client-reference-manifest.js +1 -1
  15. package/.next-prod/server/app/_not-found.html +1 -1
  16. package/.next-prod/server/app/_not-found.rsc +3 -3
  17. package/.next-prod/server/app/_not-found.segments/_full.segment.rsc +3 -3
  18. package/.next-prod/server/app/_not-found.segments/_head.segment.rsc +1 -1
  19. package/.next-prod/server/app/_not-found.segments/_index.segment.rsc +3 -3
  20. package/.next-prod/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  21. package/.next-prod/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  22. package/.next-prod/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next-prod/server/app/api/chat/deepseek/route.js +1 -1
  24. package/.next-prod/server/app/api/chat/route.js +1 -1
  25. package/.next-prod/server/app/api/extension/version/route.js.nft.json +1 -1
  26. package/.next-prod/server/app/api/projectGraph/file-functions/route.js +1 -1
  27. package/.next-prod/server/app/api/scheduled-tasks/route.js +1 -1
  28. package/.next-prod/server/app/api/terminal/bubble-order/route.js +1 -1
  29. package/.next-prod/server/app/page_client-reference-manifest.js +1 -1
  30. package/.next-prod/server/app/project/page_client-reference-manifest.js +1 -1
  31. package/.next-prod/server/app/review/[id]/page_client-reference-manifest.js +1 -1
  32. package/.next-prod/server/app-paths-manifest.json +2 -2
  33. package/.next-prod/server/chunks/2939.js +1 -1
  34. package/.next-prod/server/chunks/8916.js +1 -1
  35. package/.next-prod/server/chunks/9658.js +7 -7
  36. package/.next-prod/server/chunks/9877.js +1 -1
  37. package/.next-prod/server/functions-config-manifest.json +1 -0
  38. package/.next-prod/server/middleware-build-manifest.js +1 -1
  39. package/.next-prod/server/pages/404.html +1 -1
  40. package/.next-prod/server/pages/500.html +1 -1
  41. package/.next-prod/server/server-reference-manifest.json +1 -1
  42. package/.next-prod/static/chunks/6345-2637497e8b101740.js +14 -0
  43. package/.next-prod/static/chunks/6917-ed0e9c62a123d529.js +29 -0
  44. package/.next-prod/static/chunks/app/{layout-a0362651ba6e6e6f.js → layout-1659a95e6c4a6bb5.js} +1 -1
  45. package/.next-prod/static/chunks/app/{page-1b14cabf47df9ff7.js → page-afcbd897b4c3600f.js} +1 -1
  46. package/.next-prod/static/chunks/app/project/{page-1b14cabf47df9ff7.js → page-afcbd897b4c3600f.js} +1 -1
  47. package/.next-prod/static/css/f4a773117ca8af75.css +1 -0
  48. package/.next-prod/trace +13 -13
  49. package/.next-prod/trace-build +1 -1
  50. package/README.md +8 -7
  51. package/README.zh.md +8 -7
  52. package/bin/cock-browser.messages.mjs +176 -0
  53. package/bin/cock-browser.mjs +290 -18
  54. package/bin/cock-codegraph.mjs +21 -6
  55. package/bin/cock-connection.mjs +151 -0
  56. package/bin/cock.mjs +12 -1
  57. package/bin/setup-dev.mjs +15 -13
  58. package/chrome-extension/automation.js +684 -32
  59. package/chrome-extension/manifest.json +1 -1
  60. package/chrome-extension/messages.js +45 -0
  61. package/dist/{chunk-CZWJPTRO.mjs → chunk-GCYLMG43.mjs} +2486 -1047
  62. package/dist/chunk-O4P2J44N.mjs +314 -0
  63. package/dist/{chunk-KRTISG5I.mjs → chunk-WOM47O75.mjs} +245 -10
  64. package/dist/httpApi.mjs +140 -7
  65. package/dist/scheduledTasks.mjs +15 -1159
  66. package/dist/{server-OSOMFNXR.mjs → server-SNB4H35J.mjs} +8 -2
  67. package/dist/wsServer.mjs +27 -19
  68. package/package.json +3 -5
  69. package/server.mjs +5 -1
  70. package/.next-prod/static/chunks/5188-415582403ef0e29c.js +0 -29
  71. package/.next-prod/static/chunks/6345-e5ceeb2aeb698eb6.js +0 -14
  72. package/.next-prod/static/css/cc6d733cdf607b30.css +0 -1
  73. package/dist/chunk-ZJ6CC3MH.mjs +0 -223
  74. /package/.next-prod/static/{GAYKr2BmQpFqJgRJfvQ3D → bOkuiIr_nWzG5GjPLNqdN}/_buildManifest.js +0 -0
  75. /package/.next-prod/static/{GAYKr2BmQpFqJgRJfvQ3D → bOkuiIr_nWzG5GjPLNqdN}/_ssgManifest.js +0 -0
package/dist/httpApi.mjs CHANGED
@@ -3,6 +3,7 @@ import {
3
3
  addOutputListener,
4
4
  createPendingRequest,
5
5
  getBrowserByShortId,
6
+ getBrowserHealth,
6
7
  getFirstAvailableLine,
7
8
  getRunningCommand,
8
9
  getTerminalByShortId,
@@ -10,6 +11,7 @@ import {
10
11
  listBrowsers,
11
12
  listTerminals,
12
13
  readAround,
14
+ readBubbleTitles,
13
15
  readHead,
14
16
  readSince,
15
17
  readTail,
@@ -19,10 +21,10 @@ import {
19
21
  unregisterBrowser,
20
22
  unregisterTerminal,
21
23
  writeStdinToCommand
22
- } from "./chunk-KRTISG5I.mjs";
24
+ } from "./chunk-WOM47O75.mjs";
23
25
  import {
24
26
  getTerminalHistoryPath
25
- } from "./chunk-ZJ6CC3MH.mjs";
27
+ } from "./chunk-GCYLMG43.mjs";
26
28
  import "./chunk-7P6ASYW6.mjs";
27
29
 
28
30
  // src/lib/httpApi.ts
@@ -30,6 +32,7 @@ import { parse } from "url";
30
32
  import { readFile } from "fs/promises";
31
33
  import { randomUUID } from "crypto";
32
34
  import { WebSocket } from "ws";
35
+ import { resolve as resolvePath } from "path";
33
36
  async function readFinishedOutput(projectCwd, tabId, commandId) {
34
37
  try {
35
38
  const historyPath = getTerminalHistoryPath(projectCwd, tabId);
@@ -389,37 +392,167 @@ async function handleBrowserApi(req, res) {
389
392
  sendJson(200, { ok: true });
390
393
  return true;
391
394
  }
395
+ if (action === "health" && !cmdParams?.deep) {
396
+ if (!id) {
397
+ sendJson(400, { ok: false, error: "Missing browser id" });
398
+ return true;
399
+ }
400
+ sendJson(200, { ok: true, data: getBrowserHealth(id) });
401
+ return true;
402
+ }
392
403
  if (!id) {
393
404
  sendJson(400, { ok: false, error: "Missing browser id" });
394
405
  return true;
395
406
  }
396
407
  const browser = getBrowserByShortId(id);
397
408
  if (!browser) {
398
- sendJson(404, { ok: false, error: `Browser "${id}" not found` });
409
+ const all = listBrowsers().map((b) => b.shortId);
410
+ const suggestions = fuzzyTopK(id, all, 3);
411
+ const hint = suggestions.length ? `
412
+ Did you mean: ${suggestions.join(", ")}?` : all.length ? `
413
+ Available: ${all.join(", ")}` : "\n No browsers currently connected. Open a browser bubble in the cockpit console.";
414
+ sendJson(404, {
415
+ ok: false,
416
+ error: `Browser "${id}" not found.${hint}
417
+ Run: cockpit browser list`
418
+ });
399
419
  return true;
400
420
  }
401
421
  if (!browser.ws || browser.ws.readyState !== WebSocket.OPEN) {
402
422
  sendJson(503, {
403
423
  ok: false,
404
- error: `Browser "${id}" is disconnected`
424
+ error: `Browser "${id}" is disconnected (WS closed).
425
+ Recover:
426
+ 1. Refresh the browser tab to re-register the extension.
427
+ 2. Run \`cockpit browser list\` to confirm the shortId.
428
+ 3. If the bubble is gone, re-open it from the cockpit console panel.`
405
429
  });
406
430
  return true;
407
431
  }
432
+ const wsAction = action === "health" ? "health_deep" : action;
408
433
  const reqId = `r-${randomUUID().slice(0, 8)}`;
409
- const sent = sendCommandToBrowser(id, reqId, action, cmdParams);
434
+ const sent = sendCommandToBrowser(id, reqId, wsAction, cmdParams);
410
435
  if (!sent) {
411
- sendJson(503, { ok: false, error: "Failed to send command" });
436
+ sendJson(503, { ok: false, error: "Failed to send command (WS write failed)" });
412
437
  return true;
413
438
  }
414
439
  try {
415
440
  const data = await createPendingRequest(reqId, timeout);
416
441
  sendJson(200, { ok: true, data });
417
442
  } catch (err) {
418
- sendJson(504, { ok: false, error: err.message });
443
+ const msg = err.message;
444
+ if (/timeout/i.test(msg)) {
445
+ const h = getBrowserHealth(id);
446
+ sendJson(504, {
447
+ ok: false,
448
+ error: `${msg} (action "${action}").
449
+ Bridge state: ws=${h.ws} pending=${h.pendingCommands}` + (h.lastSuccessMs !== null ? ` lastSuccess=${Math.round(h.lastSuccessMs / 1e3)}s ago (${h.lastSuccessAction})` : "") + `
450
+ Diagnose:
451
+ cockpit browser ${id} health # cheap server-side probe
452
+ cockpit browser ${id} wait --extension-ready (Phase 2)
453
+ If the bridge state shows fresh activity, the page itself is blocked.
454
+ Consider a service-level test if driven by an async LLM/agent flow.`
455
+ });
456
+ } else {
457
+ sendJson(504, { ok: false, error: msg });
458
+ }
459
+ }
460
+ return true;
461
+ }
462
+ function fuzzyTopK(input, candidates, k) {
463
+ if (!input || !candidates.length) return [];
464
+ const inputLow = input.toLowerCase();
465
+ const bag = bagCounts(inputLow);
466
+ const scored = candidates.map((c) => {
467
+ const cl = c.toLowerCase();
468
+ const cBag = bagCounts(cl);
469
+ let inter = 0;
470
+ for (const [ch, n] of bag) inter += Math.min(n, cBag.get(ch) ?? 0);
471
+ const ratio = inter / Math.max(inputLow.length, cl.length);
472
+ const startsWith = cl.startsWith(inputLow) ? 0.5 : 0;
473
+ const contains = cl.includes(inputLow) ? 0.3 : 0;
474
+ return { c, score: ratio + startsWith + contains };
475
+ });
476
+ scored.sort((a, b) => b.score - a.score);
477
+ return scored.slice(0, k).filter((s) => s.score >= 0.6).map((s) => s.c);
478
+ }
479
+ function bagCounts(s) {
480
+ const m = /* @__PURE__ */ new Map();
481
+ for (const ch of s) m.set(ch, (m.get(ch) ?? 0) + 1);
482
+ return m;
483
+ }
484
+ async function handleConnectionApi(req, res) {
485
+ const { pathname } = parse(req.url || "", true);
486
+ const match = pathname?.match(/^\/api\/connection\/([a-z]+)$/);
487
+ if (!match || req.method !== "POST") return false;
488
+ if (match[1] !== "list") return false;
489
+ const chunks = [];
490
+ for await (const chunk of req) chunks.push(chunk);
491
+ let body = {};
492
+ try {
493
+ body = JSON.parse(Buffer.concat(chunks).toString());
494
+ } catch {
495
+ }
496
+ const sendJson = (status, data) => {
497
+ res.writeHead(status, { "Content-Type": "application/json" });
498
+ res.end(JSON.stringify(data));
499
+ };
500
+ const filterCwd = body.cwd ? resolvePath(body.cwd) : void 0;
501
+ const aliveOnly = !body.all;
502
+ const terms = listTerminals(getRunningCommand);
503
+ const browsers = listBrowsers();
504
+ const sameCwd = (entryCwd) => !filterCwd ? true : !!entryCwd && resolvePath(entryCwd) === filterCwd;
505
+ const SEP = String.fromCharCode(31);
506
+ const cwdTabPairs = /* @__PURE__ */ new Set();
507
+ for (const t of terms) {
508
+ if (t.projectCwd && t.tabId) cwdTabPairs.add(`${t.projectCwd}${SEP}${t.tabId}`);
509
+ }
510
+ for (const b of browsers) {
511
+ if (b.projectCwd && b.tabId) cwdTabPairs.add(`${b.projectCwd}${SEP}${b.tabId}`);
512
+ }
513
+ const titlesByPair = /* @__PURE__ */ new Map();
514
+ await Promise.all(
515
+ Array.from(cwdTabPairs).map(async (pair) => {
516
+ const [cwd, tabId] = pair.split(SEP);
517
+ titlesByPair.set(pair, await readBubbleTitles(cwd, tabId));
518
+ })
519
+ );
520
+ const titleOf = (cwd, tabId, key) => {
521
+ if (!cwd || !tabId) return void 0;
522
+ const t = titlesByPair.get(`${cwd}${SEP}${tabId}`)?.[key];
523
+ return t || void 0;
524
+ };
525
+ const out = [];
526
+ for (const t of terms) {
527
+ if (!sameCwd(t.projectCwd)) continue;
528
+ if (aliveOnly && !t.running) continue;
529
+ out.push({
530
+ type: "terminal",
531
+ shortId: t.shortId,
532
+ title: titleOf(t.projectCwd, t.tabId, t.commandId),
533
+ projectCwd: t.projectCwd,
534
+ tabId: t.tabId,
535
+ command: t.command,
536
+ alive: t.running
537
+ });
538
+ }
539
+ for (const b of browsers) {
540
+ if (!sameCwd(b.projectCwd)) continue;
541
+ if (aliveOnly && !b.connected) continue;
542
+ out.push({
543
+ type: "browser",
544
+ shortId: b.shortId,
545
+ title: titleOf(b.projectCwd, b.tabId, b.fullId),
546
+ projectCwd: b.projectCwd,
547
+ tabId: b.tabId,
548
+ alive: b.connected
549
+ });
419
550
  }
551
+ sendJson(200, { ok: true, data: out });
420
552
  return true;
421
553
  }
422
554
  export {
423
555
  handleBrowserApi,
556
+ handleConnectionApi,
424
557
  handleTerminalApi
425
558
  };