@coralai/sps-cli 0.51.9 → 0.51.10
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/README-CN.md +6 -1
- package/README.md +6 -1
- package/dist/commands/cardAdd.d.ts.map +1 -1
- package/dist/commands/cardAdd.js +11 -2
- package/dist/commands/cardAdd.js.map +1 -1
- package/dist/console/routes/cards.d.ts.map +1 -1
- package/dist/console/routes/cards.js +6 -0
- package/dist/console/routes/cards.js.map +1 -1
- package/dist/console-assets/assets/{index-EHLb9b5y.js → index-DKc9idxO.js} +1 -1
- package/dist/console-assets/index.html +1 -1
- package/package.json +1 -1
- package/skills/sps-pipeline/SKILL.md +2 -2
package/README-CN.md
CHANGED
|
@@ -201,7 +201,12 @@ Planning NEEDS-FIX (halt)
|
|
|
201
201
|
(人工暂存,v0.51.9+)
|
|
202
202
|
```
|
|
203
203
|
|
|
204
|
-
**v0.51.
|
|
204
|
+
**v0.51.10**:按调用方区分默认入场状态。
|
|
205
|
+
- **`sps card add`(CLI / agent / 直接调 API)** → **Backlog**(自动跑)
|
|
206
|
+
- **Console "新卡片" 表单(人在 UI 操作)** → **Planning**(暂存,等用户拖到 Backlog 派发)
|
|
207
|
+
|
|
208
|
+
CLI 用户想暂存:`sps card add ... --draft`。Console 用户想立即跑:勾"立即派发执行"。
|
|
209
|
+
卡片严格按 seq 排序;不再有 pipeline_order.json。
|
|
205
210
|
|
|
206
211
|
默认状态(可在 YAML `pm.card_states` 自定义)。
|
|
207
212
|
|
package/README.md
CHANGED
|
@@ -201,7 +201,12 @@ Planning NEEDS-FIX (halt)
|
|
|
201
201
|
(manual park, v0.51.9+)
|
|
202
202
|
```
|
|
203
203
|
|
|
204
|
-
**v0.51.
|
|
204
|
+
**v0.51.10**: caller-aware default state.
|
|
205
|
+
- **`sps card add` (CLI / agent / API default)** → **Backlog**(自动跑)
|
|
206
|
+
- **Console "新卡片" 表单(人在 UI 操作)** → **Planning**(暂存,等用户拖到 Backlog)
|
|
207
|
+
|
|
208
|
+
CLI 用户想暂存:`sps card add ... --draft`。Console 用户想立即跑:勾"立即派发执行"。
|
|
209
|
+
卡片严格按 seq 排序;不再有 pipeline_order.json。
|
|
205
210
|
|
|
206
211
|
Default states (configurable via YAML `pm.card_states`).
|
|
207
212
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cardAdd.d.ts","sourceRoot":"","sources":["../../src/commands/cardAdd.ts"],"names":[],"mappings":"AAcA,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EAAE,EACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,GACtC,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"cardAdd.d.ts","sourceRoot":"","sources":["../../src/commands/cardAdd.ts"],"names":[],"mappings":"AAcA,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EAAE,EACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,GACtC,OAAO,CAAC,IAAI,CAAC,CAwEf"}
|
package/dist/commands/cardAdd.js
CHANGED
|
@@ -24,14 +24,23 @@ export async function executeCardAdd(project, positionals, flags) {
|
|
|
24
24
|
.filter(Boolean)
|
|
25
25
|
: undefined;
|
|
26
26
|
if (!title) {
|
|
27
|
-
console.error('Usage: sps card add <project> "<title>" ["description"] [--skill name1,name2]');
|
|
27
|
+
console.error('Usage: sps card add <project> "<title>" ["description"] [--skill name1,name2] [--draft]');
|
|
28
28
|
process.exit(2);
|
|
29
29
|
}
|
|
30
|
+
// v0.51.10:默认入 Backlog(CLI 主要被 agent / 自动化调用,期望立即跑)。
|
|
31
|
+
// --draft 把卡放 Planning 等手动派发(人在终端建卡、想稍后再决定时用)。
|
|
32
|
+
const isDraft = !!flags.draft;
|
|
33
|
+
const initialState = isDraft ? 'Planning' : 'Backlog';
|
|
30
34
|
// PIPELINE_LABEL 副作用:Service 创建后 CLI 自己补 AI-PIPELINE 标签(标签是
|
|
31
35
|
// "SPS pipeline 卡"的标记,不再触发 SchedulerEngine — 因 v0.51.9 起卡直接进 Backlog)
|
|
32
36
|
// v0.51.9:删去 pipeline_order.json 副作用(统一按 seq 排序)
|
|
33
37
|
const services = createContainer();
|
|
34
|
-
const result = await services.cards.create(project, {
|
|
38
|
+
const result = await services.cards.create(project, {
|
|
39
|
+
title,
|
|
40
|
+
description: desc,
|
|
41
|
+
skills,
|
|
42
|
+
initialState,
|
|
43
|
+
});
|
|
35
44
|
if (!result.ok) {
|
|
36
45
|
const msg = result.error.message;
|
|
37
46
|
if (jsonOutput) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cardAdd.js","sourceRoot":"","sources":["../../src/commands/cardAdd.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE3D,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAe,EACf,WAAqB,EACrB,KAAuC;IAEvC,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC5C,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;IAEhC,MAAM,KAAK,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACrE,MAAM,MAAM,GAAG,SAAS;QACtB,CAAC,CAAC,SAAS;aACN,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,OAAO,CAAC;QACpB,CAAC,CAAC,SAAS,CAAC;IAEd,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC
|
|
1
|
+
{"version":3,"file":"cardAdd.js","sourceRoot":"","sources":["../../src/commands/cardAdd.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cards.d.ts","sourceRoot":"","sources":["../../../src/console/routes/cards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAIrE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,aAAa,CAAC;IACvB,SAAS,EAAE,eAAe,CAAC;CAC5B;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"cards.d.ts","sourceRoot":"","sources":["../../../src/console/routes/cards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAIrE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,aAAa,CAAC;IACvB,SAAS,EAAE,eAAe,CAAC;CAC5B;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAwG3D"}
|
|
@@ -40,11 +40,17 @@ export function createCardsRoute(deps) {
|
|
|
40
40
|
const labels = Array.isArray(body.labels)
|
|
41
41
|
? body.labels.filter((l) => typeof l === 'string' && l.trim().length > 0)
|
|
42
42
|
: undefined;
|
|
43
|
+
// v0.51.10: 默认入 Planning(console 表单是主要调用方);调用方显式传
|
|
44
|
+
// initialState 可覆盖(agent / 自动化用 'Backlog' 立即跑)
|
|
45
|
+
const initialState = typeof body.initialState === 'string' && body.initialState.trim()
|
|
46
|
+
? body.initialState.trim()
|
|
47
|
+
: 'Planning';
|
|
43
48
|
const r = await deps.cards.create(c.req.param('project'), {
|
|
44
49
|
title: body.title,
|
|
45
50
|
description: body.description,
|
|
46
51
|
skills,
|
|
47
52
|
labels,
|
|
53
|
+
initialState,
|
|
48
54
|
});
|
|
49
55
|
if (!r.ok)
|
|
50
56
|
return c.json(toProblemJson(r.error), toHttpStatus(r.error));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cards.js","sourceRoot":"","sources":["../../../src/console/routes/cards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5B,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAQpD,MAAM,UAAU,gBAAgB,CAAC,IAAoB;IACnD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,GAAG,CAAC,GAAG,CAAC,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC;QAChD,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAChF,IAAI,CAAC,CAAC,CAAC,EAAE;YAAE,OAAO,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACnC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,sBAAsB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1C,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QACpD,OAAO,UAAU,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACtC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"cards.js","sourceRoot":"","sources":["../../../src/console/routes/cards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5B,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAQpD,MAAM,UAAU,gBAAgB,CAAC,IAAoB;IACnD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,GAAG,CAAC,GAAG,CAAC,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC;QAChD,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAChF,IAAI,CAAC,CAAC,CAAC,EAAE;YAAE,OAAO,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACnC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,sBAAsB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1C,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QACpD,OAAO,UAAU,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACtC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAe1C,CAAC;QACT,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YAClE,OAAO,CAAC,CAAC,IAAI,CACX,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,GAAG,EAAE,EAC5D,GAAG,CACJ,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;YACvC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAChF,CAAC,CAAC,SAAS,CAAC;QACd,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;YACvC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;YACzE,CAAC,CAAC,SAAS,CAAC;QACd,kDAAkD;QAClD,+CAA+C;QAC/C,MAAM,YAAY,GAChB,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE;YAC/D,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE;YAC1B,CAAC,CAAC,UAAU,CAAC;QACjB,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE;YACxD,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,MAAM;YACN,MAAM;YACN,YAAY;SACb,CAAC,CAAC;QACH,IAAI,CAAC,CAAC,CAAC,EAAE;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,CAAQ,CAAC,CAAC;QAC/E,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC5C,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QACpD,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAQ1C,CAAC;QACT,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5C,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,qBAAqB,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC;QACxF,CAAC;QACD,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QACrE,IAAI,CAAC,CAAC,CAAC,EAAE;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,CAAQ,CAAC,CAAC;QAC/E,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,MAAM,CAAC,sBAAsB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC7C,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QACpD,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC;QAC/D,IAAI,CAAC,CAAC,CAAC,EAAE;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,CAAQ,CAAC,CAAC;QAC/E,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,4BAA4B,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACjD,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QACpD,6CAA6C;QAC7C,qEAAqE;QACrE,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC;QAC9D,IAAI,CAAC,CAAC,CAAC,EAAE;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,CAAQ,CAAC,CAAC;QAC/E,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,6BAA6B,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAClD,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QACpD,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC;QACjE,IAAI,CAAC,CAAC,CAAC,EAAE;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,CAAQ,CAAC,CAAC;QAC/E,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -502,7 +502,7 @@ ${n.comment}`:n.comment}this.doc.range[2]=n.offset;break}default:this.errors.pus
|
|
|
502
502
|
`)+1;for(;n!==0;)this.onNewLine(this.offset+n),n=this.source.indexOf(`
|
|
503
503
|
`,n)+1}return{type:t,offset:this.offset,indent:this.indent,source:this.source}}startBlockValue(t){switch(this.type){case"alias":case"scalar":case"single-quoted-scalar":case"double-quoted-scalar":return this.flowScalar(this.type);case"block-scalar-header":return{type:"block-scalar",offset:this.offset,indent:this.indent,props:[this.sourceToken],source:""};case"flow-map-start":case"flow-seq-start":return{type:"flow-collection",offset:this.offset,indent:this.indent,start:this.sourceToken,items:[],end:[]};case"seq-item-ind":return{type:"block-seq",offset:this.offset,indent:this.indent,items:[{start:[this.sourceToken]}]};case"explicit-key-ind":{this.onKeyLine=!0;const n=Zu(t),a=il(n);return a.push(this.sourceToken),{type:"block-map",offset:this.offset,indent:this.indent,items:[{start:a,explicitKey:!0}]}}case"map-value-ind":{this.onKeyLine=!0;const n=Zu(t),a=il(n);return{type:"block-map",offset:this.offset,indent:this.indent,items:[{start:a,key:null,sep:[this.sourceToken]}]}}}return null}atIndentedComment(t,n){return this.type!=="comment"||this.indent<=n?!1:t.every(a=>a.type==="newline"||a.type==="space")}*documentEnd(t){this.type!=="doc-mode"&&(t.end?t.end.push(this.sourceToken):t.end=[this.sourceToken],this.type==="newline"&&(yield*this.pop()))}*lineEnd(t){switch(this.type){case"comma":case"doc-start":case"doc-end":case"flow-seq-end":case"flow-map-end":case"map-value-ind":yield*this.pop(),yield*this.step();break;case"newline":this.onKeyLine=!1;case"space":case"comment":default:t.end?t.end.push(this.sourceToken):t.end=[this.sourceToken],this.type==="newline"&&(yield*this.pop())}}}function cS(e){const t=e.prettyErrors!==!1;return{lineCounter:e.lineCounter||t&&new lS||null,prettyErrors:t}}function KO(e,t={}){const{lineCounter:n,prettyErrors:a}=cS(t),s=new dg(n==null?void 0:n.addNewLine),o=new fg(t),c=Array.from(o.compose(s.parse(e)));if(a&&n)for(const f of c)f.errors.forEach(kf(e,n)),f.warnings.forEach(kf(e,n));return c.length>0?c:Object.assign([],{empty:!0},o.streamInfo())}function uS(e,t={}){const{lineCounter:n,prettyErrors:a}=cS(t),s=new dg(n==null?void 0:n.addNewLine),o=new fg(t);let c=null;for(const f of o.compose(s.parse(e),!0,e.length))if(!c)c=f;else if(c.options.logLevel!=="silent"){c.errors.push(new Jr(f.range.slice(0,2),"MULTIPLE_DOCS","Source contains multiple documents; please use YAML.parseAllDocuments()"));break}return a&&n&&(c.errors.forEach(kf(e,n)),c.warnings.forEach(kf(e,n))),c}function GO(e,t,n){let a;typeof t=="function"?a=t:n===void 0&&t&&typeof t=="object"&&(n=t);const s=uS(e,n);if(!s)return null;if(s.warnings.forEach(o=>CE(s.options.logLevel,o)),s.errors.length>0){if(s.options.logLevel!=="silent")throw s.errors[0];s.errors=[]}return s.toJS(Object.assign({reviver:a},n))}function QO(e,t,n){let a=null;if(typeof t=="function"||Array.isArray(t)?a=t:n===void 0&&t&&(n=t),typeof n=="string"&&(n=n.length),typeof n=="number"){const s=Math.round(n);n=s<1?void 0:s>8?{indent:8}:{indent:s}}if(e===void 0){const{keepUndefined:s}=n??t??{};if(!s)return}return hs(e)&&!a?e.toString(n):new Pl(e,a,n).toString(n)}const a0=Object.freeze(Object.defineProperty({__proto__:null,Alias:Ff,CST:PO,Composer:fg,Document:Pl,Lexer:sS,LineCounter:lS,Pair:bn,Parser:dg,Scalar:Be,Schema:QE,YAMLError:cg,YAMLMap:ai,YAMLParseError:Jr,YAMLSeq:Sr,YAMLWarning:VE,isAlias:kr,isCollection:Dt,isDocument:hs,isMap:Bl,isNode:zt,isPair:Rt,isScalar:St,isSeq:Ul,parse:GO,parseAllDocuments:KO,parseDocument:uS,stringify:QO,visit:ms,visitAsync:$f},Symbol.toStringTag,{value:"Module"}));function YO({projectName:e,file:t,onClose:n,onSaved:a}){const s=qn(),{alert:o}=li(),{data:c,isLoading:f,isError:h,error:m,refetch:b}=ot({queryKey:["pipeline-file",e,t],queryFn:()=>yA(e,t)}),[g,x]=O.useState("structured"),[v,E]=O.useState(null),[w,k]=O.useState(null);O.useEffect(()=>{c&&v===null&&(E(c.content),k(c.etag),c.parseError&&x("yaml"))},[c,v]),O.useEffect(()=>{const M=F=>{F.key==="Escape"&&n()};return window.addEventListener("keydown",M),()=>window.removeEventListener("keydown",M)},[n]);const _=Pn({mutationFn:()=>{if(v===null||w===null)throw new Error("no draft");return xA(e,t,v,w)},onSuccess:M=>{k(M.etag),s.invalidateQueries({queryKey:["pipeline-file",e,t]}),s.invalidateQueries({queryKey:["project-pipelines",e]}),a()},onError:M=>{const F=M.status;o({title:F===409?"文件已被其他地方修改":F===422?"YAML 语法错":"保存失败",body:M instanceof Error?M.message:String(M)})}}),A=v!==null&&c&&v!==c.content,{parsed:T,parseError:j}=O.useMemo(()=>{if(v===null)return{parsed:null,parseError:null};try{return{parsed:a0.parse(v)??{},parseError:null}}catch(M){return{parsed:null,parseError:M instanceof Error?M.message:String(M)}}},[v]),$=M=>{try{const F=a0.stringify(M,{lineWidth:0});E(F)}catch(F){o({title:"YAML 序列化失败",body:F instanceof Error?F.message:String(F)})}};return d.jsx("div",{role:"dialog","aria-modal":"true",className:"fixed inset-0 z-40 flex items-start justify-center p-6 bg-black/30 overflow-auto",children:d.jsxs("div",{className:"nb-card mt-8 w-full max-w-4xl flex flex-col",style:{maxHeight:"calc(100vh - 64px)"},children:[d.jsxs("header",{className:"flex items-start justify-between gap-3 mb-3 flex-shrink-0",children:[d.jsxs("div",{children:[d.jsxs("h2",{className:"font-[family-name:var(--font-heading)] text-2xl font-bold flex items-center gap-2",children:[d.jsx(Gv,{size:20,strokeWidth:2.5}),d.jsx("code",{className:"font-[family-name:var(--font-mono)] text-lg",children:t}),(c==null?void 0:c.isActive)&&d.jsx("span",{className:"nb-status",style:{background:"var(--color-running-bg)",color:"var(--color-running)",padding:"2px 8px"},children:"active"})]}),d.jsxs("p",{className:"text-xs text-[var(--color-text-muted)] font-[family-name:var(--font-mono)] mt-1",children:[e,"/pipelines/",t,w&&` · etag ${w}`]})]}),d.jsx("button",{className:"nb-btn nb-btn-mint p-2",onClick:n,type:"button","aria-label":"关闭",children:d.jsx(wi,{size:14,strokeWidth:3})})]}),f&&d.jsx("p",{className:"text-[var(--color-text-muted)]",children:"加载中…"}),h&&d.jsxs("p",{className:"text-[var(--color-crashed)]",children:["加载失败: ",m instanceof Error?m.message:String(m)]}),c&&v!==null&&d.jsxs(d.Fragment,{children:[d.jsxs("div",{className:"flex items-center gap-3 mb-3 flex-shrink-0 flex-wrap",children:[d.jsxs("div",{className:"flex gap-1 p-1 bg-[var(--color-bg)] border-[2px] border-[var(--color-text)] rounded-full shadow-[2px_2px_0_var(--color-text)]",children:[d.jsxs("button",{type:"button",onClick:()=>x("structured"),"aria-pressed":g==="structured",disabled:!!j,className:["px-3 py-1 rounded-full text-xs font-bold flex items-center gap-1.5",g==="structured"?"bg-[var(--color-primary)] text-[var(--color-text)] shadow-[1px_1px_0_var(--color-text)]":"text-[var(--color-text-muted)]",j?"opacity-50 cursor-not-allowed":""].join(" "),title:j??void 0,children:[d.jsx(Ec,{size:11,strokeWidth:2.5}),"结构化"]}),d.jsxs("button",{type:"button",onClick:()=>x("yaml"),"aria-pressed":g==="yaml",className:["px-3 py-1 rounded-full text-xs font-bold flex items-center gap-1.5",g==="yaml"?"bg-[var(--color-primary)] text-[var(--color-text)] shadow-[1px_1px_0_var(--color-text)]":"text-[var(--color-text-muted)]"].join(" "),children:[d.jsx(Gv,{size:11,strokeWidth:2.5}),"原始 YAML"]})]}),j&&d.jsxs("div",{className:"flex items-center gap-1 text-xs text-[var(--color-crashed)] font-bold",children:[d.jsx(rc,{size:12,strokeWidth:2.5}),"YAML parse: ",j]}),(c==null?void 0:c.isActive)&&d.jsx("span",{className:"text-xs text-[var(--color-stuck)] font-bold ml-auto",children:"⚠ 这是当前激活的 pipeline,保存后下一轮 tick 生效"})]}),d.jsxs("div",{className:"flex-1 overflow-auto",children:[g==="structured"&&T&&d.jsx(VO,{parsed:T,onChange:$}),g==="yaml"&&d.jsx("textarea",{className:"nb-input w-full font-[family-name:var(--font-mono)] text-xs",style:{minHeight:400,resize:"vertical"},value:v,onChange:M=>E(M.target.value),spellCheck:!1,"aria-label":"pipeline YAML 编辑器"})]}),d.jsxs("div",{className:"flex items-center justify-between mt-3 pt-3 border-t-2 border-dashed border-[var(--color-text)] flex-shrink-0",children:[d.jsx("span",{className:"text-xs text-[var(--color-text-muted)]",children:A?d.jsx("span",{className:"text-[var(--color-stuck)] font-bold",children:"● 未保存"}):_.isSuccess?d.jsxs("span",{className:"text-[var(--color-running)] font-bold flex items-center gap-1",children:[d.jsx(sc,{size:12,strokeWidth:2.5})," 已保存"]}):"无变化"}),d.jsxs("div",{className:"flex gap-2",children:[d.jsx("button",{className:"nb-btn",style:{padding:"6px 14px"},onClick:()=>{E(null),b()},disabled:_.isPending,type:"button",children:"重新加载"}),d.jsxs("button",{className:"nb-btn nb-btn-primary",style:{padding:"6px 14px"},onClick:()=>_.mutate(),disabled:!A||_.isPending,type:"button","aria-label":"保存 pipeline",children:[_.isPending?d.jsx(Lt,{size:13,strokeWidth:3,className:"animate-spin"}):d.jsx(Uf,{size:13,strokeWidth:3}),"保存"]})]})]})]})]})})}function VO({parsed:e,onChange:t}){const n=e.stages??[],a=h=>{t({...e,stages:h})},s=()=>{a([...n,{name:`stage-${n.length+1}`,on_complete:"move_card Done"}])},o=h=>{a(n.filter((m,b)=>b!==h))},c=(h,m)=>{const b=[...n],g=h+m;g<0||g>=b.length||([b[h],b[g]]=[b[g],b[h]],a(b))},f=(h,m)=>{a(n.map((b,g)=>g===h?{...b,...m}:b))};return d.jsxs("div",{className:"flex flex-col gap-4",children:[d.jsxs("div",{className:"flex items-center gap-3 p-3 bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] rounded-lg",children:[d.jsxs("label",{className:"flex items-center gap-2 text-sm",children:[d.jsx("span",{className:"font-bold",children:"mode:"}),d.jsxs("select",{className:"nb-input",style:{padding:"4px 10px",fontSize:12},value:e.mode??"project",onChange:h=>t({...e,mode:h.target.value}),children:[d.jsx("option",{value:"project",children:"project"}),d.jsx("option",{value:"steps",children:"steps"})]})]}),d.jsx("span",{className:"text-xs text-[var(--color-text-muted)]",children:"project = 事件驱动流水线(默认) · steps = 顺序脚本"})]}),d.jsxs("div",{children:[d.jsxs("div",{className:"flex items-center justify-between mb-2",children:[d.jsxs("h3",{className:"font-[family-name:var(--font-heading)] text-sm font-bold uppercase tracking-wider",children:["Stages (",n.length,")"]}),d.jsxs("button",{type:"button",className:"nb-btn nb-btn-mint",style:{padding:"4px 12px",fontSize:12},onClick:s,"aria-label":"添加 stage",children:[d.jsx(zi,{size:11,strokeWidth:3})," 添加 stage"]})]}),n.length===0?d.jsx("p",{className:"text-sm text-[var(--color-text-muted)] italic p-4 border-2 border-dashed border-[var(--color-text)] rounded-lg text-center",children:'还没 stage。点"添加 stage"开始。'}):d.jsx("div",{className:"flex flex-col gap-3",children:n.map((h,m)=>d.jsx(WO,{stage:h,index:m,total:n.length,onChange:b=>f(m,b),onRemove:()=>o(m),onMoveUp:()=>c(m,-1),onMoveDown:()=>c(m,1)},m))})]})]})}function WO({stage:e,index:t,total:n,onChange:a,onRemove:s,onMoveUp:o,onMoveDown:c}){const f=e.on_fail??{};return d.jsxs("div",{className:"nb-card bg-[var(--color-bg-cream)] p-4",children:[d.jsxs("div",{className:"flex items-center justify-between mb-3",children:[d.jsxs("h4",{className:"font-[family-name:var(--font-heading)] font-bold text-sm",children:["Stage #",t+1,e.name&&d.jsx("code",{className:"ml-2 text-xs font-[family-name:var(--font-mono)] bg-[var(--color-bg)] border-2 border-[var(--color-text)] px-2 py-0.5 rounded",children:e.name})]}),d.jsxs("div",{className:"flex gap-1",children:[d.jsx("button",{type:"button",className:"nb-btn",style:{padding:"3px 8px"},onClick:o,disabled:t===0,"aria-label":"上移",children:d.jsx(LT,{size:12,strokeWidth:3})}),d.jsx("button",{type:"button",className:"nb-btn",style:{padding:"3px 8px"},onClick:c,disabled:t===n-1,"aria-label":"下移",children:d.jsx(vc,{size:12,strokeWidth:3})}),d.jsx("button",{type:"button",className:"nb-btn nb-btn-danger",style:{padding:"3px 8px"},onClick:s,"aria-label":"删除 stage",children:d.jsx(zl,{size:12,strokeWidth:3})})]})]}),d.jsxs("div",{className:"grid grid-cols-2 gap-3 text-sm",children:[d.jsx(lr,{label:"name",hint:"stage 唯一名",children:d.jsx("input",{type:"text",className:"nb-input w-full font-[family-name:var(--font-mono)] text-xs",value:e.name??"",onChange:h=>a({name:h.target.value}),placeholder:"develop"})}),d.jsx(lr,{label:"profile",hint:"skill 画像,可空",children:d.jsx("input",{type:"text",className:"nb-input w-full font-[family-name:var(--font-mono)] text-xs",value:e.profile??"",onChange:h=>a({profile:h.target.value||void 0}),placeholder:"fullstack"})}),d.jsx(lr,{label:"card_state",hint:"本 stage 期间卡片状态",children:d.jsx("input",{type:"text",className:"nb-input w-full font-[family-name:var(--font-mono)] text-xs",value:e.card_state??"",onChange:h=>a({card_state:h.target.value||void 0}),placeholder:"Inprogress"})}),d.jsx(lr,{label:"timeout",hint:"可选,如 30m 2h",children:d.jsx("input",{type:"text",className:"nb-input w-full font-[family-name:var(--font-mono)] text-xs",value:e.timeout??"",onChange:h=>a({timeout:h.target.value||void 0}),placeholder:"2h"})}),d.jsx(lr,{label:"trigger",hint:"触发条件,可空走默认",children:d.jsx("input",{type:"text",className:"nb-input w-full font-[family-name:var(--font-mono)] text-xs",value:e.trigger??"",onChange:h=>a({trigger:h.target.value||void 0}),placeholder:"card_enters 'Todo'"})}),d.jsx(lr,{label:"on_complete",hint:"成功后动作",children:d.jsx("input",{type:"text",className:"nb-input w-full font-[family-name:var(--font-mono)] text-xs",value:e.on_complete??"",onChange:h=>a({on_complete:h.target.value}),placeholder:"move_card Done"})})]}),d.jsxs("div",{className:"mt-4 pt-3 border-t-2 border-dashed border-[var(--color-text)]",children:[d.jsx("h5",{className:"text-xs font-bold uppercase tracking-wider mb-2 text-[var(--color-text-muted)]",children:"on_fail"}),d.jsxs("div",{className:"grid grid-cols-2 gap-3 text-sm",children:[d.jsx(lr,{label:"action",hint:"失败时动作,如 label NEEDS-FIX",children:d.jsx("input",{type:"text",className:"nb-input w-full font-[family-name:var(--font-mono)] text-xs",value:f.action??"",onChange:h=>a({on_fail:{...f,action:h.target.value||void 0}}),placeholder:"label NEEDS-FIX"})}),d.jsx(lr,{label:"comment",hint:"写进卡片的注释",children:d.jsx("input",{type:"text",className:"nb-input w-full font-[family-name:var(--font-mono)] text-xs",value:f.comment??"",onChange:h=>a({on_fail:{...f,comment:h.target.value||void 0}}),placeholder:"Worker failed. Check logs."})})]}),d.jsxs("label",{className:"flex items-center gap-2 mt-3 text-sm cursor-pointer",children:[d.jsx("input",{type:"checkbox",checked:f.halt??!0,onChange:h=>a({on_fail:{...f,halt:h.target.checked}})}),d.jsx("span",{className:"font-bold",children:"halt"}),d.jsx("span",{className:"text-xs text-[var(--color-text-muted)]",children:"(失败后停流水线;去掉则继续下一张卡)"})]})]})]})}function lr({label:e,hint:t,children:n}){return d.jsxs("label",{className:"flex flex-col gap-1",children:[d.jsx("span",{className:"text-xs font-bold font-[family-name:var(--font-mono)]",children:e}),n,t&&d.jsx("span",{className:"text-[10px] text-[var(--color-text-muted)]",children:t})]})}function XO({onCancel:e,onCreate:t,hasActive:n,hasSample:a,isPending:s}){const[o,c]=O.useState(""),[f,h]=O.useState("blank");O.useEffect(()=>{const v=E=>{E.key==="Escape"&&e()};return window.addEventListener("keydown",v),()=>window.removeEventListener("keydown",v)},[e]);const m=o.trim(),b=m.endsWith(".yaml")?m:m?`${m}.yaml`:"",g=b&&/^[a-zA-Z0-9_.-]+\.yaml$/.test(b),x=()=>{!g||s||t(b,f)};return d.jsx("div",{role:"dialog","aria-modal":"true",className:"fixed inset-0 z-50 flex items-center justify-center p-6 bg-black/30",children:d.jsxs("div",{className:"nb-card max-w-md w-full",children:[d.jsxs("header",{className:"flex items-start justify-between mb-4",children:[d.jsx("h2",{className:"font-[family-name:var(--font-heading)] text-xl font-bold",children:"新建 pipeline"}),d.jsx("button",{className:"nb-btn nb-btn-mint p-2",onClick:e,type:"button","aria-label":"关闭",children:d.jsx(wi,{size:14,strokeWidth:3})})]}),d.jsxs("form",{onSubmit:v=>{v.preventDefault(),x()},className:"flex flex-col gap-4",children:[d.jsxs("label",{className:"flex flex-col gap-1.5",children:[d.jsx("span",{className:"text-sm font-bold",children:"文件名"}),d.jsx("input",{type:"text",className:"nb-input w-full font-[family-name:var(--font-mono)]",placeholder:"例如 ci",value:o,onChange:v=>c(v.target.value),autoFocus:!0}),d.jsxs("span",{className:"text-xs text-[var(--color-text-muted)]",children:["实际会保存为 ",d.jsx("code",{className:"font-[family-name:var(--font-mono)]",children:b||"xxx.yaml"}),"。 只允许 a-z A-Z 0-9 _ -;已有同名文件会 409 报错。"]})]}),d.jsxs("fieldset",{className:"flex flex-col gap-2",children:[d.jsx("legend",{className:"text-sm font-bold mb-1",children:"初始内容"}),d.jsx(_m,{value:"blank",current:f,label:"空白模板",desc:"最简 1 stage (develop → Done)",onSelect:h}),d.jsx(_m,{value:"sample",current:f,label:"教学模板",desc:"从 sample.yaml.example 复制(带注释,讲解所有字段)",onSelect:h,disabled:!a,disabledReason:"sample.yaml.example 不存在"}),d.jsx(_m,{value:"active",current:f,label:"复制当前活动的",desc:"从 project.yaml 复制(基于目前的配置改)",onSelect:h,disabled:!n,disabledReason:"project.yaml 不存在"})]}),d.jsxs("div",{className:"flex gap-3 justify-end pt-2",children:[d.jsx("button",{className:"nb-btn",onClick:e,type:"button",disabled:s,children:"取消"}),d.jsxs("button",{className:"nb-btn nb-btn-primary",type:"submit",disabled:!g||s,"aria-label":"创建 pipeline",children:[s?d.jsx(Lt,{size:13,strokeWidth:3,className:"animate-spin"}):d.jsx(zi,{size:13,strokeWidth:3}),"创建"]})]})]})]})})}function _m({value:e,current:t,label:n,desc:a,onSelect:s,disabled:o,disabledReason:c}){const f=t===e;return d.jsxs("label",{className:["flex items-start gap-2 p-2 rounded-lg border-2 cursor-pointer",o?"border-[var(--color-border-light)] opacity-50 cursor-not-allowed":f?"bg-[var(--color-accent-mint)] border-[var(--color-text)] shadow-[2px_2px_0_var(--color-text)]":"border-[var(--color-border-light)] hover:bg-[var(--color-bg-cream)] hover:border-[var(--color-text)]"].join(" "),children:[d.jsx("input",{type:"radio",name:"pipeline-template",value:e,checked:f,disabled:o,onChange:()=>s(e),className:"mt-1 flex-shrink-0"}),d.jsxs("div",{className:"flex-1",children:[d.jsx("div",{className:"text-sm font-bold",children:n}),d.jsx("div",{className:"text-xs text-[var(--color-text-muted)]",children:o?c:a})]})]})}function ZO(){var o;const{name:e=""}=K1(),t=wr(),[n,a]=O.useState("overview"),s=ot({queryKey:["project",e],queryFn:()=>fA(e),enabled:!!e});return d.jsxs("div",{className:"flex flex-col gap-5 max-w-4xl",children:[d.jsxs("header",{className:"flex items-center gap-3",children:[d.jsxs("button",{type:"button",onClick:()=>t("/projects"),className:"nb-btn",style:{padding:"6px 12px"},"aria-label":"返回项目列表",children:[d.jsx(tE,{size:14,strokeWidth:3}),"返回"]}),d.jsx("h1",{className:"font-[family-name:var(--font-heading)] text-3xl font-bold flex-1",children:e}),d.jsx(ds,{to:`/board?project=${encodeURIComponent(e)}`,className:"nb-btn nb-btn-mint",children:"看板"})]}),d.jsxs("nav",{className:"flex gap-2 flex-wrap",children:[d.jsx(Ju,{current:n,value:"overview",onSelect:a,icon:JT,children:"概览"}),d.jsx(Ju,{current:n,value:"config",onSelect:a,icon:sE,children:"配置"}),d.jsx(Ju,{current:n,value:"pipelines",onSelect:a,icon:uE,children:"Pipelines"}),d.jsx(Ju,{current:n,value:"danger",onSelect:a,icon:zl,children:"危险操作"})]}),n==="overview"&&d.jsx(JO,{name:e,data:s.data,loading:s.isLoading}),n==="config"&&d.jsx(eR,{name:e}),n==="pipelines"&&d.jsx(tR,{name:e}),n==="danger"&&d.jsx(nR,{name:e,repoDir:((o=s.data)==null?void 0:o.repoDir)??null})]})}function Ju({current:e,value:t,onSelect:n,icon:a,children:s}){const o=e===t;return d.jsxs("button",{type:"button",onClick:()=>n(t),"aria-current":o?"page":void 0,className:["nb-btn",o?"nb-btn-primary":""].join(" "),style:{padding:"6px 14px",fontSize:13},children:[d.jsx(a,{size:13,strokeWidth:2.5}),s]})}function JO({name:e,data:t,loading:n}){return n?d.jsx("div",{className:"nb-card",children:d.jsx("p",{className:"text-[var(--color-text-muted)]",children:"加载中…"})}):t?d.jsx("div",{className:"nb-card",children:d.jsxs("dl",{className:"grid grid-cols-[160px_1fr] gap-y-3 text-sm",children:[d.jsx("dt",{className:"font-bold",children:"仓库路径"}),d.jsx("dd",{className:"font-[family-name:var(--font-mono)]",children:t.repoDir??"—"}),d.jsx("dt",{className:"font-bold",children:"PM 后端"}),d.jsx("dd",{className:"font-[family-name:var(--font-mono)]",children:t.pmBackend}),d.jsx("dt",{className:"font-bold",children:"Agent"}),d.jsx("dd",{className:"font-[family-name:var(--font-mono)]",children:t.agentProvider}),d.jsx("dt",{className:"font-bold",children:"卡片"}),d.jsxs("dd",{className:"font-[family-name:var(--font-mono)]",children:[t.cards.total," 张 · ",t.cards.inprogress," 进行中 · ",t.cards.done," 完成"]}),d.jsx("dt",{className:"font-bold",children:"Worker"}),d.jsxs("dd",{className:"font-[family-name:var(--font-mono)]",children:[t.workers.total," 个(",t.workers.active," 活跃)"]}),d.jsx("dt",{className:"font-bold",children:"Pipeline"}),d.jsx("dd",{className:"font-[family-name:var(--font-mono)]",children:t.pipelineStatus}),d.jsx("dt",{className:"font-bold",children:"最近活动"}),d.jsx("dd",{className:"font-[family-name:var(--font-mono)]",children:t.lastActivityAt?new Date(t.lastActivityAt).toLocaleString():"—"})]})}):d.jsx("div",{className:"nb-card bg-[var(--color-crashed-bg)]",children:d.jsxs("p",{children:["项目 ",e," 不存在或无法读取。"]})})}function eR({name:e}){const t=qn(),{alert:n}=li(),{data:a,isLoading:s,isError:o,error:c,refetch:f}=ot({queryKey:["project-conf",e],queryFn:()=>hA(e)}),[h,m]=O.useState(null),[b,g]=O.useState(null);O.useEffect(()=>{a&&h===null&&(m(a.content),g(a.etag))},[a,h]);const x=h!==null&&a!==void 0&&h!==a.content,v=Pn({mutationFn:()=>{if(h===null||b===null)throw new Error("no draft");return mA(e,h,b)},onSuccess:E=>{g(E.etag),t.invalidateQueries({queryKey:["project-conf",e]}),t.invalidateQueries({queryKey:["project",e]})},onError:E=>{const w=E.status;n({title:w===409?"配置已被其他地方修改":"保存失败",body:w===409?'conf 文件在你编辑期间被改过。点"重新加载"后再编辑。':E instanceof Error?E.message:String(E)})}});return s?d.jsx("div",{className:"nb-card",children:d.jsx("p",{className:"text-[var(--color-text-muted)]",children:"加载中…"})}):o?d.jsx("div",{className:"nb-card bg-[var(--color-crashed-bg)]",children:d.jsxs("p",{children:["加载失败: ",c instanceof Error?c.message:String(c)]})}):d.jsxs("div",{className:"nb-card",children:[d.jsxs("div",{className:"flex items-center justify-between mb-3",children:[d.jsxs("div",{children:[d.jsx("h2",{className:"font-[family-name:var(--font-heading)] text-lg font-bold",children:d.jsxs("code",{className:"font-[family-name:var(--font-mono)] text-sm bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] px-2 py-0.5 rounded",children:["~/.coral/projects/",e,"/conf"]})}),b&&d.jsxs("p",{className:"text-xs text-[var(--color-text-muted)] font-[family-name:var(--font-mono)] mt-1",children:["etag: ",b]})]}),d.jsxs("div",{className:"flex gap-2",children:[d.jsxs("button",{type:"button",className:"nb-btn",style:{padding:"6px 12px"},onClick:()=>{m(null),f()},disabled:v.isPending,"aria-label":"重新加载",children:[d.jsx(Cl,{size:13,strokeWidth:2.5}),"重新加载"]}),d.jsxs("button",{type:"button",className:"nb-btn nb-btn-primary",style:{padding:"6px 12px"},onClick:()=>v.mutate(),disabled:!x||v.isPending,"aria-label":"保存配置",children:[v.isPending?d.jsx(Lt,{size:13,strokeWidth:3,className:"animate-spin"}):v.isSuccess&&!x?d.jsx(RT,{size:13,strokeWidth:3}):d.jsx(Uf,{size:13,strokeWidth:3}),"保存"]})]})]}),d.jsx("textarea",{className:"nb-input w-full font-[family-name:var(--font-mono)] text-xs",style:{minHeight:480,resize:"vertical"},value:h??"",onChange:E=>m(E.target.value),spellCheck:!1,"aria-label":"conf 文件编辑器"}),x&&d.jsx("p",{className:"text-xs text-[var(--color-stuck)] mt-2 font-bold",children:"● 未保存的修改"})]})}function tR({name:e}){const t=qn(),{confirm:n,alert:a}=li(),{data:s,isLoading:o}=ot({queryKey:["project-pipelines",e],queryFn:()=>gA(e)}),[c,f]=O.useState(null),[h,m]=O.useState(!1),b=Pn({mutationFn:E=>bA(e,E),onSuccess:()=>t.invalidateQueries({queryKey:["project-pipelines",e]}),onError:E=>{a({title:"切换失败",body:E instanceof Error?E.message:String(E)})}}),g=Pn({mutationFn:E=>EA(e,E),onSuccess:()=>t.invalidateQueries({queryKey:["project-pipelines",e]}),onError:E=>{a({title:"删除失败",body:E instanceof Error?E.message:String(E)})}}),x=Pn({mutationFn:E=>vA(e,E.name,E.template),onSuccess:E=>{t.invalidateQueries({queryKey:["project-pipelines",e]}),m(!1),f(E.name)},onError:E=>{a({title:"创建失败",body:E instanceof Error?E.message:String(E)})}});if(o)return d.jsx("div",{className:"nb-card",children:d.jsx("p",{className:"text-[var(--color-text-muted)]",children:"加载中…"})});const v=[];s!=null&&s.active&&v.push({name:s.active,isActive:!0});for(const E of(s==null?void 0:s.available)??[])v.push({name:E.name,isActive:!1});return d.jsxs(d.Fragment,{children:[d.jsxs("div",{className:"nb-card",children:[d.jsxs("div",{className:"flex items-center justify-between mb-3",children:[d.jsx("h2",{className:"font-[family-name:var(--font-heading)] text-lg font-bold",children:"Pipelines"}),d.jsxs("button",{type:"button",className:"nb-btn nb-btn-mint",style:{padding:"6px 12px",fontSize:12},onClick:()=>m(!0),disabled:x.isPending,"aria-label":"新建 pipeline",children:[d.jsx(zi,{size:12,strokeWidth:3}),"新建 pipeline"]})]}),v.length===0?d.jsx("p",{className:"text-sm text-[var(--color-text-muted)] italic p-4 border-2 border-dashed border-[var(--color-text)] rounded-lg text-center",children:'还没有 pipeline 文件。点"新建 pipeline"开始。'}):d.jsx("ul",{className:"flex flex-col gap-2",children:v.map(E=>d.jsxs("li",{className:"flex items-center gap-3 p-3 bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] rounded-lg",children:[d.jsx(uE,{size:16,strokeWidth:2.5}),d.jsx("span",{className:"font-[family-name:var(--font-mono)] font-bold flex-1",children:E.name}),E.isActive&&d.jsx("span",{className:"nb-status",style:{background:"var(--color-running-bg)",color:"var(--color-running)"},children:"active"}),d.jsxs("div",{className:"flex gap-1",children:[d.jsxs("button",{type:"button",className:"nb-btn",style:{padding:"4px 10px",fontSize:11},onClick:()=>f(E.name),"aria-label":`编辑 ${E.name}`,children:[d.jsx(Vp,{size:11,strokeWidth:2.5}),"编辑"]}),!E.isActive&&d.jsxs(d.Fragment,{children:[d.jsx("button",{type:"button",className:"nb-btn nb-btn-primary",style:{padding:"4px 10px",fontSize:11},onClick:async()=>{await n({title:`切换到 ${E.name}`,body:`当前 project.yaml 会被 ${E.name} 的内容覆盖。继续?`,confirm:"切换"})&&b.mutate(E.name)},disabled:b.isPending,"aria-label":`切换到 ${E.name}`,children:"切换"}),d.jsx("button",{type:"button",className:"nb-btn nb-btn-danger",style:{padding:"4px 10px",fontSize:11},onClick:async()=>{await n({title:`删除 ${E.name}`,body:"这个 pipeline 文件会被永久删除。",confirm:"删除",danger:!0})&&g.mutate(E.name)},disabled:g.isPending,"aria-label":`删除 ${E.name}`,children:d.jsx(zl,{size:11,strokeWidth:2.5})})]})]})]},E.name))})]}),c&&d.jsx(YO,{projectName:e,file:c,onClose:()=>f(null),onSaved:()=>{t.invalidateQueries({queryKey:["project-pipelines",e]})}}),h&&d.jsx(XO,{hasActive:!!(s!=null&&s.active),hasSample:!0,isPending:x.isPending,onCancel:()=>m(!1),onCreate:(E,w)=>x.mutate({name:E,template:w})})]})}function nR({name:e,repoDir:t}){const n=wr(),a=qn(),{alert:s}=li(),[o,c]=O.useState(""),[f,h]=O.useState(!0),m=Pn({mutationFn:()=>pA(e,{includeClaudeDir:f}),onSuccess:b=>{a.invalidateQueries({queryKey:["projects"]});const g=b.claudeRemoved.filter(x=>x.ok).map(x=>x.path);s({title:"已删除",body:g.length>0?`项目已删除。同时清理了:
|
|
504
504
|
${g.join(`
|
|
505
|
-
`)}`:"项目已删除。"}).then(()=>n("/projects"))},onError:b=>{s({title:"删除失败",body:b instanceof Error?b.message:String(b)})}});return d.jsxs("div",{className:"nb-card bg-[var(--color-crashed-bg)]",children:[d.jsx("h2",{className:"font-[family-name:var(--font-heading)] text-lg font-bold mb-2 text-[var(--color-crashed)]",children:"删除项目"}),d.jsxs("p",{className:"text-sm mb-4",children:["这会清理 ",d.jsxs("code",{className:"font-[family-name:var(--font-mono)] bg-[var(--color-bg)] border-2 border-[var(--color-text)] px-1.5 py-0.5 rounded",children:["~/.coral/projects/",e,"/"]}),"(包括所有卡片、runtime、logs)。"]}),t&&d.jsxs("label",{className:"flex items-start gap-2 mb-4 p-3 bg-[var(--color-bg)] border-2 border-[var(--color-text)] rounded-lg cursor-pointer",children:[d.jsx("input",{type:"checkbox",checked:f,onChange:b=>h(b.target.checked),className:"mt-0.5"}),d.jsxs("div",{className:"flex-1",children:[d.jsx("div",{className:"text-sm font-bold",children:"同时清理 repo 的 .claude/"}),d.jsxs("div",{className:"text-xs text-[var(--color-text-muted)] font-[family-name:var(--font-mono)]",children:[t,"/.claude/"]}),d.jsx("div",{className:"text-xs text-[var(--color-text-muted)] mt-1",children:"repo 本身不动,只清这个目录。"})]})]}),d.jsx("div",{className:"mb-4",children:d.jsxs("label",{className:"flex flex-col gap-1.5",children:[d.jsxs("span",{className:"text-sm font-bold",children:["输入项目名 ",d.jsx("code",{className:"font-[family-name:var(--font-mono)] text-xs",children:e})," 确认:"]}),d.jsx("input",{type:"text",className:"nb-input w-full font-[family-name:var(--font-mono)]",value:o,onChange:b=>c(b.target.value),placeholder:e})]})}),d.jsxs("button",{type:"button",className:"nb-btn nb-btn-danger",disabled:o!==e||m.isPending,onClick:()=>m.mutate(),"aria-label":"永久删除项目",children:[m.isPending?d.jsx(Lt,{size:14,strokeWidth:3,className:"animate-spin"}):d.jsx(zl,{size:14,strokeWidth:3}),"永久删除"]})]})}function hg(e){const t=e?`?project=${encodeURIComponent(e)}`:"";return Ft(`/api/skills${t}`)}function iR(e){return Ft(`/api/skills/${encodeURIComponent(e)}`)}function aR(e,t){return Ft(`/api/skills/${encodeURIComponent(e)}/references/${encodeURIComponent(t)}`)}async function Jf(e,t){const n=await fetch(e,{method:"POST",headers:t?{"Content-Type":"application/json"}:void 0,body:t?JSON.stringify(t):void 0});if(!n.ok)throw new Error(`${n.status}: ${await n.text()}`);return n.json().catch(()=>({}))}function rR(e,t){return Jf(`/api/skills/${encodeURIComponent(e)}/link`,{project:t})}function sR(e,t){return fetch(`/api/skills/${encodeURIComponent(e)}/link?project=${encodeURIComponent(t)}`,{method:"DELETE"}).then(n=>{if(!n.ok)throw new Error(`${n.status}`);return n.json()})}function lR(e,t){return Jf(`/api/skills/${encodeURIComponent(e)}/freeze`,{project:t})}function oR(e,t){return Jf(`/api/skills/${encodeURIComponent(e)}/unfreeze`,{project:t})}function cR(){return Jf("/api/skills/sync")}function uR({project:e,isPending:t,onCancel:n,onCreate:a}){var A;const[s,o]=O.useState(""),[c,f]=O.useState(""),[h,m]=O.useState(new Set),[b,g]=O.useState(!0),x=ot({queryKey:["skills-all",e],queryFn:()=>hg(e)});O.useEffect(()=>{const T=j=>{j.key==="Escape"&&n()};return window.addEventListener("keydown",T),()=>window.removeEventListener("keydown",T)},[n]);const E=s.trim().length>0&&s.trim().length<=200&&!t,w=T=>{const j=new Set(h);j.has(T)?j.delete(T):j.add(T),m(j)},k=()=>{E&&a({title:s.trim(),description:c.trim(),skills:[...h],labels:b?["AI-PIPELINE"]:[]})},_=((A=x.data)==null?void 0:A.data)??[];return d.jsx("div",{role:"dialog","aria-modal":"true",className:"fixed inset-0 z-40 flex items-start justify-center p-6 bg-black/30 overflow-auto",children:d.jsxs("div",{className:"nb-card mt-8 w-full max-w-xl flex flex-col",style:{maxHeight:"calc(100vh - 64px)"},children:[d.jsxs("header",{className:"flex items-center justify-between mb-4 flex-shrink-0",children:[d.jsx("h2",{className:"font-[family-name:var(--font-heading)] text-2xl font-bold",children:"新建卡片"}),d.jsx("button",{className:"nb-btn nb-btn-mint p-2",onClick:n,type:"button","aria-label":"关闭",children:d.jsx(wi,{size:14,strokeWidth:3})})]}),d.jsxs("form",{onSubmit:T=>{T.preventDefault(),k()},className:"flex flex-col gap-4 overflow-auto",children:[d.jsxs("label",{className:"flex flex-col gap-1.5",children:[d.jsx("span",{className:"text-sm font-bold",children:"标题 *"}),d.jsx("input",{type:"text",className:"nb-input w-full",placeholder:"例如:接入 GitHub OAuth 登录",value:s,onChange:T=>o(T.target.value),maxLength:200,autoFocus:!0,required:!0}),d.jsx("span",{className:"text-xs text-[var(--color-text-muted)]",children:"写简短明了的目标(<200 字符)"})]}),d.jsxs("label",{className:"flex flex-col gap-1.5",children:[d.jsx("span",{className:"text-sm font-bold",children:"描述"}),d.jsx("textarea",{className:"nb-input w-full",style:{minHeight:120,resize:"vertical"},placeholder:"用户故事、需求、验收标准、参考资料… Claude 启动时会读这里的内容",value:c,onChange:T=>f(T.target.value)}),d.jsx("span",{className:"text-xs text-[var(--color-text-muted)]",children:"支持 markdown。空的话就只有 title,Claude 只能靠 title 推断要做啥。"})]}),d.jsxs("div",{className:"flex flex-col gap-2",children:[d.jsx("span",{className:"text-sm font-bold",children:"Skills"}),d.jsx("span",{className:"text-xs text-[var(--color-text-muted)]",children:"勾选哪些 skill 会被加载(走 frontmatter `skills:`)。不选也行,Worker 默认加载项目级 skills。"}),x.isLoading&&d.jsx("p",{className:"text-xs text-[var(--color-text-muted)] italic",children:"加载 skill 列表…"}),x.isError&&d.jsxs("p",{className:"text-xs text-[var(--color-crashed)]",children:["skill 列表加载失败,不影响创建:",x.error instanceof Error?x.error.message:String(x.error)]}),_.length>0&&d.jsx("div",{className:"flex flex-wrap gap-2",children:_.map(T=>{const j=h.has(T.name);return d.jsx("button",{type:"button",onClick:()=>w(T.name),className:["px-2.5 py-1 text-xs font-[family-name:var(--font-mono)] rounded-full border-2 transition-all",j?"bg-[var(--color-accent-mint)] border-[var(--color-text)] shadow-[2px_2px_0_var(--color-text)] font-bold":"bg-[var(--color-bg)] border-[var(--color-border-light)] hover:border-[var(--color-text)]"].join(" "),"aria-pressed":j,children:T.name},T.name)})}),h.size>0&&d.jsxs("p",{className:"text-xs text-[var(--color-text-muted)]",children:["已选 ",h.size," 个:",[...h].join(", ")]})]}),d.jsxs("div",{className:"flex flex-col gap-2",children:[d.jsx("span",{className:"text-sm font-bold",children:"流水线"}),d.jsxs("label",{className:"flex items-center gap-3 cursor-pointer select-none p-3 border-[2px] border-[var(--color-text)] rounded-lg bg-[var(--color-bg-cream)]",children:[d.jsx("input",{type:"checkbox",className:"w-4 h-4 accent-[var(--color-cta)] cursor-pointer",checked:b,onChange:T=>g(T.target.checked)}),d.jsxs("div",{className:"flex-1",children:[d.jsx("div",{className:"text-sm font-bold",children:"加入流水线(`AI-PIPELINE` 标签)"}),d.jsx("div",{className:"text-xs text-[var(--color-text-muted)] mt-0.5",children:"打开后 pipeline 会识别这张卡并派 worker 跑。关闭则只是一个普通 todo,需要人工改标签才会被流水线拾起。"})]})]})]})]}),d.jsxs("div",{className:"flex gap-2 justify-end mt-4 pt-3 border-t-2 border-dashed border-[var(--color-text)] flex-shrink-0",children:[d.jsx("button",{className:"nb-btn",style:{padding:"6px 14px"},onClick:n,disabled:t,type:"button",children:"取消"}),d.jsxs("button",{className:"nb-btn nb-btn-primary",style:{padding:"6px 14px"},onClick:k,disabled:!E,type:"button","aria-label":"创建卡片",children:[t?d.jsx(Lt,{size:13,strokeWidth:3,className:"animate-spin"}):d.jsx(zi,{size:13,strokeWidth:3}),"创建"]})]})]})})}function fR(e){return Ft(`/api/projects/${encodeURIComponent(e)}/cards`)}function dR(e,t){return Ft(`/api/projects/${encodeURIComponent(e)}/cards/${t}`)}async function ql(e,t){const n=await fetch(e,{method:"POST",headers:t?{"Content-Type":"application/json"}:void 0,body:t?JSON.stringify(t):void 0});if(!n.ok){const a=await n.text();throw new Error(`${n.status} ${n.statusText}: ${a}`)}return n.json().catch(()=>({}))}function hR(e,t){return ql(`/api/projects/${encodeURIComponent(e)}/cards/${t}/reset`)}async function mR(e,t){const n=await fetch(`/api/projects/${encodeURIComponent(e)}/cards/${t}`,{method:"DELETE"});if(!n.ok){const a=await n.text();throw new Error(`${n.status}: ${a}`)}}function pR(e,t){return ql(`/api/projects/${encodeURIComponent(e)}/cards/${t}/launch`)}function gR(e,t){const n=typeof t=="string"?{title:t}:t;return ql(`/api/projects/${encodeURIComponent(e)}/cards`,n)}async function bR(e,t,n){const a=await fetch(`/api/projects/${encodeURIComponent(e)}/cards/${t}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({state:n})});if(!a.ok){const s=await a.text();throw new Error(`${a.status}: ${s}`)}}async function yR(e,t,n){const a=await fetch(`/api/projects/${encodeURIComponent(e)}/cards/${t}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)});if(!a.ok){const s=await a.text();throw new Error(`${a.status}: ${s}`)}return a.json()}function xR(e){return ql(`/api/projects/${encodeURIComponent(e)}/pipeline/start`)}function vR(e){return ql(`/api/projects/${encodeURIComponent(e)}/pipeline/stop`)}function ER(e,t){return ql(`/api/projects/${encodeURIComponent(e)}/pipeline/reset`,t??{})}function SR(e){const t=qn();O.useEffect(()=>{if(!e)return;const n=`/stream/projects/${encodeURIComponent(e)}`,a=new EventSource(n),s=f=>{try{const h=JSON.parse(f.data);t.invalidateQueries({queryKey:["cards",h.project]}),t.invalidateQueries({queryKey:["card",h.project,h.seq]}),t.invalidateQueries({queryKey:["projects"]})}catch{}},o=f=>{try{const h=JSON.parse(f.data);t.invalidateQueries({queryKey:["workers",h.project]}),t.invalidateQueries({queryKey:["projects"]})}catch{}},c=f=>{try{const h=JSON.parse(f.data);t.invalidateQueries({queryKey:["pipeline-status",h.project]}),t.invalidateQueries({queryKey:["projects"]})}catch{}};return a.addEventListener("card.created",s),a.addEventListener("card.updated",s),a.addEventListener("card.moved",s),a.addEventListener("card.deleted",s),a.addEventListener("worker.updated",o),a.addEventListener("worker.added",o),a.addEventListener("worker.deleted",o),a.addEventListener("pipeline.status",c),a.addEventListener("pipeline.started",c),a.addEventListener("pipeline.stopped",c),()=>a.close()},[e,t])}const wR=new Set(["python","typescript","golang","rust","kotlin","swift","java"]),_R=new Set(["frontend","backend","mobile","database","devops"]),kR=new Set(["backend-architect","frontend-developer","code-reviewer","database-optimizer","devops-automator","security-engineer","qa-tester","security","qa","architect","db-opt"]),NR=new Set(["coding-standards","tdd-workflow","git-workflow","architecture-decision-records","debugging-workflow"]);function TR(e){return wR.has(e)?"lang":_R.has(e)?"end":kR.has(e)?"persona":NR.has(e)?"workflow":"other"}const CR={lang:"var(--color-accent-purple)",end:"var(--color-secondary)",persona:"var(--color-primary)",workflow:"var(--color-accent-mint)",other:"var(--color-bg)"};function fS({name:e}){const t=CR[TR(e)];return d.jsx("span",{className:"nb-badge",style:{background:t},children:e})}function dS({label:e,kind:t="default"}){const n=t==="warn"?"var(--color-accent-pink)":t==="accent"?"var(--color-accent-yellow)":"var(--color-bg-cream)";return d.jsx("span",{className:"nb-badge",style:{background:n},children:e})}function AR({card:e,onClick:t,done:n,draggable:a}){const s=e.labels.some(o=>o.startsWith("STARTED-"))&&!n;return d.jsxs("article",{onClick:t,onKeyDown:o=>{(o.key==="Enter"||o.key===" ")&&(o.preventDefault(),t())},draggable:a,onDragStart:o=>{o.dataTransfer.setData("application/x-sps-card-seq",String(e.seq)),o.dataTransfer.effectAllowed="move"},tabIndex:0,role:"button","aria-label":`Card #${e.seq}: ${e.title}`,className:["bg-[var(--color-bg)] border-[3px] border-[var(--color-text)] rounded-xl p-3","shadow-[3px_3px_0_var(--color-text)] cursor-pointer","transition-[transform,box-shadow] duration-[180ms] ease-out","hover:-translate-x-0.5 hover:-translate-y-0.5 hover:shadow-[5px_5px_0_var(--color-text)]","focus:outline-none focus-visible:ring-[3px] focus-visible:ring-offset-2 focus-visible:ring-[var(--color-text)]",n?"opacity-60":"",a?"active:cursor-grabbing":""].join(" "),children:[d.jsxs("div",{className:"flex items-center justify-between gap-2 mb-2",children:[d.jsxs("span",{className:"font-[family-name:var(--font-mono)] font-bold text-[11px] px-2 py-0.5 bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] rounded-full",children:["#",e.seq]}),s&&d.jsx("span",{className:"nb-status",style:{background:"var(--color-running-bg)",color:"var(--color-running)"},children:"running"})]}),d.jsx("p",{className:`font-bold text-sm leading-5 mb-2 line-clamp-2 ${n?"line-through decoration-2":""}`,children:e.title}),(e.skills.length>0||e.labels.length>0)&&d.jsxs("div",{className:"flex flex-wrap gap-1 mb-2",children:[e.skills.slice(0,3).map(o=>d.jsx(fS,{name:o},o)),e.labels.filter(o=>o==="NEEDS-FIX").map(o=>d.jsx(dS,{label:o,kind:"warn"},o))]}),e.checklist&&e.checklist.total>0&&d.jsx(OR,{stats:e.checklist}),d.jsxs("div",{className:"pt-2 border-t-[1.5px] border-dashed border-[var(--color-border-light)] flex items-center gap-2 text-[11px] font-[family-name:var(--font-mono)] text-[var(--color-text-subtle)]",children:[d.jsx("span",{children:RR(e.updatedAt??e.createdAt)}),e.branch&&d.jsxs("span",{className:"truncate",children:["· ",e.branch]})]})]})}function OR({stats:e}){return d.jsxs("div",{className:"mb-2",children:[d.jsxs("div",{className:"flex items-center justify-between text-[11px] font-[family-name:var(--font-mono)] mb-1",children:[d.jsxs("span",{className:"font-bold",children:["检查清单 ",e.done,"/",e.total]}),d.jsxs("span",{className:"text-[var(--color-text-subtle)]",children:[e.percent,"%"]})]}),d.jsx("div",{className:"w-full h-1.5 bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] rounded-full overflow-hidden mb-1.5",children:d.jsx("div",{className:"h-full bg-[var(--color-cta)] transition-[width] duration-200",style:{width:`${e.percent}%`}})}),d.jsxs("ul",{className:"text-[11px] space-y-0.5",children:[e.items.slice(0,3).map((t,n)=>d.jsxs("li",{className:`flex items-start gap-1 ${t.done?"opacity-60 line-through":""}`,children:[d.jsx("span",{className:"flex-shrink-0 mt-0.5",children:t.done?"✓":"○"}),d.jsx("span",{className:"line-clamp-1",children:t.text})]},n)),e.items.length>3&&d.jsxs("li",{className:"text-[var(--color-text-subtle)] italic pl-3",children:["… 还有 ",e.items.length-3," 条"]})]})]})}function RR(e){if(!e)return"—";const t=new Date(e),n=Date.now()-t.getTime();return n<6e4?"刚才":n<36e5?`${Math.floor(n/6e4)}m ago`:n<864e5?`${Math.floor(n/36e5)}h ago`:t.toLocaleDateString()}function MR({label:e,bg:t,cards:n,onCardClick:a,onDropCard:s}){const[o,c]=O.useState(!1);return d.jsxs("div",{className:["flex flex-col p-3 rounded-2xl border-[3px] min-h-[280px] h-full min-h-0 overflow-hidden","transition-all",o?"border-[var(--color-cta)] shadow-[4px_4px_0_var(--color-cta)]":"border-[var(--color-text)]"].join(" "),style:{background:t},onDragOver:f=>{!s||!f.dataTransfer.types.includes("application/x-sps-card-seq")||(f.preventDefault(),f.dataTransfer.dropEffect="move",o||c(!0))},onDragLeave:()=>c(!1),onDrop:f=>{if(c(!1),!s)return;const h=f.dataTransfer.getData("application/x-sps-card-seq"),m=Number.parseInt(h,10);Number.isFinite(m)&&(f.preventDefault(),s(m))},children:[d.jsxs("div",{className:"flex items-center justify-between px-1 pb-2 mb-2 border-b-2 border-[var(--color-text)] shrink-0",children:[d.jsx("span",{className:"font-[family-name:var(--font-heading)] font-bold text-sm uppercase tracking-wider",children:e}),d.jsx("span",{className:"font-[family-name:var(--font-mono)] font-bold text-xs px-2 py-0.5 bg-[var(--color-bg)] border-2 border-[var(--color-text)] rounded-full",children:n.length})]}),d.jsxs("div",{className:"flex flex-col gap-2 flex-1 min-h-0 overflow-y-auto pr-1 -mr-1",style:{scrollbarWidth:"thin",scrollbarColor:"var(--color-text) transparent"},children:[n.length===0&&d.jsx("div",{className:"text-xs text-[var(--color-text-muted)] text-center py-6 italic",children:"— 空 —"}),n.map(f=>d.jsx(AR,{card:f,onClick:()=>a(f),done:e==="Done",draggable:!!s},f.seq))]})]})}function vp(e,t){if(!e)return"";const n=e.split(`
|
|
505
|
+
`)}`:"项目已删除。"}).then(()=>n("/projects"))},onError:b=>{s({title:"删除失败",body:b instanceof Error?b.message:String(b)})}});return d.jsxs("div",{className:"nb-card bg-[var(--color-crashed-bg)]",children:[d.jsx("h2",{className:"font-[family-name:var(--font-heading)] text-lg font-bold mb-2 text-[var(--color-crashed)]",children:"删除项目"}),d.jsxs("p",{className:"text-sm mb-4",children:["这会清理 ",d.jsxs("code",{className:"font-[family-name:var(--font-mono)] bg-[var(--color-bg)] border-2 border-[var(--color-text)] px-1.5 py-0.5 rounded",children:["~/.coral/projects/",e,"/"]}),"(包括所有卡片、runtime、logs)。"]}),t&&d.jsxs("label",{className:"flex items-start gap-2 mb-4 p-3 bg-[var(--color-bg)] border-2 border-[var(--color-text)] rounded-lg cursor-pointer",children:[d.jsx("input",{type:"checkbox",checked:f,onChange:b=>h(b.target.checked),className:"mt-0.5"}),d.jsxs("div",{className:"flex-1",children:[d.jsx("div",{className:"text-sm font-bold",children:"同时清理 repo 的 .claude/"}),d.jsxs("div",{className:"text-xs text-[var(--color-text-muted)] font-[family-name:var(--font-mono)]",children:[t,"/.claude/"]}),d.jsx("div",{className:"text-xs text-[var(--color-text-muted)] mt-1",children:"repo 本身不动,只清这个目录。"})]})]}),d.jsx("div",{className:"mb-4",children:d.jsxs("label",{className:"flex flex-col gap-1.5",children:[d.jsxs("span",{className:"text-sm font-bold",children:["输入项目名 ",d.jsx("code",{className:"font-[family-name:var(--font-mono)] text-xs",children:e})," 确认:"]}),d.jsx("input",{type:"text",className:"nb-input w-full font-[family-name:var(--font-mono)]",value:o,onChange:b=>c(b.target.value),placeholder:e})]})}),d.jsxs("button",{type:"button",className:"nb-btn nb-btn-danger",disabled:o!==e||m.isPending,onClick:()=>m.mutate(),"aria-label":"永久删除项目",children:[m.isPending?d.jsx(Lt,{size:14,strokeWidth:3,className:"animate-spin"}):d.jsx(zl,{size:14,strokeWidth:3}),"永久删除"]})]})}function hg(e){const t=e?`?project=${encodeURIComponent(e)}`:"";return Ft(`/api/skills${t}`)}function iR(e){return Ft(`/api/skills/${encodeURIComponent(e)}`)}function aR(e,t){return Ft(`/api/skills/${encodeURIComponent(e)}/references/${encodeURIComponent(t)}`)}async function Jf(e,t){const n=await fetch(e,{method:"POST",headers:t?{"Content-Type":"application/json"}:void 0,body:t?JSON.stringify(t):void 0});if(!n.ok)throw new Error(`${n.status}: ${await n.text()}`);return n.json().catch(()=>({}))}function rR(e,t){return Jf(`/api/skills/${encodeURIComponent(e)}/link`,{project:t})}function sR(e,t){return fetch(`/api/skills/${encodeURIComponent(e)}/link?project=${encodeURIComponent(t)}`,{method:"DELETE"}).then(n=>{if(!n.ok)throw new Error(`${n.status}`);return n.json()})}function lR(e,t){return Jf(`/api/skills/${encodeURIComponent(e)}/freeze`,{project:t})}function oR(e,t){return Jf(`/api/skills/${encodeURIComponent(e)}/unfreeze`,{project:t})}function cR(){return Jf("/api/skills/sync")}function uR({project:e,isPending:t,onCancel:n,onCreate:a}){var A;const[s,o]=O.useState(""),[c,f]=O.useState(""),[h,m]=O.useState(new Set),[b,g]=O.useState(!1),x=ot({queryKey:["skills-all",e],queryFn:()=>hg(e)});O.useEffect(()=>{const T=j=>{j.key==="Escape"&&n()};return window.addEventListener("keydown",T),()=>window.removeEventListener("keydown",T)},[n]);const E=s.trim().length>0&&s.trim().length<=200&&!t,w=T=>{const j=new Set(h);j.has(T)?j.delete(T):j.add(T),m(j)},k=()=>{E&&a({title:s.trim(),description:c.trim(),skills:[...h],labels:["AI-PIPELINE"],initialState:b?"Backlog":"Planning"})},_=((A=x.data)==null?void 0:A.data)??[];return d.jsx("div",{role:"dialog","aria-modal":"true",className:"fixed inset-0 z-40 flex items-start justify-center p-6 bg-black/30 overflow-auto",children:d.jsxs("div",{className:"nb-card mt-8 w-full max-w-xl flex flex-col",style:{maxHeight:"calc(100vh - 64px)"},children:[d.jsxs("header",{className:"flex items-center justify-between mb-4 flex-shrink-0",children:[d.jsx("h2",{className:"font-[family-name:var(--font-heading)] text-2xl font-bold",children:"新建卡片"}),d.jsx("button",{className:"nb-btn nb-btn-mint p-2",onClick:n,type:"button","aria-label":"关闭",children:d.jsx(wi,{size:14,strokeWidth:3})})]}),d.jsxs("form",{onSubmit:T=>{T.preventDefault(),k()},className:"flex flex-col gap-4 overflow-auto",children:[d.jsxs("label",{className:"flex flex-col gap-1.5",children:[d.jsx("span",{className:"text-sm font-bold",children:"标题 *"}),d.jsx("input",{type:"text",className:"nb-input w-full",placeholder:"例如:接入 GitHub OAuth 登录",value:s,onChange:T=>o(T.target.value),maxLength:200,autoFocus:!0,required:!0}),d.jsx("span",{className:"text-xs text-[var(--color-text-muted)]",children:"写简短明了的目标(<200 字符)"})]}),d.jsxs("label",{className:"flex flex-col gap-1.5",children:[d.jsx("span",{className:"text-sm font-bold",children:"描述"}),d.jsx("textarea",{className:"nb-input w-full",style:{minHeight:120,resize:"vertical"},placeholder:"用户故事、需求、验收标准、参考资料… Claude 启动时会读这里的内容",value:c,onChange:T=>f(T.target.value)}),d.jsx("span",{className:"text-xs text-[var(--color-text-muted)]",children:"支持 markdown。空的话就只有 title,Claude 只能靠 title 推断要做啥。"})]}),d.jsxs("div",{className:"flex flex-col gap-2",children:[d.jsx("span",{className:"text-sm font-bold",children:"Skills"}),d.jsx("span",{className:"text-xs text-[var(--color-text-muted)]",children:"勾选哪些 skill 会被加载(走 frontmatter `skills:`)。不选也行,Worker 默认加载项目级 skills。"}),x.isLoading&&d.jsx("p",{className:"text-xs text-[var(--color-text-muted)] italic",children:"加载 skill 列表…"}),x.isError&&d.jsxs("p",{className:"text-xs text-[var(--color-crashed)]",children:["skill 列表加载失败,不影响创建:",x.error instanceof Error?x.error.message:String(x.error)]}),_.length>0&&d.jsx("div",{className:"flex flex-wrap gap-2",children:_.map(T=>{const j=h.has(T.name);return d.jsx("button",{type:"button",onClick:()=>w(T.name),className:["px-2.5 py-1 text-xs font-[family-name:var(--font-mono)] rounded-full border-2 transition-all",j?"bg-[var(--color-accent-mint)] border-[var(--color-text)] shadow-[2px_2px_0_var(--color-text)] font-bold":"bg-[var(--color-bg)] border-[var(--color-border-light)] hover:border-[var(--color-text)]"].join(" "),"aria-pressed":j,children:T.name},T.name)})}),h.size>0&&d.jsxs("p",{className:"text-xs text-[var(--color-text-muted)]",children:["已选 ",h.size," 个:",[...h].join(", ")]})]}),d.jsxs("div",{className:"flex flex-col gap-2",children:[d.jsx("span",{className:"text-sm font-bold",children:"派发"}),d.jsxs("label",{className:"flex items-center gap-3 cursor-pointer select-none p-3 border-[2px] border-[var(--color-text)] rounded-lg bg-[var(--color-bg-cream)]",children:[d.jsx("input",{type:"checkbox",className:"w-4 h-4 accent-[var(--color-cta)] cursor-pointer",checked:b,onChange:T=>g(T.target.checked)}),d.jsxs("div",{className:"flex-1",children:[d.jsx("div",{className:"text-sm font-bold",children:"立即派发执行(直接进 Backlog)"}),d.jsxs("div",{className:"text-xs text-[var(--color-text-muted)] mt-0.5",children:["默认不勾:卡进 ",d.jsx("code",{className:"font-mono",children:"Planning"})," 暂存,等你看板上拖到 ",d.jsx("code",{className:"font-mono",children:"Backlog"})," 再开工。 勾上:跳过暂存,下次 tick 直接派 worker 跑。"]})]})]})]})]}),d.jsxs("div",{className:"flex gap-2 justify-end mt-4 pt-3 border-t-2 border-dashed border-[var(--color-text)] flex-shrink-0",children:[d.jsx("button",{className:"nb-btn",style:{padding:"6px 14px"},onClick:n,disabled:t,type:"button",children:"取消"}),d.jsxs("button",{className:"nb-btn nb-btn-primary",style:{padding:"6px 14px"},onClick:k,disabled:!E,type:"button","aria-label":"创建卡片",children:[t?d.jsx(Lt,{size:13,strokeWidth:3,className:"animate-spin"}):d.jsx(zi,{size:13,strokeWidth:3}),"创建"]})]})]})})}function fR(e){return Ft(`/api/projects/${encodeURIComponent(e)}/cards`)}function dR(e,t){return Ft(`/api/projects/${encodeURIComponent(e)}/cards/${t}`)}async function ql(e,t){const n=await fetch(e,{method:"POST",headers:t?{"Content-Type":"application/json"}:void 0,body:t?JSON.stringify(t):void 0});if(!n.ok){const a=await n.text();throw new Error(`${n.status} ${n.statusText}: ${a}`)}return n.json().catch(()=>({}))}function hR(e,t){return ql(`/api/projects/${encodeURIComponent(e)}/cards/${t}/reset`)}async function mR(e,t){const n=await fetch(`/api/projects/${encodeURIComponent(e)}/cards/${t}`,{method:"DELETE"});if(!n.ok){const a=await n.text();throw new Error(`${n.status}: ${a}`)}}function pR(e,t){return ql(`/api/projects/${encodeURIComponent(e)}/cards/${t}/launch`)}function gR(e,t){const n=typeof t=="string"?{title:t}:t;return ql(`/api/projects/${encodeURIComponent(e)}/cards`,n)}async function bR(e,t,n){const a=await fetch(`/api/projects/${encodeURIComponent(e)}/cards/${t}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({state:n})});if(!a.ok){const s=await a.text();throw new Error(`${a.status}: ${s}`)}}async function yR(e,t,n){const a=await fetch(`/api/projects/${encodeURIComponent(e)}/cards/${t}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)});if(!a.ok){const s=await a.text();throw new Error(`${a.status}: ${s}`)}return a.json()}function xR(e){return ql(`/api/projects/${encodeURIComponent(e)}/pipeline/start`)}function vR(e){return ql(`/api/projects/${encodeURIComponent(e)}/pipeline/stop`)}function ER(e,t){return ql(`/api/projects/${encodeURIComponent(e)}/pipeline/reset`,t??{})}function SR(e){const t=qn();O.useEffect(()=>{if(!e)return;const n=`/stream/projects/${encodeURIComponent(e)}`,a=new EventSource(n),s=f=>{try{const h=JSON.parse(f.data);t.invalidateQueries({queryKey:["cards",h.project]}),t.invalidateQueries({queryKey:["card",h.project,h.seq]}),t.invalidateQueries({queryKey:["projects"]})}catch{}},o=f=>{try{const h=JSON.parse(f.data);t.invalidateQueries({queryKey:["workers",h.project]}),t.invalidateQueries({queryKey:["projects"]})}catch{}},c=f=>{try{const h=JSON.parse(f.data);t.invalidateQueries({queryKey:["pipeline-status",h.project]}),t.invalidateQueries({queryKey:["projects"]})}catch{}};return a.addEventListener("card.created",s),a.addEventListener("card.updated",s),a.addEventListener("card.moved",s),a.addEventListener("card.deleted",s),a.addEventListener("worker.updated",o),a.addEventListener("worker.added",o),a.addEventListener("worker.deleted",o),a.addEventListener("pipeline.status",c),a.addEventListener("pipeline.started",c),a.addEventListener("pipeline.stopped",c),()=>a.close()},[e,t])}const wR=new Set(["python","typescript","golang","rust","kotlin","swift","java"]),_R=new Set(["frontend","backend","mobile","database","devops"]),kR=new Set(["backend-architect","frontend-developer","code-reviewer","database-optimizer","devops-automator","security-engineer","qa-tester","security","qa","architect","db-opt"]),NR=new Set(["coding-standards","tdd-workflow","git-workflow","architecture-decision-records","debugging-workflow"]);function TR(e){return wR.has(e)?"lang":_R.has(e)?"end":kR.has(e)?"persona":NR.has(e)?"workflow":"other"}const CR={lang:"var(--color-accent-purple)",end:"var(--color-secondary)",persona:"var(--color-primary)",workflow:"var(--color-accent-mint)",other:"var(--color-bg)"};function fS({name:e}){const t=CR[TR(e)];return d.jsx("span",{className:"nb-badge",style:{background:t},children:e})}function dS({label:e,kind:t="default"}){const n=t==="warn"?"var(--color-accent-pink)":t==="accent"?"var(--color-accent-yellow)":"var(--color-bg-cream)";return d.jsx("span",{className:"nb-badge",style:{background:n},children:e})}function AR({card:e,onClick:t,done:n,draggable:a}){const s=e.labels.some(o=>o.startsWith("STARTED-"))&&!n;return d.jsxs("article",{onClick:t,onKeyDown:o=>{(o.key==="Enter"||o.key===" ")&&(o.preventDefault(),t())},draggable:a,onDragStart:o=>{o.dataTransfer.setData("application/x-sps-card-seq",String(e.seq)),o.dataTransfer.effectAllowed="move"},tabIndex:0,role:"button","aria-label":`Card #${e.seq}: ${e.title}`,className:["bg-[var(--color-bg)] border-[3px] border-[var(--color-text)] rounded-xl p-3","shadow-[3px_3px_0_var(--color-text)] cursor-pointer","transition-[transform,box-shadow] duration-[180ms] ease-out","hover:-translate-x-0.5 hover:-translate-y-0.5 hover:shadow-[5px_5px_0_var(--color-text)]","focus:outline-none focus-visible:ring-[3px] focus-visible:ring-offset-2 focus-visible:ring-[var(--color-text)]",n?"opacity-60":"",a?"active:cursor-grabbing":""].join(" "),children:[d.jsxs("div",{className:"flex items-center justify-between gap-2 mb-2",children:[d.jsxs("span",{className:"font-[family-name:var(--font-mono)] font-bold text-[11px] px-2 py-0.5 bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] rounded-full",children:["#",e.seq]}),s&&d.jsx("span",{className:"nb-status",style:{background:"var(--color-running-bg)",color:"var(--color-running)"},children:"running"})]}),d.jsx("p",{className:`font-bold text-sm leading-5 mb-2 line-clamp-2 ${n?"line-through decoration-2":""}`,children:e.title}),(e.skills.length>0||e.labels.length>0)&&d.jsxs("div",{className:"flex flex-wrap gap-1 mb-2",children:[e.skills.slice(0,3).map(o=>d.jsx(fS,{name:o},o)),e.labels.filter(o=>o==="NEEDS-FIX").map(o=>d.jsx(dS,{label:o,kind:"warn"},o))]}),e.checklist&&e.checklist.total>0&&d.jsx(OR,{stats:e.checklist}),d.jsxs("div",{className:"pt-2 border-t-[1.5px] border-dashed border-[var(--color-border-light)] flex items-center gap-2 text-[11px] font-[family-name:var(--font-mono)] text-[var(--color-text-subtle)]",children:[d.jsx("span",{children:RR(e.updatedAt??e.createdAt)}),e.branch&&d.jsxs("span",{className:"truncate",children:["· ",e.branch]})]})]})}function OR({stats:e}){return d.jsxs("div",{className:"mb-2",children:[d.jsxs("div",{className:"flex items-center justify-between text-[11px] font-[family-name:var(--font-mono)] mb-1",children:[d.jsxs("span",{className:"font-bold",children:["检查清单 ",e.done,"/",e.total]}),d.jsxs("span",{className:"text-[var(--color-text-subtle)]",children:[e.percent,"%"]})]}),d.jsx("div",{className:"w-full h-1.5 bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] rounded-full overflow-hidden mb-1.5",children:d.jsx("div",{className:"h-full bg-[var(--color-cta)] transition-[width] duration-200",style:{width:`${e.percent}%`}})}),d.jsxs("ul",{className:"text-[11px] space-y-0.5",children:[e.items.slice(0,3).map((t,n)=>d.jsxs("li",{className:`flex items-start gap-1 ${t.done?"opacity-60 line-through":""}`,children:[d.jsx("span",{className:"flex-shrink-0 mt-0.5",children:t.done?"✓":"○"}),d.jsx("span",{className:"line-clamp-1",children:t.text})]},n)),e.items.length>3&&d.jsxs("li",{className:"text-[var(--color-text-subtle)] italic pl-3",children:["… 还有 ",e.items.length-3," 条"]})]})]})}function RR(e){if(!e)return"—";const t=new Date(e),n=Date.now()-t.getTime();return n<6e4?"刚才":n<36e5?`${Math.floor(n/6e4)}m ago`:n<864e5?`${Math.floor(n/36e5)}h ago`:t.toLocaleDateString()}function MR({label:e,bg:t,cards:n,onCardClick:a,onDropCard:s}){const[o,c]=O.useState(!1);return d.jsxs("div",{className:["flex flex-col p-3 rounded-2xl border-[3px] min-h-[280px] h-full min-h-0 overflow-hidden","transition-all",o?"border-[var(--color-cta)] shadow-[4px_4px_0_var(--color-cta)]":"border-[var(--color-text)]"].join(" "),style:{background:t},onDragOver:f=>{!s||!f.dataTransfer.types.includes("application/x-sps-card-seq")||(f.preventDefault(),f.dataTransfer.dropEffect="move",o||c(!0))},onDragLeave:()=>c(!1),onDrop:f=>{if(c(!1),!s)return;const h=f.dataTransfer.getData("application/x-sps-card-seq"),m=Number.parseInt(h,10);Number.isFinite(m)&&(f.preventDefault(),s(m))},children:[d.jsxs("div",{className:"flex items-center justify-between px-1 pb-2 mb-2 border-b-2 border-[var(--color-text)] shrink-0",children:[d.jsx("span",{className:"font-[family-name:var(--font-heading)] font-bold text-sm uppercase tracking-wider",children:e}),d.jsx("span",{className:"font-[family-name:var(--font-mono)] font-bold text-xs px-2 py-0.5 bg-[var(--color-bg)] border-2 border-[var(--color-text)] rounded-full",children:n.length})]}),d.jsxs("div",{className:"flex flex-col gap-2 flex-1 min-h-0 overflow-y-auto pr-1 -mr-1",style:{scrollbarWidth:"thin",scrollbarColor:"var(--color-text) transparent"},children:[n.length===0&&d.jsx("div",{className:"text-xs text-[var(--color-text-muted)] text-center py-6 italic",children:"— 空 —"}),n.map(f=>d.jsx(AR,{card:f,onClick:()=>a(f),done:e==="Done",draggable:!!s},f.seq))]})]})}function vp(e,t){if(!e)return"";const n=e.split(`
|
|
506
506
|
`),a=new RegExp(`^##\\s+${t}\\s*$`),s=n.findIndex(c=>a.test(c));if(s===-1)return"";let o=n.length;for(let c=s+1;c<n.length;c++)if(/^##\s+/.test(n[c]??"")){o=c;break}return n.slice(s+1,o).join(`
|
|
507
507
|
`).trim()}function km(e){return vp(e,"描述")}function jR({project:e,seq:t,onClose:n,onChanged:a}){var q,ce,V,be,R,D,X,C,G,de,re;const s=qn(),{confirm:o,alert:c}=li(),{data:f,isLoading:h,isError:m,error:b,refetch:g}=ot({queryKey:["card",e,t],queryFn:()=>dR(e,t)}),[x,v]=O.useState(!1),[E,w]=O.useState(""),[k,_]=O.useState(""),[A,T]=O.useState(new Set),[j,$]=O.useState([]),[M,F]=O.useState(""),H=ot({queryKey:["skills-all",e],queryFn:()=>hg(e),enabled:x}),L=((ce=(q=ot({queryKey:["projects"],queryFn:_r,refetchInterval:1e4}).data)==null?void 0:q.data.find(K=>K.name===e))==null?void 0:ce.pipelineStatus)==="running";O.useEffect(()=>{x&&f&&(w(f.title),_(km(f.body)),T(new Set(f.skills)),$([...f.labels]))},[x,f]),O.useEffect(()=>{const K=ue=>{ue.key==="Escape"&&(x?v(!1):n())};return window.addEventListener("keydown",K),()=>window.removeEventListener("keydown",K)},[n,x]);const J=Pn({mutationFn:()=>{if(!f)throw new Error("no data");const K={},ue=E.trim();ue&&ue!==f.title&&(K.title=ue);const Se=km(f.body);k!==Se&&(K.description=k);const Ze=[...A].sort(),it=[...f.skills].sort();return JSON.stringify(Ze)!==JSON.stringify(it)&&(K.skills=Ze),JSON.stringify(j)!==JSON.stringify(f.labels)&&(K.labels=j),Object.keys(K).length===0?Promise.resolve({ok:!0,noop:!0}):yR(e,t,K)},onSuccess:()=>{s.invalidateQueries({queryKey:["card",e,t]}),s.invalidateQueries({queryKey:["cards",e]}),v(!1),a()},onError:K=>{c({title:"保存失败",body:K instanceof Error?K.message:String(K)})}}),ae=O.useMemo(()=>{if(!x||!f)return!1;if(E.trim()!==f.title||k!==km(f.body))return!0;const K=[...A].sort(),ue=[...f.skills].sort();return JSON.stringify(K)!==JSON.stringify(ue)||JSON.stringify(j)!==JSON.stringify(f.labels)},[x,f,E,k,A,j]),ge=K=>{const ue=new Set(A);ue.has(K)?ue.delete(K):ue.add(K),T(ue)},fe=()=>{const K=M.trim();if(K){if(j.includes(K)){F("");return}$([...j,K]),F("")}},te=K=>{$(j.filter(ue=>ue!==K))};return d.jsx("div",{role:"dialog","aria-modal":"true","aria-labelledby":"card-modal-title",className:"fixed inset-0 z-40 flex items-start justify-center p-6 bg-black/30 overflow-auto",children:d.jsxs("div",{className:"nb-card mt-12 w-full max-w-3xl bg-[var(--color-bg)]",children:[d.jsxs("header",{className:"flex items-start justify-between gap-4 mb-4",children:[d.jsxs("div",{className:"flex-1 min-w-0",children:[d.jsxs("div",{className:"flex items-center gap-3 mb-1",children:[d.jsxs("span",{className:"font-[family-name:var(--font-mono)] font-bold text-xs px-2 py-0.5 bg-[var(--color-accent-purple)] border-2 border-[var(--color-text)] rounded-full",children:["#",t]}),(f==null?void 0:f.state)&&d.jsx("span",{className:"font-[family-name:var(--font-mono)] text-xs px-2 py-0.5 bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] rounded-full font-semibold",children:f.state}),x&&d.jsx("span",{className:"text-xs font-bold text-[var(--color-stuck)]",children:"⚠ 编辑中"})]}),x?d.jsx("input",{type:"text",className:"nb-input w-full font-[family-name:var(--font-heading)] text-xl font-bold",value:E,onChange:K=>w(K.target.value),maxLength:200,"aria-label":"卡片标题"}):d.jsx("h2",{id:"card-modal-title",className:"font-[family-name:var(--font-heading)] text-2xl font-bold break-words",children:(f==null?void 0:f.title)??"加载中…"})]}),d.jsxs("div",{className:"flex gap-2 flex-shrink-0",children:[!x&&f&&d.jsxs("button",{onClick:()=>v(!0),className:"nb-btn",style:{padding:"6px 12px"},type:"button","aria-label":"编辑卡片",children:[d.jsx(Vp,{size:12,strokeWidth:2.5})," 编辑"]}),d.jsx("button",{onClick:n,className:"nb-btn nb-btn-mint p-2","aria-label":"关闭",type:"button",children:d.jsx(wi,{size:14,strokeWidth:3})})]})]}),h&&d.jsx("p",{className:"text-[var(--color-text-muted)]",children:"加载中…"}),m&&d.jsxs("p",{className:"text-[var(--color-crashed)]",children:["加载失败: ",b instanceof Error?b.message:String(b)]}),f&&d.jsxs("div",{className:"flex flex-col gap-4",children:[f.branch&&!x&&d.jsxs("div",{className:"flex items-center gap-2 text-sm",children:[d.jsx(rC,{size:14}),d.jsx("span",{className:"font-[family-name:var(--font-mono)]",children:f.branch})]}),x?d.jsxs(d.Fragment,{children:[d.jsxs("div",{children:[d.jsx("div",{className:"text-sm font-bold mb-1.5",children:"Skills"}),H.isLoading&&d.jsx("p",{className:"text-xs text-[var(--color-text-muted)] italic",children:"加载 skill 列表…"}),H.data&&H.data.data.length>0&&d.jsx("div",{className:"flex flex-wrap gap-1.5",children:H.data.data.map(K=>{const ue=A.has(K.name);return d.jsx("button",{type:"button",onClick:()=>ge(K.name),"aria-pressed":ue,className:["px-2.5 py-1 text-xs font-[family-name:var(--font-mono)] rounded-full border-2 transition-all",ue?"bg-[var(--color-accent-mint)] border-[var(--color-text)] shadow-[2px_2px_0_var(--color-text)] font-bold":"bg-[var(--color-bg)] border-[var(--color-border-light)] hover:border-[var(--color-text)]"].join(" "),children:K.name},K.name)})})]}),d.jsxs("div",{children:[d.jsx("div",{className:"text-sm font-bold mb-1.5",children:"Labels"}),d.jsxs("div",{className:"flex flex-wrap gap-1.5 items-center",children:[j.map(K=>d.jsxs("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 text-xs font-[family-name:var(--font-mono)] bg-[var(--color-accent-yellow)] border-2 border-[var(--color-text)] rounded-full",children:[K,d.jsx("button",{type:"button",onClick:()=>te(K),className:"hover:text-[var(--color-crashed)]","aria-label":`删除 ${K}`,children:d.jsx(wi,{size:10,strokeWidth:3})})]},K)),d.jsx("input",{type:"text",className:"nb-input",style:{padding:"4px 8px",fontSize:12,width:140},placeholder:"+ 添加 label",value:M,onChange:K=>F(K.target.value),onKeyDown:K=>{K.key==="Enter"&&!K.nativeEvent.isComposing&&(K.preventDefault(),fe())}}),M&&d.jsx("button",{type:"button",className:"nb-btn",style:{padding:"2px 6px",fontSize:11},onClick:fe,"aria-label":"添加 label",children:d.jsx(zi,{size:10,strokeWidth:3})})]}),d.jsx("p",{className:"text-[10px] text-[var(--color-text-muted)] mt-1",children:"注意:AI-PIPELINE / STARTED-* / COMPLETED-* / NEEDS-FIX 由流水线自动管理,手动改可能被覆盖"})]})]}):d.jsxs(d.Fragment,{children:[f.skills.length>0&&d.jsxs("div",{children:[d.jsx("div",{className:"text-sm font-bold mb-1.5",children:"Skills"}),d.jsx("div",{className:"flex items-center gap-2 flex-wrap",children:f.skills.map(K=>d.jsx(fS,{name:K},K))})]}),f.labels.length>0&&d.jsxs("div",{children:[d.jsx("div",{className:"text-sm font-bold mb-1.5",children:"Labels"}),d.jsx("div",{className:"flex items-center gap-2 flex-wrap",children:f.labels.map(K=>d.jsx(dS,{label:K,kind:K==="NEEDS-FIX"?"warn":"default"},K))})]})]}),x?d.jsxs(d.Fragment,{children:[d.jsxs("div",{children:[d.jsx("h3",{className:"font-[family-name:var(--font-heading)] text-sm font-bold mb-2 uppercase tracking-wider",children:"描述"}),d.jsx("textarea",{className:"nb-input w-full font-[family-name:var(--font-mono)] text-xs",style:{minHeight:180,resize:"vertical"},value:k,onChange:K=>_(K.target.value),"aria-label":"卡片描述"}),d.jsx("p",{className:"text-[10px] text-[var(--color-text-muted)] mt-1",children:'只替换 "## 描述" 段的内容;检查清单和日志段不动。'})]}),(((C=f.checklist)==null?void 0:C.total)??0)>0&&d.jsxs("div",{className:"nb-card bg-[var(--color-bg-cream)] p-3",children:[d.jsx("div",{className:"flex items-center justify-between mb-2",children:d.jsxs("span",{className:"font-bold text-sm",children:["检查清单 ",((G=f.checklist)==null?void 0:G.done)??0,"/",((de=f.checklist)==null?void 0:de.total)??0]})}),d.jsx("ul",{className:"text-sm space-y-1",children:(((re=f.checklist)==null?void 0:re.items)??[]).map((K,ue)=>d.jsxs("li",{className:`flex items-start gap-2 ${K.done?"opacity-60 line-through":""}`,children:[d.jsx("span",{children:K.done?"✓":"○"}),d.jsx("span",{children:K.text})]},ue))})]})]}):d.jsxs(d.Fragment,{children:[d.jsxs("div",{children:[d.jsx("h3",{className:"font-[family-name:var(--font-heading)] text-sm font-bold mb-2 uppercase tracking-wider",children:"描述"}),d.jsx("pre",{className:"text-xs whitespace-pre-wrap font-[family-name:var(--font-mono)] bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] rounded-lg p-4 max-h-64 overflow-auto",children:vp(f.body,"描述")||"(空)"})]}),d.jsxs("div",{children:[d.jsxs("h3",{className:"font-[family-name:var(--font-heading)] text-sm font-bold mb-2 uppercase tracking-wider",children:["检查清单 ",d.jsxs("span",{className:"text-[var(--color-text-muted)] normal-case tracking-normal",children:[((V=f.checklist)==null?void 0:V.done)??0,"/",((be=f.checklist)==null?void 0:be.total)??0]})]}),d.jsx("div",{className:"nb-card bg-[var(--color-bg-cream)] p-3",children:(((R=f.checklist)==null?void 0:R.total)??0)>0?d.jsxs(d.Fragment,{children:[d.jsx("div",{className:"flex items-center justify-end mb-2",children:d.jsx("div",{className:"w-24 h-2 bg-[var(--color-bg)] border-2 border-[var(--color-text)] rounded-full overflow-hidden",children:d.jsx("div",{className:"h-full bg-[var(--color-cta)]",style:{width:`${((D=f.checklist)==null?void 0:D.percent)??0}%`}})})}),d.jsx("ul",{className:"text-sm space-y-1",children:(((X=f.checklist)==null?void 0:X.items)??[]).map((K,ue)=>d.jsxs("li",{className:`flex items-start gap-2 ${K.done?"opacity-60 line-through":""}`,children:[d.jsx("span",{children:K.done?"✓":"○"}),d.jsx("span",{children:K.text})]},ue))})]}):d.jsxs("p",{className:"text-xs text-[var(--color-text-muted)] italic",children:["暂无清单项。在描述里用 ",d.jsx("code",{className:"font-[family-name:var(--font-mono)]",children:"- [ ] 项"})," 语法添加。"]})})]}),d.jsxs("div",{children:[d.jsx("h3",{className:"font-[family-name:var(--font-heading)] text-sm font-bold mb-2 uppercase tracking-wider",children:"日志"}),d.jsx("pre",{className:"text-xs whitespace-pre-wrap font-[family-name:var(--font-mono)] bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] rounded-lg p-4 max-h-64 overflow-auto",children:vp(f.body,"日志")||"(空)"})]})]}),d.jsx("div",{className:"flex gap-2 pt-2 border-t-2 border-[var(--color-border-light)] justify-end flex-wrap",children:x?d.jsxs(d.Fragment,{children:[d.jsx("button",{className:"nb-btn",type:"button",onClick:()=>{v(!1),g()},disabled:J.isPending,children:"取消"}),d.jsxs("button",{className:"nb-btn nb-btn-primary",type:"button",onClick:()=>J.mutate(),disabled:!ae||!E.trim()||J.isPending,"aria-label":"保存卡片修改",children:[J.isPending?d.jsx(Lt,{size:14,strokeWidth:3,className:"animate-spin"}):d.jsx(Uf,{size:14,strokeWidth:3}),"保存"]})]}):d.jsxs(d.Fragment,{children:[d.jsxs("button",{className:"nb-btn nb-btn-primary",type:"button",disabled:f.state==="Done"||L,title:f.state==="Done"?"卡片已完成;先拖回 Todo 再启动":L?"Pipeline 正在跑——supervisor 会自动 dispatch,无需手动启动":void 0,onClick:async()=>{try{await pR(e,t),a()}catch(K){c({title:"启动 worker 失败",body:K instanceof Error?K.message:String(K)})}},children:[d.jsx(Wp,{size:14,strokeWidth:3}),"启动 worker"]}),d.jsxs("button",{className:"nb-btn nb-btn-yellow",type:"button",onClick:async()=>{if(await o({title:`重置卡片 #${t}`,body:"卡片状态会回到初始,已做的 checklist 会清空。",confirm:"重置",danger:!0}))try{await hR(e,t),a(),n()}catch(ue){c({title:"重置失败",body:ue instanceof Error?ue.message:String(ue)})}},children:[d.jsx(rE,{size:14,strokeWidth:2.5}),"重置卡片"]}),d.jsxs("button",{className:"nb-btn",style:{background:"var(--color-crashed)",color:"var(--color-bg)"},type:"button",onClick:async()=>{if(!(!await o({title:`删除卡片 #${t}`,body:`即将删除 "${f.title}"。此操作不可恢复(md 文件将被物理删除)。是否继续?`,confirm:"继续",danger:!0})||!await o({title:"最终确认",body:`请再次确认删除卡片 #${t}。`,confirm:"确定删除",danger:!0})))try{await mR(e,t),a(),n()}catch(Se){c({title:"删除失败",body:Se instanceof Error?Se.message:String(Se)})}},"aria-label":"删除卡片",children:[d.jsx(zl,{size:14,strokeWidth:2.5}),"删除卡片"]})]})})]})]})})}function DR({current:e,onChange:t}){const[n,a]=O.useState(!1),s=O.useRef(null),{data:o}=ot({queryKey:["projects"],queryFn:_r});return O.useEffect(()=>{const c=f=>{var h;(h=s.current)!=null&&h.contains(f.target)||a(!1)};return document.addEventListener("mousedown",c),()=>document.removeEventListener("mousedown",c)},[]),d.jsxs("div",{className:"relative",ref:s,children:[d.jsxs("button",{type:"button",className:"inline-flex items-center gap-2 px-3 py-2 bg-[var(--color-bg)] border-[3px] border-[var(--color-text)] rounded-xl shadow-[3px_3px_0_var(--color-text)] font-[family-name:var(--font-mono)] text-sm font-bold hover:-translate-x-px hover:-translate-y-px hover:shadow-[4px_4px_0_var(--color-text)] transition-[transform,box-shadow] duration-150",onClick:()=>a(c=>!c),children:[e,d.jsx(vc,{size:14,strokeWidth:2.5})]}),n&&o&&d.jsx("div",{className:"absolute right-0 mt-2 z-20 min-w-[200px] bg-[var(--color-bg)] border-[3px] border-[var(--color-text)] rounded-xl shadow-[5px_5px_0_var(--color-text)] overflow-hidden",children:o.data.map(c=>d.jsxs("button",{type:"button",onClick:()=>{t(c.name),a(!1)},className:["w-full text-left px-4 py-2 text-sm font-semibold",c.name===e?"bg-[var(--color-accent-mint)]":"hover:bg-[var(--color-bg-cream)]"].join(" "),children:[d.jsx("span",{className:"font-[family-name:var(--font-mono)]",children:c.name}),d.jsxs("span",{className:"ml-2 text-xs text-[var(--color-text-muted)]",children:[c.cards.total," cards"]})]},c.name))})]})}const LR=[{state:"Planning",label:"Planning",bg:"var(--color-accent-purple)"},{state:"Backlog",label:"Backlog",bg:"var(--color-bg-cream)"},{state:"Todo",label:"Todo",bg:"var(--color-accent-yellow)"},{state:"Inprogress",label:"Inprogress",bg:"var(--color-secondary)"},{state:"QA",label:"QA / Review",bg:"var(--color-accent-pink)"},{state:"Done",label:"Done",bg:"var(--color-accent-mint)"}],hS="sps-console:last-board-project";function zR(){if(typeof window>"u")return null;try{return localStorage.getItem(hS)}catch{return null}}function IR(e){if(!(typeof window>"u"))try{localStorage.setItem(hS,e)}catch{}}function BR(){var te,q,ce;const[e,t]=J1(),n=e.get("project"),[a,s]=O.useState(null),[o,c]=O.useState(""),[f,h]=O.useState(()=>new Set),[m,b]=O.useState(()=>new Set),{confirm:g,alert:x}=li();SR(n);const v=ot({queryKey:["projects"],queryFn:_r}),E=ot({queryKey:["cards",n],queryFn:()=>fR(n??""),enabled:!!n}),w=qn(),k=()=>{w.invalidateQueries({queryKey:["cards",n]}),w.invalidateQueries({queryKey:["projects"]}),w.invalidateQueries({queryKey:["pipeline-status",n]})},_=V=>{t({project:V})};O.useEffect(()=>{var be;if(n){IR(n);return}const V=zR();V&&((be=v.data)!=null&&be.data.some(R=>R.name===V))&&t({project:V},{replace:!0})},[n,v.data,t]);const A=Pn({mutationFn:()=>xR(n),onSuccess:()=>{k()},onError:V=>{x({title:"启动 pipeline 失败",body:V instanceof Error?V.message:String(V)})}}),T=Pn({mutationFn:()=>vR(n),onSuccess:()=>k(),onError:V=>{x({title:"停止 pipeline 失败",body:V instanceof Error?V.message:String(V)})}}),j=Pn({mutationFn:()=>ER(n,{all:!0}),onSuccess:()=>k(),onError:V=>{x({title:"重置失败",body:V instanceof Error?V.message:String(V)})}}),[$,M]=O.useState(!1),F=Pn({mutationFn:V=>gR(n,V),onSuccess:()=>{k(),M(!1)},onError:V=>{x({title:"新建卡片失败",body:V instanceof Error?V.message:String(V)})}}),H=Pn({mutationFn:({seq:V,state:be})=>bR(n,V,be),onMutate:async({seq:V,state:be})=>{await w.cancelQueries({queryKey:["cards",n]});const R=w.getQueryData(["cards",n]);return R&&w.setQueryData(["cards",n],{...R,data:R.data.map(D=>D.seq===V?{...D,state:be}:D)}),{prev:R}},onError:(V,be,R)=>{R!=null&&R.prev&&w.setQueryData(["cards",n],R.prev),x({title:"移动卡片失败",body:V instanceof Error?V.message:String(V)})},onSettled:()=>{w.invalidateQueries({queryKey:["cards",n]})}}),ee=((te=E.data)==null?void 0:te.data)??[],{allSkills:L,allLabels:J}=O.useMemo(()=>{const V=new Set,be=new Set;for(const R of ee){for(const D of R.skills)V.add(D);for(const D of R.labels)be.add(D)}return{allSkills:[...V].sort(),allLabels:[...be].sort()}},[ee]);if(!n)return d.jsxs("div",{className:"flex flex-col gap-6 max-w-4xl",children:[d.jsx("h1",{className:"font-[family-name:var(--font-heading)] text-4xl font-bold",children:"看板"}),d.jsxs("div",{className:"nb-card bg-[var(--color-accent-yellow)] max-w-2xl",children:[d.jsx("h2",{className:"font-[family-name:var(--font-heading)] text-xl font-bold mb-3",children:"选择一个项目 🎯"}),d.jsx("p",{className:"text-sm mb-4 text-[var(--color-text-muted)]",children:"看板按项目分。挑一个开始:"}),d.jsx("div",{className:"flex flex-wrap gap-2",children:(q=v.data)==null?void 0:q.data.map(V=>d.jsx("button",{className:"nb-btn nb-btn-blue",onClick:()=>_(V.name),type:"button",children:V.name},V.name))})]})]});const ae=ee.filter(V=>{if(o){const be=o.toLowerCase();if(!(V.title.toLowerCase().includes(be)||V.skills.some(D=>D.toLowerCase().includes(be))||V.labels.some(D=>D.toLowerCase().includes(be))))return!1}return!(f.size>0&&!V.skills.some(R=>f.has(R))||m.size>0&&!V.labels.some(R=>m.has(R)))}),ge=(ce=v.data)==null?void 0:ce.data.find(V=>V.name===n),fe=(ge==null?void 0:ge.pipelineStatus)==="running";return d.jsxs("div",{className:"flex flex-col gap-4 max-w-full flex-1 min-h-0",children:[d.jsxs("header",{className:"flex items-center justify-between flex-wrap gap-3 shrink-0",children:[d.jsxs("div",{children:[d.jsx("h1",{className:"font-[family-name:var(--font-heading)] text-4xl font-bold tracking-tight",children:"看板 ✨"}),d.jsx("p",{className:"text-[var(--color-text-muted)] text-sm mt-1",children:ge?`${ge.name} · ${ge.cards.total} cards · ${ge.workers.active} workers 活跃`:"加载中…"})]}),d.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[d.jsx(DR,{current:n,onChange:_}),d.jsxs("button",{className:fe?"nb-btn nb-btn-danger":"nb-btn nb-btn-primary",onClick:()=>fe?T.mutate():A.mutate(),disabled:A.isPending||T.isPending,type:"button","aria-label":fe?"停止 pipeline":"启动 pipeline",title:fe?"停止 pipeline":"启动 pipeline",children:[A.isPending||T.isPending?d.jsx(Lt,{size:14,strokeWidth:3,className:"animate-spin"}):fe?d.jsx(lE,{size:14,strokeWidth:3}):d.jsx(Wp,{size:14,strokeWidth:3}),fe?"停止":"启动"]}),d.jsxs("button",{className:"nb-btn nb-btn-yellow",type:"button",onClick:async()=>{await g({title:"重置整个流水线",body:"这会清空所有卡片的运行状态、worker marker、分支。不可撤销。",confirm:"重置全部",danger:!0})&&j.mutate()},disabled:j.isPending,children:[j.isPending?d.jsx(Lt,{size:14,strokeWidth:3,className:"animate-spin"}):d.jsx(rE,{size:14,strokeWidth:2.5}),"重置"]}),d.jsxs("button",{className:"nb-btn nb-btn-mint",type:"button",onClick:()=>M(!0),disabled:F.isPending,children:[F.isPending?d.jsx(Lt,{size:14,strokeWidth:3,className:"animate-spin"}):d.jsx(zi,{size:14,strokeWidth:3}),"新卡片"]})]})]}),d.jsxs("div",{className:"flex items-center gap-3 flex-wrap shrink-0",children:[d.jsxs("div",{className:"relative flex-1 max-w-md",children:[d.jsx(Sf,{size:14,className:"absolute left-3 top-1/2 -translate-y-1/2 text-[var(--color-text-subtle)]"}),d.jsx("input",{className:"nb-input pl-9 w-full",placeholder:"搜索标题 / skill / label…",value:o,onChange:V=>c(V.target.value),"aria-label":"搜索卡片"})]}),d.jsx(r0,{label:"skill",options:L,selected:f,onChange:h}),d.jsx(r0,{label:"label",options:J,selected:m,onChange:b}),(o||f.size>0||m.size>0)&&d.jsxs("button",{className:"nb-btn",style:{padding:"4px 10px",fontSize:11},onClick:()=>{c(""),h(new Set),b(new Set)},type:"button","aria-label":"清空筛选",children:[d.jsx(wi,{size:11,strokeWidth:3}),"清空"]}),d.jsxs("span",{className:"text-xs text-[var(--color-text-muted)] flex items-center gap-1 font-[family-name:var(--font-mono)]",children:[d.jsx(iC,{size:12}),ae.length," / ",ee.length]})]}),E.isError&&d.jsxs("div",{className:"nb-card bg-[var(--color-crashed-bg)]",children:[d.jsx("p",{className:"font-semibold",children:"加载卡片失败"}),d.jsx("p",{className:"text-sm mt-1 text-[var(--color-text-muted)]",children:E.error instanceof Error?E.error.message:String(E.error)})]}),!E.isError&&d.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6 auto-rows-fr gap-3 flex-1 min-h-0",children:LR.map(V=>d.jsx(MR,{label:V.label,bg:V.bg,cards:ae.filter(UR(V.state)),onCardClick:be=>s(be.seq),onDropCard:be=>H.mutate({seq:be,state:V.state})},V.state))}),a!==null&&d.jsx(jR,{project:n,seq:a,onClose:()=>s(null),onChanged:k}),$&&d.jsx(uR,{project:n,isPending:F.isPending,onCancel:()=>M(!1),onCreate:V=>F.mutate(V)})]})}function UR(e){return t=>e==="QA"?t.state==="QA"||t.state==="Review":e==="Done"?t.state==="Done"||t.state==="Canceled":t.state===e}function r0({label:e,options:t,selected:n,onChange:a}){const[s,o]=O.useState(!1),c=O.useRef(null);O.useEffect(()=>{if(!s)return;const b=x=>{var v;(v=c.current)!=null&&v.contains(x.target)||o(!1)},g=x=>{x.key==="Escape"&&o(!1)};return window.addEventListener("click",b),window.addEventListener("keydown",g),()=>{window.removeEventListener("click",b),window.removeEventListener("keydown",g)}},[s]);const f=b=>{const g=new Set(n);g.has(b)?g.delete(b):g.add(b),a(g)},h=t.length===0,m=n.size;return d.jsxs("div",{ref:c,className:"relative",children:[d.jsxs("button",{type:"button",className:"nb-btn",style:{padding:"6px 12px",fontSize:12},onClick:()=>!h&&o(b=>!b),disabled:h,"aria-haspopup":"listbox","aria-expanded":s,"aria-label":`按 ${e} 筛选`,children:[e,m>0&&d.jsx("span",{className:"ml-1 px-1.5 py-0.5 text-[10px] font-bold rounded-full bg-[var(--color-primary)] text-[var(--color-text)] border border-[var(--color-text)]",children:m}),d.jsx(vc,{size:11,strokeWidth:3,className:["transition-transform",s?"rotate-180":""].join(" ")})]}),s&&d.jsxs("div",{role:"listbox",className:"absolute left-0 top-full mt-2 z-20 min-w-[200px] max-h-64 overflow-auto nb-card p-2",style:{padding:8},children:[t.map(b=>{const g=n.has(b);return d.jsxs("label",{className:["flex items-center gap-2 px-2 py-1.5 rounded cursor-pointer text-sm font-[family-name:var(--font-mono)]",g?"bg-[var(--color-accent-mint)]":"hover:bg-[var(--color-bg-cream)]"].join(" "),children:[d.jsx("input",{type:"checkbox",checked:g,onChange:()=>f(b),className:"flex-shrink-0"}),d.jsx("span",{className:"truncate",children:b})]},b)}),m>0&&d.jsx("button",{type:"button",className:"w-full mt-2 pt-2 border-t-2 border-dashed border-[var(--color-text)] text-xs font-bold text-[var(--color-crashed)] text-center",onClick:()=>a(new Set),children:"清空选择"})]})]})}function $R(){return Ft("/api/workers/all")}function FR(e){return Ft(`/api/projects/${encodeURIComponent(e)}/workers`)}function PR(e,t){return Ft(`/api/projects/${encodeURIComponent(e)}/workers/${t}`)}async function mS(e,t){const n=await fetch(e,{method:"POST",headers:t?{"Content-Type":"application/json"}:void 0,body:t?JSON.stringify(t):void 0});if(!n.ok)throw new Error(`${n.status}: ${await n.text()}`);return n.json().catch(()=>({}))}function s0(e,t){return mS(`/api/projects/${encodeURIComponent(e)}/workers/${t}/kill`)}function qR(e,t,n){return mS(`/api/projects/${encodeURIComponent(e)}/workers/${t}/launch`,n?{seq:n}:void 0)}function mg({state:e}){const n={running:{bg:"var(--color-running-bg)",color:"var(--color-running)",label:"running"},starting:{bg:"var(--color-secondary)",color:"var(--color-text)",label:"starting",icon:d.jsx(Lt,{size:9,strokeWidth:3,className:"animate-spin"})},stuck:{bg:"var(--color-stuck-bg)",color:"var(--color-stuck)",label:"stuck"},crashed:{bg:"var(--color-crashed-bg)",color:"var(--color-crashed)",label:"crashed",icon:d.jsx($C,{size:9,strokeWidth:2.5})},idle:{bg:"var(--color-idle-bg)",color:"var(--color-idle)",label:"idle"}}[e];return d.jsxs("span",{className:"nb-status inline-flex items-center gap-1",style:{background:n.bg,color:n.color},children:[n.icon,n.label]})}function pg(e){if(e==null||e<=0)return"—";const t=Math.floor(e/1e3),n=Math.floor(t/3600),a=Math.floor(t%3600/60),s=t%60;return n>0?`${n}h ${a}m`:a>0?`${a}m ${s}s`:`${s}s`}function HR(e){if(e==null||e<=0)return"text-[var(--color-text-muted)]";const t=e/6e4;return t<10?"text-[var(--color-running)]":t<60?"text-[var(--color-stuck)]":"text-[var(--color-crashed)]"}function gg(e){const t=Date.now()-new Date(e).getTime();return t<6e4?`${Math.floor(t/1e3)}s 前`:t<36e5?`${Math.floor(t/6e4)}m 前`:`${Math.floor(t/36e5)}h 前`}function KR({alerts:e,selected:t,onSelect:n}){return e.length===0?d.jsxs("div",{className:"nb-card bg-[var(--color-running-bg)] flex items-center gap-3",children:[d.jsx(sc,{size:18,strokeWidth:2.5,className:"text-[var(--color-running)]"}),d.jsx("span",{className:"text-sm font-bold text-[var(--color-running)]",children:"全部 worker 健康"})]}):d.jsxs("section",{children:[d.jsxs("h2",{className:"font-[family-name:var(--font-heading)] text-sm font-bold uppercase tracking-wider mb-2 flex items-center gap-2 text-[var(--color-crashed)]",children:[d.jsx(VC,{size:14,strokeWidth:2.5}),"Alerts (",e.length,")"]}),d.jsx("div",{className:"flex flex-col gap-2",children:e.map(a=>{const s=(t==null?void 0:t.project)===a.project&&(t==null?void 0:t.slot)===a.slot;return d.jsxs("button",{type:"button",onClick:()=>n(a.project,a.slot),className:["nb-card p-3 text-left",a.state==="crashed"?"bg-[var(--color-crashed-bg)]":"bg-[var(--color-stuck-bg)]",s?"ring-4 ring-[var(--color-text)]":""].join(" "),children:[d.jsxs("div",{className:"flex items-center gap-2 text-sm",children:[d.jsx(mg,{state:a.state}),d.jsxs("span",{className:"font-[family-name:var(--font-mono)] font-bold",children:[a.project,"/worker-",a.slot]}),a.card&&d.jsxs("span",{className:"truncate",children:["#",a.card.seq," ",a.card.title]}),d.jsxs("span",{className:"ml-auto text-xs text-[var(--color-text-muted)] font-[family-name:var(--font-mono)] flex items-center gap-1",children:[d.jsx(PT,{size:10,strokeWidth:2.5}),pg(a.runtimeMs)]})]}),a.markerUpdatedAt&&d.jsx("div",{className:"text-xs text-[var(--color-text-muted)] mt-1 font-[family-name:var(--font-mono)]",children:a.state==="crashed"?"PID 已死。":`marker 停 ${gg(a.markerUpdatedAt)}。`})]},`${a.project}-${a.slot}`)})})]})}function GR({active:e,selected:t,onSelect:n}){return e.length===0?d.jsx("div",{className:"nb-card bg-[var(--color-bg-cream)]",children:d.jsx("p",{className:"text-sm text-[var(--color-text-muted)] italic",children:"没有 worker 在运行。"})}):d.jsxs("section",{children:[d.jsxs("h2",{className:"font-[family-name:var(--font-heading)] text-sm font-bold uppercase tracking-wider mb-2 flex items-center gap-2",children:[d.jsx(If,{size:14,strokeWidth:2.5}),"Active (",e.length,")"]}),d.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-3",children:e.map(a=>{const s=(t==null?void 0:t.project)===a.project&&(t==null?void 0:t.slot)===a.slot;return d.jsxs("button",{type:"button",onClick:()=>n(a.project,a.slot),className:["nb-card p-3 text-left",a.state==="starting"?"bg-[var(--color-secondary)]":"bg-[var(--color-running-bg)]",s?"ring-4 ring-[var(--color-text)]":""].join(" "),children:[d.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[d.jsx(mg,{state:a.state}),d.jsxs("span",{className:"font-[family-name:var(--font-mono)] font-bold text-sm flex-1 truncate",children:[a.project,"/worker-",a.slot]}),d.jsx("span",{className:`text-xs font-[family-name:var(--font-mono)] ${HR(a.runtimeMs)}`,children:pg(a.runtimeMs)})]}),a.card&&d.jsxs("div",{className:"text-sm font-semibold mb-1 truncate",children:["#",a.card.seq," · ",a.card.title]}),d.jsxs("div",{className:"text-xs text-[var(--color-text-muted)] font-[family-name:var(--font-mono)] flex items-center gap-2 mb-1",children:[a.stage&&d.jsxs("span",{children:["stage: ",a.stage]}),a.markerUpdatedAt&&d.jsxs("span",{className:"ml-auto",children:["marker ",gg(a.markerUpdatedAt)]})]}),a.lastLogLine&&d.jsxs("div",{className:"text-[11px] font-[family-name:var(--font-mono)] text-[var(--color-text-muted)] bg-[var(--color-bg)] border-2 border-[var(--color-text)] rounded px-2 py-1 mt-2 truncate",children:[d.jsx(oE,{size:9,strokeWidth:2.5,className:"inline-block mr-1 align-text-bottom"}),a.lastLogLine.msg]})]},`${a.project}-${a.slot}`)})})]})}function QR({capacity:e,selected:t,onSelect:n}){return e.length===0?null:d.jsxs("section",{children:[d.jsx("h2",{className:"font-[family-name:var(--font-heading)] text-sm font-bold uppercase tracking-wider mb-2",children:"Capacity"}),d.jsx("div",{className:"nb-card p-0 overflow-hidden",children:d.jsxs("table",{className:"w-full text-sm",children:[d.jsx("thead",{children:d.jsxs("tr",{className:"bg-[var(--color-bg-cream)] border-b-2 border-[var(--color-text)]",children:[d.jsx("th",{className:"px-3 py-2 text-left font-bold text-xs uppercase tracking-wider",children:"项目"}),d.jsx("th",{className:"px-3 py-2 text-left font-bold text-xs uppercase tracking-wider",children:"占用"}),d.jsx("th",{className:"px-3 py-2 text-right font-bold text-xs uppercase tracking-wider",children:"running"}),d.jsx("th",{className:"px-3 py-2 text-right font-bold text-xs uppercase tracking-wider",children:"其它"}),d.jsx("th",{className:"px-3 py-2"})]})}),d.jsx("tbody",{children:e.map(a=>{const s=a.running+a.starting+a.stuck+a.crashed,o=(t==null?void 0:t.project)===a.project;return d.jsxs("tr",{onClick:()=>n(a.project),className:["border-b border-dashed border-[var(--color-border-light)] last:border-0 cursor-pointer hover:bg-[var(--color-accent-yellow)]",o?"bg-[var(--color-accent-yellow)]":""].join(" "),children:[d.jsx("td",{className:"px-3 py-2 font-[family-name:var(--font-mono)] font-bold",children:a.project}),d.jsx("td",{className:"px-3 py-2",children:d.jsx(YR,{total:a.total,cap:a})}),d.jsxs("td",{className:"px-3 py-2 text-right font-[family-name:var(--font-mono)]",children:[d.jsx("span",{className:"text-[var(--color-running)] font-bold",children:a.running}),d.jsxs("span",{className:"text-[var(--color-text-muted)]",children:["/",a.total]})]}),d.jsxs("td",{className:"px-3 py-2 text-right text-xs font-[family-name:var(--font-mono)] text-[var(--color-text-muted)]",children:[a.starting>0&&d.jsxs("span",{className:"mr-2",children:["starting ",a.starting]}),a.stuck>0&&d.jsxs("span",{className:"text-[var(--color-stuck)] font-bold mr-2",children:["stuck ",a.stuck]}),a.crashed>0&&d.jsxs("span",{className:"text-[var(--color-crashed)] font-bold mr-2",children:["crashed ",a.crashed]}),s===0&&d.jsx("span",{children:"idle"})]}),d.jsx("td",{className:"px-3 py-2 text-right",children:d.jsx("span",{className:"text-xs text-[var(--color-text-muted)]",children:"详情 →"})})]},a.project)})})]})})]})}function YR({total:e,cap:t}){const n=[];for(let a=0;a<t.crashed;a++)n.push("crashed");for(let a=0;a<t.stuck;a++)n.push("stuck");for(let a=0;a<t.starting;a++)n.push("starting");for(let a=0;a<t.running;a++)n.push("running");for(let a=0;a<t.idle;a++)n.push("idle");return d.jsxs("div",{className:"flex gap-1 items-center",children:[n.map((a,s)=>d.jsx("span",{className:"inline-block w-3 h-3 rounded-full border-2 border-[var(--color-text)]",style:{background:VR(a)},title:a},s)),d.jsxs("span",{className:"text-xs text-[var(--color-text-muted)] ml-2 font-[family-name:var(--font-mono)]",children:[e," slot",e!==1?"s":""]})]})}function VR(e){switch(e){case"running":return"var(--color-running-bg)";case"starting":return"var(--color-secondary)";case"stuck":return"var(--color-stuck-bg)";case"crashed":return"var(--color-crashed-bg)";default:return"var(--color-idle-bg)"}}function WR({project:e,initialSlot:t,onChange:n}){var h;const a=ot({queryKey:["workers",e],queryFn:()=>FR(e),refetchInterval:3e3}),s=((h=a.data)==null?void 0:h.data)??[],[o,c]=O.useState(null);O.useEffect(()=>{if(s.length===0){c(null);return}const m=s[0].slot;c(b=>b!=null&&s.some(g=>g.slot===b)?b:t!=null&&s.some(g=>g.slot===t)?t:m)},[e,t,s.length]);const f=s.find(m=>m.slot===o)??null;return d.jsxs("div",{className:"flex flex-col h-full",children:[d.jsxs("div",{className:"px-4 py-3 border-b-2 border-[var(--color-text)] bg-[var(--color-bg-cream)]",children:[d.jsxs("div",{className:"flex items-center justify-between mb-2",children:[d.jsx("span",{className:"font-[family-name:var(--font-mono)] font-bold truncate",children:e}),d.jsx(ds,{to:`/board?project=${encodeURIComponent(e)}`,className:"text-xs underline text-[var(--color-text-muted)] hover:text-[var(--color-text)]",children:"看板 →"})]}),a.isLoading&&s.length===0?d.jsx("p",{className:"text-xs text-[var(--color-text-muted)] italic",children:"加载 workers…"}):s.length===0?d.jsx("p",{className:"text-xs text-[var(--color-text-muted)] italic",children:"该项目没有 worker slot。"}):d.jsx("div",{className:"flex flex-wrap gap-2",children:s.map(m=>d.jsx(XR,{worker:m,active:m.slot===o,onClick:()=>c(m.slot)},m.slot))})]}),f?d.jsx(ZR,{project:e,worker:f,onChange:n}):d.jsx("div",{className:"flex-1 flex items-center justify-center p-6 text-center",children:d.jsx("p",{className:"text-sm text-[var(--color-text-muted)]",children:s.length===0?"无 worker":"请选择一个 worker"})})]})}function XR({worker:e,active:t,onClick:n}){return d.jsxs("button",{type:"button",onClick:n,className:["nb-card p-2 text-left min-w-[130px] transition-transform",t?"ring-4 ring-[var(--color-text)]":"opacity-80 hover:opacity-100"].join(" "),children:[d.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[d.jsx(mg,{state:e.state}),d.jsxs("span",{className:"font-[family-name:var(--font-mono)] font-bold text-xs",children:["worker-",e.slot]})]}),e.card?d.jsxs("div",{className:"text-[11px] truncate font-[family-name:var(--font-mono)]",children:["#",e.card.seq," ",e.card.title]}):d.jsx("div",{className:"text-[11px] text-[var(--color-text-muted)] italic",children:"空闲"})]})}function ZR({project:e,worker:t,onChange:n}){var m,b;const{confirm:a,alert:s}=li(),o=t.state==="crashed"||t.state==="stuck",c=ot({queryKey:["worker-detail",e,t.slot],queryFn:()=>PR(e,t.slot),refetchInterval:3e3}),f=((m=c.data)==null?void 0:m.recentOutput)??[],h=((b=c.data)==null?void 0:b.recentLogs)??[];return d.jsxs(d.Fragment,{children:[d.jsxs("div",{className:"flex-1 overflow-auto p-4 flex flex-col gap-4",children:[t.card?d.jsxs("div",{children:[d.jsx("div",{className:"text-xs font-bold uppercase tracking-wider text-[var(--color-text-muted)] mb-1",children:"当前卡片"}),d.jsxs("div",{className:"text-sm font-semibold break-words",children:["#",t.card.seq," · ",t.card.title]})]}):d.jsx("div",{className:"text-sm text-[var(--color-text-muted)] italic",children:"slot 空闲,没有当前卡片。"}),d.jsxs("dl",{className:"grid grid-cols-[100px_1fr] gap-y-2 text-sm",children:[d.jsx("dt",{className:"font-bold",children:"Stage"}),d.jsx("dd",{className:"font-[family-name:var(--font-mono)]",children:t.stage??"—"}),d.jsx("dt",{className:"font-bold",children:"PID"}),d.jsx("dd",{className:"font-[family-name:var(--font-mono)]",children:t.pid??"—"}),d.jsx("dt",{className:"font-bold",children:"Runtime"}),d.jsx("dd",{className:"font-[family-name:var(--font-mono)]",children:pg(t.runtimeMs)}),d.jsx("dt",{className:"font-bold",children:"Started"}),d.jsx("dd",{className:"font-[family-name:var(--font-mono)] text-xs",children:t.startedAt?new Date(t.startedAt).toLocaleString():"—"}),d.jsx("dt",{className:"font-bold",children:"Marker"}),d.jsx("dd",{className:"font-[family-name:var(--font-mono)] text-xs",children:t.markerUpdatedAt?gg(t.markerUpdatedAt):"—"})]}),d.jsxs("div",{children:[d.jsxs("div",{className:"text-xs font-bold uppercase tracking-wider text-[var(--color-text-muted)] mb-1 flex items-center gap-1",children:[d.jsx(oE,{size:10,strokeWidth:2.5}),"Claude 输出 · 最近 ",f.length," 行"]}),c.isLoading&&f.length===0?d.jsx("p",{className:"text-xs text-[var(--color-text-muted)] italic",children:"加载中…"}):f.length===0?d.jsx("p",{className:"text-xs text-[var(--color-text-muted)] italic",children:"还没收到 session 输出。Worker 刚启动时需要几秒。"}):d.jsx("pre",{className:"text-xs font-[family-name:var(--font-mono)] bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] rounded p-2 max-h-80 overflow-auto whitespace-pre-wrap break-words",children:f.map(g=>`${g.ts?`${g.ts} [${g.kind}] `:`[${g.kind}] `}${g.text}`).join(`
|
|
508
508
|
`)})]}),h.length>0&&d.jsxs("div",{children:[d.jsxs("div",{className:"text-xs font-bold uppercase tracking-wider text-[var(--color-text-muted)] mb-1 opacity-60",children:["Supervisor 心跳 · 最近 ",h.length," 行"]}),d.jsx("pre",{className:"text-xs font-[family-name:var(--font-mono)] bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] rounded p-2 max-h-40 overflow-auto whitespace-pre-wrap break-words opacity-80",children:h.map(g=>`${g.ts??""} [${g.level}] ${g.msg}`).join(`
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
8
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
9
|
<link href="https://fonts.googleapis.com/css2?family=Fredoka:wght@400;500;600;700&family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
10
|
-
<script type="module" crossorigin src="/assets/index-
|
|
10
|
+
<script type="module" crossorigin src="/assets/index-DKc9idxO.js"></script>
|
|
11
11
|
<link rel="stylesheet" crossorigin href="/assets/index-BJ1T4p1K.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
package/package.json
CHANGED
|
@@ -188,8 +188,8 @@ Planning(用户手动暂存;不自动派发)
|
|
|
188
188
|
```
|
|
189
189
|
|
|
190
190
|
Default states (configurable in YAML `pm.card_states`):
|
|
191
|
-
- **Planning** — v0.51.
|
|
192
|
-
- **Backlog** —
|
|
191
|
+
- **Planning** — v0.51.10+:人工暂存 / 草稿。**console "新卡片" 表单**默认入此状态;用户拖到 Backlog 才会跑。
|
|
192
|
+
- **Backlog** — **`sps card add`(CLI / agent)**默认入此状态;StageEngine 抢卡执行。
|
|
193
193
|
- **Todo** — StageEngine 已 prep(建分支 / worktree),下次 tick 派 worker
|
|
194
194
|
- **Inprogress** — worker active
|
|
195
195
|
- **QA** (or **Review**) — code complete, awaiting human/auto verification
|