@devcxl/opencode-cabbage 1.1.0 → 1.3.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 (142) hide show
  1. package/.codex-plugin/plugin.json +36 -0
  2. package/README.md +53 -25
  3. package/README.zh.md +23 -23
  4. package/assets/agents/dev-lifecycle.md +208 -68
  5. package/assets/agents/team/architect.md +22 -7
  6. package/assets/agents/team/developer.md +13 -6
  7. package/assets/agents/team/goal-verify.md +4 -1
  8. package/assets/agents/team/researcher.md +59 -0
  9. package/assets/agents/team/reviewer.md +34 -18
  10. package/assets/commands/setup.md +1 -1
  11. package/assets/prompts/bootstrap.md +10 -9
  12. package/assets/prompts/stage-contract.md +25 -25
  13. package/assets/skills/flow-code/SKILL.md +23 -25
  14. package/assets/skills/flow-design/SKILL.md +94 -26
  15. package/assets/skills/flow-release/SKILL.md +41 -17
  16. package/assets/skills/flow-requirements/SKILL.md +19 -13
  17. package/assets/skills/flow-research/SKILL.md +77 -0
  18. package/assets/skills/flow-review/SKILL.md +55 -25
  19. package/assets/skills/flow-setup/SKILL.md +27 -24
  20. package/assets/skills/flow-tasks/SKILL.md +178 -35
  21. package/assets/skills/flow-tdd/SKILL.md +68 -40
  22. package/codex-skills/agent-architect/SKILL.md +79 -0
  23. package/codex-skills/agent-dev-lifecycle/SKILL.md +309 -0
  24. package/codex-skills/agent-developer/SKILL.md +51 -0
  25. package/codex-skills/agent-goal-verify/SKILL.md +45 -0
  26. package/codex-skills/agent-researcher/SKILL.md +32 -0
  27. package/codex-skills/agent-reviewer/SKILL.md +109 -0
  28. package/codex-skills/flow-code/SKILL.md +71 -0
  29. package/codex-skills/flow-design/SKILL.md +146 -0
  30. package/codex-skills/flow-release/SKILL.md +90 -0
  31. package/codex-skills/flow-requirements/SKILL.md +90 -0
  32. package/codex-skills/flow-research/SKILL.md +77 -0
  33. package/codex-skills/flow-review/SKILL.md +110 -0
  34. package/codex-skills/flow-setup/SKILL.md +75 -0
  35. package/codex-skills/flow-tasks/SKILL.md +220 -0
  36. package/codex-skills/flow-tdd/SKILL.md +235 -0
  37. package/dist/hooks/session-start.d.ts +1 -0
  38. package/dist/hooks/session-start.js +72 -0
  39. package/dist/hooks/session-start.js.map +1 -0
  40. package/dist/kernel/session-index.d.ts +8 -25
  41. package/dist/kernel/session-index.js +5 -55
  42. package/dist/kernel/session-index.js.map +1 -1
  43. package/dist/plugin/bootstrap.d.ts +0 -1
  44. package/dist/plugin/bootstrap.js +0 -3
  45. package/dist/plugin/bootstrap.js.map +1 -1
  46. package/dist/plugin/goal-store.d.ts +71 -0
  47. package/dist/plugin/goal-store.js +54 -0
  48. package/dist/plugin/goal-store.js.map +1 -0
  49. package/dist/plugin/goal.d.ts +47 -13
  50. package/dist/plugin/goal.js +228 -128
  51. package/dist/plugin/goal.js.map +1 -1
  52. package/dist/plugin/prompt-lint.js +3 -11
  53. package/dist/plugin/prompt-lint.js.map +1 -1
  54. package/dist/plugin/prompts.d.ts +0 -1
  55. package/dist/plugin/prompts.js +0 -4
  56. package/dist/plugin/prompts.js.map +1 -1
  57. package/dist/plugin/server.d.ts +3 -5
  58. package/dist/plugin/server.js +247 -155
  59. package/dist/plugin/server.js.map +1 -1
  60. package/dist/plugin/skills.d.ts +7 -1
  61. package/dist/plugin/skills.js +75 -12
  62. package/dist/plugin/skills.js.map +1 -1
  63. package/dist/plugin.d.ts +0 -1
  64. package/dist/plugin.js +1 -4
  65. package/dist/plugin.js.map +1 -1
  66. package/dist/util/gh.d.ts +0 -11
  67. package/dist/util/gh.js +0 -14
  68. package/dist/util/gh.js.map +1 -1
  69. package/dist/util/paths.d.ts +0 -14
  70. package/dist/util/paths.js +0 -69
  71. package/dist/util/paths.js.map +1 -1
  72. package/hooks/hooks.json +17 -0
  73. package/package.json +12 -4
  74. package/assets/prompts/ADR-FORMAT.md +0 -45
  75. package/assets/prompts/PRD-FORMAT.md +0 -17
  76. package/assets/templates/gitignore +0 -5
  77. package/dist/kernel/caller.d.ts +0 -48
  78. package/dist/kernel/caller.js +0 -88
  79. package/dist/kernel/caller.js.map +0 -1
  80. package/dist/kernel/flow.d.ts +0 -175
  81. package/dist/kernel/flow.js +0 -467
  82. package/dist/kernel/flow.js.map +0 -1
  83. package/dist/kernel/legacy.d.ts +0 -19
  84. package/dist/kernel/legacy.js +0 -34
  85. package/dist/kernel/legacy.js.map +0 -1
  86. package/dist/kernel/records.d.ts +0 -103
  87. package/dist/kernel/records.js +0 -240
  88. package/dist/kernel/records.js.map +0 -1
  89. package/dist/kernel/release.d.ts +0 -106
  90. package/dist/kernel/release.js +0 -241
  91. package/dist/kernel/release.js.map +0 -1
  92. package/dist/kernel/review.d.ts +0 -34
  93. package/dist/kernel/review.js +0 -82
  94. package/dist/kernel/review.js.map +0 -1
  95. package/dist/kernel/setup.d.ts +0 -95
  96. package/dist/kernel/setup.js +0 -401
  97. package/dist/kernel/setup.js.map +0 -1
  98. package/dist/kernel/slug.d.ts +0 -23
  99. package/dist/kernel/slug.js +0 -67
  100. package/dist/kernel/slug.js.map +0 -1
  101. package/dist/kernel/task.d.ts +0 -213
  102. package/dist/kernel/task.js +0 -873
  103. package/dist/kernel/task.js.map +0 -1
  104. package/dist/kernel/tdd/adapter.d.ts +0 -49
  105. package/dist/kernel/tdd/adapter.js +0 -294
  106. package/dist/kernel/tdd/adapter.js.map +0 -1
  107. package/dist/kernel/tdd/digest.d.ts +0 -18
  108. package/dist/kernel/tdd/digest.js +0 -303
  109. package/dist/kernel/tdd/digest.js.map +0 -1
  110. package/dist/kernel/tdd/evaluator.d.ts +0 -38
  111. package/dist/kernel/tdd/evaluator.js +0 -185
  112. package/dist/kernel/tdd/evaluator.js.map +0 -1
  113. package/dist/kernel/tdd/evidence.d.ts +0 -42
  114. package/dist/kernel/tdd/evidence.js +0 -48
  115. package/dist/kernel/tdd/evidence.js.map +0 -1
  116. package/dist/kernel/tdd/state.d.ts +0 -79
  117. package/dist/kernel/tdd/state.js +0 -363
  118. package/dist/kernel/tdd/state.js.map +0 -1
  119. package/dist/kernel/types.d.ts +0 -180
  120. package/dist/kernel/types.js +0 -2
  121. package/dist/kernel/types.js.map +0 -1
  122. package/dist/kernel/worktree.d.ts +0 -45
  123. package/dist/kernel/worktree.js +0 -156
  124. package/dist/kernel/worktree.js.map +0 -1
  125. package/dist/plugin/flow-control.d.ts +0 -91
  126. package/dist/plugin/flow-control.js +0 -287
  127. package/dist/plugin/flow-control.js.map +0 -1
  128. package/dist/plugin/release-control.d.ts +0 -39
  129. package/dist/plugin/release-control.js +0 -343
  130. package/dist/plugin/release-control.js.map +0 -1
  131. package/dist/plugin/setup-control.d.ts +0 -59
  132. package/dist/plugin/setup-control.js +0 -111
  133. package/dist/plugin/setup-control.js.map +0 -1
  134. package/dist/plugin/task-control.d.ts +0 -90
  135. package/dist/plugin/task-control.js +0 -208
  136. package/dist/plugin/task-control.js.map +0 -1
  137. package/dist/plugin/tdd-checkpoint.d.ts +0 -128
  138. package/dist/plugin/tdd-checkpoint.js +0 -664
  139. package/dist/plugin/tdd-checkpoint.js.map +0 -1
  140. package/dist/util/shell.d.ts +0 -1
  141. package/dist/util/shell.js +0 -4
  142. package/dist/util/shell.js.map +0 -1
@@ -2,26 +2,89 @@ import { cp, mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
3
  import path from "node:path";
4
4
  /**
5
- * skills 固定安装路径,确保跨会话稳定。
5
+ * skills 固定安装路径(按插件版本隔离,skills@<version>)。
6
6
  * 用 env CABBAGE_SKILLS_DIR 可覆盖,方便测试。
7
7
  */
8
- function resolveSkillsPath() {
8
+ function resolveSkillsPath(version) {
9
9
  if (process.env.CABBAGE_SKILLS_DIR) {
10
- return process.env.CABBAGE_SKILLS_DIR;
10
+ return path.join(process.env.CABBAGE_SKILLS_DIR, `skills@${version}`);
11
11
  }
12
- return path.join(homedir(), ".config", "opencode", "cabbage", "skills");
12
+ return path.join(homedir(), ".config", "opencode", "cabbage", `skills@${version}`);
13
13
  }
14
- export async function setupSkillsDir(sourceSkillsDir, promptsDir) {
15
- const destDir = resolveSkillsPath();
16
- // 清理旧内容,确保与插件版本一致
17
- await rm(destDir, { recursive: true, force: true });
18
- await mkdir(destDir, { recursive: true });
19
- await cp(sourceSkillsDir, destDir, { recursive: true });
14
+ /** 安装锁:mkdir 原子性互斥,防多实例并发 rm+cp 踩踏(超时放弃而非死等) */
15
+ async function acquireLock(lockPath, timeoutMs = 10_000) {
16
+ await mkdir(path.dirname(lockPath), { recursive: true });
17
+ const start = Date.now();
18
+ for (;;) {
19
+ try {
20
+ await mkdir(lockPath);
21
+ return async () => {
22
+ await rm(lockPath, { recursive: true, force: true }).catch(() => undefined);
23
+ };
24
+ }
25
+ catch (err) {
26
+ if (err.code !== "EEXIST")
27
+ throw err;
28
+ if (Date.now() - start > timeoutMs) {
29
+ throw new Error(`[cabbage] timed out waiting for skills install lock: ${lockPath}`);
30
+ }
31
+ await new Promise(r => setTimeout(r, 100));
32
+ }
33
+ }
34
+ }
35
+ /**
36
+ * 安装目录结构完整(目录列表与源一致)→ 跳过全量重建;否则重建。
37
+ * - 目录带插件版本号(skills@<version>):升级插件后自动重装新版本内容,
38
+ * 且同一机器上不同版本插件共存时互不覆盖(P2-4 多版本踩踏修复)。
39
+ * - 重建在锁内执行(mkdir 原子锁 + 锁内二次检查),防多实例并发 rm+cp 竞态。
40
+ */
41
+ export async function setupSkillsDir(sourceSkillsDir, promptsDir, version = "0.0.0") {
42
+ const destDir = resolveSkillsPath(version);
43
+ // 已安装且完整(目录列表与源一致)→ 跳过全量重建(防多实例并发踩踏与无谓 IO)
44
+ const sourceDirs = (await readdir(sourceSkillsDir, { withFileTypes: true }))
45
+ .filter(e => e.isDirectory()).map(e => e.name);
46
+ let installed = false;
47
+ try {
48
+ const destDirs = (await readdir(destDir, { withFileTypes: true }))
49
+ .filter(e => e.isDirectory()).map(e => e.name);
50
+ installed = sourceDirs.every(d => destDirs.includes(d)) && destDirs.length === sourceDirs.length;
51
+ }
52
+ catch {
53
+ installed = false;
54
+ }
55
+ if (!installed) {
56
+ const release = await acquireLock(`${destDir}.lock`);
57
+ try {
58
+ // 锁内二次检查:等待期间其它实例可能已装好,避免重复 rm+cp
59
+ let recheck = false;
60
+ try {
61
+ const destDirs = (await readdir(destDir, { withFileTypes: true }))
62
+ .filter(e => e.isDirectory()).map(e => e.name);
63
+ recheck = sourceDirs.every(d => destDirs.includes(d)) && destDirs.length === sourceDirs.length;
64
+ }
65
+ catch {
66
+ recheck = false;
67
+ }
68
+ if (!recheck) {
69
+ await rm(destDir, { recursive: true, force: true });
70
+ await mkdir(destDir, { recursive: true });
71
+ await cp(sourceSkillsDir, destDir, { recursive: true });
72
+ }
73
+ }
74
+ finally {
75
+ await release();
76
+ }
77
+ }
20
78
  if (promptsDir) {
79
+ const promptsDest = path.join(destDir, "_prompts");
21
80
  try {
22
- await cp(promptsDir, path.join(destDir, "_prompts"), { recursive: true });
81
+ // 同步 _prompts:先清空再拷贝,保证源中删除的文件不残留
82
+ await rm(promptsDest, { recursive: true, force: true });
83
+ await cp(promptsDir, promptsDest, { recursive: true });
84
+ }
85
+ catch (err) {
86
+ console.warn("[cabbage] failed to copy prompts dir into skills:", err);
23
87
  }
24
- catch { }
25
88
  }
26
89
  async function processDir(dir) {
27
90
  const entries = await readdir(dir, { withFileTypes: true });
@@ -1 +1 @@
1
- {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/plugin/skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B;;;GAGG;AACH,SAAS,iBAAiB;IACxB,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC;QACnC,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAA;IACvC,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAA;AACzE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,eAAuB,EAAE,UAAmB;IAC/E,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAA;IAEnC,kBAAkB;IAClB,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACnD,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAEzC,MAAM,EAAE,CAAC,eAAe,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAEvD,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC3E,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAED,KAAK,UAAU,UAAU,CAAC,GAAW;QACnC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;QAC3D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;YAC3C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAA;gBAC1B,SAAQ;YACV,CAAC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC9B,IAAI,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;gBAC9C,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,mBAAmB,EAAE,GAAG,OAAO,GAAG,CAAC,CAAA;gBAChE,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,UAAU,CAAC,OAAO,CAAC,CAAA;IAEzB,OAAO,OAAO,CAAA;AAChB,CAAC"}
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/plugin/skills.ts"],"names":[],"mappings":"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"}
package/dist/plugin.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  import type { Plugin } from "@opencode-ai/plugin";
2
- export declare function resolvePackageRoot(metaUrl: string): string;
3
2
  export declare const OpencodeCabbage: Plugin;
package/dist/plugin.js CHANGED
@@ -1,9 +1,6 @@
1
1
  import path from "node:path";
2
2
  import { fileURLToPath } from "node:url";
3
3
  import { createOpencodeCabbage } from "./plugin/server.js";
4
- export function resolvePackageRoot(metaUrl) {
5
- return path.resolve(path.dirname(fileURLToPath(metaUrl)), "..");
6
- }
7
- const packageRoot = resolvePackageRoot(import.meta.url);
4
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
8
5
  export const OpencodeCabbage = createOpencodeCabbage(packageRoot);
9
6
  //# sourceMappingURL=plugin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAE1D,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;AACjE,CAAC;AAED,MAAM,WAAW,GAAG,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAEvD,MAAM,CAAC,MAAM,eAAe,GAAW,qBAAqB,CAAC,WAAW,CAAC,CAAA"}
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAE1D,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;AAEpF,MAAM,CAAC,MAAM,eAAe,GAAW,qBAAqB,CAAC,WAAW,CAAC,CAAA"}
package/dist/util/gh.d.ts CHANGED
@@ -1,14 +1,3 @@
1
- /**
2
- * 执行 gh CLI 命令。
3
- *
4
- * @param args gh 子命令及参数
5
- * @param timeout 超时毫秒数(默认 30s)
6
- * @param env 可选的环境变量覆盖(如注入 GH_TOKEN)
7
- */
8
- export declare function gh(args: string, timeout?: number, env?: Record<string, string>): Promise<{
9
- stdout: string;
10
- stderr: string;
11
- }>;
12
1
  /**
13
2
  * 从 gh pr create 的 stdout(PR URL,如 https://github.com/owner/repo/pull/123)解析 PR 编号。
14
3
  * gh pr create 不支持 --json/--jq,只能解析 URL 末尾数字;解析失败返回 null。
package/dist/util/gh.js CHANGED
@@ -1,17 +1,3 @@
1
- import { exec } from "node:child_process";
2
- import { promisify } from "node:util";
3
- const execAsync = promisify(exec);
4
- /**
5
- * 执行 gh CLI 命令。
6
- *
7
- * @param args gh 子命令及参数
8
- * @param timeout 超时毫秒数(默认 30s)
9
- * @param env 可选的环境变量覆盖(如注入 GH_TOKEN)
10
- */
11
- export function gh(args, timeout = 30_000, env) {
12
- const execEnv = env ? { ...process.env, ...env } : process.env;
13
- return execAsync(`gh ${args}`, { timeout, env: execEnv });
14
- }
15
1
  /**
16
2
  * 从 gh pr create 的 stdout(PR URL,如 https://github.com/owner/repo/pull/123)解析 PR 编号。
17
3
  * gh pr create 不支持 --json/--jq,只能解析 URL 末尾数字;解析失败返回 null。
@@ -1 +1 @@
1
- {"version":3,"file":"gh.js","sourceRoot":"","sources":["../../src/util/gh.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;AAEjC;;;;;;GAMG;AACH,MAAM,UAAU,EAAE,CAAC,IAAY,EAAE,OAAO,GAAG,MAAM,EAAE,GAA4B;IAC7E,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAA;IAC9D,OAAO,SAAS,CAAC,MAAM,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAA;AAC3D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAA;IAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;IACxC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAC1B,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAChD,CAAC"}
1
+ {"version":3,"file":"gh.js","sourceRoot":"","sources":["../../src/util/gh.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAA;IAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;IACxC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAC1B,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAChD,CAAC"}
@@ -5,17 +5,3 @@ export declare const PLUGIN_ID = "opencode-cabbage";
5
5
  * ToolContext.directory 才是 session 的项目目录。优先使用它,无效(空/相对/`/`)时退化到插件级 projectDir。
6
6
  */
7
7
  export declare function resolveProjectDir(ctxDirectory: string | undefined, fallback: string): string;
8
- export declare function slugify(value: string): string;
9
- export declare function toRelativePath(projectDir: string, targetPath: string): string;
10
- export declare function prdDir(projectDir: string): string;
11
- export declare function adrDir(projectDir: string): string;
12
- export declare function devSpecsDir(projectDir: string): string;
13
- export declare function devTasksDir(projectDir: string): string;
14
- export declare function devApiDir(projectDir: string): string;
15
- export declare function devDbDir(projectDir: string): string;
16
- export declare function devGuidesDir(projectDir: string): string;
17
- export declare function prdPath(projectDir: string, name: string): string;
18
- export declare function adrPath(projectDir: string, title: string): string;
19
- export declare function taskPath(projectDir: string, taskName: string): string;
20
- export declare function pluginTemplateDir(projectDir: string): string;
21
- export declare function ensureDocsStructure(projectDir: string): Promise<string[]>;
@@ -1,6 +1,4 @@
1
- import { mkdir } from "node:fs/promises";
2
1
  import path from "node:path";
3
- import { pathExists } from "./fs.js";
4
2
  export const PLUGIN_ID = "opencode-cabbage";
5
3
  /**
6
4
  * 解析会话级项目目录。
@@ -16,71 +14,4 @@ export function resolveProjectDir(ctxDirectory, fallback) {
16
14
  }
17
15
  return fallback;
18
16
  }
19
- const MAX_SLUG_LENGTH = 60;
20
- export function slugify(value) {
21
- let slug = value
22
- .trim()
23
- .toLowerCase()
24
- .replace(/[^a-z0-9]+/g, "-")
25
- .replace(/^-+|-+$/g, "")
26
- .replace(/--+/g, "-");
27
- if (slug.length > MAX_SLUG_LENGTH) {
28
- const sliced = slug.slice(0, MAX_SLUG_LENGTH);
29
- const lastDash = sliced.lastIndexOf("-");
30
- slug = lastDash > MAX_SLUG_LENGTH / 2 ? sliced.slice(0, lastDash) : sliced;
31
- }
32
- return slug || "doc";
33
- }
34
- export function toRelativePath(projectDir, targetPath) {
35
- return path.relative(projectDir, targetPath).replace(/\\/g, "/");
36
- }
37
- function docsRoot(projectDir) {
38
- return path.join(projectDir, "docs");
39
- }
40
- export function prdDir(projectDir) {
41
- return path.join(docsRoot(projectDir), "prd");
42
- }
43
- export function adrDir(projectDir) {
44
- return path.join(docsRoot(projectDir), "adr");
45
- }
46
- export function devSpecsDir(projectDir) {
47
- return path.join(docsRoot(projectDir), "dev", "specs");
48
- }
49
- export function devTasksDir(projectDir) {
50
- return path.join(docsRoot(projectDir), "dev", "tasks");
51
- }
52
- export function devApiDir(projectDir) {
53
- return path.join(docsRoot(projectDir), "dev", "api");
54
- }
55
- export function devDbDir(projectDir) {
56
- return path.join(docsRoot(projectDir), "dev", "db");
57
- }
58
- export function devGuidesDir(projectDir) {
59
- return path.join(docsRoot(projectDir), "dev", "guides");
60
- }
61
- export function prdPath(projectDir, name) {
62
- return path.join(prdDir(projectDir), `${slugify(name)}.md`);
63
- }
64
- export function adrPath(projectDir, title) {
65
- const date = new Date().toISOString().slice(0, 10);
66
- return path.join(adrDir(projectDir), `${date}-${slugify(title)}.md`);
67
- }
68
- export function taskPath(projectDir, taskName) {
69
- return path.join(devTasksDir(projectDir), `${slugify(taskName)}.md`);
70
- }
71
- export function pluginTemplateDir(projectDir) {
72
- return path.join(projectDir, ".opencode", PLUGIN_ID, "templates");
73
- }
74
- const DOCS_SUBDIRS = ["prd", "adr", "dev/specs", "dev/tasks", "dev/api", "dev/db", "dev/guides"];
75
- export async function ensureDocsStructure(projectDir) {
76
- const created = [];
77
- for (const sub of DOCS_SUBDIRS) {
78
- const target = path.join(docsRoot(projectDir), sub);
79
- if (!(await pathExists(target))) {
80
- await mkdir(target, { recursive: true });
81
- created.push(toRelativePath(projectDir, target));
82
- }
83
- }
84
- return created;
85
- }
86
17
  //# sourceMappingURL=paths.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/util/paths.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/util/paths.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,MAAM,CAAC,MAAM,SAAS,GAAG,kBAAkB,CAAA;AAE3C;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,YAAgC,EAAE,QAAgB;IAClF,IACE,OAAO,YAAY,KAAK,QAAQ;QAChC,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE;QAC1B,YAAY,KAAK,GAAG;QACpB,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAC7B,CAAC;QACD,OAAO,YAAY,CAAA;IACrB,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC"}
@@ -0,0 +1,17 @@
1
+ {
2
+ "hooks": {
3
+ "SessionStart": [
4
+ {
5
+ "matcher": "startup|resume",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "node ${PLUGIN_ROOT}/dist/hooks/session-start.js",
10
+ "statusMessage": "Loading Cabbage development context",
11
+ "timeout": 10
12
+ }
13
+ ]
14
+ }
15
+ ]
16
+ }
17
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devcxl/opencode-cabbage",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "OpenCode 全流程开发插件 — 需求→设计→任务→编码→测试→审查→自动合并,支持自动编排与并行 Subagent",
5
5
  "repository": {
6
6
  "type": "git",
@@ -11,6 +11,11 @@
11
11
  "url": "https://github.com/devcxl/opencode-cabbage/issues"
12
12
  },
13
13
  "keywords": [
14
+ "codex",
15
+ "codex-plugin",
16
+ "development-workflow",
17
+ "orchestration",
18
+ "tdd",
14
19
  "opencode",
15
20
  "opencode-plugin"
16
21
  ],
@@ -34,7 +39,10 @@
34
39
  "files": [
35
40
  "dist",
36
41
  "assets",
37
- "README.md"
42
+ "README.md",
43
+ ".codex-plugin",
44
+ "codex-skills",
45
+ "hooks"
38
46
  ],
39
47
  "publishConfig": {
40
48
  "registry": "https://registry.npmjs.org/",
@@ -42,11 +50,11 @@
42
50
  },
43
51
  "scripts": {
44
52
  "build": "rm -rf dist && tsc -p tsconfig.json",
45
- "prepublishOnly": "npm test && npm run typecheck && npm run build",
53
+ "prepublishOnly": "npm run build",
46
54
  "typecheck": "tsc -p tsconfig.json --noEmit",
47
55
  "test": "vitest run",
48
56
  "prompt-lint": "vitest run test/plugin/prompt-lint.test.ts",
49
- "test:pack": "npm run build && pack_out=$(npm pack --dry-run 2>&1); echo \"$pack_out\" | grep -q 'dist/kernel/' || { echo 'FAIL: tarball 缺少 dist/kernel/'; exit 1; }; echo \"$pack_out\" | grep -q 'dist/flowrun/' && { echo 'FAIL: tarball 含过期 flowrun/ 残留'; exit 1; }; echo 'PASS: tarball 含 dist/kernel/,无 flowrun/ 残留'",
57
+ "test:pack": "npm run build && pack_out=$(npm pack --dry-run 2>&1); echo \"$pack_out\" | grep -q 'dist/kernel/' || { echo 'FAIL: tarball 缺少 dist/kernel/'; exit 1; }; echo \"$pack_out\" | grep -q 'dist/flowrun/' && { echo 'FAIL: tarball 含过期 flowrun/ 残留'; exit 1; }; for f in '.codex-plugin/plugin.json' 'codex-skills/flow-setup/SKILL.md' 'codex-skills/agent-dev-lifecycle/SKILL.md' 'hooks/hooks.json' 'dist/hooks/session-start.js'; do echo \"$pack_out\" | grep -q \"$f\" || { echo \"FAIL: tarball 缺少 $f\"; exit 1; }; done; echo 'PASS: tarball 含 dist/kernel/ + Codex 插件文件(manifest/skills/hooks/dist-hooks),无 flowrun/ 残留'",
50
58
  "docs:dev": "vitepress dev docs",
51
59
  "docs:build": "vitepress build docs",
52
60
  "docs:preview": "vitepress preview docs"
@@ -1,45 +0,0 @@
1
- # ADR 格式
2
-
3
- 架构决策记录(ADR)存放在 `docs/adr/` 目录中。每个 ADR 都是一个独立的 markdown 文件,记录了一项架构决策及其背景和理由。
4
-
5
- > 命名惯例:`NNNN-slug.md`(例如 `0001-use-sqlite.md`)。
6
-
7
- ## ADR 的内容
8
-
9
- ADR 的核心在于说明**为什么选择某个方案**。一个可靠的 ADR 会包含:
10
-
11
- - **标题** —— 决策的简要命名
12
- - **状态** —— 已提议 / 已接受 / 已废弃 / 已取代
13
- - **背景** —— 促使做出该决策的问题或约束
14
- - **决策** —— 团队最终选择的方案
15
- - **备选方案** —— 被考虑但未被采纳的方案,以及未采纳的原因
16
- - **后果** —— 该决策带来的影响,包括正面和负面的
17
-
18
- ## 如何解读一个 ADR
19
-
20
- 当你阅读一个 ADR 时,问自己:
21
-
22
- ### 这项决策制定了什么规矩?
23
-
24
- ADR 的核心是**决策**本身。注意那些强制性的措辞(如"必须"、"禁止"),以及明确说明的方案选择。
25
-
26
- ### 为什么这个方案优于其他方案?
27
-
28
- 阅读**备选方案**部分。团队考虑了哪些其他选择?为什么它们被否决了?这段会告诉你哪些路径是有意不走的——这一点在审查新功能时非常关键。
29
-
30
- ### 有哪些已知的权衡?
31
-
32
- 阅读**后果**部分。每一项决策都会带来取舍。了解这些取舍,你就能在审查与该决策相关的新代码时更敏锐地发现潜在的摩擦点。
33
-
34
- ### 这个 ADR 还是现行有效的吗?
35
-
36
- 检查**状态**。一个 ADR 可能被更新的 ADR 所取代(状态为 `已取代`,并在顶部标有 superseeding 引用)。如果被取代,你应当查阅取代它的 ADR,以获取最新的决策信息。
37
-
38
- ## 给子技能的说明
39
-
40
- 当 `grill-with-docs` 或 `triage` 告诉你"结合 ADR 进行审查"时,即意味着你要:
41
-
42
- 1. 阅读与该领域相关的近期 ADR
43
- 2. 检查提案是否违反了任何现行有效的 ADR
44
- 3. 如果提案与 ADR 发生冲突,判断是需要修改提案,还是应该重新审视该 ADR
45
- 4. 将你的发现连同相关 ADR 的具体引用一并列出来
@@ -1,17 +0,0 @@
1
- # PRD 格式
2
-
3
- 产品需求文档存放在 `docs/prd/` 目录中。
4
-
5
- ## PRD 内容结构
6
-
7
- - **Title**: 功能名称
8
- - **Status**: Draft | Review | Approved
9
- - **背景与动机**: 为什么要做?
10
- - **目标**: 希望达成的效果
11
- - **范围**:
12
- - In Scope: 明确包含的部分
13
- - Out of Scope: 明确不包含的部分
14
- - **用户故事**: 作为<角色>,我希望<功能>,以便<价值>
15
- - **验收标准**: 可量化、可测试的完成条件
16
- - **技术约束**: 语言、框架、部署、性能等限制
17
- - **Open Questions**: 待讨论/待确认的问题
@@ -1,5 +0,0 @@
1
- node_modules/
2
- dist/
3
-
4
- # OpenCode plugin — parallel development worktrees
5
- .worktree/
@@ -1,48 +0,0 @@
1
- /**
2
- * 工具调用者校验原语(spec §2.2)。
3
- *
4
- * 判定:`ctx.agent` 为 agent 名;session 无 parentID(经 session client 检查)→ primary;
5
- * 子会话按 agent 名映射角色,未知 agent 保守视为 reviewer(最低权限)。
6
- */
7
- export type CallerRole = "primary" | "developer" | "architect" | "reviewer" | "goal-verify";
8
- /** 5 个生命周期工具(spec §2.2 / PRD R4) */
9
- export declare const LIFECYCLE_TOOLS: readonly ["setup_control", "flow_control", "task_control", "tdd_checkpoint", "release_control"];
10
- /**
11
- * 解析工具(+op)允许的角色集。op 级覆盖优先;未知工具保守返回空集(fail-closed)。
12
- */
13
- export declare function rolesForTool(tool: string, op?: string): CallerRole[];
14
- /** requireCaller 拒绝时的错误码 */
15
- export declare const CALLER_NOT_AUTHORIZED = "CALLER_NOT_AUTHORIZED";
16
- /** 工具 execute 上下文的最小可见面(ToolContext 的子集) */
17
- export interface CallerContext {
18
- agent: string;
19
- sessionID: string;
20
- }
21
- /** session client 的最小可见面(goalClient 的子集) */
22
- export interface CallerSessionClient {
23
- session: {
24
- get(input: {
25
- sessionID: string;
26
- }): Promise<{
27
- data?: {
28
- parentID?: string | null;
29
- };
30
- }>;
31
- };
32
- }
33
- /**
34
- * 解析调用者角色:无 parentID(session 查询成功且 data 存在)→ primary;
35
- * 查询失败/无 data → 保守视为 reviewer(最低权限,fail-closed);
36
- * 子会话按 agent 名映射;未知 agent → reviewer。
37
- */
38
- export declare function resolveCaller(ctx: CallerContext, client: CallerSessionClient): Promise<CallerRole>;
39
- /**
40
- * 调用者门禁原语:角色在 allowedRoles 内返回 null(通过),
41
- * 否则返回含 CALLER_NOT_AUTHORIZED 码的错误消息(调用方组装 `{ code, message }` 响应)。
42
- */
43
- export declare function requireCaller(ctx: CallerContext, allowedRoles: CallerRole[], op: string, client: CallerSessionClient): Promise<string | null>;
44
- /**
45
- * 工具级 caller 门禁:按工具(+op)矩阵解析允许角色后校验。
46
- * 供各生命周期工具 execute 内调用(spec §2.2 第一道门;config 层为第二道门)。
47
- */
48
- export declare function requireToolCaller(ctx: CallerContext, tool: string, op: string | undefined, client: CallerSessionClient): Promise<string | null>;
@@ -1,88 +0,0 @@
1
- /**
2
- * 工具调用者校验原语(spec §2.2)。
3
- *
4
- * 判定:`ctx.agent` 为 agent 名;session 无 parentID(经 session client 检查)→ primary;
5
- * 子会话按 agent 名映射角色,未知 agent 保守视为 reviewer(最低权限)。
6
- */
7
- /** 5 个生命周期工具(spec §2.2 / PRD R4) */
8
- export const LIFECYCLE_TOOLS = [
9
- "setup_control",
10
- "flow_control",
11
- "task_control",
12
- "tdd_checkpoint",
13
- "release_control",
14
- ];
15
- /** 工具默认允许角色矩阵:primary 全量;developer 仅 tdd_checkpoint;其余角色默认无工具 */
16
- const TOOL_ROLES = {
17
- setup_control: ["primary"],
18
- flow_control: ["primary"],
19
- task_control: ["primary"],
20
- tdd_checkpoint: ["primary", "developer"],
21
- release_control: ["primary"],
22
- };
23
- /** op 级覆盖(最后匹配优先):architect 仅 flow_control.status 只读;goal-verify 仅 complete-flow;tdd_checkpoint.not-applicable 仅 primary(spec §2.3 纯文档豁免) */
24
- const OP_ROLES = {
25
- flow_control: {
26
- "complete-flow": ["goal-verify"],
27
- status: ["primary", "architect"],
28
- },
29
- tdd_checkpoint: {
30
- "not-applicable": ["primary"],
31
- },
32
- };
33
- /**
34
- * 解析工具(+op)允许的角色集。op 级覆盖优先;未知工具保守返回空集(fail-closed)。
35
- */
36
- export function rolesForTool(tool, op) {
37
- if (op && OP_ROLES[tool]?.[op])
38
- return OP_ROLES[tool][op];
39
- return TOOL_ROLES[tool] ?? [];
40
- }
41
- /** requireCaller 拒绝时的错误码 */
42
- export const CALLER_NOT_AUTHORIZED = "CALLER_NOT_AUTHORIZED";
43
- const ROLE_BY_AGENT = {
44
- "dev-lifecycle": "primary",
45
- developer: "developer",
46
- architect: "architect",
47
- reviewer: "reviewer",
48
- "goal-verify": "goal-verify",
49
- };
50
- /**
51
- * 解析调用者角色:无 parentID(session 查询成功且 data 存在)→ primary;
52
- * 查询失败/无 data → 保守视为 reviewer(最低权限,fail-closed);
53
- * 子会话按 agent 名映射;未知 agent → reviewer。
54
- */
55
- export async function resolveCaller(ctx, client) {
56
- let session;
57
- try {
58
- session = await client.session.get({ sessionID: ctx.sessionID });
59
- }
60
- catch {
61
- return "reviewer";
62
- }
63
- if (!session?.data)
64
- return "reviewer";
65
- if (session.data.parentID)
66
- return ROLE_BY_AGENT[ctx.agent] ?? "reviewer";
67
- return "primary";
68
- }
69
- /**
70
- * 调用者门禁原语:角色在 allowedRoles 内返回 null(通过),
71
- * 否则返回含 CALLER_NOT_AUTHORIZED 码的错误消息(调用方组装 `{ code, message }` 响应)。
72
- */
73
- export async function requireCaller(ctx, allowedRoles, op, client) {
74
- const role = await resolveCaller(ctx, client);
75
- if (allowedRoles.includes(role))
76
- return null;
77
- return `${CALLER_NOT_AUTHORIZED}: caller "${ctx.agent}" resolved as "${role}" is not allowed to call "${op}" (allowed: ${allowedRoles.join(", ")})`;
78
- }
79
- /**
80
- * 工具级 caller 门禁:按工具(+op)矩阵解析允许角色后校验。
81
- * 供各生命周期工具 execute 内调用(spec §2.2 第一道门;config 层为第二道门)。
82
- */
83
- export async function requireToolCaller(ctx, tool, op, client) {
84
- const allowed = rolesForTool(tool, op);
85
- const label = op ? `${tool}:{op:"${op}"}` : tool;
86
- return requireCaller(ctx, allowed, label, client);
87
- }
88
- //# sourceMappingURL=caller.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"caller.js","sourceRoot":"","sources":["../../src/kernel/caller.ts"],"names":[],"mappings":"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"}