@devcxl/opencode-cabbage 0.3.2 → 1.1.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 (179) hide show
  1. package/README.md +34 -19
  2. package/README.zh.md +34 -19
  3. package/assets/agents/dev-lifecycle.md +60 -49
  4. package/assets/agents/team/architect.md +8 -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 +6 -0
  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 +28 -79
  19. package/assets/skills/flow-release/SKILL.md +31 -51
  20. package/assets/skills/flow-requirements/SKILL.md +31 -196
  21. package/assets/skills/flow-review/SKILL.md +26 -123
  22. package/assets/skills/flow-setup/SKILL.md +40 -43
  23. package/assets/skills/flow-tasks/SKILL.md +23 -153
  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 +84 -0
  30. package/dist/kernel/context.js.map +1 -0
  31. package/dist/kernel/flow.d.ts +175 -0
  32. package/dist/kernel/flow.js +467 -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 +45 -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 +147 -0
  45. package/dist/kernel/profile.js.map +1 -0
  46. package/dist/kernel/records.d.ts +103 -0
  47. package/dist/kernel/records.js +240 -0
  48. package/dist/kernel/records.js.map +1 -0
  49. package/dist/kernel/release.d.ts +106 -0
  50. package/dist/kernel/release.js +241 -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 +82 -0
  54. package/dist/kernel/review.js.map +1 -0
  55. package/dist/kernel/session-index.d.ts +45 -0
  56. package/dist/kernel/session-index.js +136 -0
  57. package/dist/kernel/session-index.js.map +1 -0
  58. package/dist/kernel/setup.d.ts +95 -0
  59. package/dist/kernel/setup.js +401 -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 +213 -0
  65. package/dist/kernel/task.js +873 -0
  66. package/dist/kernel/task.js.map +1 -0
  67. package/dist/{flowrun → kernel/tdd}/adapter.d.ts +1 -1
  68. package/dist/{flowrun → kernel/tdd}/adapter.js +27 -26
  69. package/dist/kernel/tdd/adapter.js.map +1 -0
  70. package/dist/{flowrun → kernel/tdd}/digest.d.ts +2 -1
  71. package/dist/{flowrun → kernel/tdd}/digest.js +6 -4
  72. package/dist/kernel/tdd/digest.js.map +1 -0
  73. package/dist/{flowrun → kernel/tdd}/evaluator.d.ts +1 -1
  74. package/dist/{flowrun → kernel/tdd}/evaluator.js +1 -1
  75. package/dist/kernel/tdd/evaluator.js.map +1 -0
  76. package/dist/kernel/tdd/evidence.d.ts +42 -0
  77. package/dist/kernel/tdd/evidence.js +48 -0
  78. package/dist/kernel/tdd/evidence.js.map +1 -0
  79. package/dist/{flowrun → kernel/tdd}/state.d.ts +2 -2
  80. package/dist/{flowrun → kernel/tdd}/state.js +1 -1
  81. package/dist/kernel/tdd/state.js.map +1 -0
  82. package/dist/kernel/types.d.ts +180 -0
  83. package/dist/kernel/types.js +2 -0
  84. package/dist/kernel/types.js.map +1 -0
  85. package/dist/kernel/worktree.d.ts +45 -0
  86. package/dist/kernel/worktree.js +156 -0
  87. package/dist/kernel/worktree.js.map +1 -0
  88. package/dist/plugin/agents.d.ts +5 -17
  89. package/dist/plugin/agents.js +0 -23
  90. package/dist/plugin/agents.js.map +1 -1
  91. package/dist/plugin/flow-control.d.ts +91 -0
  92. package/dist/plugin/flow-control.js +287 -0
  93. package/dist/plugin/flow-control.js.map +1 -0
  94. package/dist/plugin/goal.d.ts +17 -46
  95. package/dist/plugin/goal.js +47 -117
  96. package/dist/plugin/goal.js.map +1 -1
  97. package/dist/plugin/prompt-lint.js +78 -6
  98. package/dist/plugin/prompt-lint.js.map +1 -1
  99. package/dist/plugin/release-control.d.ts +39 -0
  100. package/dist/plugin/release-control.js +343 -0
  101. package/dist/plugin/release-control.js.map +1 -0
  102. package/dist/plugin/server.d.ts +19 -0
  103. package/dist/plugin/server.js +198 -320
  104. package/dist/plugin/server.js.map +1 -1
  105. package/dist/plugin/setup-control.d.ts +59 -0
  106. package/dist/plugin/setup-control.js +111 -0
  107. package/dist/plugin/setup-control.js.map +1 -0
  108. package/dist/plugin/shell.d.ts +7 -34
  109. package/dist/plugin/shell.js +12 -137
  110. package/dist/plugin/shell.js.map +1 -1
  111. package/dist/plugin/skills.d.ts +1 -1
  112. package/dist/plugin/skills.js +1 -7
  113. package/dist/plugin/skills.js.map +1 -1
  114. package/dist/plugin/task-control.d.ts +90 -0
  115. package/dist/plugin/task-control.js +208 -0
  116. package/dist/plugin/task-control.js.map +1 -0
  117. package/dist/plugin/tdd-checkpoint.d.ts +128 -0
  118. package/dist/plugin/tdd-checkpoint.js +664 -0
  119. package/dist/plugin/tdd-checkpoint.js.map +1 -0
  120. package/dist/util/gh.d.ts +5 -0
  121. package/dist/util/gh.js +12 -0
  122. package/dist/util/gh.js.map +1 -1
  123. package/dist/util/paths.d.ts +6 -2
  124. package/dist/util/paths.js +15 -7
  125. package/dist/util/paths.js.map +1 -1
  126. package/package.json +4 -4
  127. package/assets/agents/team/backend.md +0 -100
  128. package/assets/agents/team/frontend.md +0 -98
  129. package/assets/commands/handoff.md +0 -4
  130. package/assets/commands/test.md +0 -4
  131. package/assets/context/CONTEXT.md +0 -41
  132. package/assets/skills/flow-handoff/SKILL.md +0 -76
  133. package/assets/skills/flow-test/SKILL.md +0 -75
  134. package/dist/flowrun/adapter.js.map +0 -1
  135. package/dist/flowrun/audit.d.ts +0 -5
  136. package/dist/flowrun/audit.js +0 -67
  137. package/dist/flowrun/audit.js.map +0 -1
  138. package/dist/flowrun/ci.d.ts +0 -64
  139. package/dist/flowrun/ci.js +0 -184
  140. package/dist/flowrun/ci.js.map +0 -1
  141. package/dist/flowrun/coverage.d.ts +0 -70
  142. package/dist/flowrun/coverage.js +0 -207
  143. package/dist/flowrun/coverage.js.map +0 -1
  144. package/dist/flowrun/digest.js.map +0 -1
  145. package/dist/flowrun/evaluator.js.map +0 -1
  146. package/dist/flowrun/gate.d.ts +0 -28
  147. package/dist/flowrun/gate.js +0 -139
  148. package/dist/flowrun/gate.js.map +0 -1
  149. package/dist/flowrun/github.d.ts +0 -24
  150. package/dist/flowrun/github.js +0 -154
  151. package/dist/flowrun/github.js.map +0 -1
  152. package/dist/flowrun/index.d.ts +0 -14
  153. package/dist/flowrun/index.js +0 -15
  154. package/dist/flowrun/index.js.map +0 -1
  155. package/dist/flowrun/merge.d.ts +0 -57
  156. package/dist/flowrun/merge.js +0 -180
  157. package/dist/flowrun/merge.js.map +0 -1
  158. package/dist/flowrun/migration.d.ts +0 -11
  159. package/dist/flowrun/migration.js +0 -276
  160. package/dist/flowrun/migration.js.map +0 -1
  161. package/dist/flowrun/resilience.d.ts +0 -18
  162. package/dist/flowrun/resilience.js +0 -80
  163. package/dist/flowrun/resilience.js.map +0 -1
  164. package/dist/flowrun/state.js.map +0 -1
  165. package/dist/flowrun/transitions.d.ts +0 -66
  166. package/dist/flowrun/transitions.js +0 -168
  167. package/dist/flowrun/transitions.js.map +0 -1
  168. package/dist/flowrun/types.d.ts +0 -356
  169. package/dist/flowrun/types.js +0 -21
  170. package/dist/flowrun/types.js.map +0 -1
  171. package/dist/flowrun/validator.d.ts +0 -19
  172. package/dist/flowrun/validator.js +0 -209
  173. package/dist/flowrun/validator.js.map +0 -1
  174. package/dist/plugin/broker.d.ts +0 -73
  175. package/dist/plugin/broker.js +0 -140
  176. package/dist/plugin/broker.js.map +0 -1
  177. package/dist/plugin/tdd-tool.d.ts +0 -62
  178. package/dist/plugin/tdd-tool.js +0 -336
  179. package/dist/plugin/tdd-tool.js.map +0 -1
@@ -0,0 +1,240 @@
1
+ import { gh as ghCli, parsePrUrlNumber } from "../util/gh.js";
2
+ import { escapeShellArg } from "../util/shell.js";
3
+ import { KeyedMutex } from "./mutex.js";
4
+ /** TDD evidence 受控 comment 的 marker(单个 comment 承载全部证据) */
5
+ export const EVIDENCE_MARKER_START = "<!-- cabbage-tdd-evidence:start -->";
6
+ export const EVIDENCE_MARKER_END = "<!-- cabbage-tdd-evidence:end -->";
7
+ /** Flow Record(Parent Issue)标签 */
8
+ export const FLOW_LABEL = "cabbage:flow";
9
+ /** 全自动授权标签:用户打此标签 = 该 flow 全自动运行,阶段确认门禁(requirements/高风险)自动放行 */
10
+ export const AUTO_LABEL = "cabbage:auto";
11
+ /** 阶段标签前缀:cabbage:stage:<stage> */
12
+ export const STAGE_LABEL_PREFIX = "cabbage:stage:";
13
+ let recordsGhExecutor = null;
14
+ export function setRecordsGhExecutor(fn) {
15
+ recordsGhExecutor = fn;
16
+ }
17
+ async function gh(args, timeout) {
18
+ if (recordsGhExecutor) {
19
+ return recordsGhExecutor(args);
20
+ }
21
+ return ghCli(args, timeout);
22
+ }
23
+ // ─── evidence comment 纯函数 ───
24
+ /** 构造 marker 包裹的受控 comment body,START marker 行内携带 revision */
25
+ export function buildEvidenceCommentBody(block, revision) {
26
+ return `${EVIDENCE_MARKER_START} revision:${revision}\n${block}\n${EVIDENCE_MARKER_END}`;
27
+ }
28
+ /** 从受控 comment body 提取 revision 与 marker 区间内容;无 marker 或畸形返回 null */
29
+ export function extractEvidenceBlock(body) {
30
+ const startIdx = body.indexOf(EVIDENCE_MARKER_START);
31
+ const endIdx = body.indexOf(EVIDENCE_MARKER_END);
32
+ if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx) {
33
+ return null;
34
+ }
35
+ const newlineAfterStart = body.indexOf("\n", startIdx);
36
+ if (newlineAfterStart === -1 || newlineAfterStart > endIdx) {
37
+ return null;
38
+ }
39
+ const header = body.slice(startIdx, newlineAfterStart);
40
+ const revisionMatch = header.match(/revision:(\d+)/);
41
+ if (!revisionMatch) {
42
+ return null;
43
+ }
44
+ const content = body.slice(newlineAfterStart + 1, endIdx).trim();
45
+ if (content === "") {
46
+ return null;
47
+ }
48
+ return { revision: Number(revisionMatch[1]), content };
49
+ }
50
+ // ─── 记录写入互斥(按 issueNumber 串行) ───
51
+ const recordMutex = new KeyedMutex();
52
+ async function readBody(issueNumber) {
53
+ const { stdout } = await gh(`issue view ${issueNumber} --json body --jq .body`);
54
+ return stdout;
55
+ }
56
+ async function writeBody(issueNumber, body) {
57
+ const escaped = escapeShellArg(body);
58
+ await gh(`issue edit ${issueNumber} --body '${escaped}'`);
59
+ }
60
+ /** 创建 Parent Issue(Flow Record),打 cabbage:flow 标签(gh 2.96:issue create 无 --draft/--json) */
61
+ export async function createFlowRecord(input) {
62
+ try {
63
+ await ensureLabel(FLOW_LABEL);
64
+ if (input.autoMode)
65
+ await ensureLabel(AUTO_LABEL);
66
+ const escapedBody = escapeShellArg(input.body);
67
+ const labelArgs = input.autoMode
68
+ ? `--label '${FLOW_LABEL}' --label '${AUTO_LABEL}'`
69
+ : `--label '${FLOW_LABEL}'`;
70
+ const { stdout } = await gh(`issue create --title '${escapeShellArg(input.slug)}' --body '${escapedBody}' ${labelArgs}`);
71
+ // issue create 不支持 --json:解析 stdout 中的 issue URL
72
+ const number = parsePrUrlNumber(stdout);
73
+ if (number === null) {
74
+ throw new Error(`invalid issue create output: ${stdout}`);
75
+ }
76
+ return { ok: true, ref: { parentIssueNumber: number, slug: input.slug } };
77
+ }
78
+ catch (err) {
79
+ return { ok: false, error: String(err) };
80
+ }
81
+ }
82
+ export async function readFlowRecord(parentIssueNumber) {
83
+ try {
84
+ const { stdout } = await gh(`issue view ${parentIssueNumber} --json body --jq .body`);
85
+ return { ok: true, body: stdout };
86
+ }
87
+ catch (err) {
88
+ return { ok: false, code: "NOT_FOUND", error: String(err) };
89
+ }
90
+ }
91
+ /**
92
+ * 乐观锁更新 Flow Record body:mutex 串行 + previousBody 比对。
93
+ * 比对不一致(外部并发修改)→ 重读最新 body,基于最新内容合并写入(retried: true)。
94
+ * 合并语义保留外部修改;跨进程完全串行化需 ETag/If-Match(GitHub REST 限制,超出范围)。
95
+ */
96
+ export async function updateFlowRecord(parentIssueNumber, previousBody, buildNewBody) {
97
+ return recordMutex.runExclusive(parentIssueNumber, async () => {
98
+ try {
99
+ const current = await readBody(parentIssueNumber);
100
+ if (current === previousBody) {
101
+ await writeBody(parentIssueNumber, buildNewBody(current));
102
+ return { ok: true, retried: false };
103
+ }
104
+ // 冲突:重读最新 body,基于最新内容合并(保留外部修改)
105
+ const latest = await readBody(parentIssueNumber);
106
+ await writeBody(parentIssueNumber, buildNewBody(latest));
107
+ return { ok: true, retried: true };
108
+ }
109
+ catch (err) {
110
+ return { ok: false, error: String(err) };
111
+ }
112
+ });
113
+ }
114
+ /** 创建关联 Parent 的 Sub Issue(Task Record) */
115
+ export async function createTaskRecord(input) {
116
+ try {
117
+ const escapedBody = escapeShellArg(input.body);
118
+ const { stdout } = await gh(`issue create --title '${escapeShellArg(input.title)}' --body '${escapedBody}' --parent ${input.parentIssueNumber}`);
119
+ // issue create 不支持 --json:解析 stdout 中的 issue URL
120
+ const number = parsePrUrlNumber(stdout);
121
+ if (number === null) {
122
+ throw new Error(`invalid issue create output: ${stdout}`);
123
+ }
124
+ return {
125
+ ok: true,
126
+ ref: { parentIssueNumber: input.parentIssueNumber, taskId: input.title, issueNumber: number },
127
+ };
128
+ }
129
+ catch (err) {
130
+ return { ok: false, error: String(err) };
131
+ }
132
+ }
133
+ /**
134
+ * 读取 Task Record 的受控 evidence comment(取最新的,兼容历史多 comment);不存在返回 null。
135
+ * 兼容旧格式注释:只有 start marker、无 end marker 的注释(旧版本插件写入)也视为受控,
136
+ * revision 从 `revision:N` 行提取;完全无法解析时返回 null。
137
+ */
138
+ export async function readTddEvidenceComment(issueNumber) {
139
+ try {
140
+ const { stdout } = await gh(`issue view ${issueNumber} --json comments --jq '[.comments[] | select(.body | contains("${EVIDENCE_MARKER_START}")) | {id: (.id|tonumber), body}] | last'`);
141
+ const trimmed = stdout.trim();
142
+ if (trimmed === "" || trimmed === "null") {
143
+ return null;
144
+ }
145
+ const parsed = JSON.parse(trimmed);
146
+ const extracted = extractEvidenceBlock(parsed.body);
147
+ if (extracted) {
148
+ return { id: parsed.id, body: parsed.body, revision: extracted.revision };
149
+ }
150
+ // 旧格式兼容:只有 start marker(无 end marker)→ 从 body 提取 revision
151
+ const legacyRevision = parsed.body.match(/revision:(\d+)/)?.[1];
152
+ if (legacyRevision === undefined) {
153
+ return null;
154
+ }
155
+ return { id: parsed.id, body: parsed.body, revision: Number(legacyRevision) };
156
+ }
157
+ catch {
158
+ return null;
159
+ }
160
+ }
161
+ /** 单条 evidence comment 超过该字节数后滚动到新 comment(GitHub comment body 上限 65536 字节) */
162
+ export const MAX_EVIDENCE_COMMENT_BYTES = 55_000;
163
+ /**
164
+ * 追加 TDD evidence 到 Task Record 的受控 comment:
165
+ * 无受控 comment → 新建(revision 1);有 → marker 区间内 append,revision+1(PATCH 更新);
166
+ * 单 comment 超限 → 滚动到新 comment(revision 从当前继续)。
167
+ * mutex 按 issueNumber 串行;block 已存在则幂等跳过(追加不重复)。
168
+ * 跨进程并发为最佳努力(PATCH 前基于最新重读的 body 构造,丢失概率显著降低);
169
+ * 完全串行化需 ETag/If-Match(GitHub REST 限制,超出当前范围)。
170
+ */
171
+ export async function appendTddEvidence(issueNumber, block) {
172
+ return recordMutex.runExclusive(issueNumber, async () => {
173
+ try {
174
+ // 幂等:block 已在最新 comment 的 marker 区间内,不重复追加
175
+ const existing = await readTddEvidenceComment(issueNumber);
176
+ if (existing && extractEvidenceBlock(existing.body)?.content.includes(block)) {
177
+ return { ok: true, revision: existing.revision };
178
+ }
179
+ if (!existing) {
180
+ const body = buildEvidenceCommentBody(block, 1);
181
+ await gh(`issue comment ${issueNumber} --body '${escapeShellArg(body)}'`);
182
+ return { ok: true, revision: 1 };
183
+ }
184
+ // 滚动:最新 comment 超限 → 新建 comment 承载新证据
185
+ if (existing.body.length > MAX_EVIDENCE_COMMENT_BYTES) {
186
+ const body = buildEvidenceCommentBody(block, existing.revision + 1);
187
+ await gh(`issue comment ${issueNumber} --body '${escapeShellArg(body)}'`);
188
+ return { ok: true, revision: existing.revision + 1 };
189
+ }
190
+ // 追加前基于最新重读的 body 构造(跨进程冲突时尽量以最新为准,防覆盖丢失)
191
+ const current = await readTddEvidenceComment(issueNumber);
192
+ const base = current && current.id === existing.id ? current : existing;
193
+ const newBody = appendBlockToEvidenceBody(base.body, block, base.revision);
194
+ const repo = await gh("repo view --json nameWithOwner --jq .nameWithOwner");
195
+ await gh(`api repos/${repo.stdout.trim()}/issues/comments/${base.id} -X PATCH -f body='${escapeShellArg(newBody)}'`);
196
+ return { ok: true, revision: base.revision + 1 };
197
+ }
198
+ catch (err) {
199
+ return { ok: false, revision: 0, error: String(err) };
200
+ }
201
+ });
202
+ }
203
+ /** 在 END marker 前插入新 block,并将 START 行 revision 递增 */
204
+ function appendBlockToEvidenceBody(body, block, revision) {
205
+ const endIdx = body.indexOf(EVIDENCE_MARKER_END);
206
+ const prefix = body.slice(0, endIdx);
207
+ const suffix = body.slice(endIdx);
208
+ return `${prefix}${block}\n${suffix}`.replace(/(revision:)\d+/, `$1${revision + 1}`);
209
+ }
210
+ // ─── labels ───
211
+ /** 确保 label 存在(gh label create --force:存在则更新,幂等);创建失败不阻塞(后续 add-label 会显式报错) */
212
+ export async function ensureLabel(name) {
213
+ try {
214
+ await gh(`label create '${escapeShellArg(name)}' --force`);
215
+ }
216
+ catch {
217
+ // 已存在或权限不足:忽略,add-label 阶段仍会暴露真实错误
218
+ }
219
+ }
220
+ /** 设置 Flow Record 的阶段标签:移除其它 cabbage:stage:*,添加当前阶段(自动创建目标标签) */
221
+ export async function setStageLabel(parentIssueNumber, stage) {
222
+ try {
223
+ const { stdout } = await gh(`issue view ${parentIssueNumber} --json labels --jq '[.labels[].name] | join(" ") | tostring'`);
224
+ const currentLabels = stdout.trim() === "" ? [] : stdout.trim().split(" ");
225
+ const target = `${STAGE_LABEL_PREFIX}${stage}`;
226
+ const stale = currentLabels.filter(l => l.startsWith(STAGE_LABEL_PREFIX) && l !== target);
227
+ const args = [];
228
+ for (const label of stale) {
229
+ args.push(`--remove-label '${escapeShellArg(label)}'`);
230
+ }
231
+ args.push(`--add-label '${escapeShellArg(target)}'`);
232
+ await ensureLabel(target);
233
+ await gh(`issue edit ${parentIssueNumber} ${args.join(" ")}`);
234
+ return { ok: true };
235
+ }
236
+ catch (err) {
237
+ return { ok: false, error: String(err) };
238
+ }
239
+ }
240
+ //# sourceMappingURL=records.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"records.js","sourceRoot":"","sources":["../../src/kernel/records.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,106 @@
1
+ export type ChangeCategory = "feature" | "fix" | "maintenance" | "docs" | "unclassified";
2
+ export type VersionType = "major" | "minor" | "patch";
3
+ export interface ReleaseChange {
4
+ sha: string;
5
+ title: string;
6
+ category: ChangeCategory;
7
+ breaking: boolean;
8
+ }
9
+ export interface Version {
10
+ major: number;
11
+ minor: number;
12
+ patch: number;
13
+ }
14
+ export interface VersionFileSpec {
15
+ path: string;
16
+ key: string;
17
+ }
18
+ /**
19
+ * 解析版本文件规则(Profile `version file` 值):
20
+ * 形如 `package.json`(默认 $.version)或 `lib/version.json $.version`;
21
+ * json 路径必须为 `$.<key>` 形式,否则返回 null。
22
+ */
23
+ export declare function parseVersionFileSpec(spec: string): VersionFileSpec | null;
24
+ /** 从 JSON 文本按 key 读取版本字符串;非字符串或解析失败返回 null */
25
+ export declare function readVersionFromJson(json: string, key: string): string | null;
26
+ /** 更新 JSON 文本中指定 key 的版本;保留缩进风格与结尾换行 */
27
+ export declare function updateVersionInJson(json: string, key: string, version: string): string;
28
+ export declare function parseVersion(raw: string): Version | null;
29
+ export declare function formatVersion(v: Version): string;
30
+ /** SemVer bump:major 重置 minor/patch,minor 重置 patch,patch +1 */
31
+ export declare function bumpVersion(current: Version, type: VersionType): Version;
32
+ /** 取最高 bump 级别:major > minor > patch */
33
+ export declare function highestBumpType(types: VersionType[]): VersionType;
34
+ type Classified = {
35
+ category: ChangeCategory;
36
+ breaking: boolean;
37
+ };
38
+ /**
39
+ * 从 commit message 分类(conventional commits,关联 Flow/Task type):
40
+ * - breaking:`type!:` 或 body 含 `BREAKING CHANGE`
41
+ * - feat→feature、fix→fix、docs→docs、chore/refactor/build/ci/perf/test/merge→maintenance
42
+ * - 其余 → unclassified
43
+ */
44
+ export declare function classifyCommitTitle(title: string): Classified;
45
+ export declare function classifyChanges(commits: {
46
+ sha: string;
47
+ title: string;
48
+ }[]): ReleaseChange[];
49
+ export type ProposeVersionResult = {
50
+ ok: true;
51
+ proposed: string;
52
+ type: VersionType;
53
+ } | {
54
+ ok: false;
55
+ code: "INVALID_VERSION";
56
+ message: string;
57
+ } | {
58
+ ok: false;
59
+ code: "UNCLASSIFIED_CHANGES";
60
+ unclassified: {
61
+ sha: string;
62
+ title: string;
63
+ }[];
64
+ message: string;
65
+ };
66
+ /**
67
+ * SemVer 提议:breaking→major(含 0.x)、feature→minor、fix/maintenance/docs→patch;
68
+ * 多变更取最高级别;存在未分类变更时拒绝(版本提议前必须分类)。
69
+ */
70
+ export declare function proposeVersion(currentVersion: string, changes: ReleaseChange[]): ProposeVersionResult;
71
+ /** 按 tag 格式(如 v{version})构建 tag;缺省 v{version} */
72
+ export declare function buildTag(version: string, tagFormat: string): string;
73
+ /** tag 名是否可安全进入 shell 命令;非法(含 tagFormat 注入)→ false */
74
+ export declare function validateTagName(tag: string): boolean;
75
+ /** tag 是否匹配格式(替换 {version} 为语义版本正则后整体匹配) */
76
+ export declare function validateTagFormat(tag: string, tagFormat: string): boolean;
77
+ /** 按分类聚合生成 Release Notes markdown;breaking 变更单独列出 */
78
+ export declare function buildReleaseNotes(version: string, changes: ReleaseChange[]): string;
79
+ export type GhFn = (args: string) => Promise<{
80
+ stdout: string;
81
+ stderr: string;
82
+ }>;
83
+ export declare function setReleaseGhExecutor(fn: GhFn | null): void;
84
+ /** 仓库上一 tag 名(tags 列表第一个);无 tag 返回 null */
85
+ export declare function latestTag(executor?: GhFn): Promise<string | null>;
86
+ /** 聚合上一 tag 之后 base 分支的全部 commit(sha + 首行标题) */
87
+ export declare function listCommitsSinceTag(tag: string, baseBranch: string, executor?: GhFn): Promise<{
88
+ sha: string;
89
+ title: string;
90
+ }[]>;
91
+ /** 远程已存在 tag 指向的 commit SHA;不存在返回 null */
92
+ export declare function existingTagSha(tag: string, executor?: GhFn): Promise<string | null>;
93
+ export type TagImmutabilityResult = {
94
+ ok: true;
95
+ reason?: string;
96
+ } | {
97
+ ok: false;
98
+ code: "TAG_ALREADY_EXISTS";
99
+ message: string;
100
+ };
101
+ /**
102
+ * tag 不可变校验:不得删除重打。
103
+ * 远程已存在且指向不同 SHA → 拒绝;指向同一 SHA → 幂等通过;不存在 → 可创建。
104
+ */
105
+ export declare function validateTagImmutability(tag: string, expectedSha: string, executor?: GhFn): Promise<TagImmutabilityResult>;
106
+ export {};
@@ -0,0 +1,241 @@
1
+ import { gh as ghCli } from "../util/gh.js";
2
+ /**
3
+ * 解析版本文件规则(Profile `version file` 值):
4
+ * 形如 `package.json`(默认 $.version)或 `lib/version.json $.version`;
5
+ * json 路径必须为 `$.<key>` 形式,否则返回 null。
6
+ */
7
+ export function parseVersionFileSpec(spec) {
8
+ const trimmed = spec.trim();
9
+ if (trimmed === "")
10
+ return null;
11
+ const parts = trimmed.split(/\s+/);
12
+ if (parts.length === 1) {
13
+ return { path: parts[0], key: "version" };
14
+ }
15
+ const jsonPath = parts[parts.length - 1];
16
+ const key = jsonPath.startsWith("$.") ? jsonPath.slice(2) : "";
17
+ if (key === "")
18
+ return null;
19
+ return { path: parts.slice(0, -1).join(" "), key };
20
+ }
21
+ /** 从 JSON 文本按 key 读取版本字符串;非字符串或解析失败返回 null */
22
+ export function readVersionFromJson(json, key) {
23
+ try {
24
+ const value = JSON.parse(json)?.[key];
25
+ return typeof value === "string" ? value : null;
26
+ }
27
+ catch {
28
+ return null;
29
+ }
30
+ }
31
+ /** 更新 JSON 文本中指定 key 的版本;保留缩进风格与结尾换行 */
32
+ export function updateVersionInJson(json, key, version) {
33
+ const parsed = JSON.parse(json);
34
+ parsed[key] = version;
35
+ const updated = JSON.stringify(parsed, null, 2);
36
+ return json.endsWith("\n") ? `${updated}\n` : updated;
37
+ }
38
+ // ─── 版本纯函数 ───
39
+ const VERSION_PATTERN = /^(\d+)\.(\d+)\.(\d+)$/;
40
+ export function parseVersion(raw) {
41
+ const match = VERSION_PATTERN.exec(raw.trim());
42
+ if (!match)
43
+ return null;
44
+ return { major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3]) };
45
+ }
46
+ export function formatVersion(v) {
47
+ return `${v.major}.${v.minor}.${v.patch}`;
48
+ }
49
+ /** SemVer bump:major 重置 minor/patch,minor 重置 patch,patch +1 */
50
+ export function bumpVersion(current, type) {
51
+ switch (type) {
52
+ case "major":
53
+ return { major: current.major + 1, minor: 0, patch: 0 };
54
+ case "minor":
55
+ return { major: current.major, minor: current.minor + 1, patch: 0 };
56
+ case "patch":
57
+ return { major: current.major, minor: current.minor, patch: current.patch + 1 };
58
+ }
59
+ }
60
+ /** 取最高 bump 级别:major > minor > patch */
61
+ export function highestBumpType(types) {
62
+ if (types.includes("major"))
63
+ return "major";
64
+ if (types.includes("minor"))
65
+ return "minor";
66
+ return "patch";
67
+ }
68
+ const CONVENTIONAL_PATTERN = /^([a-z]+)(!)?(\([^)]*\))?:/;
69
+ const MAINTENANCE_TYPES = new Set(["chore", "refactor", "build", "ci", "perf", "test", "merge"]);
70
+ /**
71
+ * 从 commit message 分类(conventional commits,关联 Flow/Task type):
72
+ * - breaking:`type!:` 或 body 含 `BREAKING CHANGE`
73
+ * - feat→feature、fix→fix、docs→docs、chore/refactor/build/ci/perf/test/merge→maintenance
74
+ * - 其余 → unclassified
75
+ */
76
+ export function classifyCommitTitle(title) {
77
+ const firstLine = title.split("\n")[0];
78
+ const breaking = /^[a-z]+!(:|\()/.test(firstLine) || title.includes("BREAKING CHANGE");
79
+ if (firstLine.startsWith("Merge ")) {
80
+ return { category: "maintenance", breaking };
81
+ }
82
+ const match = CONVENTIONAL_PATTERN.exec(firstLine);
83
+ if (!match)
84
+ return { category: "unclassified", breaking };
85
+ const type = match[1];
86
+ switch (type) {
87
+ case "feat":
88
+ return { category: "feature", breaking };
89
+ case "fix":
90
+ return { category: "fix", breaking };
91
+ case "docs":
92
+ return { category: "docs", breaking };
93
+ default:
94
+ if (MAINTENANCE_TYPES.has(type))
95
+ return { category: "maintenance", breaking };
96
+ return { category: "unclassified", breaking };
97
+ }
98
+ }
99
+ export function classifyChanges(commits) {
100
+ return commits.map(commit => {
101
+ const { category, breaking } = classifyCommitTitle(commit.title);
102
+ return { sha: commit.sha, title: commit.title.split("\n")[0], category, breaking };
103
+ });
104
+ }
105
+ /**
106
+ * SemVer 提议:breaking→major(含 0.x)、feature→minor、fix/maintenance/docs→patch;
107
+ * 多变更取最高级别;存在未分类变更时拒绝(版本提议前必须分类)。
108
+ */
109
+ export function proposeVersion(currentVersion, changes) {
110
+ const current = parseVersion(currentVersion);
111
+ if (!current) {
112
+ return { ok: false, code: "INVALID_VERSION", message: `Invalid current version: ${currentVersion}` };
113
+ }
114
+ const unclassified = changes
115
+ .filter(c => c.category === "unclassified")
116
+ .map(c => ({ sha: c.sha, title: c.title }));
117
+ if (unclassified.length > 0) {
118
+ return {
119
+ ok: false,
120
+ code: "UNCLASSIFIED_CHANGES",
121
+ unclassified,
122
+ message: `Unclassified changes must be classified before proposing a version (${unclassified.length} change(s))`,
123
+ };
124
+ }
125
+ const breaking = changes.some(c => c.breaking);
126
+ const types = [];
127
+ for (const c of changes) {
128
+ if (c.category === "feature")
129
+ types.push("minor");
130
+ else if (c.category === "fix" || c.category === "maintenance" || c.category === "docs")
131
+ types.push("patch");
132
+ }
133
+ if (breaking)
134
+ types.push("major");
135
+ const type = highestBumpType(types);
136
+ return { ok: true, proposed: formatVersion(bumpVersion(current, type)), type };
137
+ }
138
+ // ─── tag ───
139
+ /** 按 tag 格式(如 v{version})构建 tag;缺省 v{version} */
140
+ export function buildTag(version, tagFormat) {
141
+ if (tagFormat.includes("{version}")) {
142
+ return tagFormat.replace("{version}", version);
143
+ }
144
+ return `v${version}`;
145
+ }
146
+ /** git tag 名安全白名单(git ref 合法字符子集,杜绝 shell 元字符/引号/分号) */
147
+ const TAG_SAFE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
148
+ /** tag 名是否可安全进入 shell 命令;非法(含 tagFormat 注入)→ false */
149
+ export function validateTagName(tag) {
150
+ return TAG_SAFE.test(tag);
151
+ }
152
+ /** tag 是否匹配格式(替换 {version} 为语义版本正则后整体匹配) */
153
+ export function validateTagFormat(tag, tagFormat) {
154
+ const escaped = tagFormat.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{version\\}", "(\\d+\\.\\d+\\.\\d+)");
155
+ return new RegExp(`^${escaped}$`).test(tag);
156
+ }
157
+ // ─── Release Notes ───
158
+ const SECTION_TITLES = [
159
+ ["feature", "Features"],
160
+ ["fix", "Fixes"],
161
+ ["maintenance", "Maintenance"],
162
+ ["docs", "Documentation"],
163
+ ];
164
+ /** 按分类聚合生成 Release Notes markdown;breaking 变更单独列出 */
165
+ export function buildReleaseNotes(version, changes) {
166
+ const lines = [`## ${version}`];
167
+ const breaking = changes.filter(c => c.breaking);
168
+ if (breaking.length > 0) {
169
+ lines.push("", "### BREAKING CHANGES");
170
+ for (const c of breaking)
171
+ lines.push(`- ${c.title}`);
172
+ }
173
+ for (const [category, title] of SECTION_TITLES) {
174
+ const group = changes.filter(c => c.category === category);
175
+ if (group.length === 0)
176
+ continue;
177
+ lines.push("", `### ${title}`);
178
+ for (const c of group)
179
+ lines.push(`- ${c.title}`);
180
+ }
181
+ return lines.join("\n");
182
+ }
183
+ let releaseGhExecutor = null;
184
+ export function setReleaseGhExecutor(fn) {
185
+ releaseGhExecutor = fn;
186
+ }
187
+ /** 解析实际 gh 执行函数:显式 executor > 模块级 mock > 真实 gh CLI */
188
+ function ghFn(executor) {
189
+ return executor ?? releaseGhExecutor ?? ghCli;
190
+ }
191
+ /** 仓库上一 tag 名(tags 列表第一个);无 tag 返回 null */
192
+ export async function latestTag(executor) {
193
+ const { stdout } = await ghFn(executor)(`api repos/{owner}/{repo}/tags --jq '.[0].name'`);
194
+ const trimmed = stdout.trim();
195
+ if (trimmed === "" || trimmed === "null")
196
+ return null;
197
+ return trimmed;
198
+ }
199
+ /** 聚合上一 tag 之后 base 分支的全部 commit(sha + 首行标题) */
200
+ export async function listCommitsSinceTag(tag, baseBranch, executor) {
201
+ if (!validateTagName(tag)) {
202
+ throw new Error(`Invalid tag name: ${tag}`);
203
+ }
204
+ const { stdout } = await ghFn(executor)(`api repos/{owner}/{repo}/compare/${tag}...${baseBranch} --jq '.commits[] | {sha: .sha, title: (.commit.message | split("\\n")[0])}'`);
205
+ const trimmed = stdout.trim();
206
+ if (trimmed === "" || trimmed === "null")
207
+ return [];
208
+ const commits = JSON.parse(trimmed);
209
+ // jq 已截断首行,这里再截断一次(mock/调用方绕过 jq 时兜底)
210
+ return commits.map(c => ({ sha: c.sha, title: c.title.split("\n")[0] }));
211
+ }
212
+ /** 远程已存在 tag 指向的 commit SHA;不存在返回 null */
213
+ export async function existingTagSha(tag, executor) {
214
+ if (!validateTagName(tag)) {
215
+ throw new Error(`Invalid tag name: ${tag}`);
216
+ }
217
+ const { stdout } = await ghFn(executor)(`api repos/{owner}/{repo}/tags --jq '.[] | select(.name == ${JSON.stringify(tag)}) | .commit.sha'`);
218
+ const trimmed = stdout.trim();
219
+ if (trimmed === "" || trimmed === "null")
220
+ return null;
221
+ return trimmed;
222
+ }
223
+ /**
224
+ * tag 不可变校验:不得删除重打。
225
+ * 远程已存在且指向不同 SHA → 拒绝;指向同一 SHA → 幂等通过;不存在 → 可创建。
226
+ */
227
+ export async function validateTagImmutability(tag, expectedSha, executor) {
228
+ const existing = await existingTagSha(tag, executor);
229
+ if (existing === null) {
230
+ return { ok: true };
231
+ }
232
+ if (existing === expectedSha) {
233
+ return { ok: true, reason: "tag already points at the expected commit (idempotent)" };
234
+ }
235
+ return {
236
+ ok: false,
237
+ code: "TAG_ALREADY_EXISTS",
238
+ message: `Tag ${tag} already exists at ${existing}, refusing to re-point it to ${expectedSha} (tags are immutable)`,
239
+ };
240
+ }
241
+ //# sourceMappingURL=release.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release.js","sourceRoot":"","sources":["../../src/kernel/release.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * 审查与合并 kernel 逻辑(spec §4.1,自 flowrun/merge.ts + ci.ts 迁入,逻辑不变)。
3
+ * - mergeTaskPR:标准化合并 PR(--match-head-commit 防偷换)
4
+ * - checkBranchProtection:默认分支保护探测
5
+ * - createRevertPR:回滚 PR
6
+ */
7
+ export type GhFn = (args: string) => Promise<{
8
+ stdout: string;
9
+ stderr: string;
10
+ }>;
11
+ export declare function setMergeGhExecutor(fn: GhFn | null): void;
12
+ export interface BranchProtectionStatus {
13
+ exists: boolean;
14
+ requiredChecks: string[];
15
+ requiresPR: boolean;
16
+ dismissesStale: boolean;
17
+ }
18
+ export declare function checkBranchProtection(owner: string, repo: string): Promise<BranchProtectionStatus>;
19
+ /**
20
+ * Task PR 合并(带 --match-head-commit 安全检查)。
21
+ *
22
+ * 步骤:
23
+ * 1. 验证 verifiedSha 非空
24
+ * 2. 使用 gh pr merge --squash --delete-branch --match-head-commit <verifiedSha>
25
+ * 3. 失败时返回错误
26
+ */
27
+ export declare function mergeTaskPR(prNumber: number, verifiedSha: string): Promise<{
28
+ success: boolean;
29
+ error?: string;
30
+ }>;
31
+ export declare function createRevertPR(prNumber: number, reason: string): Promise<{
32
+ prNumber?: number;
33
+ error?: string;
34
+ }>;