@coralai/sps-cli 0.50.6 → 0.50.8

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 (91) hide show
  1. package/dist/console-assets/assets/{index-C95GbuxW.js → index-CGiD8z0L.js} +1 -1
  2. package/dist/console-assets/index.html +1 -1
  3. package/dist/services/PipelineService.d.ts +1 -0
  4. package/dist/services/PipelineService.d.ts.map +1 -1
  5. package/dist/services/PipelineService.js +35 -0
  6. package/dist/services/PipelineService.js.map +1 -1
  7. package/dist/services/executors.d.ts +11 -0
  8. package/dist/services/executors.d.ts.map +1 -1
  9. package/dist/services/executors.js +117 -0
  10. package/dist/services/executors.js.map +1 -1
  11. package/package.json +1 -1
  12. package/dist/console/sse/eventBus.d.ts +0 -25
  13. package/dist/console/sse/eventBus.d.ts.map +0 -1
  14. package/dist/console/sse/eventBus.js +0 -32
  15. package/dist/console/sse/eventBus.js.map +0 -1
  16. package/dist/console-server/index.d.ts +0 -29
  17. package/dist/console-server/index.d.ts.map +0 -1
  18. package/dist/console-server/index.js +0 -180
  19. package/dist/console-server/index.js.map +0 -1
  20. package/dist/console-server/lib/cardReader.d.ts +0 -27
  21. package/dist/console-server/lib/cardReader.d.ts.map +0 -1
  22. package/dist/console-server/lib/cardReader.js +0 -201
  23. package/dist/console-server/lib/cardReader.js.map +0 -1
  24. package/dist/console-server/lib/lockFile.d.ts +0 -17
  25. package/dist/console-server/lib/lockFile.d.ts.map +0 -1
  26. package/dist/console-server/lib/lockFile.js +0 -61
  27. package/dist/console-server/lib/lockFile.js.map +0 -1
  28. package/dist/console-server/lib/portPicker.d.ts +0 -3
  29. package/dist/console-server/lib/portPicker.d.ts.map +0 -1
  30. package/dist/console-server/lib/portPicker.js +0 -25
  31. package/dist/console-server/lib/portPicker.js.map +0 -1
  32. package/dist/console-server/lib/spawnCli.d.ts +0 -31
  33. package/dist/console-server/lib/spawnCli.d.ts.map +0 -1
  34. package/dist/console-server/lib/spawnCli.js +0 -64
  35. package/dist/console-server/lib/spawnCli.js.map +0 -1
  36. package/dist/console-server/routes/cards.d.ts +0 -7
  37. package/dist/console-server/routes/cards.d.ts.map +0 -1
  38. package/dist/console-server/routes/cards.js +0 -185
  39. package/dist/console-server/routes/cards.js.map +0 -1
  40. package/dist/console-server/routes/chat.d.ts +0 -36
  41. package/dist/console-server/routes/chat.d.ts.map +0 -1
  42. package/dist/console-server/routes/chat.js +0 -458
  43. package/dist/console-server/routes/chat.js.map +0 -1
  44. package/dist/console-server/routes/logs.d.ts +0 -14
  45. package/dist/console-server/routes/logs.d.ts.map +0 -1
  46. package/dist/console-server/routes/logs.js +0 -283
  47. package/dist/console-server/routes/logs.js.map +0 -1
  48. package/dist/console-server/routes/pipeline.d.ts +0 -8
  49. package/dist/console-server/routes/pipeline.d.ts.map +0 -1
  50. package/dist/console-server/routes/pipeline.js +0 -96
  51. package/dist/console-server/routes/pipeline.js.map +0 -1
  52. package/dist/console-server/routes/projects.d.ts +0 -11
  53. package/dist/console-server/routes/projects.d.ts.map +0 -1
  54. package/dist/console-server/routes/projects.js +0 -583
  55. package/dist/console-server/routes/projects.js.map +0 -1
  56. package/dist/console-server/routes/skills.d.ts +0 -7
  57. package/dist/console-server/routes/skills.d.ts.map +0 -1
  58. package/dist/console-server/routes/skills.js +0 -267
  59. package/dist/console-server/routes/skills.js.map +0 -1
  60. package/dist/console-server/routes/system.d.ts +0 -7
  61. package/dist/console-server/routes/system.d.ts.map +0 -1
  62. package/dist/console-server/routes/system.js +0 -288
  63. package/dist/console-server/routes/system.js.map +0 -1
  64. package/dist/console-server/routes/workers.d.ts +0 -18
  65. package/dist/console-server/routes/workers.d.ts.map +0 -1
  66. package/dist/console-server/routes/workers.js +0 -351
  67. package/dist/console-server/routes/workers.js.map +0 -1
  68. package/dist/console-server/sse/eventBus.d.ts +0 -25
  69. package/dist/console-server/sse/eventBus.d.ts.map +0 -1
  70. package/dist/console-server/sse/eventBus.js +0 -32
  71. package/dist/console-server/sse/eventBus.js.map +0 -1
  72. package/dist/console-server/sse/projectStream.d.ts +0 -10
  73. package/dist/console-server/sse/projectStream.d.ts.map +0 -1
  74. package/dist/console-server/sse/projectStream.js +0 -86
  75. package/dist/console-server/sse/projectStream.js.map +0 -1
  76. package/dist/console-server/watchers/cardWatcher.d.ts +0 -17
  77. package/dist/console-server/watchers/cardWatcher.d.ts.map +0 -1
  78. package/dist/console-server/watchers/cardWatcher.js +0 -68
  79. package/dist/console-server/watchers/cardWatcher.js.map +0 -1
  80. package/dist/console-server/watchers/markerWatcher.d.ts +0 -7
  81. package/dist/console-server/watchers/markerWatcher.d.ts.map +0 -1
  82. package/dist/console-server/watchers/markerWatcher.js +0 -63
  83. package/dist/console-server/watchers/markerWatcher.js.map +0 -1
  84. package/dist/console-server/watchers/pipelinePoller.d.ts +0 -2
  85. package/dist/console-server/watchers/pipelinePoller.d.ts.map +0 -1
  86. package/dist/console-server/watchers/pipelinePoller.js +0 -52
  87. package/dist/console-server/watchers/pipelinePoller.js.map +0 -1
  88. package/dist/models/types.d.ts +0 -103
  89. package/dist/models/types.d.ts.map +0 -1
  90. package/dist/models/types.js +0 -17
  91. package/dist/models/types.js.map +0 -1
@@ -1,351 +0,0 @@
1
- /**
2
- * @module console-server/routes/workers
3
- * @description Worker slot 列表 + kill/launch
4
- */
5
- import { Hono } from 'hono';
6
- import { createReadStream, existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
7
- import { createInterface } from 'node:readline';
8
- import { resolve } from 'node:path';
9
- import { readCard } from '../lib/cardReader.js';
10
- import { spawnCliSync } from '../lib/spawnCli.js';
11
- const HOME = process.env.HOME || '/home/coral';
12
- const STUCK_THRESHOLD_MS = 5 * 60 * 1000; // 5 min 无 marker 更新 = stuck
13
- const ACK_TIMEOUT_MS = 60 * 1000; // 60s dispatch 但无 STARTED-* 标签 = 仍在 starting
14
- function projectRuntimeDir(project) {
15
- return resolve(HOME, '.coral', 'projects', project, 'runtime');
16
- }
17
- function isPidAlive(pid) {
18
- if (!pid)
19
- return false;
20
- try {
21
- process.kill(pid, 0);
22
- return true;
23
- }
24
- catch {
25
- return false;
26
- }
27
- }
28
- function parseMarker(markerPath) {
29
- const basename = markerPath.split('/').pop() ?? '';
30
- // v0.49.16: marker 实际文件名是 worker-worker-<N>-current.json(worker-manager 传 slot="worker-<N>" 给
31
- // getMarkerPath,后者再拼 worker-${slot} → 双 worker- 前缀)。兼容老格式(单前缀)。
32
- const m = basename.match(/^worker-(?:worker-)?(\d+)-current\.json$/);
33
- if (!m)
34
- return null;
35
- const slot = Number.parseInt(m[1] ?? '', 10);
36
- if (!Number.isFinite(slot))
37
- return null;
38
- try {
39
- const data = JSON.parse(readFileSync(markerPath, 'utf-8'));
40
- return { slot, data };
41
- }
42
- catch {
43
- return { slot, data: null };
44
- }
45
- }
46
- function workerFromMarker(project, slot, markerPath) {
47
- const now = Date.now();
48
- let pid = null;
49
- let card = null;
50
- let stage = null;
51
- let startedAt = null;
52
- let markerUpdatedAt = null;
53
- // v0.49.15:marker schema 是 { cardId: "md-<seq>", stage, dispatchedAt, pid, sessionId }
54
- // —— 以前按 seq/title/startedAt 读永远空,导致 UI 永远显示 idle。
55
- const parsed = parseMarker(markerPath);
56
- if (parsed?.data) {
57
- const d = parsed.data;
58
- if (typeof d.pid === 'number')
59
- pid = d.pid;
60
- if (typeof d.cardId === 'string') {
61
- const m = d.cardId.match(/^(?:md-)?(\d+)$/);
62
- if (m) {
63
- const seq = Number.parseInt(m[1] ?? '', 10);
64
- if (Number.isFinite(seq)) {
65
- let title = `#${seq}`;
66
- try {
67
- const detail = readCard(resolve(HOME, '.coral', 'projects', project), seq);
68
- if (detail?.title)
69
- title = detail.title;
70
- }
71
- catch { /* cardReader 失败就用 #seq */ }
72
- card = { seq, title };
73
- }
74
- }
75
- }
76
- if (typeof d.stage === 'string')
77
- stage = d.stage;
78
- if (typeof d.dispatchedAt === 'string')
79
- startedAt = d.dispatchedAt;
80
- // 兼容老字段(旧版 marker 可能有)
81
- if (typeof d.startedAt === 'string')
82
- startedAt = startedAt ?? d.startedAt;
83
- }
84
- try {
85
- const stat = statSync(markerPath);
86
- markerUpdatedAt = new Date(stat.mtimeMs).toISOString();
87
- }
88
- catch {
89
- /* ignore */
90
- }
91
- const alive = isPidAlive(pid);
92
- const fresh = markerUpdatedAt ? now - new Date(markerUpdatedAt).getTime() < STUCK_THRESHOLD_MS : false;
93
- const ageMs = markerUpdatedAt ? now - new Date(markerUpdatedAt).getTime() : null;
94
- // v0.49.9: 5 态模型
95
- // crashed: PID 死但有卡片 → 掉线
96
- // idle: 无卡片
97
- // starting: 进程活 + marker 刚写 < 60s + 卡片无 STARTED-<stage> 标签(ACK 未到)
98
- // stuck: 进程活 + marker 停滞 > 5min
99
- // running: 其它健康情况
100
- let state;
101
- if (!alive) {
102
- state = card !== null ? 'crashed' : 'idle';
103
- }
104
- else if (card === null) {
105
- state = 'idle';
106
- }
107
- else {
108
- // 检查是否 starting:marker 很新 + 卡片没 STARTED-<stage> 标签
109
- const isStarting = (() => {
110
- if (ageMs === null || ageMs > ACK_TIMEOUT_MS)
111
- return false;
112
- if (!stage)
113
- return false;
114
- try {
115
- const cardDetail = readCard(resolve(HOME, '.coral', 'projects', project), card.seq);
116
- if (!cardDetail)
117
- return false;
118
- return !cardDetail.labels.includes(`STARTED-${stage}`);
119
- }
120
- catch {
121
- return false;
122
- }
123
- })();
124
- if (isStarting)
125
- state = 'starting';
126
- else if (!fresh)
127
- state = 'stuck';
128
- else
129
- state = 'running';
130
- }
131
- const runtimeMs = startedAt ? now - new Date(startedAt).getTime() : null;
132
- return { slot, pid, state, card, stage, startedAt, runtimeMs, markerUpdatedAt };
133
- }
134
- /**
135
- * Tail the most recent pipeline log, filter for lines tagged with worker-<slot>.
136
- * Used by the worker detail popover. Capped at 4MB scan + `limit` lines out.
137
- */
138
- async function readWorkerLogTail(project, slot, limit) {
139
- const logsDir = resolve(HOME, '.coral', 'projects', project, 'logs');
140
- if (!existsSync(logsDir))
141
- return [];
142
- // Prefer pipeline-*.log (current pipeline run); fall back to any .log sorted by mtime
143
- const candidates = readdirSync(logsDir)
144
- .filter((f) => f.endsWith('.log'))
145
- .map((f) => ({ f, full: resolve(logsDir, f), mtime: statSync(resolve(logsDir, f)).mtimeMs }))
146
- .sort((a, b) => b.mtime - a.mtime);
147
- const pipeline = candidates.find((c) => c.f.startsWith('pipeline-'));
148
- const file = pipeline?.full ?? candidates[0]?.full;
149
- if (!file)
150
- return [];
151
- const MAX_BYTES = 4 * 1024 * 1024;
152
- const stat = statSync(file);
153
- const start = Math.max(0, stat.size - MAX_BYTES);
154
- const matches = [];
155
- const slotTag = `worker-${slot}`;
156
- await new Promise((done) => {
157
- const stream = createReadStream(file, { start, encoding: 'utf-8' });
158
- const rl = createInterface({ input: stream });
159
- rl.on('line', (raw) => {
160
- if (!raw.includes(slotTag))
161
- return;
162
- const cleaned = raw.replace(/\[[0-9;]*m/g, '');
163
- const m = cleaned.match(/(\d{4}-\d{2}-\d{2}[T ][\d:.]+Z?)\s*(?:\[)?(DEBUG|INFO|WARN|WARNING|ERROR|TRACE)\]?\s*(.*)$/i);
164
- matches.push({
165
- ts: m?.[1] ?? null,
166
- level: (m?.[2] ?? 'info').toLowerCase().replace('warning', 'warn'),
167
- msg: m?.[3] ?? cleaned,
168
- });
169
- if (matches.length > limit * 3)
170
- matches.splice(0, matches.length - limit * 3);
171
- });
172
- rl.on('close', () => done());
173
- rl.on('error', () => done());
174
- });
175
- return matches.slice(-limit);
176
- }
177
- function listWorkerMarkerPaths(project) {
178
- const dir = projectRuntimeDir(project);
179
- if (!existsSync(dir))
180
- return [];
181
- // v0.49.16:支持 worker-worker-N-current.json(真实格式)和 worker-N-current.json(老兼容)
182
- const re = /^worker-(?:worker-)?(\d+)-current\.json$/;
183
- return readdirSync(dir)
184
- .filter((f) => re.test(f))
185
- .map((f) => ({
186
- slot: Number.parseInt((f.match(re) ?? ['', '0'])[1] ?? '0', 10),
187
- path: resolve(dir, f),
188
- }))
189
- .filter((m) => Number.isFinite(m.slot) && m.slot > 0)
190
- .sort((a, b) => a.slot - b.slot);
191
- }
192
- export function createWorkersRoute() {
193
- const app = new Hono();
194
- app.get('/:project/workers', (c) => {
195
- const project = c.req.param('project');
196
- if (!existsSync(projectRuntimeDir(project))) {
197
- return c.json({ data: [] });
198
- }
199
- const markers = listWorkerMarkerPaths(project);
200
- const workers = markers.map((m) => workerFromMarker(project, m.slot, m.path));
201
- return c.json({ data: workers });
202
- });
203
- /**
204
- * GET /api/projects/:project/workers/:slot
205
- * Returns worker detail + last N log lines filtered for this worker.
206
- * Used by the Console worker detail popover (v0.48).
207
- */
208
- app.get('/:project/workers/:slot', async (c) => {
209
- const project = c.req.param('project');
210
- const slot = Number.parseInt(c.req.param('slot'), 10);
211
- if (!Number.isFinite(slot) || slot < 1) {
212
- return c.json({ type: 'validation', title: 'invalid slot', status: 422 }, 422);
213
- }
214
- const runtimeDir = projectRuntimeDir(project);
215
- // v0.49.16:真实文件名是 worker-worker-N-current.json(双前缀),老格式做 fallback
216
- let markerPath = resolve(runtimeDir, `worker-worker-${slot}-current.json`);
217
- if (!existsSync(markerPath)) {
218
- const legacy = resolve(runtimeDir, `worker-${slot}-current.json`);
219
- if (!existsSync(legacy)) {
220
- return c.json({ type: 'not-found', title: 'worker marker not found', status: 404 }, 404);
221
- }
222
- markerPath = legacy;
223
- }
224
- const worker = workerFromMarker(project, slot, markerPath);
225
- const markerData = parseMarker(markerPath)?.data ?? null;
226
- const recentLogs = await readWorkerLogTail(project, slot, 20);
227
- return c.json({
228
- ...worker,
229
- markerPath: markerPath.replace(HOME, '~'),
230
- markerData,
231
- recentLogs,
232
- });
233
- });
234
- app.post('/:project/workers/:slot/kill', async (c) => {
235
- const project = c.req.param('project');
236
- const slot = c.req.param('slot');
237
- const result = await spawnCliSync(['worker', 'kill', project, slot], { timeoutMs: 15_000 });
238
- if (result.exitCode !== 0) {
239
- return c.json({ type: 'cli-error', title: 'kill failed', status: 500, detail: result.stderr }, 500);
240
- }
241
- return c.json({ ok: true });
242
- });
243
- app.post('/:project/workers/:slot/launch', async (c) => {
244
- const project = c.req.param('project');
245
- const slot = c.req.param('slot');
246
- const body = await c.req.json().catch(() => ({}));
247
- const args = ['worker', 'launch', project, slot];
248
- if (typeof body?.seq === 'number')
249
- args.push(String(body.seq));
250
- const result = await spawnCliSync(args, { timeoutMs: 15_000 });
251
- if (result.exitCode !== 0) {
252
- return c.json({ type: 'cli-error', title: 'launch failed', status: 500, detail: result.stderr }, 500);
253
- }
254
- return c.json({ ok: true });
255
- });
256
- return app;
257
- }
258
- /**
259
- * GET /api/workers/all
260
- * 扫描 ~/.coral/projects/* 的 runtime/worker-N-current.json,聚合所有 worker。
261
- * 返回 {alerts: Worker[], active: Worker[], capacity: ProjectCapacity[]}。
262
- * - alerts: state === 'stuck' 或 'crashed'
263
- * - active: state === 'running' 或 'starting'
264
- * - capacity: 按项目统计各状态数量
265
- * Active 的每个 worker 带 lastLogLine(尾 pipeline log 最近一行带 worker-N 的)。
266
- */
267
- export function createWorkersAggregateRoute() {
268
- const app = new Hono();
269
- app.get('/all', async (c) => {
270
- const projectsDir = resolve(HOME, '.coral', 'projects');
271
- if (!existsSync(projectsDir)) {
272
- return c.json({ alerts: [], active: [], capacity: [] });
273
- }
274
- const projectNames = readdirSync(projectsDir, { withFileTypes: true })
275
- .filter((e) => e.isDirectory())
276
- .map((e) => e.name)
277
- .sort();
278
- const alerts = [];
279
- const active = [];
280
- const capacity = [];
281
- for (const project of projectNames) {
282
- const markers = listWorkerMarkerPaths(project);
283
- const stat = {
284
- project,
285
- total: markers.length,
286
- running: 0,
287
- starting: 0,
288
- stuck: 0,
289
- crashed: 0,
290
- idle: 0,
291
- };
292
- for (const m of markers) {
293
- const w = workerFromMarker(project, m.slot, m.path);
294
- stat[w.state]++;
295
- if (w.state === 'stuck' || w.state === 'crashed') {
296
- alerts.push({ ...w, project, lastLogLine: await readLatestLogLine(project, m.slot) });
297
- }
298
- else if (w.state === 'running' || w.state === 'starting') {
299
- active.push({ ...w, project, lastLogLine: await readLatestLogLine(project, m.slot) });
300
- }
301
- }
302
- capacity.push(stat);
303
- }
304
- // 按 state 严重度 + runtime 倒序(stuck 比 crashed 更需看;old runtime 先看)
305
- alerts.sort((a, b) => {
306
- if (a.state !== b.state)
307
- return a.state === 'stuck' ? -1 : 1;
308
- return (b.runtimeMs ?? 0) - (a.runtimeMs ?? 0);
309
- });
310
- active.sort((a, b) => (b.runtimeMs ?? 0) - (a.runtimeMs ?? 0));
311
- return c.json({ alerts, active, capacity });
312
- });
313
- return app;
314
- }
315
- /** Read only the latest log line tagged with worker-<slot>. Same file selection as readWorkerLogTail. */
316
- async function readLatestLogLine(project, slot) {
317
- const logsDir = resolve(HOME, '.coral', 'projects', project, 'logs');
318
- if (!existsSync(logsDir))
319
- return null;
320
- const candidates = readdirSync(logsDir)
321
- .filter((f) => f.endsWith('.log'))
322
- .map((f) => ({ f, full: resolve(logsDir, f), mtime: statSync(resolve(logsDir, f)).mtimeMs }))
323
- .sort((a, b) => b.mtime - a.mtime);
324
- const pipeline = candidates.find((c) => c.f.startsWith('pipeline-'));
325
- const file = pipeline?.full ?? candidates[0]?.full;
326
- if (!file)
327
- return null;
328
- const MAX_BYTES = 512 * 1024; // 只扫尾 512KB — 聚合视图优先速度
329
- const stat = statSync(file);
330
- const start = Math.max(0, stat.size - MAX_BYTES);
331
- const slotTag = `worker-${slot}`;
332
- let latest = null;
333
- await new Promise((done) => {
334
- const stream = createReadStream(file, { start, encoding: 'utf-8' });
335
- const rl = createInterface({ input: stream });
336
- rl.on('line', (raw) => {
337
- if (!raw.includes(slotTag))
338
- return;
339
- const cleaned = raw.replace(/\[[0-9;]*m/g, '');
340
- const m = cleaned.match(/(\d{4}-\d{2}-\d{2}[T ][\d:.]+Z?)\s*(?:\[[^\]]+\]\s*)?(.*)$/);
341
- latest = {
342
- ts: m?.[1] ?? null,
343
- msg: (m?.[2] ?? cleaned).slice(0, 200),
344
- };
345
- });
346
- rl.on('close', () => done());
347
- rl.on('error', () => done());
348
- });
349
- return latest;
350
- }
351
- //# sourceMappingURL=workers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"workers.js","sourceRoot":"","sources":["../../../src/console-server/routes/workers.ts"],"names":[],"mappings":"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"}
@@ -1,25 +0,0 @@
1
- /**
2
- * @module console-server/sse/eventBus
3
- * @description 内部事件总线 —— watchers 推事件,SSE handlers 订阅推给客户端
4
- *
5
- * @role core
6
- * @layer console-server
7
- * @boundedContext console
8
- */
9
- import { EventEmitter } from 'node:events';
10
- export interface BusEvent {
11
- id: number;
12
- event: string;
13
- data: unknown;
14
- ts: number;
15
- }
16
- declare class ConsoleEventBus extends EventEmitter {
17
- private lastEventId;
18
- private history;
19
- publish(event: string, data: unknown): number;
20
- since(lastEventId: number): BusEvent[];
21
- clearHistory(): void;
22
- }
23
- export declare const eventBus: ConsoleEventBus;
24
- export {};
25
- //# sourceMappingURL=eventBus.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"eventBus.d.ts","sourceRoot":"","sources":["../../../src/console-server/sse/eventBus.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;CACZ;AAID,cAAM,eAAgB,SAAQ,YAAY;IACxC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,OAAO,CAAkB;IAEjC,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM;IAU7C,KAAK,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,EAAE;IAItC,YAAY,IAAI,IAAI;CAGrB;AAED,eAAO,MAAM,QAAQ,iBAAwB,CAAC"}
@@ -1,32 +0,0 @@
1
- /**
2
- * @module console-server/sse/eventBus
3
- * @description 内部事件总线 —— watchers 推事件,SSE handlers 订阅推给客户端
4
- *
5
- * @role core
6
- * @layer console-server
7
- * @boundedContext console
8
- */
9
- import { EventEmitter } from 'node:events';
10
- const MAX_HISTORY = 1000;
11
- class ConsoleEventBus extends EventEmitter {
12
- lastEventId = 0;
13
- history = [];
14
- publish(event, data) {
15
- const id = ++this.lastEventId;
16
- const record = { id, event, data, ts: Date.now() };
17
- this.history.push(record);
18
- if (this.history.length > MAX_HISTORY)
19
- this.history.shift();
20
- this.emit(event, data);
21
- this.emit('*', record);
22
- return id;
23
- }
24
- since(lastEventId) {
25
- return this.history.filter((h) => h.id > lastEventId);
26
- }
27
- clearHistory() {
28
- this.history = [];
29
- }
30
- }
31
- export const eventBus = new ConsoleEventBus();
32
- //# sourceMappingURL=eventBus.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"eventBus.js","sourceRoot":"","sources":["../../../src/console-server/sse/eventBus.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAS3C,MAAM,WAAW,GAAG,IAAI,CAAC;AAEzB,MAAM,eAAgB,SAAQ,YAAY;IAChC,WAAW,GAAG,CAAC,CAAC;IAChB,OAAO,GAAe,EAAE,CAAC;IAEjC,OAAO,CAAC,KAAa,EAAE,IAAa;QAClC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC;QAC9B,MAAM,MAAM,GAAa,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAC7D,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1B,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,WAAW;YAAE,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC5D,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACvB,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACvB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,KAAK,CAAC,WAAmB;QACvB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,WAAW,CAAC,CAAC;IACxD,CAAC;IAED,YAAY;QACV,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;IACpB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,eAAe,EAAE,CAAC"}
@@ -1,10 +0,0 @@
1
- /**
2
- * @module console-server/sse/projectStream
3
- * @description /stream/projects/:name —— 单项目的 card / worker / pipeline 事件流
4
- *
5
- * 订阅 eventBus,过滤 project 匹配的事件,以 SSE 格式写给客户端。
6
- * 支持 Last-Event-ID 断线补偿。
7
- */
8
- import { Hono } from 'hono';
9
- export declare function createProjectStreamRoute(): Hono;
10
- //# sourceMappingURL=projectStream.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"projectStream.d.ts","sourceRoot":"","sources":["../../../src/console-server/sse/projectStream.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAe5B,wBAAgB,wBAAwB,IAAI,IAAI,CAsE/C"}
@@ -1,86 +0,0 @@
1
- /**
2
- * @module console-server/sse/projectStream
3
- * @description /stream/projects/:name —— 单项目的 card / worker / pipeline 事件流
4
- *
5
- * 订阅 eventBus,过滤 project 匹配的事件,以 SSE 格式写给客户端。
6
- * 支持 Last-Event-ID 断线补偿。
7
- */
8
- import { Hono } from 'hono';
9
- import { eventBus } from './eventBus.js';
10
- const HEARTBEAT_MS = 15_000;
11
- function formatSse(id, event, data) {
12
- return `id: ${id}\nevent: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
13
- }
14
- function isProjectEvent(record, project) {
15
- if (typeof record.data !== 'object' || record.data === null)
16
- return false;
17
- const d = record.data;
18
- return d.project === project;
19
- }
20
- export function createProjectStreamRoute() {
21
- const app = new Hono();
22
- app.get('/:project', (c) => {
23
- const project = c.req.param('project');
24
- const lastEventId = Number.parseInt(c.req.header('last-event-id') ?? '0', 10) || 0;
25
- c.header('Content-Type', 'text/event-stream');
26
- c.header('Cache-Control', 'no-cache, no-transform');
27
- c.header('Connection', 'keep-alive');
28
- c.header('X-Accel-Buffering', 'no');
29
- const stream = new ReadableStream({
30
- start(controller) {
31
- const enc = new TextEncoder();
32
- let closed = false;
33
- const safeWrite = (chunk) => {
34
- if (closed)
35
- return;
36
- try {
37
- controller.enqueue(enc.encode(chunk));
38
- }
39
- catch {
40
- closed = true;
41
- }
42
- };
43
- // 1. 补发断线期间的历史事件
44
- if (lastEventId > 0) {
45
- const history = eventBus.since(lastEventId).filter((r) => isProjectEvent(r, project));
46
- for (const r of history) {
47
- safeWrite(formatSse(r.id, r.event, r.data));
48
- }
49
- }
50
- // 2. 订阅实时
51
- const onEvent = (record) => {
52
- if (!isProjectEvent(record, project))
53
- return;
54
- safeWrite(formatSse(record.id, record.event, record.data));
55
- };
56
- eventBus.on('*', onEvent);
57
- // 3. 心跳保活
58
- const heartbeat = setInterval(() => {
59
- safeWrite(`: heartbeat ${Date.now()}\n\n`);
60
- }, HEARTBEAT_MS);
61
- // 4. 客户端断开 → 清理
62
- c.req.raw.signal?.addEventListener('abort', () => {
63
- closed = true;
64
- eventBus.off('*', onEvent);
65
- clearInterval(heartbeat);
66
- try {
67
- controller.close();
68
- }
69
- catch {
70
- /* ignore */
71
- }
72
- });
73
- },
74
- });
75
- return new Response(stream, {
76
- headers: {
77
- 'Content-Type': 'text/event-stream',
78
- 'Cache-Control': 'no-cache, no-transform',
79
- Connection: 'keep-alive',
80
- 'X-Accel-Buffering': 'no',
81
- },
82
- });
83
- });
84
- return app;
85
- }
86
- //# sourceMappingURL=projectStream.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"projectStream.js","sourceRoot":"","sources":["../../../src/console-server/sse/projectStream.ts"],"names":[],"mappings":"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"}
@@ -1,17 +0,0 @@
1
- /**
2
- * @module console-server/watchers/cardWatcher
3
- * @description chokidar 监听 cards 目录变化,推 card.created/updated/deleted 事件
4
- *
5
- * v0.49.8:chokidar v4+ 删除了 glob 支持(官方 breaking change)。
6
- * 所以 v0.44.0 写的 `projects/.../cards/*.md` glob 一直不工作,
7
- * SSE 实时更新从上线就是假的。改为 watch 项目根目录递归 + 事件过滤。
8
- */
9
- import { type FSWatcher } from 'chokidar';
10
- /**
11
- * Chokidar v4+ 没 glob 了,只能 watch 绝对路径(文件或目录)。
12
- * 策略:watch `${coralRoot}/projects` 根,让 chokidar 递归监听所有子目录。
13
- * 进 event handler 后用 extractProjectAndSeq 正则挑出卡片 md 文件。
14
- * 其它 md 文件(conf、pipeline.yaml 等不是 md、自动过滤掉)。
15
- */
16
- export declare function startCardWatcher(coralRoot: string): FSWatcher;
17
- //# sourceMappingURL=cardWatcher.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cardWatcher.d.ts","sourceRoot":"","sources":["../../../src/console-server/watchers/cardWatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAiB,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAgCpD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAsB7D"}
@@ -1,68 +0,0 @@
1
- /**
2
- * @module console-server/watchers/cardWatcher
3
- * @description chokidar 监听 cards 目录变化,推 card.created/updated/deleted 事件
4
- *
5
- * v0.49.8:chokidar v4+ 删除了 glob 支持(官方 breaking change)。
6
- * 所以 v0.44.0 写的 `projects/.../cards/*.md` glob 一直不工作,
7
- * SSE 实时更新从上线就是假的。改为 watch 项目根目录递归 + 事件过滤。
8
- */
9
- import chokidar from 'chokidar';
10
- import { resolve } from 'node:path';
11
- import { readCard } from '../lib/cardReader.js';
12
- import { eventBus } from '../sse/eventBus.js';
13
- const HOME = process.env.HOME || '/home/coral';
14
- function extractProjectAndSeq(path) {
15
- // 允许可选的 state 子目录层级(cards/<state>/N-title.md)+ 兼容顶层 cards/N.md
16
- const match = path.match(/projects\/([^/]+)\/cards\/(?:[^/]+\/)?(\d+)(?:-[^/]*)?\.md$/);
17
- if (!match)
18
- return null;
19
- const seq = Number.parseInt(match[2] ?? '', 10);
20
- if (!Number.isFinite(seq))
21
- return null;
22
- return { project: match[1] ?? '', seq };
23
- }
24
- function publishCardEvent(event, path) {
25
- const info = extractProjectAndSeq(path);
26
- if (!info)
27
- return;
28
- const projectDir = resolve(HOME, '.coral', 'projects', info.project);
29
- if (event === 'card.deleted') {
30
- eventBus.publish('card.deleted', info);
31
- return;
32
- }
33
- const card = readCard(projectDir, info.seq);
34
- eventBus.publish(event, {
35
- project: info.project,
36
- seq: info.seq,
37
- card: card ?? null,
38
- });
39
- }
40
- /**
41
- * Chokidar v4+ 没 glob 了,只能 watch 绝对路径(文件或目录)。
42
- * 策略:watch `${coralRoot}/projects` 根,让 chokidar 递归监听所有子目录。
43
- * 进 event handler 后用 extractProjectAndSeq 正则挑出卡片 md 文件。
44
- * 其它 md 文件(conf、pipeline.yaml 等不是 md、自动过滤掉)。
45
- */
46
- export function startCardWatcher(coralRoot) {
47
- const root = resolve(coralRoot, 'projects');
48
- const watcher = chokidar.watch(root, {
49
- persistent: true,
50
- ignoreInitial: true,
51
- awaitWriteFinish: { stabilityThreshold: 100, pollInterval: 50 },
52
- // Depth 4 够:projects/<name>/cards/<state>/<file>.md
53
- depth: 4,
54
- // 忽略 node_modules / .git / 隐藏文件
55
- ignored: (path) => /\/(node_modules|\.git|\.DS_Store)(\/|$)/.test(path),
56
- });
57
- const handle = (event, path) => {
58
- if (!path.endsWith('.md'))
59
- return;
60
- publishCardEvent(event, path);
61
- };
62
- watcher
63
- .on('add', (path) => handle('card.created', path))
64
- .on('change', (path) => handle('card.updated', path))
65
- .on('unlink', (path) => handle('card.deleted', path));
66
- return watcher;
67
- }
68
- //# sourceMappingURL=cardWatcher.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cardWatcher.js","sourceRoot":"","sources":["../../../src/console-server/watchers/cardWatcher.ts"],"names":[],"mappings":"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"}