@surething/cockpit 1.0.232 → 1.0.234

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 (220) hide show
  1. package/.next-prod/BUILD_ID +1 -1
  2. package/.next-prod/build-manifest.json +3 -3
  3. package/.next-prod/prerender-manifest.json +3 -3
  4. package/.next-prod/react-loadable-manifest.json +7 -0
  5. package/.next-prod/server/app/_global-error/page.js.nft.json +1 -1
  6. package/.next-prod/server/app/_global-error/page_client-reference-manifest.js +1 -1
  7. package/.next-prod/server/app/_global-error.html +1 -1
  8. package/.next-prod/server/app/_global-error.rsc +1 -1
  9. package/.next-prod/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/.next-prod/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  11. package/.next-prod/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  12. package/.next-prod/server/app/_global-error.segments/_head.segment.rsc +1 -1
  13. package/.next-prod/server/app/_global-error.segments/_index.segment.rsc +1 -1
  14. package/.next-prod/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  15. package/.next-prod/server/app/_not-found/page.js.nft.json +1 -1
  16. package/.next-prod/server/app/_not-found/page_client-reference-manifest.js +1 -1
  17. package/.next-prod/server/app/_not-found.html +2 -2
  18. package/.next-prod/server/app/_not-found.rsc +3 -3
  19. package/.next-prod/server/app/_not-found.segments/_full.segment.rsc +3 -3
  20. package/.next-prod/server/app/_not-found.segments/_head.segment.rsc +1 -1
  21. package/.next-prod/server/app/_not-found.segments/_index.segment.rsc +3 -3
  22. package/.next-prod/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  23. package/.next-prod/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  24. package/.next-prod/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  25. package/.next-prod/server/app/api/agent/test/route.js.nft.json +1 -1
  26. package/.next-prod/server/app/api/bash/route.js.nft.json +1 -1
  27. package/.next-prod/server/app/api/chat/codex/route.js +1 -1
  28. package/.next-prod/server/app/api/chat/codex/route.js.nft.json +1 -1
  29. package/.next-prod/server/app/api/chat/deepseek/route.js +1 -1
  30. package/.next-prod/server/app/api/chat/deepseek/route.js.nft.json +1 -1
  31. package/.next-prod/server/app/api/chat/kimi/route.js +1 -1
  32. package/.next-prod/server/app/api/chat/kimi/route.js.nft.json +1 -1
  33. package/.next-prod/server/app/api/chat/ollama/route.js +1 -1
  34. package/.next-prod/server/app/api/chat/ollama/route.js.nft.json +1 -1
  35. package/.next-prod/server/app/api/chat/pty-input/route.js.nft.json +1 -1
  36. package/.next-prod/server/app/api/chat/route.js +1 -1
  37. package/.next-prod/server/app/api/chat/route.js.nft.json +1 -1
  38. package/.next-prod/server/app/api/chat/stop/route.js.nft.json +1 -1
  39. package/.next-prod/server/app/api/claude-stats/route.js.nft.json +1 -1
  40. package/.next-prod/server/app/api/commands/route.js +1 -1
  41. package/.next-prod/server/app/api/commands/route.js.nft.json +1 -1
  42. package/.next-prod/server/app/api/comments/route.js.nft.json +1 -1
  43. package/.next-prod/server/app/api/db/columns/route.js.nft.json +1 -1
  44. package/.next-prod/server/app/api/db/connect/route.js.nft.json +1 -1
  45. package/.next-prod/server/app/api/db/disconnect/route.js.nft.json +1 -1
  46. package/.next-prod/server/app/api/db/export/route.js.nft.json +1 -1
  47. package/.next-prod/server/app/api/db/query/route.js.nft.json +1 -1
  48. package/.next-prod/server/app/api/db/schemas/route.js.nft.json +1 -1
  49. package/.next-prod/server/app/api/dev/spans/route.js.nft.json +1 -1
  50. package/.next-prod/server/app/api/extension/version/route.js.nft.json +1 -1
  51. package/.next-prod/server/app/api/file/route.js.nft.json +1 -1
  52. package/.next-prod/server/app/api/files/blame/route.js.nft.json +1 -1
  53. package/.next-prod/server/app/api/files/clipboard/route.js.nft.json +1 -1
  54. package/.next-prod/server/app/api/files/copy/route.js.nft.json +1 -1
  55. package/.next-prod/server/app/api/files/delete/route.js.nft.json +1 -1
  56. package/.next-prod/server/app/api/files/expanded/route.js.nft.json +1 -1
  57. package/.next-prod/server/app/api/files/index/route.js.nft.json +1 -1
  58. package/.next-prod/server/app/api/files/init/route.js.nft.json +1 -1
  59. package/.next-prod/server/app/api/files/paste/route.js.nft.json +1 -1
  60. package/.next-prod/server/app/api/files/read/route.js.nft.json +1 -1
  61. package/.next-prod/server/app/api/files/readdir/route.js.nft.json +1 -1
  62. package/.next-prod/server/app/api/files/recent/route.js.nft.json +1 -1
  63. package/.next-prod/server/app/api/files/save/route.js.nft.json +1 -1
  64. package/.next-prod/server/app/api/files/search/route.js.nft.json +1 -1
  65. package/.next-prod/server/app/api/files/stat/route.js.nft.json +1 -1
  66. package/.next-prod/server/app/api/files/text/route.js.nft.json +1 -1
  67. package/.next-prod/server/app/api/git/branch-diff/route.js.nft.json +1 -1
  68. package/.next-prod/server/app/api/git/branches/route.js.nft.json +1 -1
  69. package/.next-prod/server/app/api/git/commit-diff/route.js.nft.json +1 -1
  70. package/.next-prod/server/app/api/git/commits/route.js.nft.json +1 -1
  71. package/.next-prod/server/app/api/git/current-branch/route.js.nft.json +1 -1
  72. package/.next-prod/server/app/api/git/diff/route.js.nft.json +1 -1
  73. package/.next-prod/server/app/api/git/discard/route.js.nft.json +1 -1
  74. package/.next-prod/server/app/api/git/stage/route.js.nft.json +1 -1
  75. package/.next-prod/server/app/api/git/status/route.js.nft.json +1 -1
  76. package/.next-prod/server/app/api/git/unstage/route.js.nft.json +1 -1
  77. package/.next-prod/server/app/api/git/worktree/route.js.nft.json +1 -1
  78. package/.next-prod/server/app/api/global-state/route.js +1 -1
  79. package/.next-prod/server/app/api/global-state/route.js.nft.json +1 -1
  80. package/.next-prod/server/app/api/health/route.js.nft.json +1 -1
  81. package/.next-prod/server/app/api/jupyter/load/route.js.nft.json +1 -1
  82. package/.next-prod/server/app/api/jupyter/save/route.js.nft.json +1 -1
  83. package/.next-prod/server/app/api/jupyter/shutdown/route.js.nft.json +1 -1
  84. package/.next-prod/server/app/api/lsp/definition/route.js.nft.json +1 -1
  85. package/.next-prod/server/app/api/lsp/hover/route.js.nft.json +1 -1
  86. package/.next-prod/server/app/api/lsp/references/route.js.nft.json +1 -1
  87. package/.next-prod/server/app/api/lsp/status/route.js.nft.json +1 -1
  88. package/.next-prod/server/app/api/lsp/warmup/route.js.nft.json +1 -1
  89. package/.next-prod/server/app/api/mysql/columns/route.js.nft.json +1 -1
  90. package/.next-prod/server/app/api/mysql/connect/route.js.nft.json +1 -1
  91. package/.next-prod/server/app/api/mysql/disconnect/route.js.nft.json +1 -1
  92. package/.next-prod/server/app/api/mysql/export/route.js.nft.json +1 -1
  93. package/.next-prod/server/app/api/mysql/query/route.js.nft.json +1 -1
  94. package/.next-prod/server/app/api/mysql/schemas/route.js.nft.json +1 -1
  95. package/.next-prod/server/app/api/neo4j/connect/route.js.nft.json +1 -1
  96. package/.next-prod/server/app/api/neo4j/disconnect/route.js.nft.json +1 -1
  97. package/.next-prod/server/app/api/neo4j/query/route.js.nft.json +1 -1
  98. package/.next-prod/server/app/api/neo4j/schema/route.js.nft.json +1 -1
  99. package/.next-prod/server/app/api/note/route.js.nft.json +1 -1
  100. package/.next-prod/server/app/api/ollama/models/route.js.nft.json +1 -1
  101. package/.next-prod/server/app/api/ollama/start/route.js.nft.json +1 -1
  102. package/.next-prod/server/app/api/open-cursor/route.js.nft.json +1 -1
  103. package/.next-prod/server/app/api/open-vscode/route.js.nft.json +1 -1
  104. package/.next-prod/server/app/api/pick-folder/route.js.nft.json +1 -1
  105. package/.next-prod/server/app/api/pinned-sessions/route.js.nft.json +1 -1
  106. package/.next-prod/server/app/api/project-settings/route.js.nft.json +1 -1
  107. package/.next-prod/server/app/api/project-state/route.js.nft.json +1 -1
  108. package/.next-prod/server/app/api/projectGraph/affected/route.js.nft.json +1 -1
  109. package/.next-prod/server/app/api/projectGraph/callees/route.js.nft.json +1 -1
  110. package/.next-prod/server/app/api/projectGraph/callers/route.js.nft.json +1 -1
  111. package/.next-prod/server/app/api/projectGraph/coedit/route.js.nft.json +1 -1
  112. package/.next-prod/server/app/api/projectGraph/context/route.js.nft.json +1 -1
  113. package/.next-prod/server/app/api/projectGraph/file/route.js.nft.json +1 -1
  114. package/.next-prod/server/app/api/projectGraph/file-functions/route.js.nft.json +1 -1
  115. package/.next-prod/server/app/api/projectGraph/impact/route.js.nft.json +1 -1
  116. package/.next-prod/server/app/api/projectGraph/related/route.js.nft.json +1 -1
  117. package/.next-prod/server/app/api/projectGraph/risk/route.js.nft.json +1 -1
  118. package/.next-prod/server/app/api/projectGraph/search/route.js.nft.json +1 -1
  119. package/.next-prod/server/app/api/projects/route.js.nft.json +1 -1
  120. package/.next-prod/server/app/api/push/public-key/route.js +1 -1
  121. package/.next-prod/server/app/api/push/public-key/route.js.nft.json +1 -1
  122. package/.next-prod/server/app/api/push/subscribe/route.js +1 -1
  123. package/.next-prod/server/app/api/push/subscribe/route.js.nft.json +1 -1
  124. package/.next-prod/server/app/api/push/unsubscribe/route.js +1 -1
  125. package/.next-prod/server/app/api/push/unsubscribe/route.js.nft.json +1 -1
  126. package/.next-prod/server/app/api/redis/command/route.js.nft.json +1 -1
  127. package/.next-prod/server/app/api/redis/connect/route.js.nft.json +1 -1
  128. package/.next-prod/server/app/api/redis/delete/route.js.nft.json +1 -1
  129. package/.next-prod/server/app/api/redis/disconnect/route.js.nft.json +1 -1
  130. package/.next-prod/server/app/api/redis/get/route.js.nft.json +1 -1
  131. package/.next-prod/server/app/api/redis/keys/route.js.nft.json +1 -1
  132. package/.next-prod/server/app/api/redis/set/route.js.nft.json +1 -1
  133. package/.next-prod/server/app/api/review/[id]/comments/route.js.nft.json +1 -1
  134. package/.next-prod/server/app/api/review/[id]/replies/route.js.nft.json +1 -1
  135. package/.next-prod/server/app/api/review/[id]/route.js.nft.json +1 -1
  136. package/.next-prod/server/app/api/review/identify/route.js.nft.json +1 -1
  137. package/.next-prod/server/app/api/review/order/route.js.nft.json +1 -1
  138. package/.next-prod/server/app/api/review/route.js.nft.json +1 -1
  139. package/.next-prod/server/app/api/review/share-info/route.js.nft.json +1 -1
  140. package/.next-prod/server/app/api/review/users/route.js.nft.json +1 -1
  141. package/.next-prod/server/app/api/scheduled-tasks/route.js +2 -2
  142. package/.next-prod/server/app/api/scheduled-tasks/route.js.nft.json +1 -1
  143. package/.next-prod/server/app/api/services/config/route.js.nft.json +1 -1
  144. package/.next-prod/server/app/api/services/scripts/route.js.nft.json +1 -1
  145. package/.next-prod/server/app/api/session/[sessionId]/fork/route.js.nft.json +1 -1
  146. package/.next-prod/server/app/api/session/[sessionId]/history/route.js +1 -1
  147. package/.next-prod/server/app/api/session/[sessionId]/history/route.js.nft.json +1 -1
  148. package/.next-prod/server/app/api/session-by-path/route.js +1 -1
  149. package/.next-prod/server/app/api/session-by-path/route.js.nft.json +1 -1
  150. package/.next-prod/server/app/api/sessions/projects/[encodedPath]/route.js.nft.json +1 -1
  151. package/.next-prod/server/app/api/sessions/projects/route.js.nft.json +1 -1
  152. package/.next-prod/server/app/api/sessions/route.js.nft.json +1 -1
  153. package/.next-prod/server/app/api/settings/route.js.nft.json +1 -1
  154. package/.next-prod/server/app/api/skills/[id]/route.js.nft.json +1 -1
  155. package/.next-prod/server/app/api/skills/content/route.js.nft.json +1 -1
  156. package/.next-prod/server/app/api/skills/route.js.nft.json +1 -1
  157. package/.next-prod/server/app/api/terminal/aliases/route.js.nft.json +1 -1
  158. package/.next-prod/server/app/api/terminal/autocomplete/route.js.nft.json +1 -1
  159. package/.next-prod/server/app/api/terminal/bubble-order/route.js.nft.json +1 -1
  160. package/.next-prod/server/app/api/terminal/env/route.js.nft.json +1 -1
  161. package/.next-prod/server/app/api/terminal/history/route.js.nft.json +1 -1
  162. package/.next-prod/server/app/api/version/route.js.nft.json +1 -1
  163. package/.next-prod/server/app/favicon.ico/route.js.nft.json +1 -1
  164. package/.next-prod/server/app/m/page.js +2 -2
  165. package/.next-prod/server/app/m/page.js.nft.json +1 -1
  166. package/.next-prod/server/app/m/page_client-reference-manifest.js +1 -1
  167. package/.next-prod/server/app/manifest.webmanifest/route.js.nft.json +1 -1
  168. package/.next-prod/server/app/page.js +1 -1
  169. package/.next-prod/server/app/page.js.nft.json +1 -1
  170. package/.next-prod/server/app/page_client-reference-manifest.js +1 -1
  171. package/.next-prod/server/app/project/page.js +1 -1
  172. package/.next-prod/server/app/project/page.js.nft.json +1 -1
  173. package/.next-prod/server/app/project/page_client-reference-manifest.js +1 -1
  174. package/.next-prod/server/app/review/[id]/page.js +2 -2
  175. package/.next-prod/server/app/review/[id]/page.js.nft.json +1 -1
  176. package/.next-prod/server/app/review/[id]/page_client-reference-manifest.js +1 -1
  177. package/.next-prod/server/chunks/3863.js +2 -2
  178. package/.next-prod/server/chunks/{3633.js → 5897.js} +373 -3
  179. package/.next-prod/server/chunks/9658.js +26 -26
  180. package/.next-prod/server/chunks/9830.js +1 -1
  181. package/.next-prod/server/middleware-build-manifest.js +1 -1
  182. package/.next-prod/server/middleware-react-loadable-manifest.js +1 -1
  183. package/.next-prod/server/pages/404.html +2 -2
  184. package/.next-prod/server/pages/500.html +1 -1
  185. package/.next-prod/server/server-reference-manifest.json +1 -1
  186. package/.next-prod/static/chunks/{2625-bc4748f0cd7db618.js → 1332-5e141e2acf28015a.js} +10 -10
  187. package/.next-prod/static/chunks/{217-4f8250a204080159.js → 217-e929c46c0bd599a7.js} +4 -4
  188. package/.next-prod/static/chunks/2502-fb8682bc7a61e04d.js +4 -0
  189. package/.next-prod/static/chunks/{2576-6420f6bad0b8ffb3.js → 2576-11e41242c7dd98f1.js} +2 -2
  190. package/.next-prod/static/chunks/4523.3f277a24fbcfde6d.js +138 -0
  191. package/.next-prod/static/chunks/9304-ddde9008da31b2ce.js +1 -0
  192. package/.next-prod/static/chunks/app/{layout-ac2f1f67df01cc89.js → layout-d202f8e0bcc90661.js} +1 -1
  193. package/.next-prod/static/chunks/app/m/page-71570a066f3eacf8.js +1 -0
  194. package/.next-prod/static/chunks/app/{page-1f0a6f49656a4c52.js → page-814b50b5b440249d.js} +1 -1
  195. package/.next-prod/static/chunks/app/project/{page-1f0a6f49656a4c52.js → page-814b50b5b440249d.js} +1 -1
  196. package/.next-prod/static/chunks/app/review/[id]/{page-39fa3a843adf617e.js → page-0c5d03d65758c7dc.js} +1 -1
  197. package/.next-prod/static/chunks/webpack-2c71a79c277961bc.js +1 -0
  198. package/.next-prod/static/css/fa7218e60ff464b5.css +1 -0
  199. package/.next-prod/trace +13 -13
  200. package/.next-prod/trace-build +1 -1
  201. package/bin/cock-browser.mjs +12 -9
  202. package/bin/cock.mjs +5 -5
  203. package/bin/postinstall.mjs +6 -6
  204. package/chrome-extension/automation.js +45 -40
  205. package/chrome-extension/background.js +70 -67
  206. package/chrome-extension/content.js +38 -38
  207. package/chrome-extension/disguise.js +4 -4
  208. package/chrome-extension/network-capture.js +16 -16
  209. package/dist/{chunk-VHFWPI2X.mjs → chunk-3M3JSZ5R.mjs} +28 -1
  210. package/dist/scheduledTasks.mjs +437 -3
  211. package/dist/wsServer.mjs +6 -31
  212. package/package.json +1 -1
  213. package/server.mjs +122 -26
  214. package/.next-prod/server/chunks/7003.js +0 -1
  215. package/.next-prod/static/chunks/471-504b396c8302f4f2.js +0 -4
  216. package/.next-prod/static/chunks/app/m/page-8b1af6f31b60c485.js +0 -1
  217. package/.next-prod/static/chunks/webpack-dbba7fa77ee1faa4.js +0 -1
  218. package/.next-prod/static/css/2a854655f4108c3a.css +0 -1
  219. /package/.next-prod/static/{Z3Em1C_kM7x4RjcH7E7v2 → JfwcuC5YjyhQWeQD-4Gvn}/_buildManifest.js +0 -0
  220. /package/.next-prod/static/{Z3Em1C_kM7x4RjcH7E7v2 → JfwcuC5YjyhQWeQD-4Gvn}/_ssgManifest.js +0 -0
package/server.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { createServer } from 'http';
2
+ import { createGzip, constants as zlibConstants } from 'zlib';
2
3
  import { exec, execSync } from 'child_process';
3
4
  import { networkInterfaces, homedir } from 'os';
4
5
  import { writeFileSync, mkdirSync, readFileSync, realpathSync } from 'fs';
@@ -53,17 +54,22 @@ async function ensureSingleInstance() {
53
54
  }
54
55
 
55
56
  // ============================================
56
- // 进程生命周期防护
57
+ // Process lifecycle guards
57
58
  //
58
- // 1) 父进程死亡后 stdout/stderr 管道断裂,Next.js 的 uncaughtException handler
59
- // 会尝试 console.log 报错 stdout EPIPE再次触发 handler → CPU 死循环
60
- // 在管道错误升级为 uncaughtException 之前拦截,直接退出。
59
+ // 1) When the parent process dies, the stdout/stderr pipes break. Next.js's
60
+ // uncaughtException handler then tries to console.log the errorwrites
61
+ // to stdout → EPIPE → triggers the handler again → CPU spin loop.
62
+ // Intercept pipe errors before they escalate to uncaughtException and
63
+ // exit immediately.
61
64
  //
62
- // 2) Next.js dev 模式下会在自己的子进程里跑 `next-server` workerturbopack)。
63
- // 如果父进程被异常杀掉(npm reinstall、Ctrl+C npm 包了一层、IDE 杀任务等),
64
- // next-server 子进程不会跟着死,而是会失去父进程后**重新绑定到 next 自带的默认
65
- // 端口 3000**,然后把后续 `npm run dev` 卡死(Next 通过 .next/dev/logs 检测到
66
- // "已有 dev server 在跑"而拒绝再启)。所以父进程退出前必须显式杀掉所有直接子进程。
65
+ // 2) In dev mode Next.js runs a `next-server` worker (turbopack) in its own
66
+ // child process. If the parent is killed abnormally (npm reinstall,
67
+ // Ctrl+C through an npm wrapper, IDE killing the task, etc.), the
68
+ // next-server child doesn't die with it having lost its parent it
69
+ // **re-binds to Next's default port 3000** and then wedges every later
70
+ // `npm run dev` (Next detects "a dev server is already running" via
71
+ // .next/dev/logs and refuses to start). So the parent must explicitly
72
+ // kill all direct children before exiting.
67
73
  // ============================================
68
74
  // Assigned once the server-side bundle is loaded (see app.prepare below). Lets the
69
75
  // synchronous exit hook flush live PTY scrollback to disk so a graceful restart
@@ -75,7 +81,8 @@ function killChildren() {
75
81
  if (_cleanupRan) return;
76
82
  _cleanupRan = true;
77
83
  if (process.platform === 'win32') {
78
- // Windows: wmic 列出子 PID 再逐个 taskkill /F /T,避免 /T 把自己也带走
84
+ // Windows: list child PIDs via wmic, then taskkill /F /T each one —
85
+ // running /T on ourselves would take this process down too
79
86
  try {
80
87
  const out = execSync(`wmic process where (ParentProcessId=${process.pid}) get ProcessId /value`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] });
81
88
  const pids = (out.match(/ProcessId=(\d+)/g) || []).map(s => s.split('=')[1]).filter(Boolean);
@@ -85,34 +92,39 @@ function killChildren() {
85
92
  } catch {}
86
93
  return;
87
94
  }
88
- // POSIX: pkill -P 只杀直接子进程,不递归(next-server 等都是直接子进程,足够)
89
- // pkill 在没有匹配到任何进程时返回 1,不当作错误
95
+ // POSIX: pkill -P kills direct children only, no recursion (next-server
96
+ // and friends are all direct children — enough).
97
+ // pkill exits 1 when nothing matches; not treated as an error.
90
98
  try { execSync(`pkill -TERM -P ${process.pid}`, { stdio: 'ignore' }); } catch {}
91
99
  }
92
100
 
93
- // 正常退出路径(包括所有的 process.exit() 调用)—— Node 保证此 handler 同步执行。
94
- // 所有信号/异常路径最终都走 process.exit() 触发 'exit' 这一个点覆盖全部优雅退出。
95
- // 先把活着的 PTY 滚动缓冲同步落盘,再杀子进程(flush 读的是本进程内存,与子进程无关)。
101
+ // Normal exit path (including every process.exit() call) Node guarantees
102
+ // this handler runs synchronously. All signal/exception paths ultimately go
103
+ // through process.exit() 'exit' fires → this single hook covers every
104
+ // graceful shutdown. Flush live PTY scrollback to disk first, then kill the
105
+ // children (the flush reads this process's own memory — independent of them).
96
106
  process.on('exit', () => {
97
107
  try { flushRunningSync?.(); } catch {}
98
108
  killChildren();
99
109
  });
100
110
 
101
- // 信号路径 —— 先杀子进程再退出,并让 shell 看到正确的退出码
111
+ // Signal paths kill children first, then exit with the code the shell expects
102
112
  const cleanupAndExit = (code) => () => { killChildren(); process.exit(code); };
103
113
  process.on('SIGINT', cleanupAndExit(130));
104
114
  process.on('SIGTERM', cleanupAndExit(143));
105
115
  process.on('SIGQUIT', cleanupAndExit(131));
106
116
  process.on('SIGHUP', cleanupAndExit(0));
107
117
 
108
- // 未捕获异常 —— 不能让 Next.js 的默认 handler 再走 console.log 触发 EPIPE 死循环
118
+ // Uncaught exceptions don't let Next.js's default handler console.log its
119
+ // way back into the EPIPE spin loop
109
120
  process.on('uncaughtException', (err) => {
110
121
  try { console.error('uncaughtException:', err); } catch {}
111
122
  killChildren();
112
123
  process.exit(1);
113
124
  });
114
125
 
115
- // stdout/stderr 管道断裂立刻退出(exit handler 会顺手清子进程)
126
+ // Broken stdout/stderr pipe → exit immediately (the exit handler cleans up
127
+ // the children on the way out)
116
128
  process.stdout.on('error', (err) => {
117
129
  if (err.code === 'EPIPE' || err.code === 'ERR_STREAM_DESTROYED') process.exit(0);
118
130
  });
@@ -134,7 +146,7 @@ app.prepare().then(async () => {
134
146
  flushRunningSync = httpApi.flushAllRunningSync || null;
135
147
  const { scheduledTaskManager } = await import(dev ? '@cockpit/feature-agent/server/scheduledTasks' : './dist/scheduledTasks.mjs');
136
148
 
137
- // 初始化定时任务管理器
149
+ // Initialize the scheduled-task manager
138
150
  scheduledTaskManager.setOnTaskFired((task) => {
139
151
  broadcastToGlobalState({ type: 'task-fired', taskId: task.id, cwd: task.cwd, tabId: task.tabId, sessionId: task.sessionId });
140
152
  });
@@ -176,10 +188,92 @@ app.prepare().then(async () => {
176
188
  return false;
177
189
  };
178
190
 
191
+ // ============================================
192
+ // /api/* JSON gzip — Next's built-in compression only runs under
193
+ // `next start`; with this custom server, API JSON goes out uncompressed
194
+ // (fine locally at <10ms, but behind a tunnel like ngrok a 200KB+
195
+ // session-by-path response means seconds of latency). Transparently wrap
196
+ // application/json responses in gzip; SSE / HTML / static assets (which
197
+ // Next already compresses) are untouched.
198
+ // ============================================
199
+ const gzipJsonResponse = (req, res) => {
200
+ if (!/\bgzip\b/i.test(String(req.headers['accept-encoding'] || ''))) return;
201
+ const origWriteHead = res.writeHead.bind(res);
202
+ const origWrite = res.write.bind(res);
203
+ const origEnd = res.end.bind(res);
204
+ let gzip = null;
205
+ let decided = false;
206
+
207
+ // Decide at first output (writeHead/write/end): only compress JSON that
208
+ // isn't already encoded.
209
+ const decide = () => {
210
+ if (decided) return;
211
+ decided = true;
212
+ const ct = String(res.getHeader('content-type') || '');
213
+ if (!ct.includes('application/json') || res.getHeader('content-encoding')) return;
214
+ res.removeHeader('content-length');
215
+ res.setHeader('content-encoding', 'gzip');
216
+ const vary = String(res.getHeader('vary') || '');
217
+ if (!/\baccept-encoding\b/i.test(vary)) {
218
+ res.setHeader('vary', vary ? `${vary}, Accept-Encoding` : 'Accept-Encoding');
219
+ }
220
+ gzip = createGzip({ flush: zlibConstants.Z_SYNC_FLUSH });
221
+ gzip.on('data', (chunk) => origWrite(chunk));
222
+ gzip.on('end', () => origEnd());
223
+ gzip.on('error', () => { try { origEnd(); } catch {} });
224
+ };
225
+
226
+ // writeHead accepts headers in three shapes: object, flat array
227
+ // [k1,v1,k2,v2,...] (what Next uses internally), and nested array
228
+ // [[k,v],...]. Normalize all of them through setHeader before deciding
229
+ // on compression.
230
+ const applyHeaders = (h) => {
231
+ if (!h) return;
232
+ if (Array.isArray(h)) {
233
+ const pairs = Array.isArray(h[0])
234
+ ? h
235
+ : Array.from({ length: h.length >> 1 }, (_, i) => [h[i * 2], h[i * 2 + 1]]);
236
+ for (const [k, v] of pairs) {
237
+ if (k === undefined || v === undefined) continue;
238
+ const key = String(k);
239
+ const prev = res.getHeader(key);
240
+ // Merge duplicate headers (e.g. set-cookie) into an array instead of overwriting
241
+ res.setHeader(key, prev === undefined ? v : [].concat(prev, v));
242
+ }
243
+ } else {
244
+ for (const [k, v] of Object.entries(h)) {
245
+ if (v !== undefined) res.setHeader(k, v);
246
+ }
247
+ }
248
+ };
249
+
250
+ res.writeHead = (status, arg2, arg3) => {
251
+ applyHeaders(typeof arg2 === 'object' ? arg2 : arg3);
252
+ decide();
253
+ return typeof arg2 === 'string' ? origWriteHead(status, arg2) : origWriteHead(status);
254
+ };
255
+ res.write = (chunk, ...args) => {
256
+ decide();
257
+ if (gzip) { gzip.write(chunk); return true; }
258
+ return origWrite(chunk, ...args);
259
+ };
260
+ res.end = (chunk, ...args) => {
261
+ decide();
262
+ if (gzip) {
263
+ if (chunk && typeof chunk !== 'function') gzip.write(chunk);
264
+ gzip.end();
265
+ return res;
266
+ }
267
+ return origEnd(chunk, ...args);
268
+ };
269
+ };
270
+
179
271
  const server = createServer(async (req, res) => {
180
272
  if (applyHttpGate(req, res)) return;
273
+ if (req.url?.startsWith('/api/')) gzipJsonResponse(req, res);
181
274
 
182
- // /api/browser/* 必须在自定义 server 中处理(与 WS 共享 BrowserBridge 内存)
275
+ // /api/browser/* must be handled inside the custom server (it shares
276
+ // BrowserBridge memory with the WS side)
183
277
  if (req.url?.startsWith('/api/browser/') && req.method === 'POST') {
184
278
  const handled = await handleBrowserApi(req, res);
185
279
  if (handled) return;
@@ -207,19 +301,20 @@ app.prepare().then(async () => {
207
301
  }
208
302
  });
209
303
 
210
- // COCKPIT_HOST: 默认 127.0.0.1(本地),云沙盒等场景设为 0.0.0.0
304
+ // COCKPIT_HOST: defaults to 127.0.0.1 (local-only); set 0.0.0.0 for cloud
305
+ // sandboxes and similar environments
211
306
  const host = process.env.COCKPIT_HOST || '127.0.0.1';
212
307
  server.listen(port, host, () => {
213
308
  const url = `http://localhost:${port}`;
214
309
  console.log(`> Ready on ${url}`);
215
310
 
216
- // 写入 server.json CLI 子命令读取端口
311
+ // Write server.json so CLI subcommands can read the port
217
312
  try {
218
313
  mkdirSync(cockpitHome, { recursive: true });
219
314
  writeFileSync(join(cockpitHome, 'server.json'), JSON.stringify({ pid: process.pid, port }, null, 2));
220
315
  } catch {}
221
316
 
222
- // prod 模式自动打开浏览器(--no-open 禁用)
317
+ // Auto-open the browser in prod mode (disable with --no-open)
223
318
  if (!dev && !process.env.COCKPIT_NO_OPEN) {
224
319
  const openProject = process.env.COCKPIT_OPEN_PROJECT;
225
320
  const openUrl = openProject ? `${url}/?cwd=${encodeURIComponent(openProject)}` : url;
@@ -229,8 +324,8 @@ app.prepare().then(async () => {
229
324
  });
230
325
 
231
326
  // ============================================
232
- // Share Server - LAN 分享评审服务
233
- // 路由白名单:仅开放 /review/* 和相关资源
327
+ // Share Server LAN review-sharing service.
328
+ // Route allowlist: only /review/* and its supporting assets are exposed.
234
329
  // ============================================
235
330
  const sharePort = port + 1000; // dev 3456→4456, prod 3457→4457
236
331
 
@@ -260,8 +355,9 @@ app.prepare().then(async () => {
260
355
  // Token gate first (share is also covered). Read the gate BEFORE we inject
261
356
  // x-forwarded-for below, so the injection can't fool the local check.
262
357
  if (applyHttpGate(req, res)) return;
358
+ if (req.url?.startsWith('/api/')) gzipJsonResponse(req, res);
263
359
  if (isShareAllowed(req.url || '')) {
264
- // 注入客户端真实 IP,供 /api/review/identify 使用
360
+ // Inject the client's real IP for /api/review/identify
265
361
  const clientIp = req.socket.remoteAddress || '';
266
362
  req.headers['x-forwarded-for'] = clientIp;
267
363
  handle(req, res);
@@ -1 +0,0 @@
1
- "use strict";exports.id=7003,exports.ids=[7003],exports.modules={7939:(a,b,c)=>{c.d(b,{$A:()=>M,A0:()=>X,An:()=>$,BF:()=>I,Ct:()=>Q,Eu:()=>H,Ex:()=>u,GB:()=>r,JE:()=>Z,JY:()=>L,Ki:()=>C,Kk:()=>R,Kv:()=>j,LN:()=>k,Mx:()=>D,N9:()=>ac,O0:()=>B,Sr:()=>J,Tb:()=>s,Ux:()=>ab,Wd:()=>Y,aO:()=>m,at:()=>y,ec:()=>o,eg:()=>V,h9:()=>x,i4:()=>G,iK:()=>p,im:()=>T,iy:()=>P,jp:()=>t,lT:()=>z,lq:()=>F,ls:()=>K,mT:()=>w,n6:()=>n,oK:()=>O,oZ:()=>S,of:()=>E,po:()=>N,tP:()=>q,th:()=>v,v4:()=>l,vI:()=>W,yw:()=>U});var d=c(21820),e=c(33873),f=c(79748),g=c(29021),h=c(79646);let i=(0,d.homedir)(),j=process.env.COCKPIT_HOME?(0,e.resolve)(process.env.COCKPIT_HOME.replace(/^~(?=$|\/)/,i)):(0,e.join)(i,".cockpit"),k=(0,e.join)(j,"projects"),l=(0,e.join)(j,"state.json"),m=(0,e.join)(j,"pinned-sessions.json"),n=(0,e.join)(j,"push-subscriptions.json"),o=(0,e.join)(j,"note.md"),p=(0,e.join)(j,"scheduled-tasks.json"),q=(0,e.join)(j,"settings.json"),r=(0,e.join)(j,"skills.json"),s=(0,e.join)(j,"review"),t=(0,e.join)(s,"_signal");function u(){try{(0,g.existsSync)(s)||(0,g.mkdirSync)(s,{recursive:!0}),(0,g.writeFileSync)(t,Date.now().toString())}catch{}}let v=(0,e.join)(i,".claude"),w=(0,e.join)(v,"projects"),x=(0,e.join)(i,".claude2"),y=(0,e.join)(x,"projects"),z=(0,e.join)(j,"deepseek"),A=(0,e.join)(z,"projects");function B(a){return a.replace(/[/.]/g,"-")}function C(a){return(0,e.join)(k,B(a))}function D(a){return(0,e.join)(C(a),"session.json")}function E(a){return(0,e.join)(C(a),"recent-files.json")}function F(a){return(0,e.join)(C(a),"expanded-paths.json")}function G(a){return(0,e.join)(C(a),"comments.json")}function H(a){return(0,e.join)(C(a),"services.json")}function I(a){return(0,e.join)(C(a),"note.md")}function J(a,b){return(0,e.join)(C(a),`terminal-history-${b}.jsonl`)}function K(a,b){return(0,e.join)(C(a),`terminal-output-${b}.txt`)}function L(a,b){let c=b?`terminal-env-${b}.json`:"terminal-env-global.json";return(0,e.join)(C(a),c)}function M(){return(0,e.join)(j,"terminal-aliases.json")}function N(){return(0,e.join)(j,"services.json")}function O(a){return(0,e.join)(C(a),"project-settings.json")}function P(a,b){return(0,e.join)(C(a),`terminal-bubble-order-${b}.json`)}function Q(a){return(0,e.join)(s,`${a}.json`)}function R(a,b){return(0,e.join)((0,e.join)(w,B(a)),`${b}.jsonl`)}function S(a,b){return(0,e.join)((0,e.join)(y,B(a)),`${b}.jsonl`)}function T(a,b){return(0,e.join)((0,e.join)(A,B(a)),`${b}.jsonl`)}function U(a,b){return(0,e.join)((0,e.join)(j,"ollama-sessions",B(a)),`${b}.jsonl`)}function V(a){let b=(0,e.join)(i,".codex","sessions");if(!(0,g.existsSync)(b))return null;try{let c=(0,h.execSync)(`find ${JSON.stringify(b)} -name "*${a}.jsonl" -type f 2>/dev/null`,{encoding:"utf8",timeout:3e3}).trim();if(c)return c.split("\n")[0]}catch{}return null}function W(a){let b=(0,e.join)(i,".kimi","sessions");if(!(0,g.existsSync)(b))return null;try{for(let c of(0,g.readdirSync)(b)){let d=(0,e.join)(b,c,a,"context.jsonl");if((0,g.existsSync)(d))return d}}catch{}return null}async function X(a){(0,g.existsSync)(a)||await (0,f.mkdir)(a,{recursive:!0})}async function Y(a){let b=(0,e.join)(a,"..");await X(b)}async function Z(a,b){try{let b=await (0,f.readFile)(a,"utf-8");return JSON.parse(b)}catch{return b}}async function $(a,b){await Y(a),await (0,f.writeFile)(a,JSON.stringify(b,null,2),"utf-8")}let _=globalThis,aa=_.__cockpitFileLocks??(_.__cockpitFileLocks=new Map);function ab(a,b){let c=(aa.get(a)??Promise.resolve()).then(b),d=c.then(()=>{},()=>{});return aa.set(a,d),d.then(()=>{aa.get(a)===d&&aa.delete(a)}),c}function ac(a,b,c){return ab(a,async()=>{let d=await Z(a,b),e=await c(d);return await $(a,e),e})}},38433:(a,b,c)=>{c.d(b,{SG:()=>m,a_:()=>l,hO:()=>k,lG:()=>j});var d=c(51181),e=c.n(d),f=c(7939);let g=null,h="https://github.com/Surething-io/cockpit";async function i(){if(g)return g;let a=await (0,f.Ux)(f.tP,async()=>{let a=await (0,f.JE)(f.tP,{});if(a.push?.publicKey&&a.push?.privateKey){let b=!function(a){if(!a||a.includes("localhost"))return!1;if(a.startsWith("https://"))return!0;let b=/^mailto:[^\s@]+@([^\s@]+)$/.exec(a);return!!b&&b[1].includes(".")}(a.push.subject)?h:a.push.subject;return b!==a.push.subject&&await (0,f.An)(f.tP,{...a,push:{...a.push,subject:b}}),{publicKey:a.push.publicKey,privateKey:a.push.privateKey,subject:b}}let b=e().generateVAPIDKeys(),c={publicKey:b.publicKey,privateKey:b.privateKey,subject:h};return await (0,f.An)(f.tP,{...a,push:c}),c});return e().setVapidDetails(a.subject,a.publicKey,a.privateKey),g=a,a}async function j(){return(await i()).publicKey}async function k(a){await (0,f.Ux)(f.n6,async()=>{let b=await (0,f.JE)(f.n6,{subscriptions:[]});b.subscriptions.some(b=>b.endpoint===a.endpoint)||(b.subscriptions.push(a),await (0,f.An)(f.n6,b))})}async function l(a){await (0,f.Ux)(f.n6,async()=>{let b=await (0,f.JE)(f.n6,{subscriptions:[]}),c=b.subscriptions.filter(b=>b.endpoint!==a);c.length!==b.subscriptions.length&&await (0,f.An)(f.n6,{subscriptions:c})})}async function m(a){try{await i()}catch{return{sent:0,pruned:0}}let b=await (0,f.JE)(f.n6,{subscriptions:[]});if(0===b.subscriptions.length)return{sent:0,pruned:0};let c=JSON.stringify(a),d=[],g=0;return await Promise.all(b.subscriptions.map(async a=>{try{await e().sendNotification(a,c),g++}catch(c){let b=c?.statusCode;if(404===b||410===b)d.push(a.endpoint);else{let d=a.endpoint;try{d=new URL(a.endpoint).host}catch{}console.error(`[push] send failed (${b??"?"}) to ${d}: ${c?.body||c?.message||"unknown"}`)}}})),d.length&&await (0,f.Ux)(f.n6,async()=>{let a=await (0,f.JE)(f.n6,{subscriptions:[]});await (0,f.An)(f.n6,{subscriptions:a.subscriptions.filter(a=>!d.includes(a.endpoint))})}),{sent:g,pruned:d.length}}},72891:(a,b,c)=>{c.a(a,async(a,d)=>{try{c.d(b,{OZ:()=>o,RL:()=>n,k9:()=>p,ok:()=>l});var e=c(37625),f=c(52693),g=c(18412),h=c(89705),i=c(94506),j=c(770),k=a([i]);i=(k.then?(await k)():k)[0];let l=(a,b=200)=>new Response(JSON.stringify(a),{status:b,headers:{"content-type":"application/json"}}),m=a=>{let b=e.od(a);if(f.Ru(b)){let a=b.value,c=(0,j.Sh)(a);return new Response(JSON.stringify({error:(a=>{let b=a.message;if("string"==typeof b&&b.length>0)return b;let c=a.cause;if(c instanceof Error&&c.message.length>0)return c.message;switch(a._tag){case"ValidationError":return`Invalid ${a.field}: ${a.reason}`;case"NotFoundError":return`${a.resource} not found: ${a.id}`;case"PermissionError":return`Permission denied: ${a.action} on ${a.resource}`;case"DBError":return`${a.db} ${a.op} failed`;case"FSError":return`${a.op} ${a.path} failed`;case"WSError":return`${a.proto} ${a.kind} failed`;case"AgentError":return`${a.provider} ${a.kind} failed`;default:return a._tag}})(a),tag:a._tag}),{status:c,headers:{"content-type":"application/json"}})}return console.error("[handler] uncaught defect:\n"+e.j9(a)),new Response(JSON.stringify({error:"Internal Server Error",tag:"InternalError"}),{status:500,headers:{"content-type":"application/json"}})},n=a=>async b=>{let c=await i.s9.runPromiseExit(a(b));return g.YW(c,{onFailure:a=>m(a),onSuccess:a=>a})},o=a=>async(b,c)=>{let d=await c.params,e=await i.s9.runPromiseExit(a(b,d));return g.YW(e,{onFailure:a=>m(a),onSuccess:a=>a})},p=a=>h.$mh({try:()=>a.json(),catch:()=>new j.yI({field:"body",reason:"invalid JSON"})});d()}catch(a){d(a)}})}};