@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.
- package/dist/console-assets/assets/{index-C95GbuxW.js → index-CGiD8z0L.js} +1 -1
- package/dist/console-assets/index.html +1 -1
- package/dist/services/PipelineService.d.ts +1 -0
- package/dist/services/PipelineService.d.ts.map +1 -1
- package/dist/services/PipelineService.js +35 -0
- package/dist/services/PipelineService.js.map +1 -1
- package/dist/services/executors.d.ts +11 -0
- package/dist/services/executors.d.ts.map +1 -1
- package/dist/services/executors.js +117 -0
- package/dist/services/executors.js.map +1 -1
- package/package.json +1 -1
- package/dist/console/sse/eventBus.d.ts +0 -25
- package/dist/console/sse/eventBus.d.ts.map +0 -1
- package/dist/console/sse/eventBus.js +0 -32
- package/dist/console/sse/eventBus.js.map +0 -1
- package/dist/console-server/index.d.ts +0 -29
- package/dist/console-server/index.d.ts.map +0 -1
- package/dist/console-server/index.js +0 -180
- package/dist/console-server/index.js.map +0 -1
- package/dist/console-server/lib/cardReader.d.ts +0 -27
- package/dist/console-server/lib/cardReader.d.ts.map +0 -1
- package/dist/console-server/lib/cardReader.js +0 -201
- package/dist/console-server/lib/cardReader.js.map +0 -1
- package/dist/console-server/lib/lockFile.d.ts +0 -17
- package/dist/console-server/lib/lockFile.d.ts.map +0 -1
- package/dist/console-server/lib/lockFile.js +0 -61
- package/dist/console-server/lib/lockFile.js.map +0 -1
- package/dist/console-server/lib/portPicker.d.ts +0 -3
- package/dist/console-server/lib/portPicker.d.ts.map +0 -1
- package/dist/console-server/lib/portPicker.js +0 -25
- package/dist/console-server/lib/portPicker.js.map +0 -1
- package/dist/console-server/lib/spawnCli.d.ts +0 -31
- package/dist/console-server/lib/spawnCli.d.ts.map +0 -1
- package/dist/console-server/lib/spawnCli.js +0 -64
- package/dist/console-server/lib/spawnCli.js.map +0 -1
- package/dist/console-server/routes/cards.d.ts +0 -7
- package/dist/console-server/routes/cards.d.ts.map +0 -1
- package/dist/console-server/routes/cards.js +0 -185
- package/dist/console-server/routes/cards.js.map +0 -1
- package/dist/console-server/routes/chat.d.ts +0 -36
- package/dist/console-server/routes/chat.d.ts.map +0 -1
- package/dist/console-server/routes/chat.js +0 -458
- package/dist/console-server/routes/chat.js.map +0 -1
- package/dist/console-server/routes/logs.d.ts +0 -14
- package/dist/console-server/routes/logs.d.ts.map +0 -1
- package/dist/console-server/routes/logs.js +0 -283
- package/dist/console-server/routes/logs.js.map +0 -1
- package/dist/console-server/routes/pipeline.d.ts +0 -8
- package/dist/console-server/routes/pipeline.d.ts.map +0 -1
- package/dist/console-server/routes/pipeline.js +0 -96
- package/dist/console-server/routes/pipeline.js.map +0 -1
- package/dist/console-server/routes/projects.d.ts +0 -11
- package/dist/console-server/routes/projects.d.ts.map +0 -1
- package/dist/console-server/routes/projects.js +0 -583
- package/dist/console-server/routes/projects.js.map +0 -1
- package/dist/console-server/routes/skills.d.ts +0 -7
- package/dist/console-server/routes/skills.d.ts.map +0 -1
- package/dist/console-server/routes/skills.js +0 -267
- package/dist/console-server/routes/skills.js.map +0 -1
- package/dist/console-server/routes/system.d.ts +0 -7
- package/dist/console-server/routes/system.d.ts.map +0 -1
- package/dist/console-server/routes/system.js +0 -288
- package/dist/console-server/routes/system.js.map +0 -1
- package/dist/console-server/routes/workers.d.ts +0 -18
- package/dist/console-server/routes/workers.d.ts.map +0 -1
- package/dist/console-server/routes/workers.js +0 -351
- package/dist/console-server/routes/workers.js.map +0 -1
- package/dist/console-server/sse/eventBus.d.ts +0 -25
- package/dist/console-server/sse/eventBus.d.ts.map +0 -1
- package/dist/console-server/sse/eventBus.js +0 -32
- package/dist/console-server/sse/eventBus.js.map +0 -1
- package/dist/console-server/sse/projectStream.d.ts +0 -10
- package/dist/console-server/sse/projectStream.d.ts.map +0 -1
- package/dist/console-server/sse/projectStream.js +0 -86
- package/dist/console-server/sse/projectStream.js.map +0 -1
- package/dist/console-server/watchers/cardWatcher.d.ts +0 -17
- package/dist/console-server/watchers/cardWatcher.d.ts.map +0 -1
- package/dist/console-server/watchers/cardWatcher.js +0 -68
- package/dist/console-server/watchers/cardWatcher.js.map +0 -1
- package/dist/console-server/watchers/markerWatcher.d.ts +0 -7
- package/dist/console-server/watchers/markerWatcher.d.ts.map +0 -1
- package/dist/console-server/watchers/markerWatcher.js +0 -63
- package/dist/console-server/watchers/markerWatcher.js.map +0 -1
- package/dist/console-server/watchers/pipelinePoller.d.ts +0 -2
- package/dist/console-server/watchers/pipelinePoller.d.ts.map +0 -1
- package/dist/console-server/watchers/pipelinePoller.js +0 -52
- package/dist/console-server/watchers/pipelinePoller.js.map +0 -1
- package/dist/models/types.d.ts +0 -103
- package/dist/models/types.d.ts.map +0 -1
- package/dist/models/types.js +0 -17
- package/dist/models/types.js.map +0 -1
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module console-server/lib/cardReader
|
|
3
|
-
* @description 解析卡片 markdown + frontmatter,供 routes/cards 和 routes/projects 用
|
|
4
|
-
*/
|
|
5
|
-
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
6
|
-
import { resolve } from 'node:path';
|
|
7
|
-
function parseFrontmatter(raw) {
|
|
8
|
-
if (!raw.startsWith('---'))
|
|
9
|
-
return { frontmatter: {}, body: raw };
|
|
10
|
-
const end = raw.indexOf('\n---', 3);
|
|
11
|
-
if (end === -1)
|
|
12
|
-
return { frontmatter: {}, body: raw };
|
|
13
|
-
const yaml = raw.slice(3, end).trim();
|
|
14
|
-
const body = raw.slice(end + 4).replace(/^\n/, '');
|
|
15
|
-
const fm = {};
|
|
16
|
-
let currentKey = null;
|
|
17
|
-
const arrayBuffer = [];
|
|
18
|
-
const flushArray = () => {
|
|
19
|
-
if (currentKey)
|
|
20
|
-
fm[currentKey] = [...arrayBuffer];
|
|
21
|
-
arrayBuffer.length = 0;
|
|
22
|
-
currentKey = null;
|
|
23
|
-
};
|
|
24
|
-
for (const line of yaml.split('\n')) {
|
|
25
|
-
const trimmed = line.trimEnd();
|
|
26
|
-
if (!trimmed)
|
|
27
|
-
continue;
|
|
28
|
-
if (line.startsWith(' - ')) {
|
|
29
|
-
arrayBuffer.push(line.slice(4).trim());
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
if (currentKey && arrayBuffer.length > 0)
|
|
33
|
-
flushArray();
|
|
34
|
-
const m = trimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.*)$/);
|
|
35
|
-
if (m) {
|
|
36
|
-
const [, key, value] = m;
|
|
37
|
-
if (value === '') {
|
|
38
|
-
currentKey = key ?? '';
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
fm[key ?? ''] = stripQuotes(value ?? '');
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
if (currentKey && arrayBuffer.length > 0)
|
|
46
|
-
flushArray();
|
|
47
|
-
return { frontmatter: fm, body };
|
|
48
|
-
}
|
|
49
|
-
function stripQuotes(s) {
|
|
50
|
-
const t = s.trim();
|
|
51
|
-
if ((t.startsWith('"') && t.endsWith('"')) || (t.startsWith("'") && t.endsWith("'"))) {
|
|
52
|
-
return t.slice(1, -1);
|
|
53
|
-
}
|
|
54
|
-
return t;
|
|
55
|
-
}
|
|
56
|
-
function parseChecklist(body) {
|
|
57
|
-
const lines = body.split('\n');
|
|
58
|
-
const items = [];
|
|
59
|
-
for (const line of lines) {
|
|
60
|
-
const m = line.match(/^\s*-\s*\[([ x])\]\s*(.+?)\s*$/);
|
|
61
|
-
if (m)
|
|
62
|
-
items.push({ text: m[2] ?? '', done: m[1] === 'x' });
|
|
63
|
-
}
|
|
64
|
-
const total = items.length;
|
|
65
|
-
const done = items.filter((i) => i.done).length;
|
|
66
|
-
const percent = total === 0 ? 0 : Math.round((done / total) * 100);
|
|
67
|
-
return { total, done, percent, items };
|
|
68
|
-
}
|
|
69
|
-
export function cardsDir(projectDir) {
|
|
70
|
-
return resolve(projectDir, 'cards');
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* v0.49.5 修复:MarkdownTaskBackend 把卡片存在 `cards/<state>/N-title.md` 子目录里,
|
|
74
|
-
* 物理目录名就是 state(小写,如 planning/backlog/todo/inprogress/qa/done)。
|
|
75
|
-
* 之前 listCards 只扫顶层 `cards/*.md` → 永远返回空。
|
|
76
|
-
*
|
|
77
|
-
* 改法:
|
|
78
|
-
* - 遍历 cards/ 的所有一级子目录
|
|
79
|
-
* - 子目录名小写,正规化成首字母大写的 canonical state(Planning/Backlog/...)
|
|
80
|
-
* - card.state 直接用目录名,不再读 frontmatter(frontmatter 里通常没 state 字段)
|
|
81
|
-
* - 顶层 *.md 也兼容读(老版本可能写过那)
|
|
82
|
-
*/
|
|
83
|
-
const DIR_NAME_TO_STATE = {
|
|
84
|
-
planning: 'Planning',
|
|
85
|
-
backlog: 'Backlog',
|
|
86
|
-
todo: 'Todo',
|
|
87
|
-
inprogress: 'Inprogress',
|
|
88
|
-
qa: 'QA',
|
|
89
|
-
review: 'Review',
|
|
90
|
-
done: 'Done',
|
|
91
|
-
canceled: 'Canceled',
|
|
92
|
-
};
|
|
93
|
-
function normalizeState(dirName) {
|
|
94
|
-
const lower = dirName.toLowerCase();
|
|
95
|
-
return DIR_NAME_TO_STATE[lower] ?? dirName;
|
|
96
|
-
}
|
|
97
|
-
export function listCards(projectDir) {
|
|
98
|
-
const dir = cardsDir(projectDir);
|
|
99
|
-
if (!existsSync(dir))
|
|
100
|
-
return [];
|
|
101
|
-
const results = [];
|
|
102
|
-
for (const entry of readdirSync(dir)) {
|
|
103
|
-
const full = resolve(dir, entry);
|
|
104
|
-
let isDir = false;
|
|
105
|
-
try {
|
|
106
|
-
isDir = statSync(full).isDirectory();
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
if (isDir) {
|
|
112
|
-
const stateFromDir = normalizeState(entry);
|
|
113
|
-
for (const f of readdirSync(full)) {
|
|
114
|
-
if (!/^\d+.*\.md$/.test(f))
|
|
115
|
-
continue;
|
|
116
|
-
const card = readCardFromFile(resolve(full, f), stateFromDir);
|
|
117
|
-
if (card)
|
|
118
|
-
results.push(card);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
else if (/^\d+.*\.md$/.test(entry)) {
|
|
122
|
-
// 兼容:老格式/用户手动放的顶层 md
|
|
123
|
-
const card = readCardFromFile(full, null);
|
|
124
|
-
if (card)
|
|
125
|
-
results.push(card);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
// 按 seq 倒序(新卡在前)
|
|
129
|
-
return results.sort((a, b) => b.seq - a.seq);
|
|
130
|
-
}
|
|
131
|
-
export function readCard(projectDir, seq) {
|
|
132
|
-
const dir = cardsDir(projectDir);
|
|
133
|
-
if (!existsSync(dir))
|
|
134
|
-
return null;
|
|
135
|
-
// 先扫子目录找
|
|
136
|
-
for (const entry of readdirSync(dir)) {
|
|
137
|
-
const full = resolve(dir, entry);
|
|
138
|
-
let isDir = false;
|
|
139
|
-
try {
|
|
140
|
-
isDir = statSync(full).isDirectory();
|
|
141
|
-
}
|
|
142
|
-
catch {
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
if (!isDir)
|
|
146
|
-
continue;
|
|
147
|
-
const stateFromDir = normalizeState(entry);
|
|
148
|
-
const file = readdirSync(full).find((f) => new RegExp(`^${seq}[^0-9]`).test(f));
|
|
149
|
-
if (file) {
|
|
150
|
-
const path = resolve(full, file);
|
|
151
|
-
const raw = readFileSync(path, 'utf-8');
|
|
152
|
-
const { frontmatter, body } = parseFrontmatter(raw);
|
|
153
|
-
return buildCardDetail(seq, frontmatter, body, stateFromDir);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
// Fallback:顶层 md
|
|
157
|
-
const topFile = readdirSync(dir).find((f) => new RegExp(`^${seq}[^0-9]`).test(f));
|
|
158
|
-
if (!topFile)
|
|
159
|
-
return null;
|
|
160
|
-
const path = resolve(dir, topFile);
|
|
161
|
-
const raw = readFileSync(path, 'utf-8');
|
|
162
|
-
const { frontmatter, body } = parseFrontmatter(raw);
|
|
163
|
-
return buildCardDetail(seq, frontmatter, body, null);
|
|
164
|
-
}
|
|
165
|
-
function readCardFromFile(path, stateFromDir) {
|
|
166
|
-
try {
|
|
167
|
-
const raw = readFileSync(path, 'utf-8');
|
|
168
|
-
const { frontmatter } = parseFrontmatter(raw);
|
|
169
|
-
const seq = Number(frontmatter.seq);
|
|
170
|
-
if (!Number.isFinite(seq))
|
|
171
|
-
return null;
|
|
172
|
-
return buildCard(seq, frontmatter, stateFromDir);
|
|
173
|
-
}
|
|
174
|
-
catch {
|
|
175
|
-
return null;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
function buildCard(seq, fm, stateFromDir) {
|
|
179
|
-
// Priority: 物理目录名 > frontmatter.state > fallback 'Backlog'
|
|
180
|
-
const state = stateFromDir ?? (fm.state ? String(fm.state) : 'Backlog');
|
|
181
|
-
return {
|
|
182
|
-
seq,
|
|
183
|
-
title: String(fm.title ?? fm.name ?? ''),
|
|
184
|
-
state,
|
|
185
|
-
skills: Array.isArray(fm.skills) ? fm.skills : [],
|
|
186
|
-
labels: Array.isArray(fm.labels) ? fm.labels : [],
|
|
187
|
-
branch: fm.branch ? String(fm.branch) : null,
|
|
188
|
-
createdAt: fm.created ? String(fm.created) : null,
|
|
189
|
-
updatedAt: fm.updated ? String(fm.updated) : null,
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
function buildCardDetail(seq, fm, body, stateFromDir) {
|
|
193
|
-
const card = buildCard(seq, fm, stateFromDir);
|
|
194
|
-
return {
|
|
195
|
-
...card,
|
|
196
|
-
body,
|
|
197
|
-
checklist: parseChecklist(body),
|
|
198
|
-
activeWorkerSlot: null, // 由 routes 合并 marker 数据填
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
//# sourceMappingURL=cardReader.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cardReader.js","sourceRoot":"","sources":["../../../src/console-server/lib/cardReader.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export interface LockPayload {
|
|
2
|
-
pid: number;
|
|
3
|
-
port: number;
|
|
4
|
-
startedAt: string;
|
|
5
|
-
version: string;
|
|
6
|
-
}
|
|
7
|
-
export declare const LOCK_PATH: string;
|
|
8
|
-
export declare function readLock(): LockPayload | null;
|
|
9
|
-
export declare function isProcessAlive(pid: number): boolean;
|
|
10
|
-
export declare function acquireLock(pid: number, port: number, version: string): void;
|
|
11
|
-
export declare function releaseLock(): void;
|
|
12
|
-
/**
|
|
13
|
-
* 检查已有 console 是否活着。
|
|
14
|
-
* @returns payload if another console is running, null otherwise
|
|
15
|
-
*/
|
|
16
|
-
export declare function detectRunningConsole(): LockPayload | null;
|
|
17
|
-
//# sourceMappingURL=lockFile.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lockFile.d.ts","sourceRoot":"","sources":["../../../src/console-server/lib/lockFile.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAGD,eAAO,MAAM,SAAS,QAA0C,CAAC;AAEjE,wBAAgB,QAAQ,IAAI,WAAW,GAAG,IAAI,CAO7C;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnD;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAQ5E;AAED,wBAAgB,WAAW,IAAI,IAAI,CAMlC;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,WAAW,GAAG,IAAI,CAOzD"}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module console-server/lib/lockFile
|
|
3
|
-
* @description 单实例锁:~/.coral/console.lock 保存运行中 console 的 pid + port。
|
|
4
|
-
* stale lock (进程已死) 会被重建。
|
|
5
|
-
*/
|
|
6
|
-
import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
7
|
-
import { resolve } from 'node:path';
|
|
8
|
-
const HOME = process.env.HOME || '/home/coral';
|
|
9
|
-
export const LOCK_PATH = resolve(HOME, '.coral', 'console.lock');
|
|
10
|
-
export function readLock() {
|
|
11
|
-
if (!existsSync(LOCK_PATH))
|
|
12
|
-
return null;
|
|
13
|
-
try {
|
|
14
|
-
return JSON.parse(readFileSync(LOCK_PATH, 'utf-8'));
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
export function isProcessAlive(pid) {
|
|
21
|
-
try {
|
|
22
|
-
process.kill(pid, 0);
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
export function acquireLock(pid, port, version) {
|
|
30
|
-
const payload = {
|
|
31
|
-
pid,
|
|
32
|
-
port,
|
|
33
|
-
startedAt: new Date().toISOString(),
|
|
34
|
-
version,
|
|
35
|
-
};
|
|
36
|
-
writeFileSync(LOCK_PATH, JSON.stringify(payload, null, 2));
|
|
37
|
-
}
|
|
38
|
-
export function releaseLock() {
|
|
39
|
-
try {
|
|
40
|
-
if (existsSync(LOCK_PATH))
|
|
41
|
-
unlinkSync(LOCK_PATH);
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
/* ignore */
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* 检查已有 console 是否活着。
|
|
49
|
-
* @returns payload if another console is running, null otherwise
|
|
50
|
-
*/
|
|
51
|
-
export function detectRunningConsole() {
|
|
52
|
-
const lock = readLock();
|
|
53
|
-
if (!lock)
|
|
54
|
-
return null;
|
|
55
|
-
if (isProcessAlive(lock.pid))
|
|
56
|
-
return lock;
|
|
57
|
-
// stale lock —— 清理
|
|
58
|
-
releaseLock();
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
//# sourceMappingURL=lockFile.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lockFile.js","sourceRoot":"","sources":["../../../src/console-server/lib/lockFile.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,aAAa,CAAC;AAC/C,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;AAEjE,MAAM,UAAU,QAAQ;IACtB,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAgB,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,IAAY,EAAE,OAAe;IACpE,MAAM,OAAO,GAAgB;QAC3B,GAAG;QACH,IAAI;QACJ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,OAAO;KACR,CAAC;IACF,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,YAAY;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;IACxB,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,mBAAmB;IACnB,WAAW,EAAE,CAAC;IACd,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"portPicker.d.ts","sourceRoot":"","sources":["../../../src/console-server/lib/portPicker.ts"],"names":[],"mappings":"AAMA,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,SAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CASxF;AAED,wBAAsB,QAAQ,CAC5B,SAAS,EAAE,MAAM,EACjB,QAAQ,SAAK,EACb,IAAI,SAAc,GACjB,OAAO,CAAC,MAAM,CAAC,CASjB"}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module console-server/lib/portPicker
|
|
3
|
-
* @description 找可用端口。默认 4311 起尝试,连续 N 次失败则报错。
|
|
4
|
-
*/
|
|
5
|
-
import { createServer } from 'node:net';
|
|
6
|
-
export async function isPortAvailable(port, host = '127.0.0.1') {
|
|
7
|
-
return new Promise((resolve) => {
|
|
8
|
-
const server = createServer();
|
|
9
|
-
server.once('error', () => resolve(false));
|
|
10
|
-
server.once('listening', () => {
|
|
11
|
-
server.close(() => resolve(true));
|
|
12
|
-
});
|
|
13
|
-
server.listen(port, host);
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
export async function pickPort(preferred, maxTries = 10, host = '127.0.0.1') {
|
|
17
|
-
for (let i = 0; i < maxTries; i++) {
|
|
18
|
-
const port = preferred + i;
|
|
19
|
-
// eslint-disable-next-line no-await-in-loop
|
|
20
|
-
if (await isPortAvailable(port, host))
|
|
21
|
-
return port;
|
|
22
|
-
}
|
|
23
|
-
throw new Error(`Ports ${preferred}–${preferred + maxTries - 1} all in use. Use --port <n> to specify.`);
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=portPicker.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"portPicker.js","sourceRoot":"","sources":["../../../src/console-server/lib/portPicker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY,EAAE,IAAI,GAAG,WAAW;IACpE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;YAC5B,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,SAAiB,EACjB,QAAQ,GAAG,EAAE,EACb,IAAI,GAAG,WAAW;IAElB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,SAAS,GAAG,CAAC,CAAC;QAC3B,4CAA4C;QAC5C,IAAI,MAAM,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IACrD,CAAC;IACD,MAAM,IAAI,KAAK,CACb,SAAS,SAAS,IAAI,SAAS,GAAG,QAAQ,GAAG,CAAC,yCAAyC,CACxF,CAAC;AACJ,CAAC"}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module console-server/lib/spawnCli
|
|
3
|
-
* @description 把 sps console 接到现有 CLI 的底层工具:spawn 子进程跑 sps 命令
|
|
4
|
-
*
|
|
5
|
-
* 有两种调用:
|
|
6
|
-
* - spawnCliSync: 短任务(如 card add),等完成拿到 stdout/stderr
|
|
7
|
-
* - spawnCliDetached: 长任务(如 tick pipeline),后台跑 + detach + 写 pid 文件
|
|
8
|
-
*/
|
|
9
|
-
import { type ChildProcess } from 'node:child_process';
|
|
10
|
-
export interface CliResult {
|
|
11
|
-
exitCode: number | null;
|
|
12
|
-
stdout: string;
|
|
13
|
-
stderr: string;
|
|
14
|
-
}
|
|
15
|
-
export declare function spawnCliSync(args: string[], opts?: {
|
|
16
|
-
cwd?: string;
|
|
17
|
-
timeoutMs?: number;
|
|
18
|
-
}): Promise<CliResult>;
|
|
19
|
-
/**
|
|
20
|
-
* 后台长任务:spawn detach + pipe 到 log file
|
|
21
|
-
* 适合 sps tick / sps agent 这类生命周期持续的命令
|
|
22
|
-
*/
|
|
23
|
-
export declare function spawnCliDetached(args: string[], opts: {
|
|
24
|
-
logPath: string;
|
|
25
|
-
cwd?: string;
|
|
26
|
-
}): ChildProcess;
|
|
27
|
-
/**
|
|
28
|
-
* 同步版(慢路径 fallback):阻塞,较重的操作别用
|
|
29
|
-
*/
|
|
30
|
-
export declare function spawnCliBlocking(args: string[], cwd?: string): string;
|
|
31
|
-
//# sourceMappingURL=spawnCli.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spawnCli.d.ts","sourceRoot":"","sources":["../../../src/console-server/lib/spawnCli.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAS,KAAK,YAAY,EAAgB,MAAM,oBAAoB,CAAC;AAQ5E,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1C,OAAO,CAAC,SAAS,CAAC,CAyBpB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACtC,YAAY,CAWd;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAGrE"}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module console-server/lib/spawnCli
|
|
3
|
-
* @description 把 sps console 接到现有 CLI 的底层工具:spawn 子进程跑 sps 命令
|
|
4
|
-
*
|
|
5
|
-
* 有两种调用:
|
|
6
|
-
* - spawnCliSync: 短任务(如 card add),等完成拿到 stdout/stderr
|
|
7
|
-
* - spawnCliDetached: 长任务(如 tick pipeline),后台跑 + detach + 写 pid 文件
|
|
8
|
-
*/
|
|
9
|
-
import { spawn, execFileSync } from 'node:child_process';
|
|
10
|
-
import { openSync } from 'node:fs';
|
|
11
|
-
function cliEntry() {
|
|
12
|
-
// process.argv[0] = node, process.argv[1] = sps/dist/main.js
|
|
13
|
-
return { node: process.argv[0] ?? 'node', entry: process.argv[1] ?? 'sps' };
|
|
14
|
-
}
|
|
15
|
-
export async function spawnCliSync(args, opts) {
|
|
16
|
-
const { node, entry } = cliEntry();
|
|
17
|
-
return new Promise((resolve) => {
|
|
18
|
-
const child = spawn(node, [entry, ...args], {
|
|
19
|
-
cwd: opts?.cwd,
|
|
20
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
21
|
-
});
|
|
22
|
-
let stdout = '';
|
|
23
|
-
let stderr = '';
|
|
24
|
-
child.stdout?.on('data', (d) => { stdout += d.toString(); });
|
|
25
|
-
child.stderr?.on('data', (d) => { stderr += d.toString(); });
|
|
26
|
-
const timer = opts?.timeoutMs
|
|
27
|
-
? setTimeout(() => child.kill('SIGTERM'), opts.timeoutMs)
|
|
28
|
-
: null;
|
|
29
|
-
child.on('close', (code) => {
|
|
30
|
-
if (timer)
|
|
31
|
-
clearTimeout(timer);
|
|
32
|
-
resolve({ exitCode: code, stdout, stderr });
|
|
33
|
-
});
|
|
34
|
-
child.on('error', (err) => {
|
|
35
|
-
if (timer)
|
|
36
|
-
clearTimeout(timer);
|
|
37
|
-
resolve({ exitCode: -1, stdout, stderr: stderr + String(err) });
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* 后台长任务:spawn detach + pipe 到 log file
|
|
43
|
-
* 适合 sps tick / sps agent 这类生命周期持续的命令
|
|
44
|
-
*/
|
|
45
|
-
export function spawnCliDetached(args, opts) {
|
|
46
|
-
const { node, entry } = cliEntry();
|
|
47
|
-
const logFd = openSync(opts.logPath, 'a');
|
|
48
|
-
const child = spawn(node, [entry, ...args], {
|
|
49
|
-
cwd: opts.cwd,
|
|
50
|
-
detached: true,
|
|
51
|
-
stdio: ['ignore', logFd, logFd],
|
|
52
|
-
});
|
|
53
|
-
// 不跟踪子进程,父退出后子继续跑
|
|
54
|
-
child.unref();
|
|
55
|
-
return child;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* 同步版(慢路径 fallback):阻塞,较重的操作别用
|
|
59
|
-
*/
|
|
60
|
-
export function spawnCliBlocking(args, cwd) {
|
|
61
|
-
const { node, entry } = cliEntry();
|
|
62
|
-
return execFileSync(node, [entry, ...args], { cwd, encoding: 'utf-8' });
|
|
63
|
-
}
|
|
64
|
-
//# sourceMappingURL=spawnCli.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spawnCli.js","sourceRoot":"","sources":["../../../src/console-server/lib/spawnCli.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cards.d.ts","sourceRoot":"","sources":["../../../src/console-server/routes/cards.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAmB5B,wBAAgB,gBAAgB,IAAI,IAAI,CA+MvC"}
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module console-server/routes/cards
|
|
3
|
-
* @description 卡片相关 REST 路由
|
|
4
|
-
*/
|
|
5
|
-
import { Hono } from 'hono';
|
|
6
|
-
import { existsSync } from 'node:fs';
|
|
7
|
-
import { resolve } from 'node:path';
|
|
8
|
-
import { listCards, readCard } from '../lib/cardReader.js';
|
|
9
|
-
import { spawnCliSync } from '../lib/spawnCli.js';
|
|
10
|
-
const HOME = process.env.HOME || '/home/coral';
|
|
11
|
-
function projectDir(name) {
|
|
12
|
-
return resolve(HOME, '.coral', 'projects', name);
|
|
13
|
-
}
|
|
14
|
-
function notFound(c, name) {
|
|
15
|
-
return c.json({ type: 'not-found', title: 'Project not found', status: 404, detail: name }, 404);
|
|
16
|
-
}
|
|
17
|
-
export function createCardsRoute() {
|
|
18
|
-
const app = new Hono();
|
|
19
|
-
app.get('/:project/cards', (c) => {
|
|
20
|
-
const project = c.req.param('project');
|
|
21
|
-
const dir = projectDir(project);
|
|
22
|
-
if (!existsSync(dir))
|
|
23
|
-
return notFound(c, project);
|
|
24
|
-
const state = c.req.query('state');
|
|
25
|
-
let cards = listCards(dir);
|
|
26
|
-
if (state)
|
|
27
|
-
cards = cards.filter((card) => card.state === state);
|
|
28
|
-
return c.json({ data: cards });
|
|
29
|
-
});
|
|
30
|
-
app.get('/:project/cards/:seq', (c) => {
|
|
31
|
-
const project = c.req.param('project');
|
|
32
|
-
const seq = Number.parseInt(c.req.param('seq'), 10);
|
|
33
|
-
const dir = projectDir(project);
|
|
34
|
-
if (!existsSync(dir))
|
|
35
|
-
return notFound(c, project);
|
|
36
|
-
const detail = readCard(dir, seq);
|
|
37
|
-
if (!detail) {
|
|
38
|
-
return c.json({
|
|
39
|
-
type: 'not-found',
|
|
40
|
-
title: 'Card not found',
|
|
41
|
-
status: 404,
|
|
42
|
-
detail: `${project}/#${seq}`,
|
|
43
|
-
}, 404);
|
|
44
|
-
}
|
|
45
|
-
return c.json(detail);
|
|
46
|
-
});
|
|
47
|
-
app.post('/:project/cards', async (c) => {
|
|
48
|
-
const project = c.req.param('project');
|
|
49
|
-
const body = (await c.req.json().catch(() => null));
|
|
50
|
-
if (!body || typeof body.title !== 'string' || !body.title.trim()) {
|
|
51
|
-
return c.json({ type: 'validation', title: 'title required', status: 422 }, 422);
|
|
52
|
-
}
|
|
53
|
-
// v0.49.6: 透传 description + skills 给 sps card add
|
|
54
|
-
// cmd: sps card add <project> "<title>" ["description"] [--skill a,b]
|
|
55
|
-
const args = ['card', 'add', project, body.title];
|
|
56
|
-
if (body.description && body.description.trim()) {
|
|
57
|
-
args.push(body.description);
|
|
58
|
-
}
|
|
59
|
-
if (Array.isArray(body.skills) && body.skills.length > 0) {
|
|
60
|
-
const clean = body.skills
|
|
61
|
-
.map((s) => String(s).trim())
|
|
62
|
-
.filter((s) => /^[a-zA-Z0-9_-]+$/.test(s));
|
|
63
|
-
if (clean.length > 0) {
|
|
64
|
-
args.push('--skill', clean.join(','));
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
const result = await spawnCliSync(args, { timeoutMs: 10_000 });
|
|
68
|
-
if (result.exitCode !== 0) {
|
|
69
|
-
return c.json({ type: 'cli-error', title: 'card add failed', status: 500, detail: result.stderr }, 500);
|
|
70
|
-
}
|
|
71
|
-
return c.json({ ok: true, output: result.stdout.trim() });
|
|
72
|
-
});
|
|
73
|
-
/**
|
|
74
|
-
* PATCH /api/projects/:project/cards/:seq
|
|
75
|
-
* Body: 任意字段组合(至少一个)
|
|
76
|
-
* { state?: CardState } — 拖拽换列(搬 md 到新目录)
|
|
77
|
-
* { title?: string } — 改标题 + 重命名文件
|
|
78
|
-
* { description?: string } — 替换 body 的 "## 描述" 段
|
|
79
|
-
* { skills?: string[] } — 全量替换 frontmatter.skills
|
|
80
|
-
* { labels?: string[] } — 全量替换 frontmatter.labels
|
|
81
|
-
* 按字段顺序依次应用;任何一步失败返回 500 + detail。
|
|
82
|
-
*/
|
|
83
|
-
app.patch('/:project/cards/:seq', async (c) => {
|
|
84
|
-
const project = c.req.param('project');
|
|
85
|
-
const seq = c.req.param('seq');
|
|
86
|
-
const body = (await c.req.json().catch(() => null));
|
|
87
|
-
if (!body || Object.keys(body).length === 0) {
|
|
88
|
-
return c.json({ type: 'validation', title: 'no fields to update', status: 422 }, 422);
|
|
89
|
-
}
|
|
90
|
-
const ALLOWED_STATES = ['Planning', 'Backlog', 'Todo', 'Inprogress', 'Review', 'QA', 'Done', 'Canceled'];
|
|
91
|
-
if (body.state !== undefined && (typeof body.state !== 'string' || !ALLOWED_STATES.includes(body.state))) {
|
|
92
|
-
return c.json({ type: 'validation', title: 'invalid state', status: 422, detail: `allowed: ${ALLOWED_STATES.join(', ')}` }, 422);
|
|
93
|
-
}
|
|
94
|
-
if (body.title !== undefined && (typeof body.title !== 'string' || !body.title.trim())) {
|
|
95
|
-
return c.json({ type: 'validation', title: 'title cannot be empty', status: 422 }, 422);
|
|
96
|
-
}
|
|
97
|
-
if (body.skills !== undefined && !Array.isArray(body.skills)) {
|
|
98
|
-
return c.json({ type: 'validation', title: 'skills must be array', status: 422 }, 422);
|
|
99
|
-
}
|
|
100
|
-
if (body.labels !== undefined && !Array.isArray(body.labels)) {
|
|
101
|
-
return c.json({ type: 'validation', title: 'labels must be array', status: 422 }, 422);
|
|
102
|
-
}
|
|
103
|
-
try {
|
|
104
|
-
const { ProjectContext } = await import('../../core/context.js');
|
|
105
|
-
const { createTaskBackend } = await import('../../providers/registry.js');
|
|
106
|
-
const ctx = ProjectContext.load(project);
|
|
107
|
-
const backend = createTaskBackend(ctx.config);
|
|
108
|
-
await backend.bootstrap();
|
|
109
|
-
// Apply in this order:
|
|
110
|
-
// 1) title (renames file) — do early so subsequent reads find the new path
|
|
111
|
-
// 2) description
|
|
112
|
-
// 3) skills
|
|
113
|
-
// 4) labels
|
|
114
|
-
// 5) state (move, last so other edits write to the original location first)
|
|
115
|
-
if (body.title !== undefined) {
|
|
116
|
-
await backend.setTitle(seq, body.title);
|
|
117
|
-
}
|
|
118
|
-
if (body.description !== undefined) {
|
|
119
|
-
await backend.setDescription(seq, body.description);
|
|
120
|
-
}
|
|
121
|
-
if (body.skills !== undefined) {
|
|
122
|
-
await backend.setSkills(seq, body.skills.filter((s) => typeof s === 'string'));
|
|
123
|
-
}
|
|
124
|
-
if (body.labels !== undefined) {
|
|
125
|
-
await backend.setLabels(seq, body.labels.filter((l) => typeof l === 'string'));
|
|
126
|
-
}
|
|
127
|
-
if (body.state !== undefined) {
|
|
128
|
-
await backend.move(seq, body.state);
|
|
129
|
-
}
|
|
130
|
-
return c.json({ ok: true, seq: Number(seq) });
|
|
131
|
-
}
|
|
132
|
-
catch (err) {
|
|
133
|
-
return c.json({
|
|
134
|
-
type: 'internal',
|
|
135
|
-
title: 'patch failed',
|
|
136
|
-
status: 500,
|
|
137
|
-
detail: err instanceof Error ? err.message : String(err),
|
|
138
|
-
}, 500);
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
app.delete('/:project/cards/:seq', async (c) => {
|
|
142
|
-
const project = c.req.param('project');
|
|
143
|
-
const seq = c.req.param('seq');
|
|
144
|
-
const dir = projectDir(project);
|
|
145
|
-
if (!existsSync(dir))
|
|
146
|
-
return notFound(c, project);
|
|
147
|
-
try {
|
|
148
|
-
const { ProjectContext } = await import('../../core/context.js');
|
|
149
|
-
const { createTaskBackend } = await import('../../providers/registry.js');
|
|
150
|
-
const ctx = ProjectContext.load(project);
|
|
151
|
-
const backend = createTaskBackend(ctx.config);
|
|
152
|
-
await backend.bootstrap();
|
|
153
|
-
await backend.delete(seq);
|
|
154
|
-
return c.json({ ok: true, seq: Number(seq) });
|
|
155
|
-
}
|
|
156
|
-
catch (err) {
|
|
157
|
-
return c.json({
|
|
158
|
-
type: 'internal',
|
|
159
|
-
title: 'delete failed',
|
|
160
|
-
status: 500,
|
|
161
|
-
detail: err instanceof Error ? err.message : String(err),
|
|
162
|
-
}, 500);
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
app.post('/:project/cards/:seq/reset', async (c) => {
|
|
166
|
-
const project = c.req.param('project');
|
|
167
|
-
const seq = c.req.param('seq');
|
|
168
|
-
const result = await spawnCliSync(['reset', project, '--card', seq], { timeoutMs: 30_000 });
|
|
169
|
-
if (result.exitCode !== 0) {
|
|
170
|
-
return c.json({ type: 'cli-error', title: 'card reset failed', status: 500, detail: result.stderr }, 500);
|
|
171
|
-
}
|
|
172
|
-
return c.json({ ok: true });
|
|
173
|
-
});
|
|
174
|
-
app.post('/:project/cards/:seq/launch', async (c) => {
|
|
175
|
-
const project = c.req.param('project');
|
|
176
|
-
const seq = c.req.param('seq');
|
|
177
|
-
const result = await spawnCliSync(['worker', 'launch', project, seq], { timeoutMs: 10_000 });
|
|
178
|
-
if (result.exitCode !== 0) {
|
|
179
|
-
return c.json({ type: 'cli-error', title: 'worker launch failed', status: 500, detail: result.stderr }, 500);
|
|
180
|
-
}
|
|
181
|
-
return c.json({ ok: true });
|
|
182
|
-
});
|
|
183
|
-
return app;
|
|
184
|
-
}
|
|
185
|
-
//# sourceMappingURL=cards.js.map
|