@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,324 @@
1
+ import { exec } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { readdir, access, constants, readFile, writeFile, mkdir } from "node:fs/promises";
4
+ import { join, basename } from "node:path";
5
+ import { readProjectProfile, upsertProjectProfile } from "./profile.js";
6
+ import { KeyedMutex } from "./mutex.js";
7
+ import { escapeShellArg } from "../util/shell.js";
8
+ const execAsync = promisify(exec);
9
+ let setupGitExecutor = null;
10
+ let setupGhExecutor = null;
11
+ export function setSetupGitExecutor(fn) {
12
+ setupGitExecutor = fn;
13
+ }
14
+ export function setSetupGhExecutor(fn) {
15
+ setupGhExecutor = fn;
16
+ }
17
+ async function runGit(args, cwd) {
18
+ if (setupGitExecutor)
19
+ return setupGitExecutor(args, cwd);
20
+ return execAsync(`git ${args}`, { cwd });
21
+ }
22
+ async function runGh(args) {
23
+ if (setupGhExecutor)
24
+ return setupGhExecutor(args);
25
+ return execAsync(`gh ${args}`, {});
26
+ }
27
+ /**
28
+ * 探测项目 setup 就绪度(PRD R10)。
29
+ * development-ready:git/gh + Profile 确认 + TDD 命令可执行 + CI workflow + 分支保护;
30
+ * release-ready:额外版本规则 + release workflow。
31
+ */
32
+ export async function probe(projectDir) {
33
+ const gitAvailable = await tryRun(() => runGit("--version", projectDir));
34
+ const ghAuthenticated = await tryRun(() => runGh("auth status"));
35
+ let remoteUrl = null;
36
+ try {
37
+ const { stdout } = await runGit("remote get-url origin", projectDir);
38
+ remoteUrl = stdout.trim() || null;
39
+ }
40
+ catch {
41
+ remoteUrl = null;
42
+ }
43
+ const hasRemote = remoteUrl !== null;
44
+ let defaultBranch = null;
45
+ try {
46
+ const { stdout } = await runGit("symbolic-ref --short refs/remotes/origin/HEAD", projectDir);
47
+ defaultBranch = stdout.trim() || null;
48
+ }
49
+ catch {
50
+ defaultBranch = null;
51
+ }
52
+ const profile = await readProjectProfile(projectDir);
53
+ const profileConfirmed = profile.testCommand !== null;
54
+ const versionRuleConfirmed = profile.versionBumpRule !== null && profile.versionFile !== null && profile.tagFormat !== null;
55
+ const tddCommandExecutable = await isCommandExecutable(profile.testCommand);
56
+ const { ci, release } = await scanWorkflows(projectDir, profile.releaseWorkflowPath);
57
+ const contextMdPresent = await fileExists(join(projectDir, "CONTEXT.md"));
58
+ let branchProtection = false;
59
+ const ownerRepo = remoteUrl ? parseGithubRemote(remoteUrl) : null;
60
+ if (ownerRepo && defaultBranch) {
61
+ branchProtection = await tryRun(() => runGh(`api repos/${ownerRepo.owner}/${ownerRepo.repo}/branches/${defaultBranch}/protection`));
62
+ }
63
+ const developmentReady = gitAvailable && ghAuthenticated && profileConfirmed && tddCommandExecutable && ci !== null && branchProtection;
64
+ const releaseReady = developmentReady && versionRuleConfirmed && release !== null;
65
+ return {
66
+ gitAvailable,
67
+ ghAuthenticated,
68
+ hasRemote,
69
+ defaultBranch,
70
+ profileConfirmed,
71
+ tddCommandExecutable,
72
+ ciWorkflow: ci,
73
+ releaseWorkflow: release,
74
+ contextMdPresent,
75
+ branchProtection,
76
+ versionRuleConfirmed,
77
+ developmentReady,
78
+ releaseReady,
79
+ };
80
+ }
81
+ /** 从 git remote URL 解析 GitHub owner/repo;非 GitHub 仓库返回 null */
82
+ export function parseGithubRemote(url) {
83
+ const patterns = [
84
+ /^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/,
85
+ /^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/,
86
+ /^ssh:\/\/git@github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/,
87
+ ];
88
+ for (const pattern of patterns) {
89
+ const match = pattern.exec(url);
90
+ if (match)
91
+ return { owner: match[1], repo: match[2] };
92
+ }
93
+ return null;
94
+ }
95
+ /** 扫描 .github/workflows/:文件名含 ci → CI workflow;含 release 或 Profile 指定路径 → release workflow */
96
+ async function scanWorkflows(projectDir, profileReleasePath) {
97
+ const workflowsDir = join(projectDir, ".github", "workflows");
98
+ let files = [];
99
+ try {
100
+ files = (await readdir(workflowsDir)).filter(f => f.endsWith(".yml") || f.endsWith(".yaml"));
101
+ }
102
+ catch {
103
+ files = [];
104
+ }
105
+ let ci = null;
106
+ let release = null;
107
+ for (const file of files) {
108
+ const lower = file.toLowerCase();
109
+ if (ci === null && lower.includes("ci"))
110
+ ci = `.github/workflows/${file}`;
111
+ if (release === null && lower.includes("release"))
112
+ release = `.github/workflows/${file}`;
113
+ }
114
+ if (profileReleasePath && (await fileExists(join(projectDir, profileReleasePath)))) {
115
+ release = profileReleasePath;
116
+ }
117
+ return { ci, release };
118
+ }
119
+ /** TDD 命令可执行:首个 token 存在于 PATH(相对路径则直接检查可执行) */
120
+ async function isCommandExecutable(testCommand) {
121
+ if (!testCommand)
122
+ return false;
123
+ const firstToken = testCommand.trim().split(/\s+/)[0];
124
+ if (!firstToken)
125
+ return false;
126
+ const candidates = firstToken.includes("/")
127
+ ? [firstToken]
128
+ : (process.env.PATH ?? "").split(":").filter(Boolean).map(dir => join(dir, firstToken));
129
+ for (const candidate of candidates) {
130
+ if (await isExecutable(candidate))
131
+ return true;
132
+ }
133
+ return false;
134
+ }
135
+ async function isExecutable(path) {
136
+ try {
137
+ await access(path, constants.X_OK);
138
+ return true;
139
+ }
140
+ catch {
141
+ return false;
142
+ }
143
+ }
144
+ async function fileExists(path) {
145
+ try {
146
+ await access(path);
147
+ return true;
148
+ }
149
+ catch {
150
+ return false;
151
+ }
152
+ }
153
+ async function tryRun(fn) {
154
+ try {
155
+ await fn();
156
+ return true;
157
+ }
158
+ catch {
159
+ return false;
160
+ }
161
+ }
162
+ // ─── generate-workflows:缺失时生成 CI/release 草案 + Setup PR ───
163
+ const SETUP_WORKFLOWS_BRANCH = "chore/setup-workflows";
164
+ /**
165
+ * 缺失时生成 CI/release workflow 草案(技术栈无关,不硬编码包管理器),
166
+ * 创建 chore/setup-workflows 分支 + commit + push + Setup PR(人工合入)。
167
+ */
168
+ export async function generateWorkflows(projectDir, input) {
169
+ const profile = await readProjectProfile(projectDir);
170
+ const testCommand = input.testCommand ?? profile.testCommand;
171
+ const tagFormat = input.tagFormat ?? profile.tagFormat;
172
+ const releaseWorkflowPath = input.releaseWorkflowPath ?? profile.releaseWorkflowPath;
173
+ let defaultBranch = input.defaultBranch ?? null;
174
+ if (!defaultBranch) {
175
+ try {
176
+ const { stdout } = await runGit("symbolic-ref --short refs/remotes/origin/HEAD", projectDir);
177
+ defaultBranch = stdout.trim() || null;
178
+ }
179
+ catch {
180
+ defaultBranch = null;
181
+ }
182
+ }
183
+ const workflowsDir = join(projectDir, ".github", "workflows");
184
+ await mkdir(workflowsDir, { recursive: true });
185
+ const { ci, release } = await scanWorkflows(projectDir, releaseWorkflowPath);
186
+ const created = [];
187
+ const existing = [];
188
+ if (ci === null) {
189
+ await writeFile(join(workflowsDir, "ci.yml"), buildCiWorkflow(testCommand, defaultBranch));
190
+ created.push(".github/workflows/ci.yml");
191
+ }
192
+ else {
193
+ existing.push(ci);
194
+ }
195
+ if (release === null) {
196
+ const fileName = releaseWorkflowPath ? basename(releaseWorkflowPath) : "release.yml";
197
+ await writeFile(join(workflowsDir, fileName), buildReleaseWorkflow(tagFormat));
198
+ created.push(`.github/workflows/${fileName}`);
199
+ }
200
+ else {
201
+ existing.push(release);
202
+ }
203
+ if (created.length === 0) {
204
+ return { ok: true, created, existing, branch: null, prNumber: null };
205
+ }
206
+ try {
207
+ const prTitle = input.prTitle || "chore: add CI/release workflow drafts";
208
+ const prBody = `Setup generated workflow drafts for manual review:\n\n${created.map(f => `- ${f}`).join("\n")}`;
209
+ await runGit(`checkout -b ${SETUP_WORKFLOWS_BRANCH}`, projectDir);
210
+ await runGit("add .github/workflows", projectDir);
211
+ await runGit(`commit -m ${shellQuote(prTitle)}`, projectDir);
212
+ await runGit(`push -u origin ${SETUP_WORKFLOWS_BRANCH}`, projectDir);
213
+ const { stdout } = await runGh(`pr create --title ${shellQuote(prTitle)} --body ${shellQuote(prBody)} --base ${defaultBranch ?? "main"} --head ${SETUP_WORKFLOWS_BRANCH} --json number --jq .number`);
214
+ return {
215
+ ok: true,
216
+ created,
217
+ existing,
218
+ branch: SETUP_WORKFLOWS_BRANCH,
219
+ prNumber: Number(stdout.trim()) || null,
220
+ };
221
+ }
222
+ catch (err) {
223
+ return { ok: false, created, existing, branch: null, prNumber: null, error: String(err) };
224
+ }
225
+ }
226
+ /** CI workflow 草案:PR check 触发,运行 Profile 的测试命令(无则占位) */
227
+ export function buildCiWorkflow(testCommand, defaultBranch) {
228
+ const command = testCommand ?? "<test-command>";
229
+ const branch = defaultBranch ?? "**";
230
+ return [
231
+ "name: CI",
232
+ "",
233
+ "on:",
234
+ " pull_request:",
235
+ " branches:",
236
+ ` - '${branch}'`,
237
+ "",
238
+ "jobs:",
239
+ " check:",
240
+ " runs-on: ubuntu-latest",
241
+ " steps:",
242
+ " - uses: actions/checkout@v4",
243
+ ` - run: ${command}`,
244
+ "",
245
+ ].join("\n");
246
+ }
247
+ /** release workflow 草案:tag 触发,技术栈无关占位步骤 */
248
+ export function buildReleaseWorkflow(tagFormat) {
249
+ const tag = tagFormat ?? "v*";
250
+ return [
251
+ "name: Release",
252
+ "",
253
+ "on:",
254
+ " push:",
255
+ " tags:",
256
+ ` - '${tag}'`,
257
+ "",
258
+ "jobs:",
259
+ " release:",
260
+ " runs-on: ubuntu-latest",
261
+ " steps:",
262
+ " - uses: actions/checkout@v4",
263
+ " - run: echo \"Define project-specific release steps here (version bump + artifact publish)\"",
264
+ "",
265
+ ].join("\n");
266
+ }
267
+ function shellQuote(value) {
268
+ return `'${escapeShellArg(value)}'`;
269
+ }
270
+ const profileMutex = new KeyedMutex();
271
+ /** overrides JSON 键 → Profile 区块行键(§9.1 顺序) */
272
+ const PROFILE_KEY_ORDER = [
273
+ { jsonKey: "testCommand", sectionKey: "test command" },
274
+ { jsonKey: "regressionCommand", sectionKey: "regression command" },
275
+ { jsonKey: "testFilePatterns", sectionKey: "test file patterns" },
276
+ { jsonKey: "implementationFilePatterns", sectionKey: "implementation file patterns" },
277
+ { jsonKey: "tddDefaultMode", sectionKey: "tdd default mode" },
278
+ { jsonKey: "versionBumpRule", sectionKey: "version bump rule" },
279
+ { jsonKey: "versionFile", sectionKey: "version file" },
280
+ { jsonKey: "tagFormat", sectionKey: "tag format" },
281
+ { jsonKey: "releaseWorkflowPath", sectionKey: "release workflow" },
282
+ { jsonKey: "riskPatterns", sectionKey: "risk patterns" },
283
+ ];
284
+ /** 由用户确认的 overrides 生成完整 `## Project Profile` 区块(未提供的键省略) */
285
+ export function buildProfileBlock(overrides) {
286
+ const lines = ["## Project Profile", ""];
287
+ for (const { jsonKey, sectionKey } of PROFILE_KEY_ORDER) {
288
+ const value = overrides[jsonKey];
289
+ if (value === undefined || value === null)
290
+ continue;
291
+ const formatted = Array.isArray(value) ? value.join(", ") : String(value);
292
+ if (formatted === "")
293
+ continue;
294
+ lines.push(`- ${sectionKey}: \`${formatted}\``);
295
+ }
296
+ return lines.join("\n");
297
+ }
298
+ /**
299
+ * 用户确认后把 Profile 区块写回根 AGENTS.md(§9.3)。
300
+ * 先读后写,按 key 串行(mutex);testCommand 为必需键。
301
+ */
302
+ export async function confirmProjectProfile(projectDir, overridesJson) {
303
+ let overrides;
304
+ try {
305
+ overrides = JSON.parse(overridesJson);
306
+ }
307
+ catch {
308
+ return { ok: false, code: "POLICY_INVALID", message: "profile_overrides is not valid JSON" };
309
+ }
310
+ if (typeof overrides !== "object" || overrides === null || Array.isArray(overrides)) {
311
+ return { ok: false, code: "POLICY_INVALID", message: "profile_overrides must be a JSON object" };
312
+ }
313
+ if (typeof overrides.testCommand !== "string" || overrides.testCommand.trim() === "") {
314
+ return { ok: false, code: "POLICY_INVALID", message: "testCommand is required to confirm the profile" };
315
+ }
316
+ const block = buildProfileBlock(overrides);
317
+ const agentsPath = join(projectDir, "AGENTS.md");
318
+ await profileMutex.runExclusive("agents-md", async () => {
319
+ const markdown = await readFile(agentsPath, "utf8").catch(() => "");
320
+ await writeFile(agentsPath, upsertProjectProfile(markdown, block));
321
+ });
322
+ return { ok: true, block };
323
+ }
324
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/kernel/setup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export declare const MAX_SLUG_LENGTH = 60;
2
+ export type BranchType = "feat" | "fix" | "chore" | "docs";
3
+ export type SlugValidationResult = {
4
+ ok: true;
5
+ slug: string;
6
+ } | {
7
+ ok: false;
8
+ code: "EMPTY_TITLE" | "INVALID_FORMAT" | "SLUG_TOO_LONG" | "GENERIC_TITLE";
9
+ message: string;
10
+ };
11
+ /**
12
+ * 严格 slug 派生:沿用 util/paths.ts slugify 的归一化规则,
13
+ * 但不做 "doc" 兜底——无意义输入返回空串,由调用方判定。
14
+ */
15
+ export declare function deriveSlug(value: string): string;
16
+ /**
17
+ * 校验功能标题(须已是 kebab-case slug):
18
+ * - 空标题、非法字符(大写/下划线/空格/连续连字符/首尾连字符)、过长(>60)→ 格式拒绝
19
+ * - 纯序号或全部由泛化词组成(task-001、implement-task、fix-bug)→ GENERIC_TITLE
20
+ */
21
+ export declare function validateTitle(title: string): SlugValidationResult;
22
+ export declare function branchFor(slug: string, type: BranchType): string;
23
+ export declare function worktreeFor(slug: string): string;
@@ -0,0 +1,67 @@
1
+ export const MAX_SLUG_LENGTH = 60;
2
+ /** 合法 slug:小写字母/数字分段,段间单个连字符 */
3
+ const SLUG_FORMAT = /^[a-z0-9]+(-[a-z0-9]+)*$/;
4
+ /** 泛化/占位词:与数字或其他泛化词组合时无法表达具体功能 */
5
+ const GENERIC_WORDS = new Set([
6
+ "add", "bug", "bugs", "chore", "create", "delete", "docs", "feature",
7
+ "features", "fix", "fixes", "implement", "issue", "issues", "refactor",
8
+ "remove", "support", "task", "tasks", "test", "tests", "update", "wip",
9
+ ]);
10
+ /**
11
+ * 严格 slug 派生:沿用 util/paths.ts slugify 的归一化规则,
12
+ * 但不做 "doc" 兜底——无意义输入返回空串,由调用方判定。
13
+ */
14
+ export function deriveSlug(value) {
15
+ let slug = value
16
+ .trim()
17
+ .toLowerCase()
18
+ .replace(/[^a-z0-9]+/g, "-")
19
+ .replace(/^-+|-+$/g, "")
20
+ .replace(/--+/g, "-");
21
+ if (slug.length > MAX_SLUG_LENGTH) {
22
+ const sliced = slug.slice(0, MAX_SLUG_LENGTH);
23
+ const lastDash = sliced.lastIndexOf("-");
24
+ slug = lastDash > MAX_SLUG_LENGTH / 2 ? sliced.slice(0, lastDash) : sliced;
25
+ }
26
+ return slug;
27
+ }
28
+ /**
29
+ * 校验功能标题(须已是 kebab-case slug):
30
+ * - 空标题、非法字符(大写/下划线/空格/连续连字符/首尾连字符)、过长(>60)→ 格式拒绝
31
+ * - 纯序号或全部由泛化词组成(task-001、implement-task、fix-bug)→ GENERIC_TITLE
32
+ */
33
+ export function validateTitle(title) {
34
+ if (title.trim() === "") {
35
+ return { ok: false, code: "EMPTY_TITLE", message: "Title must not be empty" };
36
+ }
37
+ if (title.length > MAX_SLUG_LENGTH) {
38
+ return { ok: false, code: "SLUG_TOO_LONG", message: `Title must be at most ${MAX_SLUG_LENGTH} characters` };
39
+ }
40
+ if (!SLUG_FORMAT.test(title)) {
41
+ return {
42
+ ok: false,
43
+ code: "INVALID_FORMAT",
44
+ message: "Title must be a kebab-case slug: lowercase letters, digits, and single hyphens between segments",
45
+ };
46
+ }
47
+ if (isGenericSlug(title)) {
48
+ return {
49
+ ok: false,
50
+ code: "GENERIC_TITLE",
51
+ message: "Title is too generic: use a functional slug that describes the concrete behavior",
52
+ };
53
+ }
54
+ return { ok: true, slug: title };
55
+ }
56
+ /** 纯序号,或所有分段均为泛化词/数字 → 无法描述具体功能 */
57
+ function isGenericSlug(slug) {
58
+ const segments = slug.split("-");
59
+ return segments.every(seg => /^\d+$/.test(seg) || GENERIC_WORDS.has(seg));
60
+ }
61
+ export function branchFor(slug, type) {
62
+ return `${type}/${slug}`;
63
+ }
64
+ export function worktreeFor(slug) {
65
+ return `.worktree/${slug}`;
66
+ }
67
+ //# sourceMappingURL=slug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slug.js","sourceRoot":"","sources":["../../src/kernel/slug.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,208 @@
1
+ import { type ProjectProfile } from "./profile.js";
2
+ import { type WorkspaceBaseline } from "./tdd/evidence.js";
3
+ import type { AcceptanceCriterion, TaskRecordRef, TddEvidence, TddPolicy } from "./types.js";
4
+ /** Task Record 状态标签前缀:cabbage:task:<status> */
5
+ export declare const TASK_STATUS_LABEL_PREFIX = "cabbage:task:";
6
+ /** Task 状态标签取值 */
7
+ export type TaskStatus = "running" | "reviewing" | "merged" | "cancelled";
8
+ /** 默认最大并行 Task 数(PRD R7,Profile 可覆盖但内核按此判定) */
9
+ export declare const MAX_PARALLEL_TASKS = 5;
10
+ /** 内核内置风险 pattern(spec §12 #12:migrations/auth/permissions/release workflow/密钥/公共 API),与 Profile riskPatterns 合并 */
11
+ export declare const BUILTIN_RISK_PATTERNS: string[];
12
+ export type CmdResult = {
13
+ stdout: string;
14
+ stderr: string;
15
+ };
16
+ export type CmdFn = (args: string) => Promise<CmdResult>;
17
+ export declare function setTaskGhExecutor(fn: CmdFn | null): void;
18
+ export declare function setTaskGitExecutor(fn: CmdFn | null): void;
19
+ export declare function taskGh(args: string, timeout?: number): Promise<CmdResult>;
20
+ export declare function taskGit(args: string): Promise<CmdResult>;
21
+ /**
22
+ * 新建 Task Record 的 body:acceptance criteria + 依赖 + 状态 checklist + Closes 约定。
23
+ * criteria 渲染为 `- [ ] <id>: <description> [<verification>]`,可被 parseCriteriaFromBody 还原。
24
+ */
25
+ export declare function buildTaskBody(slug: string, criteria: AcceptanceCriterion[], dependencies: number[]): string;
26
+ /** TDD 跨批协议:Task Record body 内 TDD 上下文块 marker(tdd_checkpoint 工具解析;spec §2.3/§4) */
27
+ export declare const TASK_TDD_TAG = "<!-- cabbage-task-tdd -->";
28
+ /** 构造 TDD 上下文块 JSON(policy + criteria + worktreeDir),供 tdd_checkpoint resolveTaskContext 解析 */
29
+ export declare function buildTaskTddBlock(policy: TddPolicy, criteria: AcceptanceCriterion[], worktreePath: string): string;
30
+ /** 解析 create-task 传入的 acceptance_criteria JSON(字符串数组 → AcceptanceCriterion[]);非法返回 null */
31
+ export declare function parseAcceptanceCriteria(json: string): AcceptanceCriterion[] | null;
32
+ /** 从 Task Record body 还原 acceptance criteria(buildTaskBody 的逆操作) */
33
+ export declare function parseCriteriaFromBody(body: string): AcceptanceCriterion[];
34
+ /** 从 Task Record body 的 Dependencies 区块解析依赖 Issue 号 */
35
+ export declare function parseDependenciesFromBody(body: string): number[];
36
+ /** 解析 create-task 的 depends_on 参数:"12, 13" 或 "#12,#13" → [12, 13];空/非法输入返回 [] */
37
+ export declare function parseDependenciesArg(raw: string | undefined): number[];
38
+ /** 从 Project Profile 冻结 TDD policy:enforcement 固定 runtime(PRD R6 行为变更强制 Runtime TDD) */
39
+ export declare function freezeTddPolicy(profile: ProjectProfile): TddPolicy;
40
+ /** 轻量 glob 匹配(支持 **、*、?),风险 pattern 匹配专用 */
41
+ export declare function matchRiskPattern(filePath: string, pattern: string): boolean;
42
+ /**
43
+ * 风险双层判定:模型初判 + 内核按实际 diff 升级,只升不降(PRD R8 / spec §12 #12)。
44
+ * modelRisk 为 high → high;否则 diff 命中任一 risk pattern → high;否则 low。
45
+ */
46
+ export declare function escalateRisk(modelRisk: "low" | "high", changedFiles: string[], riskPatterns: string[]): "low" | "high";
47
+ export interface ParsedEvidenceBlock {
48
+ stage: string;
49
+ fields: Record<string, string>;
50
+ }
51
+ /** 解析受控 evidence comment 为结构化 blocks;无 marker 或畸形返回 null */
52
+ export declare function parseEvidenceComment(body: string): ParsedEvidenceBlock[] | null;
53
+ /** 把受控 comment 还原为 TddEvidence(供 evaluateTddCompliance 判定);无 marker 返回 null */
54
+ export declare function evidenceCommentToTddEvidence(comment: {
55
+ id: number;
56
+ body: string;
57
+ revision: number;
58
+ }): TddEvidence | null;
59
+ export interface TaskRuntimeState {
60
+ slug: string;
61
+ parentIssueNumber: number;
62
+ issueNumber: number;
63
+ branch: string;
64
+ worktreePath: string;
65
+ policy: TddPolicy;
66
+ baseline: WorkspaceBaseline;
67
+ startedAt: string;
68
+ }
69
+ export declare function taskStatePath(projectDir: string, slug: string): string;
70
+ export declare function writeTaskState(projectDir: string, state: TaskRuntimeState): Promise<void>;
71
+ export declare function readTaskState(projectDir: string, slug: string): Promise<TaskRuntimeState | null>;
72
+ /** 设置 Task Record 状态标签(移除其它 cabbage:task:*,添加当前) */
73
+ export declare function setTaskStatusLabel(issueNumber: number, status: TaskStatus): Promise<{
74
+ ok: boolean;
75
+ error?: string;
76
+ }>;
77
+ export interface CreateTaskInput {
78
+ projectDir: string;
79
+ parentIssueNumber: number;
80
+ title: string;
81
+ acceptanceCriteriaJson?: string;
82
+ dependencies?: number[];
83
+ }
84
+ export type CreateTaskResult = {
85
+ ok: true;
86
+ ref: TaskRecordRef;
87
+ } | {
88
+ ok: false;
89
+ code: string;
90
+ message: string;
91
+ };
92
+ /**
93
+ * create-task(spec §2.3):validateTitle → slug → 未完成同名冲突检查(branch/worktree 已存在)→
94
+ * createTaskRecord(Sub Issue,body 含 acceptance criteria、依赖、Closes 约定)关联 Parent。
95
+ */
96
+ export declare function createTask(input: CreateTaskInput): Promise<CreateTaskResult>;
97
+ export type StartTaskResult = {
98
+ ok: true;
99
+ issueNumber: number;
100
+ branch: string;
101
+ worktreePath: string;
102
+ policy: TddPolicy;
103
+ baseline: WorkspaceBaseline;
104
+ } | {
105
+ ok: false;
106
+ code: string;
107
+ message: string;
108
+ };
109
+ /**
110
+ * start-task(spec §2.3):前置门禁(Planning Baseline 已合并、依赖 Task 已 merged、并行数 <5)→
111
+ * worktree-start → captureWorkspaceBaseline → freezeTddPolicy → 写 Task Record 状态。
112
+ */
113
+ export declare function startTask(projectDir: string, parentIssueNumber: number, taskId: string): Promise<StartTaskResult>;
114
+ export type SubmitTaskResult = {
115
+ ok: true;
116
+ prNumber: number;
117
+ evidenceRevision: number;
118
+ } | {
119
+ ok: false;
120
+ code: string;
121
+ message: string;
122
+ missing?: string[];
123
+ };
124
+ /**
125
+ * submit-task(spec §4.4):TDD 硬门禁——evidence 不完整(无 comment、regression 未 pass、
126
+ * compliance 未 pass)→ 拒绝创建 PR;通过后 push 分支 → gh pr create(body 引用 Task Record +
127
+ * evidence comment 链接,含 Closes 约定)→ 标记 reviewing。
128
+ */
129
+ export declare function submitTask(projectDir: string, parentIssueNumber: number, taskId: string): Promise<SubmitTaskResult>;
130
+ export type SubmitReviewResult = {
131
+ ok: true;
132
+ prNumber: number;
133
+ verdict: "approve" | "request-changes";
134
+ } | {
135
+ ok: false;
136
+ code: string;
137
+ message: string;
138
+ };
139
+ /** submit-review(spec §2.3):primary 提交 reviewer 双轴审查结果(reviewer 本身只读) */
140
+ export declare function submitReview(prNumber: number, verdict: "approve" | "request-changes", comment?: string): Promise<SubmitReviewResult>;
141
+ export type MergeTaskResult = {
142
+ ok: true;
143
+ prNumber: number;
144
+ risk: "low" | "high";
145
+ warning?: string;
146
+ } | {
147
+ ok: false;
148
+ code: string;
149
+ message: string;
150
+ };
151
+ /**
152
+ * merge-task(spec §2.3 + PRD R8):CI checks 通过 + 分支保护 + 风险双层判定(只升不降)+
153
+ * 高风险需非作者人类 approval → mergeTaskPR(--match-head-commit)→ 关闭 Sub Issue →
154
+ * worktree 干净销毁。
155
+ */
156
+ export declare function mergeTask(projectDir: string, parentIssueNumber: number, taskId: string, modelRisk: "low" | "high"): Promise<MergeTaskResult>;
157
+ /** 将原始 statusCheckRollup 映射为 {name, state}(纯函数,供测试直接验证 jq 语义) */
158
+ export declare function mapCheckRollup(raw: unknown[]): Array<{
159
+ name: string;
160
+ state: string;
161
+ }>;
162
+ export type TaskLifecycleResult = {
163
+ ok: true;
164
+ issueNumber: number;
165
+ } | {
166
+ ok: false;
167
+ code: string;
168
+ message: string;
169
+ };
170
+ export type DestroyTaskWorktreeResult = {
171
+ ok: true;
172
+ reason: string;
173
+ } | {
174
+ ok: false;
175
+ code: string;
176
+ message: string;
177
+ };
178
+ export interface TaskStatusReport {
179
+ task: {
180
+ issueNumber: number;
181
+ slug: string;
182
+ state: string;
183
+ labels: string[];
184
+ };
185
+ pullRequests: Array<{
186
+ number: number;
187
+ state: string;
188
+ headRefName: string;
189
+ checks: Array<{
190
+ name: string;
191
+ state: string;
192
+ }>;
193
+ }>;
194
+ }
195
+ export type TaskStatusResult = {
196
+ ok: true;
197
+ report: TaskStatusReport;
198
+ } | {
199
+ ok: false;
200
+ code: string;
201
+ message: string;
202
+ };
203
+ /** cancel-task:受控取消(user_confirmed)→ 关闭 Sub Issue + 状态标签 cancelled */
204
+ export declare function cancelTask(projectDir: string, parentIssueNumber: number, taskId: string, userConfirmed: boolean): Promise<TaskLifecycleResult>;
205
+ /** destroy-worktree:preflight 销毁(§3.3),需 user_confirmed(除非 PR 已合并且干净) */
206
+ export declare function destroyTaskWorktree(projectDir: string, parentIssueNumber: number, taskId: string, userConfirmed: boolean): Promise<DestroyTaskWorktreeResult>;
207
+ /** status-task:读 Task Record + PR + checks 汇总 */
208
+ export declare function readTaskStatus(projectDir: string, parentIssueNumber: number, taskId: string): Promise<TaskStatusResult>;