@devcxl/opencode-cabbage 0.3.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/README.md +34 -19
  2. package/README.zh.md +34 -19
  3. package/assets/agents/dev-lifecycle.md +60 -41
  4. package/assets/agents/team/architect.md +36 -1
  5. package/assets/agents/team/developer.md +89 -0
  6. package/assets/agents/team/goal-verify.md +5 -1
  7. package/assets/agents/team/reviewer.md +42 -1
  8. package/assets/commands/code.md +3 -2
  9. package/assets/commands/design.md +3 -2
  10. package/assets/commands/release.md +3 -2
  11. package/assets/commands/requirements.md +3 -2
  12. package/assets/commands/review.md +3 -2
  13. package/assets/commands/setup.md +3 -2
  14. package/assets/commands/tasks.md +2 -1
  15. package/assets/prompts/bootstrap.md +9 -8
  16. package/assets/prompts/stage-contract.md +55 -0
  17. package/assets/skills/flow-code/SKILL.md +38 -140
  18. package/assets/skills/flow-design/SKILL.md +33 -74
  19. package/assets/skills/flow-release/SKILL.md +31 -51
  20. package/assets/skills/flow-requirements/SKILL.md +47 -45
  21. package/assets/skills/flow-review/SKILL.md +26 -112
  22. package/assets/skills/flow-setup/SKILL.md +40 -43
  23. package/assets/skills/flow-tasks/SKILL.md +30 -139
  24. package/assets/skills/flow-tdd/SKILL.md +30 -31
  25. package/dist/kernel/caller.d.ts +48 -0
  26. package/dist/kernel/caller.js +88 -0
  27. package/dist/kernel/caller.js.map +1 -0
  28. package/dist/kernel/context.d.ts +27 -0
  29. package/dist/kernel/context.js +73 -0
  30. package/dist/kernel/context.js.map +1 -0
  31. package/dist/kernel/flow.d.ts +166 -0
  32. package/dist/kernel/flow.js +387 -0
  33. package/dist/kernel/flow.js.map +1 -0
  34. package/dist/kernel/legacy.d.ts +19 -0
  35. package/dist/kernel/legacy.js +34 -0
  36. package/dist/kernel/legacy.js.map +1 -0
  37. package/dist/kernel/mutex.d.ts +8 -0
  38. package/dist/kernel/mutex.js +23 -0
  39. package/dist/kernel/mutex.js.map +1 -0
  40. package/dist/kernel/permission.d.ts +21 -0
  41. package/dist/kernel/permission.js +37 -0
  42. package/dist/kernel/permission.js.map +1 -0
  43. package/dist/kernel/profile.d.ts +35 -0
  44. package/dist/kernel/profile.js +144 -0
  45. package/dist/kernel/profile.js.map +1 -0
  46. package/dist/kernel/records.d.ts +87 -0
  47. package/dist/kernel/records.js +197 -0
  48. package/dist/kernel/records.js.map +1 -0
  49. package/dist/kernel/release.d.ts +104 -0
  50. package/dist/kernel/release.js +229 -0
  51. package/dist/kernel/release.js.map +1 -0
  52. package/dist/kernel/review.d.ts +34 -0
  53. package/dist/kernel/review.js +81 -0
  54. package/dist/kernel/review.js.map +1 -0
  55. package/dist/kernel/session-index.d.ts +43 -0
  56. package/dist/kernel/session-index.js +120 -0
  57. package/dist/kernel/session-index.js.map +1 -0
  58. package/dist/kernel/setup.d.ts +70 -0
  59. package/dist/kernel/setup.js +324 -0
  60. package/dist/kernel/setup.js.map +1 -0
  61. package/dist/kernel/slug.d.ts +23 -0
  62. package/dist/kernel/slug.js +67 -0
  63. package/dist/kernel/slug.js.map +1 -0
  64. package/dist/kernel/task.d.ts +208 -0
  65. package/dist/kernel/task.js +788 -0
  66. package/dist/kernel/task.js.map +1 -0
  67. package/dist/{flowrun → kernel/tdd}/adapter.d.ts +1 -1
  68. package/dist/kernel/tdd/adapter.js.map +1 -0
  69. package/dist/{flowrun → kernel/tdd}/digest.d.ts +1 -1
  70. package/dist/kernel/tdd/digest.js.map +1 -0
  71. package/dist/{flowrun → kernel/tdd}/evaluator.d.ts +1 -1
  72. package/dist/kernel/tdd/evaluator.js.map +1 -0
  73. package/dist/kernel/tdd/evidence.d.ts +42 -0
  74. package/dist/kernel/tdd/evidence.js +48 -0
  75. package/dist/kernel/tdd/evidence.js.map +1 -0
  76. package/dist/{flowrun → kernel/tdd}/state.d.ts +1 -1
  77. package/dist/kernel/tdd/state.js.map +1 -0
  78. package/dist/kernel/types.d.ts +180 -0
  79. package/dist/kernel/types.js +2 -0
  80. package/dist/kernel/types.js.map +1 -0
  81. package/dist/kernel/worktree.d.ts +45 -0
  82. package/dist/kernel/worktree.js +127 -0
  83. package/dist/kernel/worktree.js.map +1 -0
  84. package/dist/plugin/agents.d.ts +5 -17
  85. package/dist/plugin/agents.js +0 -23
  86. package/dist/plugin/agents.js.map +1 -1
  87. package/dist/plugin/flow-control.d.ts +80 -0
  88. package/dist/plugin/flow-control.js +254 -0
  89. package/dist/plugin/flow-control.js.map +1 -0
  90. package/dist/plugin/goal.d.ts +7 -46
  91. package/dist/plugin/goal.js +32 -116
  92. package/dist/plugin/goal.js.map +1 -1
  93. package/dist/plugin/prompt-lint.js +78 -5
  94. package/dist/plugin/prompt-lint.js.map +1 -1
  95. package/dist/plugin/release-control.d.ts +37 -0
  96. package/dist/plugin/release-control.js +304 -0
  97. package/dist/plugin/release-control.js.map +1 -0
  98. package/dist/plugin/server.d.ts +19 -0
  99. package/dist/plugin/server.js +147 -302
  100. package/dist/plugin/server.js.map +1 -1
  101. package/dist/plugin/setup-control.d.ts +45 -0
  102. package/dist/plugin/setup-control.js +80 -0
  103. package/dist/plugin/setup-control.js.map +1 -0
  104. package/dist/plugin/shell.d.ts +7 -34
  105. package/dist/plugin/shell.js +12 -137
  106. package/dist/plugin/shell.js.map +1 -1
  107. package/dist/plugin/skills.d.ts +1 -1
  108. package/dist/plugin/skills.js +16 -17
  109. package/dist/plugin/skills.js.map +1 -1
  110. package/dist/plugin/task-control.d.ts +90 -0
  111. package/dist/plugin/task-control.js +201 -0
  112. package/dist/plugin/task-control.js.map +1 -0
  113. package/dist/plugin/tdd-checkpoint.d.ts +118 -0
  114. package/dist/plugin/tdd-checkpoint.js +581 -0
  115. package/dist/plugin/tdd-checkpoint.js.map +1 -0
  116. package/dist/util/paths.d.ts +0 -2
  117. package/dist/util/paths.js +1 -7
  118. package/dist/util/paths.js.map +1 -1
  119. package/package.json +1 -1
  120. package/assets/agents/team/backend.md +0 -66
  121. package/assets/agents/team/frontend.md +0 -63
  122. package/assets/commands/handoff.md +0 -4
  123. package/assets/commands/test.md +0 -4
  124. package/assets/context/CONTEXT.md +0 -40
  125. package/assets/skills/flow-handoff/SKILL.md +0 -76
  126. package/assets/skills/flow-requirements/references/interview-guide.md +0 -35
  127. package/assets/skills/flow-test/SKILL.md +0 -75
  128. package/dist/flowrun/adapter.js.map +0 -1
  129. package/dist/flowrun/audit.d.ts +0 -5
  130. package/dist/flowrun/audit.js +0 -67
  131. package/dist/flowrun/audit.js.map +0 -1
  132. package/dist/flowrun/ci.d.ts +0 -64
  133. package/dist/flowrun/ci.js +0 -184
  134. package/dist/flowrun/ci.js.map +0 -1
  135. package/dist/flowrun/coverage.d.ts +0 -70
  136. package/dist/flowrun/coverage.js +0 -207
  137. package/dist/flowrun/coverage.js.map +0 -1
  138. package/dist/flowrun/digest.js.map +0 -1
  139. package/dist/flowrun/evaluator.js.map +0 -1
  140. package/dist/flowrun/gate.d.ts +0 -28
  141. package/dist/flowrun/gate.js +0 -139
  142. package/dist/flowrun/gate.js.map +0 -1
  143. package/dist/flowrun/github.d.ts +0 -24
  144. package/dist/flowrun/github.js +0 -154
  145. package/dist/flowrun/github.js.map +0 -1
  146. package/dist/flowrun/index.d.ts +0 -14
  147. package/dist/flowrun/index.js +0 -15
  148. package/dist/flowrun/index.js.map +0 -1
  149. package/dist/flowrun/merge.d.ts +0 -57
  150. package/dist/flowrun/merge.js +0 -180
  151. package/dist/flowrun/merge.js.map +0 -1
  152. package/dist/flowrun/migration.d.ts +0 -11
  153. package/dist/flowrun/migration.js +0 -276
  154. package/dist/flowrun/migration.js.map +0 -1
  155. package/dist/flowrun/resilience.d.ts +0 -18
  156. package/dist/flowrun/resilience.js +0 -80
  157. package/dist/flowrun/resilience.js.map +0 -1
  158. package/dist/flowrun/state.js.map +0 -1
  159. package/dist/flowrun/transitions.d.ts +0 -66
  160. package/dist/flowrun/transitions.js +0 -168
  161. package/dist/flowrun/transitions.js.map +0 -1
  162. package/dist/flowrun/types.d.ts +0 -356
  163. package/dist/flowrun/types.js +0 -21
  164. package/dist/flowrun/types.js.map +0 -1
  165. package/dist/flowrun/validator.d.ts +0 -19
  166. package/dist/flowrun/validator.js +0 -209
  167. package/dist/flowrun/validator.js.map +0 -1
  168. package/dist/plugin/broker.d.ts +0 -73
  169. package/dist/plugin/broker.js +0 -140
  170. package/dist/plugin/broker.js.map +0 -1
  171. package/dist/plugin/tdd-tool.d.ts +0 -62
  172. package/dist/plugin/tdd-tool.js +0 -336
  173. package/dist/plugin/tdd-tool.js.map +0 -1
  174. /package/dist/{flowrun → kernel/tdd}/adapter.js +0 -0
  175. /package/dist/{flowrun → kernel/tdd}/digest.js +0 -0
  176. /package/dist/{flowrun → kernel/tdd}/evaluator.js +0 -0
  177. /package/dist/{flowrun → kernel/tdd}/state.js +0 -0
@@ -0,0 +1,48 @@
1
+ /**
2
+ * 工具调用者校验原语(spec §2.2)。
3
+ *
4
+ * 判定:`ctx.agent` 为 agent 名;session 无 parentID(经 session client 检查)→ primary;
5
+ * 子会话按 agent 名映射角色,未知 agent 保守视为 reviewer(最低权限)。
6
+ */
7
+ export type CallerRole = "primary" | "developer" | "architect" | "reviewer" | "goal-verify";
8
+ /** 5 个生命周期工具(spec §2.2 / PRD R4) */
9
+ export declare const LIFECYCLE_TOOLS: readonly ["setup_control", "flow_control", "task_control", "tdd_checkpoint", "release_control"];
10
+ /**
11
+ * 解析工具(+op)允许的角色集。op 级覆盖优先;未知工具保守返回空集(fail-closed)。
12
+ */
13
+ export declare function rolesForTool(tool: string, op?: string): CallerRole[];
14
+ /** requireCaller 拒绝时的错误码 */
15
+ export declare const CALLER_NOT_AUTHORIZED = "CALLER_NOT_AUTHORIZED";
16
+ /** 工具 execute 上下文的最小可见面(ToolContext 的子集) */
17
+ export interface CallerContext {
18
+ agent: string;
19
+ sessionID: string;
20
+ }
21
+ /** session client 的最小可见面(goalClient 的子集) */
22
+ export interface CallerSessionClient {
23
+ session: {
24
+ get(input: {
25
+ sessionID: string;
26
+ }): Promise<{
27
+ data?: {
28
+ parentID?: string | null;
29
+ };
30
+ }>;
31
+ };
32
+ }
33
+ /**
34
+ * 解析调用者角色:无 parentID(session 查询成功且 data 存在)→ primary;
35
+ * 查询失败/无 data → 保守视为 reviewer(最低权限,fail-closed);
36
+ * 子会话按 agent 名映射;未知 agent → reviewer。
37
+ */
38
+ export declare function resolveCaller(ctx: CallerContext, client: CallerSessionClient): Promise<CallerRole>;
39
+ /**
40
+ * 调用者门禁原语:角色在 allowedRoles 内返回 null(通过),
41
+ * 否则返回含 CALLER_NOT_AUTHORIZED 码的错误消息(调用方组装 `{ code, message }` 响应)。
42
+ */
43
+ export declare function requireCaller(ctx: CallerContext, allowedRoles: CallerRole[], op: string, client: CallerSessionClient): Promise<string | null>;
44
+ /**
45
+ * 工具级 caller 门禁:按工具(+op)矩阵解析允许角色后校验。
46
+ * 供各生命周期工具 execute 内调用(spec §2.2 第一道门;config 层为第二道门)。
47
+ */
48
+ export declare function requireToolCaller(ctx: CallerContext, tool: string, op: string | undefined, client: CallerSessionClient): Promise<string | null>;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * 工具调用者校验原语(spec §2.2)。
3
+ *
4
+ * 判定:`ctx.agent` 为 agent 名;session 无 parentID(经 session client 检查)→ primary;
5
+ * 子会话按 agent 名映射角色,未知 agent 保守视为 reviewer(最低权限)。
6
+ */
7
+ /** 5 个生命周期工具(spec §2.2 / PRD R4) */
8
+ export const LIFECYCLE_TOOLS = [
9
+ "setup_control",
10
+ "flow_control",
11
+ "task_control",
12
+ "tdd_checkpoint",
13
+ "release_control",
14
+ ];
15
+ /** 工具默认允许角色矩阵:primary 全量;developer 仅 tdd_checkpoint;其余角色默认无工具 */
16
+ const TOOL_ROLES = {
17
+ setup_control: ["primary"],
18
+ flow_control: ["primary"],
19
+ task_control: ["primary"],
20
+ tdd_checkpoint: ["primary", "developer"],
21
+ release_control: ["primary"],
22
+ };
23
+ /** op 级覆盖(最后匹配优先):architect 仅 flow_control.status 只读;goal-verify 仅 complete-flow;tdd_checkpoint.not-applicable 仅 primary(spec §2.3 纯文档豁免) */
24
+ const OP_ROLES = {
25
+ flow_control: {
26
+ "complete-flow": ["goal-verify"],
27
+ status: ["primary", "architect"],
28
+ },
29
+ tdd_checkpoint: {
30
+ "not-applicable": ["primary"],
31
+ },
32
+ };
33
+ /**
34
+ * 解析工具(+op)允许的角色集。op 级覆盖优先;未知工具保守返回空集(fail-closed)。
35
+ */
36
+ export function rolesForTool(tool, op) {
37
+ if (op && OP_ROLES[tool]?.[op])
38
+ return OP_ROLES[tool][op];
39
+ return TOOL_ROLES[tool] ?? [];
40
+ }
41
+ /** requireCaller 拒绝时的错误码 */
42
+ export const CALLER_NOT_AUTHORIZED = "CALLER_NOT_AUTHORIZED";
43
+ const ROLE_BY_AGENT = {
44
+ "dev-lifecycle": "primary",
45
+ developer: "developer",
46
+ architect: "architect",
47
+ reviewer: "reviewer",
48
+ "goal-verify": "goal-verify",
49
+ };
50
+ /**
51
+ * 解析调用者角色:无 parentID(session 查询成功且 data 存在)→ primary;
52
+ * 查询失败/无 data → 保守视为 reviewer(最低权限,fail-closed);
53
+ * 子会话按 agent 名映射;未知 agent → reviewer。
54
+ */
55
+ export async function resolveCaller(ctx, client) {
56
+ let session;
57
+ try {
58
+ session = await client.session.get({ sessionID: ctx.sessionID });
59
+ }
60
+ catch {
61
+ return "reviewer";
62
+ }
63
+ if (!session?.data)
64
+ return "reviewer";
65
+ if (session.data.parentID)
66
+ return ROLE_BY_AGENT[ctx.agent] ?? "reviewer";
67
+ return "primary";
68
+ }
69
+ /**
70
+ * 调用者门禁原语:角色在 allowedRoles 内返回 null(通过),
71
+ * 否则返回含 CALLER_NOT_AUTHORIZED 码的错误消息(调用方组装 `{ code, message }` 响应)。
72
+ */
73
+ export async function requireCaller(ctx, allowedRoles, op, client) {
74
+ const role = await resolveCaller(ctx, client);
75
+ if (allowedRoles.includes(role))
76
+ return null;
77
+ return `${CALLER_NOT_AUTHORIZED}: caller "${ctx.agent}" resolved as "${role}" is not allowed to call "${op}" (allowed: ${allowedRoles.join(", ")})`;
78
+ }
79
+ /**
80
+ * 工具级 caller 门禁:按工具(+op)矩阵解析允许角色后校验。
81
+ * 供各生命周期工具 execute 内调用(spec §2.2 第一道门;config 层为第二道门)。
82
+ */
83
+ export async function requireToolCaller(ctx, tool, op, client) {
84
+ const allowed = rolesForTool(tool, op);
85
+ const label = op ? `${tool}:{op:"${op}"}` : tool;
86
+ return requireCaller(ctx, allowed, label, client);
87
+ }
88
+ //# sourceMappingURL=caller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caller.js","sourceRoot":"","sources":["../../src/kernel/caller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /** 注入块内的防重复 marker(message transform 据此跳过已注入的会话) */
2
+ export declare const CONTEXT_MARKER = "cabbage-project-context";
3
+ /** CONTEXT.md 全文注入的行数上限,超长截断并提示 */
4
+ export declare const MAX_CONTEXT_LINES = 200;
5
+ export interface ContextDigest {
6
+ /** 根 CONTEXT.md 的绝对路径 */
7
+ path: string;
8
+ /** 文件 mtime(毫秒),用于缓存刷新判定 */
9
+ mtimeMs: number;
10
+ /** sha256(内容) 前 16 位十六进制 */
11
+ digest: string;
12
+ /** 从 CONTEXT.md 提取的 ## 标题列表 */
13
+ terms: string[];
14
+ }
15
+ export interface ContextBlock extends ContextDigest {
16
+ /** 可直接注入到 prompt 的块文本 */
17
+ block: string;
18
+ }
19
+ export declare function resetContextCache(): void;
20
+ /**
21
+ * 发现并摘要项目根 CONTEXT.md。
22
+ * - 缺失 → 返回 null(不报错)
23
+ * - mtime 变化才重读,否则命中缓存
24
+ */
25
+ export declare function getContextBlock(projectDir: string): Promise<ContextBlock | null>;
26
+ /** 取注入块文本;无块时返回空串(调用方无需判空) */
27
+ export declare function formatContextBlock(block: ContextBlock | null): string;
@@ -0,0 +1,73 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFile, stat } from "node:fs/promises";
3
+ import path from "node:path";
4
+ /** 注入块内的防重复 marker(message transform 据此跳过已注入的会话) */
5
+ export const CONTEXT_MARKER = "cabbage-project-context";
6
+ /** CONTEXT.md 全文注入的行数上限,超长截断并提示 */
7
+ export const MAX_CONTEXT_LINES = 200;
8
+ let _cache = null;
9
+ export function resetContextCache() {
10
+ _cache = null;
11
+ }
12
+ /**
13
+ * 发现并摘要项目根 CONTEXT.md。
14
+ * - 缺失 → 返回 null(不报错)
15
+ * - mtime 变化才重读,否则命中缓存
16
+ */
17
+ export async function getContextBlock(projectDir) {
18
+ const filePath = path.join(projectDir, "CONTEXT.md");
19
+ let stats;
20
+ try {
21
+ stats = await stat(filePath);
22
+ }
23
+ catch {
24
+ _cache = null;
25
+ return null;
26
+ }
27
+ if (_cache?.projectDir === projectDir && _cache.mtimeMs === stats.mtimeMs) {
28
+ return buildContextBlock(projectDir, filePath, stats.mtimeMs, _cache.content);
29
+ }
30
+ const content = await readFile(filePath, "utf8");
31
+ _cache = { projectDir, mtimeMs: stats.mtimeMs, content };
32
+ return buildContextBlock(projectDir, filePath, stats.mtimeMs, content);
33
+ }
34
+ /** 取注入块文本;无块时返回空串(调用方无需判空) */
35
+ export function formatContextBlock(block) {
36
+ return block?.block ?? "";
37
+ }
38
+ function buildContextBlock(projectDir, filePath, mtimeMs, content) {
39
+ const digest = createHash("sha256").update(content).digest("hex").slice(0, 16);
40
+ const terms = extractTerms(content);
41
+ return {
42
+ path: filePath,
43
+ mtimeMs,
44
+ digest,
45
+ terms,
46
+ block: renderBlock(projectDir, filePath, mtimeMs, digest, terms, content),
47
+ };
48
+ }
49
+ function extractTerms(content) {
50
+ const terms = [];
51
+ for (const line of content.split("\n")) {
52
+ const match = /^##\s+(.+)$/.exec(line);
53
+ if (match)
54
+ terms.push(match[1].trim());
55
+ }
56
+ return terms;
57
+ }
58
+ function renderBlock(projectDir, filePath, mtimeMs, digest, terms, content) {
59
+ const lines = content.split("\n");
60
+ const truncated = lines.length > MAX_CONTEXT_LINES;
61
+ const body = truncated ? lines.slice(0, MAX_CONTEXT_LINES).join("\n") : content;
62
+ const header = [
63
+ "## Project Context (auto-injected)",
64
+ `<!-- ${CONTEXT_MARKER} -->`,
65
+ `来源: ${path.relative(projectDir, filePath)} · mtime: ${new Date(mtimeMs).toISOString()} · digest: ${digest}`,
66
+ terms.length > 0 ? `主题: ${terms.join(", ")}` : "",
67
+ ].filter(Boolean).join("\n");
68
+ const truncationNote = truncated
69
+ ? `\n\n> ⚠️ CONTEXT.md 超过 ${MAX_CONTEXT_LINES} 行,已截断。请直接读取完整文件。`
70
+ : "";
71
+ return `${header}\n\n${body}${truncationNote}`;
72
+ }
73
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/kernel/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,166 @@
1
+ export type CmdResult = {
2
+ stdout: string;
3
+ stderr: string;
4
+ };
5
+ export type CmdFn = (args: string) => Promise<CmdResult>;
6
+ export declare function setFlowGhExecutor(fn: CmdFn | null): void;
7
+ export declare function setFlowGitExecutor(fn: CmdFn | null): void;
8
+ export declare function flowGh(args: string): Promise<CmdResult>;
9
+ export declare function flowGit(args: string): Promise<CmdResult>;
10
+ export type FlowStage = "requirements" | "design" | "tasks" | "code" | "review";
11
+ export declare const FLOW_STAGES: FlowStage[];
12
+ /** 高风险 Flow 标签:design 与 tasks 之间需用户确认(PRD R11) */
13
+ export declare const RISK_LABEL = "cabbage:risk:high";
14
+ /** 新建 Flow Record 的 body:目标/验收/阶段 checklist(spec §2.3 create-flow) */
15
+ export declare function buildFlowBody(slug: string): string;
16
+ /** 从 body checklist 提取已完成阶段(按流程顺序) */
17
+ export declare function getCompletedStages(body: string): FlowStage[];
18
+ /** 把 stage 的 checkbox 标记为完成;已标记或缺失时幂等返回原 body */
19
+ export declare function markStageComplete(body: string, stage: FlowStage): string;
20
+ /** 从 issue labels 提取当前阶段(阶段序号最大的 cabbage:stage:* 标签) */
21
+ export declare function getCurrentStage(labels: string[]): FlowStage | null;
22
+ export type StageGateResult = {
23
+ ok: true;
24
+ } | {
25
+ ok: false;
26
+ code: string;
27
+ message: string;
28
+ };
29
+ export type StageOp = "stage-start" | "stage-complete";
30
+ /**
31
+ * 前置门禁判定:
32
+ * - stage-start X:前驱阶段须已 completed(requirements 无前置)
33
+ * - stage-complete X:X 未完成时前驱须已 completed;requirements 完成需 user_confirmed 一次
34
+ * - stage-start tasks:高风险 Flow(cabbage:risk:high)需 user_confirmed 确认
35
+ * - 已完成阶段重复 start/complete → 幂等通过
36
+ */
37
+ export declare function checkStageGate(op: StageOp, stage: FlowStage, completed: FlowStage[], highRisk: boolean, userConfirmed: boolean): StageGateResult;
38
+ export interface FlowRecordSummary {
39
+ number: number;
40
+ title: string;
41
+ state: string;
42
+ labels: string[];
43
+ }
44
+ export interface SubtaskSummary {
45
+ number: number;
46
+ title: string;
47
+ state: string;
48
+ }
49
+ export interface CheckSummary {
50
+ name: string;
51
+ state: string;
52
+ }
53
+ export interface RelatedPrSummary {
54
+ number: number;
55
+ title: string;
56
+ state: string;
57
+ headRefName: string;
58
+ checks: CheckSummary[];
59
+ }
60
+ export interface FlowStatusReport {
61
+ flow: FlowRecordSummary;
62
+ stages: {
63
+ completed: FlowStage[];
64
+ current: FlowStage | null;
65
+ };
66
+ subtasks: SubtaskSummary[];
67
+ pullRequests: RelatedPrSummary[];
68
+ }
69
+ export type FlowStatusResult = {
70
+ ok: true;
71
+ status: FlowStatusReport;
72
+ } | {
73
+ ok: false;
74
+ code: "NOT_FOUND" | "GITHUB_ERROR";
75
+ message: string;
76
+ };
77
+ /** 关联 PR:PR body 引用了 Flow 或任一子任务 Issue 号(保留 PR 原始字段) */
78
+ export declare function filterRelatedPrs<T extends {
79
+ number: number;
80
+ body?: string;
81
+ }>(prs: T[], parentIssueNumber: number, subtaskNumbers: number[]): T[];
82
+ /** 把 statusCheckRollup 精简为 {name, state} 列表(name 兼容 .name/.context) */
83
+ export declare function summarizeChecks(rollup: Array<{
84
+ name?: string;
85
+ context?: string;
86
+ state: string;
87
+ }>): CheckSummary[];
88
+ /** 读 Flow Record + 子任务 + 关联 PR checks 汇总(spec §2.3 status) */
89
+ export declare function readFlowStatus(parentIssueNumber: number): Promise<FlowStatusResult>;
90
+ export type PlanningResult = {
91
+ ok: true;
92
+ worktreePath: string;
93
+ branch: string;
94
+ prNumber?: number;
95
+ reused?: boolean;
96
+ } | {
97
+ ok: false;
98
+ code: string;
99
+ message: string;
100
+ };
101
+ /** 创建 planning worktree `.worktree/planning-<slug>`(architect 在此写文档) */
102
+ export declare function planningStart(projectDir: string, parentIssueNumber: number): Promise<PlanningResult>;
103
+ /** 对 planning worktree 的变更创建 Planning PR(Planning Baseline) */
104
+ export declare function planningPr(projectDir: string, parentIssueNumber: number): Promise<PlanningResult>;
105
+ export interface CreateFlowInput {
106
+ projectDir: string;
107
+ title: string;
108
+ sessionID: string;
109
+ /** 提供时对已有 Issue 建立 Flow 绑定(不新建)——legacy 检测 + 双 session 检查 */
110
+ parentIssueNumber?: number;
111
+ }
112
+ export type CreateFlowResult = {
113
+ ok: true;
114
+ ref: {
115
+ parentIssueNumber: number;
116
+ slug: string;
117
+ };
118
+ } | {
119
+ ok: false;
120
+ code: string;
121
+ message: string;
122
+ };
123
+ /**
124
+ * create-flow:
125
+ * - 新建模式:validateTitle → Profile 门禁 → Draft Parent Issue(body 含目标/验收/阶段 checklist)→ bindSession
126
+ * - 绑定模式(提供 parentIssueNumber):legacy 检测(§11.2)→ bindSession 双 session 检查(§10.3)
127
+ */
128
+ export declare function createFlow(input: CreateFlowInput): Promise<CreateFlowResult>;
129
+ export type FlowLifecycleResult = {
130
+ ok: true;
131
+ parentIssueNumber: number;
132
+ } | {
133
+ ok: false;
134
+ code: string;
135
+ message: string;
136
+ };
137
+ /** complete-flow(仅 goal-verify 调用,goal 已验证):关闭 Parent Issue + 标记 completed */
138
+ export declare function completeFlow(projectDir: string, parentIssueNumber: number): Promise<FlowLifecycleResult>;
139
+ /** cancel-flow:受控取消(user_confirmed)→ 关闭 Issue + 标记 cancelled */
140
+ export declare function cancelFlow(projectDir: string, parentIssueNumber: number, userConfirmed: boolean): Promise<FlowLifecycleResult>;
141
+ export type TakeoverFlowResult = {
142
+ ok: true;
143
+ parentIssueNumber: number;
144
+ oldSessionID: string | null;
145
+ } | {
146
+ ok: false;
147
+ code: string;
148
+ message: string;
149
+ };
150
+ /** takeover:双 session 接管(user_confirmed)→ 旧 session 置 paused + 新 session 绑定(§10.3) */
151
+ export declare function takeoverFlow(projectDir: string, parentIssueNumber: number, newSessionID: string, userConfirmed: boolean): Promise<TakeoverFlowResult>;
152
+ export type ApplyStageResult = {
153
+ ok: true;
154
+ stage: FlowStage;
155
+ completedStages: FlowStage[];
156
+ highRisk: boolean;
157
+ } | {
158
+ ok: false;
159
+ code: string;
160
+ message: string;
161
+ };
162
+ /**
163
+ * stage-start / stage-complete:
164
+ * 门禁(checkStageGate)→ stage-complete 更新 body checklist(乐观锁)→ setStageLabel。
165
+ */
166
+ export declare function applyStageOp(projectDir: string, parentIssueNumber: number, op: StageOp, stage: FlowStage, userConfirmed: boolean): Promise<ApplyStageResult>;