@devcxl/opencode-cabbage 1.0.0 → 1.2.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 (126) hide show
  1. package/README.md +19 -25
  2. package/README.zh.md +17 -23
  3. package/assets/agents/dev-lifecycle.md +208 -68
  4. package/assets/agents/team/architect.md +22 -4
  5. package/assets/agents/team/developer.md +13 -6
  6. package/assets/agents/team/goal-verify.md +4 -1
  7. package/assets/agents/team/researcher.md +59 -0
  8. package/assets/agents/team/reviewer.md +34 -18
  9. package/assets/commands/setup.md +1 -1
  10. package/assets/prompts/bootstrap.md +10 -9
  11. package/assets/prompts/stage-contract.md +25 -25
  12. package/assets/skills/flow-code/SKILL.md +23 -25
  13. package/assets/skills/flow-design/SKILL.md +94 -26
  14. package/assets/skills/flow-release/SKILL.md +41 -17
  15. package/assets/skills/flow-requirements/SKILL.md +19 -13
  16. package/assets/skills/flow-research/SKILL.md +77 -0
  17. package/assets/skills/flow-review/SKILL.md +55 -25
  18. package/assets/skills/flow-setup/SKILL.md +27 -24
  19. package/assets/skills/flow-tasks/SKILL.md +178 -35
  20. package/assets/skills/flow-tdd/SKILL.md +68 -40
  21. package/dist/kernel/context.js +12 -1
  22. package/dist/kernel/context.js.map +1 -1
  23. package/dist/kernel/permission.d.ts +1 -1
  24. package/dist/kernel/permission.js +9 -1
  25. package/dist/kernel/permission.js.map +1 -1
  26. package/dist/kernel/profile.js +5 -2
  27. package/dist/kernel/profile.js.map +1 -1
  28. package/dist/kernel/session-index.d.ts +12 -27
  29. package/dist/kernel/session-index.js +46 -80
  30. package/dist/kernel/session-index.js.map +1 -1
  31. package/dist/plugin/bootstrap.d.ts +0 -1
  32. package/dist/plugin/bootstrap.js +0 -3
  33. package/dist/plugin/bootstrap.js.map +1 -1
  34. package/dist/plugin/goal.d.ts +57 -6
  35. package/dist/plugin/goal.js +234 -86
  36. package/dist/plugin/goal.js.map +1 -1
  37. package/dist/plugin/prompt-lint.js +3 -12
  38. package/dist/plugin/prompt-lint.js.map +1 -1
  39. package/dist/plugin/prompts.d.ts +0 -1
  40. package/dist/plugin/prompts.js +0 -4
  41. package/dist/plugin/prompts.js.map +1 -1
  42. package/dist/plugin/server.d.ts +2 -5
  43. package/dist/plugin/server.js +260 -136
  44. package/dist/plugin/server.js.map +1 -1
  45. package/dist/plugin/skills.d.ts +7 -1
  46. package/dist/plugin/skills.js +75 -12
  47. package/dist/plugin/skills.js.map +1 -1
  48. package/dist/plugin.d.ts +0 -1
  49. package/dist/plugin.js +1 -4
  50. package/dist/plugin.js.map +1 -1
  51. package/dist/util/gh.d.ts +3 -9
  52. package/dist/util/gh.js +9 -11
  53. package/dist/util/gh.js.map +1 -1
  54. package/dist/util/paths.d.ts +6 -14
  55. package/dist/util/paths.js +12 -67
  56. package/dist/util/paths.js.map +1 -1
  57. package/package.json +5 -5
  58. package/assets/prompts/ADR-FORMAT.md +0 -45
  59. package/assets/prompts/PRD-FORMAT.md +0 -17
  60. package/assets/templates/gitignore +0 -5
  61. package/dist/kernel/caller.d.ts +0 -48
  62. package/dist/kernel/caller.js +0 -88
  63. package/dist/kernel/caller.js.map +0 -1
  64. package/dist/kernel/flow.d.ts +0 -166
  65. package/dist/kernel/flow.js +0 -387
  66. package/dist/kernel/flow.js.map +0 -1
  67. package/dist/kernel/legacy.d.ts +0 -19
  68. package/dist/kernel/legacy.js +0 -34
  69. package/dist/kernel/legacy.js.map +0 -1
  70. package/dist/kernel/records.d.ts +0 -87
  71. package/dist/kernel/records.js +0 -197
  72. package/dist/kernel/records.js.map +0 -1
  73. package/dist/kernel/release.d.ts +0 -104
  74. package/dist/kernel/release.js +0 -229
  75. package/dist/kernel/release.js.map +0 -1
  76. package/dist/kernel/review.d.ts +0 -34
  77. package/dist/kernel/review.js +0 -81
  78. package/dist/kernel/review.js.map +0 -1
  79. package/dist/kernel/setup.d.ts +0 -70
  80. package/dist/kernel/setup.js +0 -324
  81. package/dist/kernel/setup.js.map +0 -1
  82. package/dist/kernel/slug.d.ts +0 -23
  83. package/dist/kernel/slug.js +0 -67
  84. package/dist/kernel/slug.js.map +0 -1
  85. package/dist/kernel/task.d.ts +0 -208
  86. package/dist/kernel/task.js +0 -788
  87. package/dist/kernel/task.js.map +0 -1
  88. package/dist/kernel/tdd/adapter.d.ts +0 -49
  89. package/dist/kernel/tdd/adapter.js +0 -293
  90. package/dist/kernel/tdd/adapter.js.map +0 -1
  91. package/dist/kernel/tdd/digest.d.ts +0 -17
  92. package/dist/kernel/tdd/digest.js +0 -301
  93. package/dist/kernel/tdd/digest.js.map +0 -1
  94. package/dist/kernel/tdd/evaluator.d.ts +0 -38
  95. package/dist/kernel/tdd/evaluator.js +0 -185
  96. package/dist/kernel/tdd/evaluator.js.map +0 -1
  97. package/dist/kernel/tdd/evidence.d.ts +0 -42
  98. package/dist/kernel/tdd/evidence.js +0 -48
  99. package/dist/kernel/tdd/evidence.js.map +0 -1
  100. package/dist/kernel/tdd/state.d.ts +0 -79
  101. package/dist/kernel/tdd/state.js +0 -363
  102. package/dist/kernel/tdd/state.js.map +0 -1
  103. package/dist/kernel/types.d.ts +0 -180
  104. package/dist/kernel/types.js +0 -2
  105. package/dist/kernel/types.js.map +0 -1
  106. package/dist/kernel/worktree.d.ts +0 -45
  107. package/dist/kernel/worktree.js +0 -127
  108. package/dist/kernel/worktree.js.map +0 -1
  109. package/dist/plugin/flow-control.d.ts +0 -80
  110. package/dist/plugin/flow-control.js +0 -254
  111. package/dist/plugin/flow-control.js.map +0 -1
  112. package/dist/plugin/release-control.d.ts +0 -37
  113. package/dist/plugin/release-control.js +0 -304
  114. package/dist/plugin/release-control.js.map +0 -1
  115. package/dist/plugin/setup-control.d.ts +0 -45
  116. package/dist/plugin/setup-control.js +0 -80
  117. package/dist/plugin/setup-control.js.map +0 -1
  118. package/dist/plugin/task-control.d.ts +0 -90
  119. package/dist/plugin/task-control.js +0 -201
  120. package/dist/plugin/task-control.js.map +0 -1
  121. package/dist/plugin/tdd-checkpoint.d.ts +0 -118
  122. package/dist/plugin/tdd-checkpoint.js +0 -581
  123. package/dist/plugin/tdd-checkpoint.js.map +0 -1
  124. package/dist/util/shell.d.ts +0 -1
  125. package/dist/util/shell.js +0 -4
  126. package/dist/util/shell.js.map +0 -1
@@ -1,34 +0,0 @@
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
- }>;
@@ -1,81 +0,0 @@
1
- /**
2
- * 审查与合并 kernel 逻辑(spec §4.1,自 flowrun/merge.ts + ci.ts 迁入,逻辑不变)。
3
- * - mergeTaskPR:标准化合并 PR(--match-head-commit 防偷换)
4
- * - checkBranchProtection:默认分支保护探测
5
- * - createRevertPR:回滚 PR
6
- */
7
- let mergeGhExecutor = null;
8
- export function setMergeGhExecutor(fn) {
9
- mergeGhExecutor = fn;
10
- }
11
- async function gh(args) {
12
- if (mergeGhExecutor) {
13
- return mergeGhExecutor(args);
14
- }
15
- const mod = await import("../util/gh.js");
16
- return mod.gh(args);
17
- }
18
- // ─── Branch Protection ───
19
- export async function checkBranchProtection(owner, repo) {
20
- try {
21
- const { stdout } = await gh(`api repos/${owner}/${repo}/branches/main/protection`);
22
- const data = JSON.parse(stdout);
23
- const checks = [];
24
- const requiredPulls = data?.required_pull_request_reviews ?? null;
25
- const requiredChecks = data?.required_status_checks?.checks ?? [];
26
- for (const c of requiredChecks) {
27
- checks.push(c.context);
28
- }
29
- return {
30
- exists: true,
31
- requiredChecks: checks,
32
- requiresPR: !!requiredPulls,
33
- dismissesStale: requiredPulls?.dismiss_stale_reviews ?? false,
34
- };
35
- }
36
- catch {
37
- return {
38
- exists: false,
39
- requiredChecks: [],
40
- requiresPR: false,
41
- dismissesStale: false,
42
- };
43
- }
44
- }
45
- // ─── PR 合并操作 ───
46
- /**
47
- * Task PR 合并(带 --match-head-commit 安全检查)。
48
- *
49
- * 步骤:
50
- * 1. 验证 verifiedSha 非空
51
- * 2. 使用 gh pr merge --squash --delete-branch --match-head-commit <verifiedSha>
52
- * 3. 失败时返回错误
53
- */
54
- export async function mergeTaskPR(prNumber, verifiedSha) {
55
- if (!verifiedSha) {
56
- return { success: false, error: "verifiedSha is required for merge --match-head-commit" };
57
- }
58
- try {
59
- // --match-head-commit 确保只有 verified 的 commit 才会被合并
60
- await gh(`pr merge ${prNumber} --squash --delete-branch --match-head-commit ${verifiedSha}`);
61
- return { success: true };
62
- }
63
- catch (err) {
64
- return { success: false, error: String(err) };
65
- }
66
- }
67
- // ─── Revert ───
68
- export async function createRevertPR(prNumber, reason) {
69
- try {
70
- const { stdout } = await gh(`pr view ${prNumber} --json headRefName,headRepository,body,title`);
71
- const pr = JSON.parse(stdout);
72
- const revertTitle = `revert: ${pr.title}`;
73
- const revertBody = `Reverts #${prNumber}\n\nReason: ${reason}\n\nAuto-generated by opencode-cabbage.`;
74
- const { stdout: newPR } = await gh(`pr create --title '${revertTitle}' --body '${revertBody}' --base main --head main`);
75
- return { prNumber: parseInt(newPR.trim().split("/").pop() || "0", 10) };
76
- }
77
- catch (err) {
78
- return { error: String(err) };
79
- }
80
- }
81
- //# sourceMappingURL=review.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/kernel/review.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,IAAI,eAAe,GAAgB,IAAI,CAAA;AAEvC,MAAM,UAAU,kBAAkB,CAAC,EAAe;IAChD,eAAe,GAAG,EAAE,CAAA;AACtB,CAAC;AAED,KAAK,UAAU,EAAE,CAAC,IAAY;IAC5B,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,eAAe,CAAC,IAAI,CAAC,CAAA;IAC9B,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAA;IACzC,OAAO,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAA;AACrB,CAAC;AAWD,4BAA4B;AAE5B,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAAa,EAAE,IAAY;IACrE,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,aAAa,KAAK,IAAI,IAAI,2BAA2B,CAAC,CAAA;QAClF,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QAE/B,MAAM,MAAM,GAAa,EAAE,CAAA;QAC3B,MAAM,aAAa,GAAG,IAAI,EAAE,6BAA6B,IAAI,IAAI,CAAA;QACjE,MAAM,cAAc,GAAG,IAAI,EAAE,sBAAsB,EAAE,MAAM,IAAI,EAAE,CAAA;QAEjE,KAAK,MAAM,CAAC,IAAI,cAAc,EAAE,CAAC;YAC/B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;QACxB,CAAC;QAED,OAAO;YACL,MAAM,EAAE,IAAI;YACZ,cAAc,EAAE,MAAM;YACtB,UAAU,EAAE,CAAC,CAAC,aAAa;YAC3B,cAAc,EAAE,aAAa,EAAE,qBAAqB,IAAI,KAAK;SAC9D,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,MAAM,EAAE,KAAK;YACb,cAAc,EAAE,EAAE;YAClB,UAAU,EAAE,KAAK;YACjB,cAAc,EAAE,KAAK;SACtB,CAAA;IACH,CAAC;AACH,CAAC;AAED,kBAAkB;AAElB;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAgB,EAAE,WAAmB;IACrE,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,uDAAuD,EAAE,CAAA;IAC3F,CAAC;IAED,IAAI,CAAC;QACH,mDAAmD;QACnD,MAAM,EAAE,CAAC,YAAY,QAAQ,iDAAiD,WAAW,EAAE,CAAC,CAAA;QAC5F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IAC1B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAA;IAC/C,CAAC;AACH,CAAC;AAED,iBAAiB;AAEjB,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB,EAAE,MAAc;IACnE,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,WAAW,QAAQ,+CAA+C,CAAC,CAAA;QAC/F,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QAE7B,MAAM,WAAW,GAAG,WAAW,EAAE,CAAC,KAAK,EAAE,CAAA;QACzC,MAAM,UAAU,GAAG,YAAY,QAAQ,eAAe,MAAM,yCAAyC,CAAA;QAErG,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,CAAC,sBAAsB,WAAW,aAAa,UAAU,2BAA2B,CAAC,CAAA;QACvH,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC,EAAE,CAAA;IACzE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAA;IAC/B,CAAC;AACH,CAAC"}
@@ -1,70 +0,0 @@
1
- export type CmdResult = {
2
- stdout: string;
3
- stderr: string;
4
- };
5
- export type CmdFn = (args: string, cwd?: string) => Promise<CmdResult>;
6
- export declare function setSetupGitExecutor(fn: CmdFn | null): void;
7
- export declare function setSetupGhExecutor(fn: CmdFn | null): void;
8
- export interface SetupProbeReport {
9
- gitAvailable: boolean;
10
- ghAuthenticated: boolean;
11
- hasRemote: boolean;
12
- defaultBranch: string | null;
13
- profileConfirmed: boolean;
14
- tddCommandExecutable: boolean;
15
- ciWorkflow: string | null;
16
- releaseWorkflow: string | null;
17
- contextMdPresent: boolean;
18
- branchProtection: boolean;
19
- versionRuleConfirmed: boolean;
20
- developmentReady: boolean;
21
- releaseReady: boolean;
22
- }
23
- /**
24
- * 探测项目 setup 就绪度(PRD R10)。
25
- * development-ready:git/gh + Profile 确认 + TDD 命令可执行 + CI workflow + 分支保护;
26
- * release-ready:额外版本规则 + release workflow。
27
- */
28
- export declare function probe(projectDir: string): Promise<SetupProbeReport>;
29
- /** 从 git remote URL 解析 GitHub owner/repo;非 GitHub 仓库返回 null */
30
- export declare function parseGithubRemote(url: string): {
31
- owner: string;
32
- repo: string;
33
- } | null;
34
- export interface GenerateWorkflowsInput {
35
- prTitle: string;
36
- defaultBranch?: string | null;
37
- testCommand?: string | null;
38
- tagFormat?: string | null;
39
- releaseWorkflowPath?: string | null;
40
- }
41
- export interface GenerateWorkflowsResult {
42
- ok: boolean;
43
- created: string[];
44
- existing: string[];
45
- branch: string | null;
46
- prNumber: number | null;
47
- error?: string;
48
- }
49
- /**
50
- * 缺失时生成 CI/release workflow 草案(技术栈无关,不硬编码包管理器),
51
- * 创建 chore/setup-workflows 分支 + commit + push + Setup PR(人工合入)。
52
- */
53
- export declare function generateWorkflows(projectDir: string, input: GenerateWorkflowsInput): Promise<GenerateWorkflowsResult>;
54
- /** CI workflow 草案:PR check 触发,运行 Profile 的测试命令(无则占位) */
55
- export declare function buildCiWorkflow(testCommand: string | null, defaultBranch: string | null): string;
56
- /** release workflow 草案:tag 触发,技术栈无关占位步骤 */
57
- export declare function buildReleaseWorkflow(tagFormat: string | null): string;
58
- export interface ConfirmProfileResult {
59
- ok: boolean;
60
- block?: string;
61
- code?: string;
62
- message?: string;
63
- }
64
- /** 由用户确认的 overrides 生成完整 `## Project Profile` 区块(未提供的键省略) */
65
- export declare function buildProfileBlock(overrides: Record<string, unknown>): string;
66
- /**
67
- * 用户确认后把 Profile 区块写回根 AGENTS.md(§9.3)。
68
- * 先读后写,按 key 串行(mutex);testCommand 为必需键。
69
- */
70
- export declare function confirmProjectProfile(projectDir: string, overridesJson: string): Promise<ConfirmProfileResult>;
@@ -1,324 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/kernel/setup.ts"],"names":[],"mappings":"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"}
@@ -1,23 +0,0 @@
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;
@@ -1,67 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"slug.js","sourceRoot":"","sources":["../../src/kernel/slug.ts"],"names":[],"mappings":"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"}