@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
@@ -0,0 +1,314 @@
1
+ import {
2
+ GLOBAL_STATE_FILE,
3
+ findCodexSessionPath,
4
+ findKimiSessionPath,
5
+ getClaude2SessionPath,
6
+ getClaudeSessionPath,
7
+ getOllamaSessionPath,
8
+ readJsonFile,
9
+ withFileLock,
10
+ writeJsonFile
11
+ } from "./chunk-GCYLMG43.mjs";
12
+
13
+ // packages/feature/agent/src/server/state/globalState.ts
14
+ import { createReadStream, existsSync } from "fs";
15
+ import { createInterface } from "readline";
16
+ var MAX_SESSIONS = 15;
17
+ var MAX_TEXT_LEN = 50;
18
+ function truncate(s) {
19
+ if (!s) return s;
20
+ const chars = [...s];
21
+ return chars.length <= MAX_TEXT_LEN ? s : chars.slice(0, MAX_TEXT_LEN).join("") + "\u2026";
22
+ }
23
+ async function updateGlobalState(cwd, sessionId, status, title, lastUserMessage) {
24
+ if (!existsSync(cwd)) {
25
+ return;
26
+ }
27
+ return withFileLock(GLOBAL_STATE_FILE, async () => {
28
+ const state = await readJsonFile(GLOBAL_STATE_FILE, { sessions: [] });
29
+ for (const s of state.sessions) {
30
+ if (!s.status) {
31
+ const legacy = s;
32
+ s.status = legacy.isLoading ? "loading" : "normal";
33
+ delete legacy.isLoading;
34
+ }
35
+ }
36
+ const existingIndex = state.sessions.findIndex(
37
+ (s) => s.cwd === cwd && s.sessionId === sessionId
38
+ );
39
+ const existed = existingIndex >= 0;
40
+ const existing = existed ? state.sessions[existingIndex] : void 0;
41
+ const newSession = {
42
+ cwd,
43
+ sessionId,
44
+ lastActive: Date.now(),
45
+ status,
46
+ title: truncate(title || existing?.title),
47
+ lastUserMessage: truncate(lastUserMessage || existing?.lastUserMessage)
48
+ };
49
+ if (existingIndex >= 0) {
50
+ state.sessions[existingIndex] = newSession;
51
+ } else {
52
+ state.sessions.push(newSession);
53
+ }
54
+ state.sessions.sort((a, b) => b.lastActive - a.lastActive);
55
+ state.sessions = state.sessions.slice(0, MAX_SESSIONS);
56
+ await writeJsonFile(GLOBAL_STATE_FILE, state);
57
+ });
58
+ }
59
+ async function getSessionTitle(cwd, sessionId) {
60
+ const claudePath = getClaudeSessionPath(cwd, sessionId);
61
+ if (existsSync(claudePath)) {
62
+ return getClaudeStyleTitle(claudePath);
63
+ }
64
+ const claude2Path = getClaude2SessionPath(cwd, sessionId);
65
+ if (existsSync(claude2Path)) {
66
+ return getClaudeStyleTitle(claude2Path);
67
+ }
68
+ const ollamaPath = getOllamaSessionPath(cwd, sessionId);
69
+ if (existsSync(ollamaPath)) {
70
+ return getClaudeStyleTitle(ollamaPath);
71
+ }
72
+ const codexPath = findCodexSessionPath(sessionId);
73
+ if (codexPath && existsSync(codexPath)) {
74
+ const title = await getCodexTitle(codexPath);
75
+ return title || "Untitled Session";
76
+ }
77
+ const kimiPath = findKimiSessionPath(sessionId);
78
+ if (kimiPath && existsSync(kimiPath)) {
79
+ const title = await getKimiTitle(kimiPath);
80
+ return title || "Untitled Session";
81
+ }
82
+ return "Untitled Session";
83
+ }
84
+ async function getLastUserMessage(cwd, sessionId) {
85
+ const claudePath = getClaudeSessionPath(cwd, sessionId);
86
+ if (existsSync(claudePath)) {
87
+ return await getClaudeStyleLastUserMessage(claudePath);
88
+ }
89
+ const claude2Path = getClaude2SessionPath(cwd, sessionId);
90
+ if (existsSync(claude2Path)) {
91
+ return await getClaudeStyleLastUserMessage(claude2Path);
92
+ }
93
+ const ollamaPath = getOllamaSessionPath(cwd, sessionId);
94
+ if (existsSync(ollamaPath)) {
95
+ return await getClaudeStyleLastUserMessage(ollamaPath);
96
+ }
97
+ const codexPath = findCodexSessionPath(sessionId);
98
+ if (codexPath && existsSync(codexPath)) {
99
+ return await getCodexLastUserMessage(codexPath);
100
+ }
101
+ const kimiPath = findKimiSessionPath(sessionId);
102
+ if (kimiPath && existsSync(kimiPath)) {
103
+ return await getKimiLastUserMessage(kimiPath);
104
+ }
105
+ return void 0;
106
+ }
107
+ function filterCommandTags(text) {
108
+ let filtered = text.replace(/<command-[^>]*>[\s\S]*?<\/command-[^>]*>/g, "");
109
+ filtered = filtered.replace(/<local-command-[^>]*>[\s\S]*?<\/local-command-[^>]*>/g, "");
110
+ filtered = filtered.trim();
111
+ return filtered;
112
+ }
113
+ function isValidUserMessage(text) {
114
+ if (text.startsWith("This session is being continued")) return false;
115
+ if (text.startsWith("Caveat: The messages below")) return false;
116
+ if (!text.trim()) return false;
117
+ return true;
118
+ }
119
+ async function getClaudeStyleTitle(filePath) {
120
+ try {
121
+ const fileStream = createReadStream(filePath);
122
+ const rl = createInterface({ input: fileStream, crlfDelay: Infinity });
123
+ let summary = "";
124
+ const userMessages = [];
125
+ for await (const line of rl) {
126
+ if (!line.trim()) continue;
127
+ try {
128
+ const entry = JSON.parse(line);
129
+ if (entry.type === "summary" && entry.summary) {
130
+ summary = entry.summary;
131
+ }
132
+ if (entry.type === "user") {
133
+ const message = entry.message;
134
+ if (!message?.content) continue;
135
+ if (typeof message.content === "string") {
136
+ userMessages.push(message.content);
137
+ } else if (Array.isArray(message.content)) {
138
+ for (const block of message.content) {
139
+ if (block.type === "text" && block.text) userMessages.push(block.text);
140
+ }
141
+ }
142
+ }
143
+ } catch {
144
+ }
145
+ }
146
+ return generateTitle(summary, userMessages);
147
+ } catch {
148
+ return "Untitled Session";
149
+ }
150
+ }
151
+ async function getClaudeStyleLastUserMessage(filePath) {
152
+ try {
153
+ const fileStream = createReadStream(filePath);
154
+ const rl = createInterface({ input: fileStream, crlfDelay: Infinity });
155
+ let lastUserMessage;
156
+ for await (const line of rl) {
157
+ if (!line.trim()) continue;
158
+ try {
159
+ const entry = JSON.parse(line);
160
+ if (entry.type !== "user") continue;
161
+ const message = entry.message;
162
+ if (!message?.content) continue;
163
+ let text = "";
164
+ if (typeof message.content === "string") {
165
+ text = message.content;
166
+ } else if (Array.isArray(message.content)) {
167
+ for (const block of message.content) {
168
+ if (block.type === "text" && block.text) {
169
+ text = block.text;
170
+ break;
171
+ }
172
+ }
173
+ }
174
+ if (!text) continue;
175
+ const filtered = filterCommandTags(text);
176
+ if (filtered && isValidUserMessage(filtered)) {
177
+ lastUserMessage = filtered;
178
+ }
179
+ } catch {
180
+ }
181
+ }
182
+ return lastUserMessage;
183
+ } catch {
184
+ return void 0;
185
+ }
186
+ }
187
+ async function getCodexLastUserMessage(filePath) {
188
+ try {
189
+ const fileStream = createReadStream(filePath);
190
+ const rl = createInterface({ input: fileStream, crlfDelay: Infinity });
191
+ let last;
192
+ for await (const line of rl) {
193
+ if (!line.trim()) continue;
194
+ let entry;
195
+ try {
196
+ entry = JSON.parse(line);
197
+ } catch {
198
+ continue;
199
+ }
200
+ if (entry.type !== "response_item") continue;
201
+ const payload = entry.payload;
202
+ if (!payload || payload.type !== "message" || payload.role !== "user") continue;
203
+ const text = payload.content?.filter((c) => c.type === "input_text" && c.text).map((c) => c.text).join("") || "";
204
+ if (!text || text.startsWith("<") || text.startsWith("#")) continue;
205
+ const filtered = filterCommandTags(text);
206
+ if (filtered && isValidUserMessage(filtered)) {
207
+ last = filtered;
208
+ }
209
+ }
210
+ return last;
211
+ } catch {
212
+ return void 0;
213
+ }
214
+ }
215
+ async function getCodexTitle(filePath) {
216
+ try {
217
+ const fileStream = createReadStream(filePath);
218
+ const rl = createInterface({ input: fileStream, crlfDelay: Infinity });
219
+ for await (const line of rl) {
220
+ if (!line.trim()) continue;
221
+ let entry;
222
+ try {
223
+ entry = JSON.parse(line);
224
+ } catch {
225
+ continue;
226
+ }
227
+ if (entry.type !== "response_item") continue;
228
+ const payload = entry.payload;
229
+ if (!payload || payload.type !== "message" || payload.role !== "user") continue;
230
+ const text = payload.content?.filter((c) => c.type === "input_text" && c.text).map((c) => c.text).join("") || "";
231
+ if (!text || text.startsWith("<") || text.startsWith("#")) continue;
232
+ return text.slice(0, 80);
233
+ }
234
+ return void 0;
235
+ } catch {
236
+ return void 0;
237
+ }
238
+ }
239
+ async function getKimiLastUserMessage(filePath) {
240
+ try {
241
+ const fileStream = createReadStream(filePath);
242
+ const rl = createInterface({ input: fileStream, crlfDelay: Infinity });
243
+ let last;
244
+ for await (const line of rl) {
245
+ if (!line.trim()) continue;
246
+ let entry;
247
+ try {
248
+ entry = JSON.parse(line);
249
+ } catch {
250
+ continue;
251
+ }
252
+ if (entry.role !== "user") continue;
253
+ const text = typeof entry.content === "string" ? entry.content : Array.isArray(entry.content) ? entry.content.filter((c) => (c.type === "input_text" || c.type === "text") && c.text).map((c) => c.text).join("") : "";
254
+ if (!text || text.startsWith("<system") || text.startsWith("<environment") || text.startsWith("# AGENTS.md") || text.startsWith("<permissions")) {
255
+ continue;
256
+ }
257
+ const filtered = filterCommandTags(text);
258
+ if (filtered && isValidUserMessage(filtered)) {
259
+ last = filtered;
260
+ }
261
+ }
262
+ return last;
263
+ } catch {
264
+ return void 0;
265
+ }
266
+ }
267
+ async function getKimiTitle(filePath) {
268
+ try {
269
+ const fileStream = createReadStream(filePath);
270
+ const rl = createInterface({ input: fileStream, crlfDelay: Infinity });
271
+ for await (const line of rl) {
272
+ if (!line.trim()) continue;
273
+ let entry;
274
+ try {
275
+ entry = JSON.parse(line);
276
+ } catch {
277
+ continue;
278
+ }
279
+ if (entry.role !== "user") continue;
280
+ const text = typeof entry.content === "string" ? entry.content : Array.isArray(entry.content) ? entry.content.filter((c) => (c.type === "input_text" || c.type === "text") && c.text).map((c) => c.text).join("") : "";
281
+ if (!text || text.startsWith("<system") || text.startsWith("<environment") || text.startsWith("# AGENTS.md") || text.startsWith("<permissions")) {
282
+ continue;
283
+ }
284
+ return text.slice(0, 80);
285
+ }
286
+ return void 0;
287
+ } catch {
288
+ return void 0;
289
+ }
290
+ }
291
+ function generateTitle(summary, userMessages) {
292
+ if (summary) return summary;
293
+ let commandName = "";
294
+ for (const msg of userMessages) {
295
+ const filtered = filterCommandTags(msg);
296
+ if (!filtered) continue;
297
+ if (filtered.startsWith("/") && !commandName) {
298
+ commandName = filtered;
299
+ continue;
300
+ }
301
+ if (commandName) {
302
+ return `${commandName} ${filtered}`;
303
+ }
304
+ return filtered;
305
+ }
306
+ if (commandName) return commandName;
307
+ return "Untitled Session";
308
+ }
309
+
310
+ export {
311
+ updateGlobalState,
312
+ getSessionTitle,
313
+ getLastUserMessage
314
+ };
@@ -1,8 +1,19 @@
1
1
  import {
2
+ AppRuntime,
3
+ Cause_exports,
4
+ Effect_exports,
5
+ Exit_exports,
6
+ FSError,
7
+ Option_exports,
8
+ ValidationError,
2
9
  ensureParentDir,
10
+ errorToStatus,
11
+ getBubbleOrderPath,
3
12
  getTerminalHistoryPath,
4
- getTerminalOutputPath
5
- } from "./chunk-ZJ6CC3MH.mjs";
13
+ getTerminalOutputPath,
14
+ readJsonFile,
15
+ writeJsonFile
16
+ } from "./chunk-GCYLMG43.mjs";
6
17
 
7
18
  // packages/feature/console/src/server/plugins/browser/BrowserBridge.ts
8
19
  import { WebSocket } from "ws";
@@ -33,9 +44,9 @@ function toShortId(fullId) {
33
44
  var g_browser = globalThis;
34
45
  var registry = g_browser.__cockpitBrowserRegistry ?? (g_browser.__cockpitBrowserRegistry = /* @__PURE__ */ new Map());
35
46
  var fullIdToShort = g_browser.__cockpitBrowserFullIdToShort ?? (g_browser.__cockpitBrowserFullIdToShort = /* @__PURE__ */ new Map());
36
- function registerBrowser(fullId, ws) {
47
+ function registerBrowser(fullId, ws, projectCwd, tabId) {
37
48
  const shortId = toShortId(fullId);
38
- registry.set(shortId, { fullId, ws, lastSeen: Date.now() });
49
+ registry.set(shortId, { fullId, ws, lastSeen: Date.now(), projectCwd, tabId });
39
50
  fullIdToShort.set(fullId, shortId);
40
51
  return shortId;
41
52
  }
@@ -65,7 +76,9 @@ function listBrowsers() {
65
76
  result.push({
66
77
  shortId,
67
78
  fullId: entry.fullId,
68
- connected: entry.ws !== null && entry.ws.readyState === WebSocket.OPEN
79
+ connected: entry.ws !== null && entry.ws.readyState === WebSocket.OPEN,
80
+ projectCwd: entry.projectCwd,
81
+ tabId: entry.tabId
69
82
  });
70
83
  }
71
84
  return result;
@@ -75,22 +88,28 @@ function createPendingRequest(reqId, timeout) {
75
88
  return new Promise((resolve, reject) => {
76
89
  const timer = setTimeout(() => {
77
90
  pendingRequests.delete(reqId);
91
+ recordCommandResolved(reqId, false);
78
92
  reject(new Error(`Timeout after ${timeout}ms`));
79
93
  }, timeout);
80
94
  pendingRequests.set(reqId, { resolve, reject, timer });
81
95
  });
82
96
  }
83
- function resolvePendingRequest(reqId, ok, data, error) {
97
+ function resolvePendingRequest(reqId, ok2, data, error) {
84
98
  const pending = pendingRequests.get(reqId);
85
- if (!pending) return;
99
+ if (!pending) {
100
+ recordCommandResolved(reqId, ok2);
101
+ return;
102
+ }
86
103
  clearTimeout(pending.timer);
87
104
  pendingRequests.delete(reqId);
88
- if (ok) {
105
+ recordCommandResolved(reqId, ok2);
106
+ if (ok2) {
89
107
  pending.resolve(data);
90
108
  } else {
91
109
  pending.reject(new Error(error || "Browser command failed"));
92
110
  }
93
111
  }
112
+ var reqIdMeta = globalThis.__cockpitBrowserReqMeta ?? (globalThis.__cockpitBrowserReqMeta = /* @__PURE__ */ new Map());
94
113
  function sendCommandToBrowser(shortId, reqId, action, params) {
95
114
  const entry = registry.get(shortId);
96
115
  if (!entry || !entry.ws || entry.ws.readyState !== WebSocket.OPEN) {
@@ -102,8 +121,48 @@ function sendCommandToBrowser(shortId, reqId, action, params) {
102
121
  action,
103
122
  params
104
123
  }));
124
+ reqIdMeta.set(reqId, { shortId, action });
105
125
  return true;
106
126
  }
127
+ function recordCommandResolved(reqId, ok2) {
128
+ const meta = reqIdMeta.get(reqId);
129
+ if (!meta) return;
130
+ reqIdMeta.delete(reqId);
131
+ if (ok2) {
132
+ const entry = registry.get(meta.shortId);
133
+ if (entry) {
134
+ entry.lastSuccessTs = Date.now();
135
+ entry.lastSuccessAction = meta.action;
136
+ entry.lastSeen = Date.now();
137
+ }
138
+ }
139
+ }
140
+ function getBrowserHealth(shortId) {
141
+ const entry = registry.get(shortId);
142
+ if (!entry) {
143
+ return {
144
+ found: false,
145
+ ws: "unknown",
146
+ lastSeenMs: null,
147
+ lastSuccessMs: null,
148
+ lastSuccessAction: null,
149
+ pendingCommands: 0
150
+ };
151
+ }
152
+ const now = Date.now();
153
+ let pending = 0;
154
+ for (const reqId of pendingRequests.keys()) {
155
+ if (reqIdMeta.get(reqId)?.shortId === shortId) pending += 1;
156
+ }
157
+ return {
158
+ found: true,
159
+ ws: entry.ws && entry.ws.readyState === WebSocket.OPEN ? "open" : "closed",
160
+ lastSeenMs: entry.lastSeen ? now - entry.lastSeen : null,
161
+ lastSuccessMs: entry.lastSuccessTs ? now - entry.lastSuccessTs : null,
162
+ lastSuccessAction: entry.lastSuccessAction ?? null,
163
+ pendingCommands: pending
164
+ };
165
+ }
107
166
 
108
167
  // packages/feature/console/src/server/plugins/jupyter/JupyterKernelManager.ts
109
168
  import { spawn } from "child_process";
@@ -440,7 +499,8 @@ function listTerminals(getRunning) {
440
499
  tabId: entry.tabId,
441
500
  command: entry.command,
442
501
  pid: cmd?.pid ?? 0,
443
- running: !!cmd
502
+ running: !!cmd,
503
+ projectCwd: entry.projectCwd
444
504
  });
445
505
  }
446
506
  return result;
@@ -926,6 +986,178 @@ function grepOutput(cmd, pattern, opts = {}) {
926
986
  };
927
987
  }
928
988
 
989
+ // packages/shared/effect-runtime/src/next.ts
990
+ var ok = (body, status = 200) => new Response(JSON.stringify(body), {
991
+ status,
992
+ headers: { "content-type": "application/json" }
993
+ });
994
+ var extractErrorMessage = (e) => {
995
+ const maybeMsg = e.message;
996
+ if (typeof maybeMsg === "string" && maybeMsg.length > 0) {
997
+ return maybeMsg;
998
+ }
999
+ const cause = e.cause;
1000
+ if (cause instanceof Error && cause.message.length > 0) {
1001
+ return cause.message;
1002
+ }
1003
+ switch (e._tag) {
1004
+ case "ValidationError": {
1005
+ const v = e;
1006
+ return `Invalid ${v.field}: ${v.reason}`;
1007
+ }
1008
+ case "NotFoundError": {
1009
+ const n = e;
1010
+ return `${n.resource} not found: ${n.id}`;
1011
+ }
1012
+ case "PermissionError": {
1013
+ const p = e;
1014
+ return `Permission denied: ${p.action} on ${p.resource}`;
1015
+ }
1016
+ case "DBError": {
1017
+ const d = e;
1018
+ return `${d.db} ${d.op} failed`;
1019
+ }
1020
+ case "FSError": {
1021
+ const f = e;
1022
+ return `${f.op} ${f.path} failed`;
1023
+ }
1024
+ case "WSError": {
1025
+ const w = e;
1026
+ return `${w.proto} ${w.kind} failed`;
1027
+ }
1028
+ case "AgentError": {
1029
+ const a = e;
1030
+ return `${a.provider} ${a.kind} failed`;
1031
+ }
1032
+ default:
1033
+ return e._tag;
1034
+ }
1035
+ };
1036
+ var errorToResponse = (cause) => {
1037
+ const failure = Cause_exports.failureOption(cause);
1038
+ if (Option_exports.isSome(failure)) {
1039
+ const e = failure.value;
1040
+ const status = errorToStatus(e);
1041
+ return new Response(
1042
+ JSON.stringify({ error: extractErrorMessage(e), tag: e._tag }),
1043
+ {
1044
+ status,
1045
+ headers: { "content-type": "application/json" }
1046
+ }
1047
+ );
1048
+ }
1049
+ console.error("[handler] uncaught defect:\n" + Cause_exports.pretty(cause));
1050
+ return new Response(
1051
+ JSON.stringify({ error: "Internal Server Error", tag: "InternalError" }),
1052
+ {
1053
+ status: 500,
1054
+ headers: { "content-type": "application/json" }
1055
+ }
1056
+ );
1057
+ };
1058
+ var handler = (fn) => async (req) => {
1059
+ const exit = await AppRuntime.runPromiseExit(fn(req));
1060
+ return Exit_exports.match(exit, {
1061
+ onFailure: (cause) => errorToResponse(cause),
1062
+ onSuccess: (res) => res
1063
+ });
1064
+ };
1065
+ var parseJsonRaw = (req) => Effect_exports.tryPromise({
1066
+ try: () => req.json(),
1067
+ catch: () => new ValidationError({
1068
+ field: "body",
1069
+ reason: "invalid JSON"
1070
+ })
1071
+ });
1072
+
1073
+ // packages/feature/console/src/server/api/terminal/bubble-order.ts
1074
+ async function readBubbleTitles(cwd, tabId) {
1075
+ try {
1076
+ const raw = await readJsonFile(getBubbleOrderPath(cwd, tabId), []);
1077
+ return normalise(raw).titles;
1078
+ } catch {
1079
+ return {};
1080
+ }
1081
+ }
1082
+ function normalise(raw) {
1083
+ if (Array.isArray(raw)) return { order: raw, titles: {} };
1084
+ if (raw && typeof raw === "object") {
1085
+ const r = raw;
1086
+ return {
1087
+ order: Array.isArray(r.order) ? r.order : [],
1088
+ titles: r.titles && typeof r.titles === "object" ? r.titles : {}
1089
+ };
1090
+ }
1091
+ return { order: [], titles: {} };
1092
+ }
1093
+ var GET = handler(
1094
+ (req) => Effect_exports.gen(function* () {
1095
+ const sp = new URL(req.url).searchParams;
1096
+ const cwd = sp.get("cwd");
1097
+ const tabId = sp.get("tabId");
1098
+ if (!cwd || !tabId) {
1099
+ return yield* Effect_exports.fail(
1100
+ new ValidationError({
1101
+ field: !cwd ? "cwd" : "tabId",
1102
+ reason: "missing"
1103
+ })
1104
+ );
1105
+ }
1106
+ const orderPath = getBubbleOrderPath(cwd, tabId);
1107
+ const raw = yield* Effect_exports.tryPromise({
1108
+ try: () => readJsonFile(orderPath, []),
1109
+ catch: (cause) => new FSError({ path: orderPath, op: "read", cause })
1110
+ });
1111
+ const file = normalise(raw);
1112
+ return ok({ order: file.order, titles: file.titles });
1113
+ })
1114
+ );
1115
+ var POST = handler(
1116
+ (req) => Effect_exports.gen(function* () {
1117
+ const body = yield* parseJsonRaw(req);
1118
+ if (!body.cwd || !body.tabId) {
1119
+ return yield* Effect_exports.fail(
1120
+ new ValidationError({
1121
+ field: !body.cwd ? "cwd" : "tabId",
1122
+ reason: "missing"
1123
+ })
1124
+ );
1125
+ }
1126
+ const hasOrder = Array.isArray(body.order);
1127
+ const hasTitles = body.titles && typeof body.titles === "object";
1128
+ if (!hasOrder && !hasTitles) {
1129
+ return yield* Effect_exports.fail(
1130
+ new ValidationError({ field: "order|titles", reason: "missing \u2014 provide at least one" })
1131
+ );
1132
+ }
1133
+ const orderPath = getBubbleOrderPath(body.cwd, body.tabId);
1134
+ const existing = normalise(
1135
+ yield* Effect_exports.tryPromise({
1136
+ try: () => readJsonFile(orderPath, []),
1137
+ catch: (cause) => new FSError({ path: orderPath, op: "read", cause })
1138
+ })
1139
+ );
1140
+ const next = {
1141
+ order: hasOrder ? body.order : existing.order,
1142
+ titles: hasTitles ? mergeTitles(existing.titles, body.titles) : existing.titles
1143
+ };
1144
+ yield* Effect_exports.tryPromise({
1145
+ try: () => writeJsonFile(orderPath, next),
1146
+ catch: (cause) => new FSError({ path: orderPath, op: "write", cause })
1147
+ });
1148
+ return ok({ success: true });
1149
+ })
1150
+ );
1151
+ function mergeTitles(base, patch) {
1152
+ const out = { ...base };
1153
+ for (const [k, v] of Object.entries(patch)) {
1154
+ if (typeof v !== "string") continue;
1155
+ if (v === "") delete out[k];
1156
+ else out[k] = v.slice(0, 256);
1157
+ }
1158
+ return out;
1159
+ }
1160
+
929
1161
  export {
930
1162
  registerBrowser,
931
1163
  unregisterBrowser,
@@ -935,6 +1167,8 @@ export {
935
1167
  createPendingRequest,
936
1168
  resolvePendingRequest,
937
1169
  sendCommandToBrowser,
1170
+ recordCommandResolved,
1171
+ getBrowserHealth,
938
1172
  kernelManager,
939
1173
  registerTerminal,
940
1174
  finalizeTerminal,
@@ -965,5 +1199,6 @@ export {
965
1199
  readTail,
966
1200
  readHead,
967
1201
  readAround,
968
- grepOutput
1202
+ grepOutput,
1203
+ readBubbleTitles
969
1204
  };