ccgx-workflow 2.4.1 → 2.5.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 (46) hide show
  1. package/README.md +134 -277
  2. package/README.zh-CN.md +134 -272
  3. package/dist/chunks/version-build.mjs +1 -1
  4. package/dist/cli.mjs +1 -1
  5. package/dist/index.d.mts +709 -16
  6. package/dist/index.d.ts +709 -16
  7. package/dist/index.mjs +1061 -30
  8. package/dist/shared/{ccgx-workflow.j1spUsik.mjs → ccgx-workflow.CdHnJLak.mjs} +106 -22
  9. package/package.json +1 -1
  10. package/templates/commands/agents/code-fixer.md +6 -6
  11. package/templates/commands/agents/phase-runner.md +46 -14
  12. package/templates/commands/agents/plan-checker.md +10 -0
  13. package/templates/commands/analyze.md +66 -25
  14. package/templates/commands/autonomous.md +428 -225
  15. package/templates/commands/cancel.md +9 -0
  16. package/templates/commands/codex-exec.md +12 -11
  17. package/templates/commands/context.md +14 -0
  18. package/templates/commands/debate.md +10 -6
  19. package/templates/commands/execute.md +76 -28
  20. package/templates/commands/optimize.md +53 -25
  21. package/templates/commands/plan.md +78 -28
  22. package/templates/commands/review.md +26 -19
  23. package/templates/commands/spec-impl.md +68 -127
  24. package/templates/commands/spec-plan.md +61 -82
  25. package/templates/commands/spec-research.md +35 -92
  26. package/templates/commands/spec-review.md +34 -119
  27. package/templates/commands/status.md +1 -0
  28. package/templates/commands/team-exec.md +45 -13
  29. package/templates/commands/team.md +64 -167
  30. package/templates/commands/test.md +56 -34
  31. package/templates/commands/verify-work.md +36 -13
  32. package/templates/commands/verify.md +35 -0
  33. package/templates/commands/workflow.md +22 -37
  34. package/templates/hooks/ccg-loop-detector.cjs +39 -8
  35. package/templates/hooks/ccg-statusline.js +142 -2
  36. package/templates/hooks/ccg-stop-gate.cjs +248 -19
  37. package/templates/hooks/ccg-subagent-context.cjs +505 -0
  38. package/templates/scripts/ccg-state-lock.cjs +510 -0
  39. package/templates/scripts/ccg-team-schedule.cjs +328 -0
  40. package/templates/scripts/ccgx-call-plugin.mjs +494 -141
  41. package/templates/scripts/invoke-model.mjs +28 -1
  42. package/templates/scripts/task-store.cjs +614 -0
  43. package/templates/skills/tools/verify-change/SKILL.md +7 -0
  44. package/templates/skills/tools/verify-module/SKILL.md +7 -0
  45. package/templates/skills/tools/verify-quality/SKILL.md +7 -0
  46. package/templates/skills/tools/verify-security/SKILL.md +8 -0
@@ -13,7 +13,7 @@ import { join as join$2 } from 'node:path/posix';
13
13
  import { join as join$1 } from 'node:path';
14
14
  import i18next from 'i18next';
15
15
 
16
- const version = "2.4.1";
16
+ const version = "2.5.0";
17
17
 
18
18
  function cmd(id, order, category, name, nameEn, description, descriptionEn, cmdOverride) {
19
19
  return {
@@ -90,13 +90,16 @@ const HOOK_FILES = [
90
90
  "ccg-session-state.cjs",
91
91
  "ccg-loop-detector.cjs",
92
92
  "ccg-skill-router.cjs",
93
- "ccg-stop-gate.cjs"
93
+ "ccg-stop-gate.cjs",
94
+ "ccg-subagent-context.cjs"
94
95
  ];
95
96
  const POST_TOOL_MATCHER = "Bash|Edit|Write|MultiEdit|Agent|Task";
96
97
  const POST_TOOL_TIMEOUT_SEC = 10;
97
98
  const SESSION_START_TIMEOUT_SEC = 15;
98
99
  const USER_PROMPT_TIMEOUT_SEC = 5;
99
100
  const STOP_TIMEOUT_SEC = 5;
101
+ const PRE_TOOL_MATCHER = "Task|Agent";
102
+ const PRE_TOOL_TIMEOUT_SEC = 10;
100
103
  const CCG_SKILL_OVERRIDES = {
101
104
  "codex:rescue": "user-invocable-only",
102
105
  "gemini:rescue": "user-invocable-only"
@@ -141,6 +144,7 @@ async function patchSettingsJson(ctx) {
141
144
  const loopDetectorPath = join(hooksDir, "ccg-loop-detector.cjs");
142
145
  const skillRouterPath = join(hooksDir, "ccg-skill-router.cjs");
143
146
  const stopGatePath = join(hooksDir, "ccg-stop-gate.cjs");
147
+ const subagentContextPath = join(hooksDir, "ccg-subagent-context.cjs");
144
148
  let settings = {};
145
149
  if (await fs.pathExists(settingsPath)) {
146
150
  try {
@@ -256,6 +260,26 @@ async function patchSettingsJson(ctx) {
256
260
  }
257
261
  }
258
262
  }
263
+ if (await fs.pathExists(subagentContextPath)) {
264
+ if (!settings.hooks) settings.hooks = {};
265
+ if (!Array.isArray(settings.hooks.PreToolUse)) settings.hooks.PreToolUse = [];
266
+ const alreadyRegistered = settings.hooks.PreToolUse.some(
267
+ (entry) => entry?.hooks?.some((h) => typeof h?.command === "string" && h.command.includes("ccg-subagent-context"))
268
+ );
269
+ if (!alreadyRegistered) {
270
+ settings.hooks.PreToolUse.push({
271
+ matcher: PRE_TOOL_MATCHER,
272
+ hooks: [
273
+ {
274
+ type: "command",
275
+ command: buildHookCommand(subagentContextPath),
276
+ timeout: PRE_TOOL_TIMEOUT_SEC
277
+ }
278
+ ]
279
+ });
280
+ modified = true;
281
+ }
282
+ }
259
283
  if (typeof settings.skillOverrides !== "object" || settings.skillOverrides === null) {
260
284
  settings.skillOverrides = {};
261
285
  }
@@ -333,6 +357,24 @@ async function uninstallHooks(installDir) {
333
357
  modified = true;
334
358
  }
335
359
  }
360
+ if (Array.isArray(settings.hooks?.PreToolUse)) {
361
+ const before = settings.hooks.PreToolUse.length;
362
+ settings.hooks.PreToolUse = settings.hooks.PreToolUse.filter((entry) => {
363
+ const hasCcg = entry?.hooks?.some(
364
+ (h) => typeof h?.command === "string" && h.command.includes("ccg-subagent-context")
365
+ );
366
+ return !hasCcg;
367
+ });
368
+ if (settings.hooks.PreToolUse.length !== before) modified = true;
369
+ if (settings.hooks.PreToolUse.length === 0) {
370
+ delete settings.hooks.PreToolUse;
371
+ modified = true;
372
+ }
373
+ if (settings.hooks && Object.keys(settings.hooks).length === 0) {
374
+ delete settings.hooks;
375
+ modified = true;
376
+ }
377
+ }
336
378
  if (Array.isArray(settings.hooks?.UserPromptSubmit)) {
337
379
  const before = settings.hooks.UserPromptSubmit.length;
338
380
  settings.hooks.UserPromptSubmit = settings.hooks.UserPromptSubmit.filter((entry) => {
@@ -519,7 +561,7 @@ function findPackageRoot$1(startDir) {
519
561
  Start dir: ${startDir}
520
562
  Last checked: ${dir}
521
563
  This will cause commands/skills/prompts to not be installed.
522
- Please report this issue at: https://github.com/fengshao1227/ccg-workflow/issues`
564
+ Please report this issue at: https://github.com/wzyxdwll/ccgx-workflow/issues`
523
565
  );
524
566
  return startDir;
525
567
  }
@@ -666,6 +708,8 @@ function normalizeSkillRecord(skillsDir, skillDir, meta) {
666
708
  const contextRaw = String(meta.context || "inline").toLowerCase();
667
709
  const context = contextRaw === "fork" ? "fork" : "inline";
668
710
  const paths = meta.paths ? meta.paths.split(",").map((p) => p.trim()).filter(Boolean) : [];
711
+ const gateTypeRaw = String(meta["gate-type"] || "").toLowerCase();
712
+ const gateType = ["pre-flight", "revision-loop", "escalation", "abort"].find((g) => g === gateTypeRaw);
669
713
  return {
670
714
  name,
671
715
  description,
@@ -679,7 +723,8 @@ function normalizeSkillRecord(skillsDir, skillDir, meta) {
679
723
  skillPath: join(skillDir, "SKILL.md"),
680
724
  scriptPath: scriptEntries[0] || null,
681
725
  context,
682
- paths
726
+ paths,
727
+ gateType
683
728
  };
684
729
  }
685
730
  function collectSkills(skillsDir) {
@@ -1485,7 +1530,7 @@ async function installShim(ctx) {
1485
1530
  const srcMjs = join(ctx.templateDir, "scripts", "invoke-model.mjs");
1486
1531
  if (!await fs.pathExists(srcMjs)) {
1487
1532
  ctx.result.errors.push(
1488
- `Bundled invoke-model.mjs missing at ${srcMjs}. npm package may be incomplete \u2014 try: npm cache clean --force && npx ccg-workflow@latest`
1533
+ `Bundled invoke-model.mjs missing at ${srcMjs}. npm package may be incomplete \u2014 try: npm cache clean --force && npx ccgx-workflow@latest`
1489
1534
  );
1490
1535
  ctx.result.success = false;
1491
1536
  return;
@@ -1527,6 +1572,38 @@ async function installShim(ctx) {
1527
1572
  await fs.chmod(destSpecSuggestion, 493);
1528
1573
  }
1529
1574
  }
1575
+ const srcTaskStore = join(ctx.templateDir, "scripts", "task-store.cjs");
1576
+ if (await fs.pathExists(srcTaskStore)) {
1577
+ const destTaskStore = join(scriptDir, "task-store.cjs");
1578
+ await fs.copy(srcTaskStore, destTaskStore, { overwrite: true });
1579
+ if (process.platform !== "win32") {
1580
+ await fs.chmod(destTaskStore, 493);
1581
+ }
1582
+ }
1583
+ const srcTeamSchedule = join(ctx.templateDir, "scripts", "ccg-team-schedule.cjs");
1584
+ if (await fs.pathExists(srcTeamSchedule)) {
1585
+ const destTeamSchedule = join(scriptDir, "ccg-team-schedule.cjs");
1586
+ await fs.copy(srcTeamSchedule, destTeamSchedule, { overwrite: true });
1587
+ if (process.platform !== "win32") {
1588
+ await fs.chmod(destTeamSchedule, 493);
1589
+ }
1590
+ }
1591
+ const srcStateLock = join(ctx.templateDir, "scripts", "ccg-state-lock.cjs");
1592
+ if (await fs.pathExists(srcStateLock)) {
1593
+ const destStateLock = join(scriptDir, "ccg-state-lock.cjs");
1594
+ await fs.copy(srcStateLock, destStateLock, { overwrite: true });
1595
+ if (process.platform !== "win32") {
1596
+ await fs.chmod(destStateLock, 493);
1597
+ }
1598
+ }
1599
+ const srcRepatch = join(ctx.templateDir, "scripts", "repatch-gemini-plugin.mjs");
1600
+ if (await fs.pathExists(srcRepatch)) {
1601
+ const destRepatch = join(scriptDir, "repatch-gemini-plugin.mjs");
1602
+ await fs.copy(srcRepatch, destRepatch, { overwrite: true });
1603
+ if (process.platform !== "win32") {
1604
+ await fs.chmod(destRepatch, 493);
1605
+ }
1606
+ }
1530
1607
  if (process.platform === "win32") {
1531
1608
  const cmdMjs = destMjs.replace(/\//g, "\\");
1532
1609
  const cmdPath = join(binDir, "codeagent-wrapper.cmd");
@@ -1585,7 +1662,7 @@ async function installWorkflows(workflowIds, installDir, force = false, config)
1585
1662
  }
1586
1663
  };
1587
1664
  if (!await fs.pathExists(ctx.templateDir)) {
1588
- const errorMsg = `Template directory not found: ${ctx.templateDir} (PACKAGE_ROOT=${PACKAGE_ROOT$1}). This usually means the npm package is incomplete or the cache is corrupted. Try: npm cache clean --force && npx ccg-workflow@latest`;
1665
+ const errorMsg = `Template directory not found: ${ctx.templateDir} (PACKAGE_ROOT=${PACKAGE_ROOT$1}). This usually means the npm package is incomplete or the cache is corrupted. Try: npm cache clean --force && npx ccgx-workflow@latest`;
1589
1666
  ctx.result.errors.push(errorMsg);
1590
1667
  ctx.result.success = false;
1591
1668
  return ctx.result;
@@ -4144,7 +4221,7 @@ async function init(options = {}) {
4144
4221
  if (!result.success) {
4145
4222
  console.log();
4146
4223
  console.log(ansis.yellow(` \u5C1D\u8BD5\u4FEE\u590D / Try to fix:`));
4147
- console.log(ansis.cyan(` npx ccg-workflow@latest init --force`));
4224
+ console.log(ansis.cyan(` npx ccgx-workflow@latest init --force`));
4148
4225
  console.log(ansis.gray(` \u5982\u4ECD\u5931\u8D25\uFF0C\u8BF7\u63D0\u4EA4 issue \u5E76\u9644\u4E0A\u4EE5\u4E0A\u9519\u8BEF\u4FE1\u606F`));
4149
4226
  console.log(ansis.gray(` If still failing, report an issue with the errors above`));
4150
4227
  }
@@ -4351,6 +4428,7 @@ function findPackageRoot(startDir) {
4351
4428
  }
4352
4429
  }
4353
4430
  const PACKAGE_ROOT = findPackageRoot(__dirname$1);
4431
+ const PACKAGE_NAME = "ccgx-workflow";
4354
4432
  async function readPackageVersion(pkgPath) {
4355
4433
  try {
4356
4434
  if (!await fs.pathExists(pkgPath)) {
@@ -4388,7 +4466,7 @@ async function getCurrentVersion() {
4388
4466
  }
4389
4467
  return process.env.npm_package_version || "0.0.0";
4390
4468
  }
4391
- async function getLatestVersion(packageName = "ccg-workflow") {
4469
+ async function getLatestVersion(packageName = PACKAGE_NAME) {
4392
4470
  try {
4393
4471
  const { stdout } = await execAsync$2(`npm view ${packageName} version`);
4394
4472
  return stdout.trim();
@@ -4481,8 +4559,8 @@ async function update() {
4481
4559
  }
4482
4560
  async function checkIfGlobalInstall$1() {
4483
4561
  try {
4484
- const { stdout } = await execAsync$1("npm list -g ccg-workflow --depth=0", { timeout: 5e3 });
4485
- return stdout.includes("ccg-workflow@");
4562
+ const { stdout } = await execAsync$1(`npm list -g ${PACKAGE_NAME} --depth=0`, { timeout: 5e3 });
4563
+ return stdout.includes(`${PACKAGE_NAME}@`);
4486
4564
  } catch {
4487
4565
  return false;
4488
4566
  }
@@ -4503,7 +4581,7 @@ async function performUpdate(fromVersion, toVersion, isNewVersion) {
4503
4581
  console.log();
4504
4582
  console.log(`${i18n.t("update:recommendNpm")}`);
4505
4583
  console.log();
4506
- console.log(ansis.cyan(" npm install -g ccg-workflow@latest"));
4584
+ console.log(ansis.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
4507
4585
  console.log();
4508
4586
  console.log(ansis.gray(i18n.t("update:willUpdateBoth")));
4509
4587
  console.log();
@@ -4517,7 +4595,7 @@ async function performUpdate(fromVersion, toVersion, isNewVersion) {
4517
4595
  console.log();
4518
4596
  console.log(ansis.cyan(i18n.t("update:runInNewTerminal")));
4519
4597
  console.log();
4520
- console.log(ansis.cyan.bold(" npm install -g ccg-workflow@latest"));
4598
+ console.log(ansis.cyan.bold(` npm install -g ${PACKAGE_NAME}@latest`));
4521
4599
  console.log();
4522
4600
  console.log(ansis.gray(`(${i18n.t("update:autoUpdateAfter")})`));
4523
4601
  console.log();
@@ -4543,7 +4621,7 @@ async function performUpdate(fromVersion, toVersion, isNewVersion) {
4543
4621
  }
4544
4622
  }
4545
4623
  spinner.text = i18n.t("update:downloading");
4546
- await execAsync$1(`npx --yes ccg-workflow@latest --version`, { timeout: 6e4 });
4624
+ await execAsync$1(`npx --yes ${PACKAGE_NAME}@latest --version`, { timeout: 6e4 });
4547
4625
  spinner.succeed(i18n.t("update:downloadDone"));
4548
4626
  } catch (error) {
4549
4627
  spinner.fail(i18n.t("update:downloadFailed"));
@@ -4614,9 +4692,9 @@ async function performUpdate(fromVersion, toVersion, isNewVersion) {
4614
4692
  spinner = ora(i18n.t("update:installingNew")).start();
4615
4693
  let installSuccess = false;
4616
4694
  try {
4617
- await execAsync$1(`npx --yes ccg-workflow@latest init --force --skip-mcp --skip-prompt`, {
4695
+ await execAsync$1(`npx --yes ${PACKAGE_NAME}@latest init --force --skip-mcp --skip-prompt`, {
4618
4696
  timeout: 3e5,
4619
- // 5min — binary download from GitHub Release may be slow (especially in China)
4697
+ // 5min — npx downloading the npm package may be slow (especially in China)
4620
4698
  env: {
4621
4699
  ...process.env,
4622
4700
  CCG_UPDATE_MODE: "true"
@@ -4624,7 +4702,9 @@ async function performUpdate(fromVersion, toVersion, isNewVersion) {
4624
4702
  });
4625
4703
  const commandsDir = join(installDir, "commands", "ccg");
4626
4704
  const hasCommands = await fs.pathExists(commandsDir) && (await fs.readdir(commandsDir)).some((f) => f.endsWith(".md"));
4627
- if (hasCommands) {
4705
+ const fingerprintPath = join(installDir, ".ccg", "scripts", "invoke-model.mjs");
4706
+ const hasFingerprint = await fs.pathExists(fingerprintPath);
4707
+ if (hasCommands && hasFingerprint) {
4628
4708
  installSuccess = true;
4629
4709
  spinner.succeed(i18n.t("update:installDone"));
4630
4710
  const config = await readCcgConfig();
@@ -4637,7 +4717,11 @@ async function performUpdate(fromVersion, toVersion, isNewVersion) {
4637
4717
  }
4638
4718
  } else {
4639
4719
  spinner.fail(i18n.t("update:installFailed"));
4640
- console.log(ansis.red(" Install subprocess completed but no command files were created"));
4720
+ if (!hasCommands) {
4721
+ console.log(ansis.red(" Install subprocess completed but no command files were created"));
4722
+ } else {
4723
+ console.log(ansis.red(` Install fingerprint missing: ${fingerprintPath}`));
4724
+ }
4641
4725
  }
4642
4726
  } catch (error) {
4643
4727
  spinner.fail(i18n.t("update:installFailed"));
@@ -4674,7 +4758,7 @@ async function performUpdate(fromVersion, toVersion, isNewVersion) {
4674
4758
  }
4675
4759
  console.log();
4676
4760
  console.log(ansis.yellow(i18n.t("update:manualRetry")));
4677
- console.log(ansis.cyan(" npx ccg-workflow@latest"));
4761
+ console.log(ansis.cyan(` npx ${PACKAGE_NAME}@latest`));
4678
4762
  return;
4679
4763
  }
4680
4764
  console.log();
@@ -5095,7 +5179,7 @@ async function configModelRouting() {
5095
5179
  const spinner = ora(i18n.t("init:model.reinstalling")).start();
5096
5180
  try {
5097
5181
  const { execSync } = await import('node:child_process');
5098
- execSync("npx --yes ccg-workflow init --force --skip-prompt --skip-mcp", {
5182
+ execSync(`npx --yes ${PACKAGE_NAME} init --force --skip-prompt --skip-mcp`, {
5099
5183
  timeout: 3e5,
5100
5184
  stdio: "pipe",
5101
5185
  env: { ...process.env, CCG_UPDATE_MODE: "true" }
@@ -5236,8 +5320,8 @@ async function handleInstallClaude() {
5236
5320
  }
5237
5321
  async function checkIfGlobalInstall() {
5238
5322
  try {
5239
- const { stdout } = await execAsync("npm list -g ccg-workflow --depth=0", { timeout: 5e3 });
5240
- return stdout.includes("ccg-workflow@");
5323
+ const { stdout } = await execAsync(`npm list -g ${PACKAGE_NAME} --depth=0`, { timeout: 5e3 });
5324
+ return stdout.includes(`${PACKAGE_NAME}@`);
5241
5325
  } catch {
5242
5326
  return false;
5243
5327
  }
@@ -5299,7 +5383,7 @@ async function uninstall() {
5299
5383
  console.log();
5300
5384
  console.log(` ${i18n.t("menu:uninstall.runInNewTerminal")}`);
5301
5385
  console.log();
5302
- console.log(ansis.cyan.bold(" npm uninstall -g ccg-workflow"));
5386
+ console.log(ansis.cyan.bold(` npm uninstall -g ${PACKAGE_NAME}`));
5303
5387
  console.log();
5304
5388
  console.log(ansis.gray(` (${i18n.t("menu:uninstall.afterDone")})`));
5305
5389
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccgx-workflow",
3
- "version": "2.4.1",
3
+ "version": "2.5.0",
4
4
  "description": "Multi-model orchestration for Claude Code. Codex + Gemini parallel collaboration with fresh-context subagent protocols, OS-level process isolation, and Plan-Critic-Verify quality tiers. Successor to ccg-workflow.",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.17.1",
@@ -34,7 +34,7 @@ color: orange
34
34
  | `current_branch` | 用户当前所在分支(cleanup 第 1 步 ff-only merge 的目标) |
35
35
  | `workdir` | 项目绝对路径 |
36
36
  | `fix_scope` | `critical_warning`(默认)/ `all`(含 Info)/ `auto`(多轮收敛) |
37
- | `auto_round` | `--auto` 模式下传入,当前轮次(1-indexed),用于多轮收敛识别 |
37
+ | `auto_round` | 多轮模式(`--fix` Ralph auto-retry 与 `--fix --auto` 都算)下传入,当前轮次(1-indexed),用于多轮收敛识别 |
38
38
 
39
39
  ---
40
40
 
@@ -186,7 +186,7 @@ rm .context/review-fix-recovery-pending.json
186
186
  # REVIEW-FIX Report
187
187
 
188
188
  **Status**: completed | partial | escalated
189
- **Round**: <auto_round> / 3 (仅 --auto 模式)
189
+ **Round**: <auto_round> / 3 (多轮模式)
190
190
  **Findings processed**: <N>
191
191
  **Commits made**: <M>
192
192
 
@@ -206,12 +206,12 @@ rm .context/review-fix-recovery-pending.json
206
206
  - sentinel_remove: ok
207
207
  ```
208
208
 
209
- ### Phase G. 多轮收敛(仅 `--auto` 模式)
209
+ ### Phase G. 多轮收敛(多轮模式:`--fix` Ralph auto-retry / `--fix --auto`)
210
210
 
211
- `--auto` 模式下,主线在你完成后会再跑一次 `/ccg:review` 生成新 REVIEW.md,再 spawn 你做下一轮。**收敛判定由主线**用 `decideConverge()` helper 做:
211
+ 多轮模式(`--fix` Ralph auto-retry 与 `--fix --auto` 都算)下,主线在你完成后会再跑一次 `/ccg:review` 生成新 REVIEW.md,再 spawn 你做下一轮。**收敛判定由主线**用 `decideConverge()` helper 做,收敛口径(blocking 第三参)也归主线按 flag 选择——`--fix` 用 `'critical'`(无 Critical 即 pass through),`--fix --auto` 用 `'critical_warning'`(critical+warning 全清):
212
212
 
213
- - `continue` → 主线再 spawn 你跑下一轮
214
- - `converged` → critical+warning 全清,主线停
213
+ - `continue` → 主线再 spawn 你跑下一轮(不问用户)
214
+ - `converged` → blocking 口径下 finding 全清,主线停(pass through)
215
215
  - `escalate` → 达到 3 轮 cap 或 stall(连续 2 轮 finding 数没下降),主线升级用户
216
216
 
217
217
  **你的责任**:每轮跑完老老实实输出 REVIEW-FIX.md,不要自作主张多跑 / 少跑。`AUTO_CONVERGE_CAP = 3` 是 CCG 全体系硬规约(与 plan-checker / verify-work 一致)。
@@ -32,19 +32,23 @@ color: cyan
32
32
 
33
33
  | `nested_rescue` 值 | 行为 |
34
34
  |--------------------|------|
35
- | `true` | 按 phase_type 路由 spawn rescue plugin 委派代码改动 |
35
+ | `true` | 按 phase_type 路由 **Bash 直调 plugin helper** 委派代码改动(你是 fresh-context subagent,工具列表不含 Agent/Task,**只能走 Bash** 委派——见下方"为什么是 Bash 直调") |
36
36
  | `false` 或缺省 | 自实施模式,**默认** |
37
37
 
38
38
  ### 路由(仅 `nested_rescue: true` 时)
39
39
 
40
- | phase_type | 委派路径 |
40
+ 占位符 `{{CODEX_BASH_TASK}}` / `{{GEMINI_BASH_TASK}}` 由 install 渲染为 `node <ccgx-call-plugin.mjs 绝对路径> <vendor> --json`:
41
+
42
+ | phase_type | 委派路径(Bash 直调 helper) |
41
43
  |-----------|---------|
42
- | `backend` | `Agent(subagent_type="codex:codex-rescue")` |
43
- | `frontend` | `Agent(subagent_type="gemini:gemini-rescue")` |
44
- | `fullstack` | 串行:先 codex(schema/逻辑),再 gemini(前端联动) |
44
+ | `backend` | Write 任务到 tmpfile → `Bash({ command: \`{{CODEX_BASH_TASK}} --prompt-file <tmpfile>\`, run_in_background: false })` |
45
+ | `frontend` | Write 任务到 tmpfile → `Bash({ command: \`{{GEMINI_BASH_TASK}} --prompt-file <tmpfile>\`, run_in_background: false })` |
46
+ | `fullstack` | 串行:先 codex(schema/逻辑)helper,再 gemini(前端联动)helper |
45
47
  | `docs` / `generic` | 自实施(rescue plugin 对文档/通用任务无优势) |
46
48
 
47
- 接口名严格按 ground_truth_path 校验——双前缀 `codex:codex-rescue` / `gemini:gemini-rescue`(不是单前缀 `codex:rescue`)。
49
+ **为什么是 Bash 直调**:你是主进程 sidechain subagent,工具列表**不含 Agent/Task**(引擎硬限制,line 19),所以委派只能通过 Bash 调 helper——这同时绕开 `Agent→gemini-companion→ACP` 慢路径(gemini 实测 5+min 卡死)与 sonnet wrapper silent-fallback。**tmpfile 内容必须含硬约束"必须前台执行,禁止 --background / --wait"**(helper 已被你以 `run_in_background: false` 同步等待;plugin 内再 background = 双重后台,状态全盲),并写"角色定义见对应 reviewer/architect 路径,先 Read 再开始"。`JSON.parse(stdout).text` 取委派结果。
50
+
51
+ 接口/占位符名严格按 ground_truth_path 校验——vendor 为 `codex` / `gemini`。
48
52
 
49
53
  ### 单 phase nested CAP
50
54
 
@@ -64,10 +68,10 @@ color: cyan
64
68
 
65
69
  | 失败场景 | 行为 |
66
70
  |---------|------|
67
- | Agent spawn 立即报错(plugin 未装 / subagent_type 不存在)| 当前 phase 切自实施 + 摘要 STATUS=degraded + NOTES 标 `plugin-unavailable: <name>` |
68
- | Plugin 报告 partial / failed | 自己评估能否修补:能修自己 Edit;不能修就 STATUS=partial 上报 |
69
- | Plugin 超时 / 卡死 | 30 分钟后强制 STATUS=partial + NOTES 标 `nested-timeout` |
70
- | 同一 phase spawn 2 次都失败 | 不再尝试 nested,剩余切自实施 + STATUS=degraded |
71
+ | Bash 直调 helper 立即报错(plugin 未装 / exit 0 / stdout < 100B)| 当前 phase 切自实施 + 摘要 STATUS=degraded + NOTES 标 `plugin-unavailable: <name>` |
72
+ | Plugin 报告 partial / failed(`JSON.parse(stdout)` status 非 ok)| 自己评估能否修补:能修自己 Edit;不能修就 STATUS=partial 上报 |
73
+ | Plugin 超时 / 卡死(helper 已带 wall/idle 双层超时,可显式 `--timeout-ms`)| 30 分钟后强制 STATUS=partial + NOTES 标 `nested-timeout` |
74
+ | 同一 phase 内委派 2 次都失败 | 不再尝试 nested,剩余切自实施 + STATUS=degraded |
71
75
 
72
76
  ### 摘要扩展字段
73
77
 
@@ -105,8 +109,12 @@ color: cyan
105
109
  | `commit_prefix` | git commit message 前缀,如 `feat(v4-p2):` |
106
110
  | `design_brief`(可选) | triple/debate 模式 plan wave 后由主线注入的 Markdown brief(共识 / 分歧 / 必决策点);fast 模式下缺省 |
107
111
  | `verify_findings`(可选) | 修订轮(revise)由主线注入的 verify wave critical findings 反馈块,要求"仅修复 critical,不重做整个 phase" |
108
- | `nested_rescue`(可选) | 布尔;`true` 启用 nested rescue 委派(按 phase_type spawn `codex:codex-rescue` / `gemini:gemini-rescue`),`false` 或缺省走自实施。详见"Nested rescue delegation"段 |
112
+ | `nested_rescue`(可选) | 布尔;`true` 启用 nested rescue 委派(按 phase_type Bash 直调 `{{CODEX_BASH_TASK}}` / `{{GEMINI_BASH_TASK}}` helper),`false` 或缺省走自实施。详见"路由"段 |
109
113
  | `job_id`(可选) | 主线 launcher 分配的 job-id;用于读 `.context/jobs/<job_id>/degraded.flag` 决定是否中止 nested |
114
+ | `summary_format`(可选) | **Workflow 编排模式专属**;值为 `json` 时最终摘要输出为 7 字段 JSON 对象(见"Workflow 编排模式"段)。缺省走 Phase G 文本格式 |
115
+ | `checkpoint_path`(可选) | **Workflow 编排模式专属**;开工前 Read 它做幂等重入,收尾把摘要 JSON Write 到此路径 |
116
+ | `cancel_flag_path`(可选) | **Workflow 编排模式专属**;开工前 Read,文件存在 → 立即返回 `{status:'failed', notes:'cancel-flag-detected'}` |
117
+ | `progress_log`(可选) | **Workflow 编排模式专属**;收尾向此 jsonl append 一行 `{"type":"phase-result","phase_id":...,"status":...}` |
110
118
 
111
119
  **禁止从 `~/.claude/.ccg/config.toml` 读 `BACKEND_PRIMARY/FRONTEND_PRIMARY`**——主线在 prompt 里明确告知模型路由(避免双源不一致)。
112
120
 
@@ -167,12 +175,12 @@ color: cyan
167
175
  **两条路径,由 `nested_rescue` 字段决定**:
168
176
 
169
177
  - **`nested_rescue: false`(默认)**:自己用 Edit/Write/Bash 做完所有事
170
- - **`nested_rescue: true`**:按"Nested rescue delegation"段路由 spawn `codex:codex-rescue` / `gemini:gemini-rescue` 委派代码改动;spawn 前先 Read `degraded.flag` 校验;遵守 CAP=3;失败按降级路径处理
178
+ - **`nested_rescue: true`**:按"路由"段 Bash 直调 `{{CODEX_BASH_TASK}}` / `{{GEMINI_BASH_TASK}}` helper(`run_in_background: false` 同步等待,tmpfile 含"禁止 --background"硬约束)委派代码改动;委派前先 Read `degraded.flag` 校验;遵守 CAP=3;失败按降级路径处理
171
179
 
172
180
  实施过程(两路径共用):
173
181
  1. **理解 phase**:Read phase_goal / phase_acceptance / phase_depends_on(依赖产物文件)
174
182
  2. **codebase 探索**:用 Glob/Grep/Read 找相关文件 + 现有 pattern
175
- 3. **代码改动**:自实施时 Edit/Write 落地;nested 时 spawn rescue 委派 + 拿回报告 + 自己 wrap up
183
+ 3. **代码改动**:自实施时 Edit/Write 落地;nested 时 Bash 直调 helper 委派 + `JSON.parse(stdout).text` 拿回报告 + 自己 wrap up
176
184
  4. **走完 acceptance 每条**:每改完一项立即用 Bash 跑命令验证(test focused / typecheck / grep 等)
177
185
 
178
186
  ### Phase C. 写报告
@@ -233,7 +241,7 @@ challenger 钩子由主线层编排(与 nested rescue 是两个独立机制)
233
241
  输出**严格 200 token 内**的字符串给主线:
234
242
 
235
243
  ```
236
- STATUS: completed | partial | failed
244
+ STATUS: completed | partial | failed | degraded
237
245
  COMMIT: <sha7> | none
238
246
  TESTS: <pass>/<total> passed (delta +<n> from <baseline>)
239
247
  TYPECHECK: pass | fail
@@ -251,6 +259,30 @@ NOTES: <一行关键发现 / 灰区决策点 / 下一步建议>
251
259
 
252
260
  **禁止超过 200 token**——主线推进 phase 决策只看这个摘要。多余信息放报告文件 + git commit message。
253
261
 
262
+ ### Workflow 编排模式(summary_format: json)
263
+
264
+ 主线走 `/ccg:autonomous` 原生 Workflow 编排时,prompt 含 `summary_format: json`。此模式下你的**最终输出**不再是 Phase G 的文本格式,而是符合以下 7 字段 JSON schema 的对象(Workflow 引擎 schema 强制结构化返回):
265
+
266
+ ```json
267
+ {
268
+ "status": "completed | partial | failed | degraded",
269
+ "commit": "<sha7> 或 \"none\"",
270
+ "tests": "<pass>/<total> passed (delta +<n>) 或 \"n/a\"",
271
+ "typecheck": "pass | fail | unknown",
272
+ "handoff_taken": ["git_commit", "test_run", "typecheck"],
273
+ "context_delta": "≤50 字",
274
+ "notes": "≤80 字"
275
+ }
276
+ ```
277
+
278
+ 字段名小写下划线,语义与 Phase G 文本字段 1:1 对应(schema 真相源:`src/utils/workflow-autonomous.ts` 的 `PHASE_SUMMARY_SCHEMA`)。**文本格式仍是 legacy 默认**——`summary_format` 缺省时照旧输出 Phase G 文本,零行为变化。
279
+
280
+ 三项额外责任(按时序):
281
+
282
+ 1. **cancel.flag 检查(开工前)**:Read `cancel_flag_path`,文件存在 → 立即返回 `{"status":"failed","notes":"cancel-flag-detected","commit":"none","tests":"n/a","typecheck":"unknown","handoff_taken":[],"context_delta":"canceled before start"}`,不做任何代码改动
283
+ 2. **checkpoint 幂等重入(开工前)**:Read `checkpoint_path`,存在且其 `status` 为 `completed` → **原样返回其内容**,不重做实施(`--resume` 缓存未命中时防重复工作)
284
+ 3. **checkpoint + progress 落盘(收尾)**:Write `checkpoint_path`(内容 = 你的摘要 JSON 本体)+ 向 `progress_log` append 一行 `{"type":"phase-result","phase_id":"<id>","status":"<status>"}`(供 `/ccg:status` dashboard / tail 观测)
285
+
254
286
  ---
255
287
 
256
288
  ## 失败模式
@@ -9,6 +9,7 @@ color: purple
9
9
 
10
10
  ## 核心定位
11
11
 
12
+ - **Gate 类型**:revision-loop(max 3)→ escalation(taxonomy 见 `/ccg:verify` 的 Gates Taxonomy 段,SSoT = `src/utils/verify-orchestrator.ts:GATE_REGISTRY`)
12
13
  - **5 维度强校验**:GSD plan-checker 12 维度的高 ROI 子集(Dim 1 / 2 / 5 / 7b / 10)
13
14
  - **判定算法显式化**:每个维度都有明确触发条件 + 修复建议格式
14
15
  - **max-3-loop 收敛环**:BLOCKER 退回 planner,最多 3 轮;超限升级用户决策
@@ -62,6 +63,14 @@ for r in missing:
62
63
 
63
64
  **注意**:大小写不敏感匹配(`REQ-01` == `req-01`)。
64
65
 
66
+ **REQ-ID 来源格式**(确定性提取,规则权威 `src/utils/plan-checker.ts`):
67
+
68
+ | 来源 | 格式 | 提取函数 |
69
+ |------|------|---------|
70
+ | roadmap | `- **Requirements**: REQ-01, REQ-02` 行(phase 块内) | `extractPhaseRequirementIds` |
71
+ | OPSX proposal | checkbox `- [ ] **REQ-NN** <描述>` 或表格首列 `| REQ-NN | ... |` | `extractRequirementIds` |
72
+ | plan 声明 | frontmatter `requirements: [REQ-01, REQ-02]`(inline 或多行 list) | `parsePlanFrontmatter` |
73
+
65
74
  #### Dim 2: Task Completeness(任务完整性)
66
75
 
67
76
  **算法**:对每个 task 检查 4 字段(中英双语字段名都接受):
@@ -188,6 +197,7 @@ if loop_count == 3 and result.hasBlocker:
188
197
  - 单次 loop 内 plan-checker 必须返回完整 findings(不允许"再确认一下"中途返回)
189
198
  - planner 修订时**只允许针对 BLOCKER**改动(不要顺手改其他段,避免引入新问题)
190
199
  - 第 3 次 loop 仍失败 → **不允许默认通过**,必须 AskUserQuestion 升级
200
+ - **stall detection(提前升级)**:连续两轮 BLOCKER 数不下降(本轮 ≥ 上一轮)→ 不等满 3 轮直接 AskUserQuestion 升级(`src/utils/verify-orchestrator.ts:resolveVerifyGateAction` 同源语义——收敛环不收敛就别空转)
191
201
 
192
202
  ---
193
203
 
@@ -37,14 +37,14 @@ argument-hint: "<分析问题或任务> [--role=architect|critic|implementer|tes
37
37
 
38
38
  ## 调用通道路由(CCG codeagent 退役)
39
39
 
40
- CCG 把双模型并行通道从 `Bash(codeagent-wrapper)` **默认切换**为 plugin spawn:
40
+ CCG 把双模型并行通道从 `Bash(codeagent-wrapper)` **默认切换**为 Bash 直调 plugin 快路径:
41
41
 
42
- 1. **优先 plugin spawn**(默认):装了 `codex@openai-codex` + gemini plugin(推荐 `gemini@gemini-ccgx` fork,含 P-1..P-21 + W1/W2/I1 patch;或上游 `gemini@google-gemini` 配 repatch 脚本)→ 用 `Agent(subagent_type="codex:codex-rescue")` + `Agent(subagent_type="gemini:gemini-rescue")` 并行,主线接 ≤200 token 摘要。
42
+ 1. **优先 Bash 直调 plugin 快路径**(默认):装了 `codex@openai-codex` + gemini plugin(推荐 `gemini@gemini-ccgx` fork,含 P-1..P-21 + W1/W2/I1 patch;或上游 `gemini@google-gemini` 配 repatch 脚本)→ 用 `{{CODEX_BASH_TASK}}` / `{{GEMINI_BASH_TASK}}` 占位符 + `--prompt-file` 并行 Bash 直调(review.md 同款),绕开 sonnet wrapper silent-fallback;**仅 `gemini-ccgx` fork 走 gemini-batch 29s 快路径,上游 + repatch 仍走 companion(ACP) 慢路径**(Windows 实测 5+min 卡死风险仍在),主线 `JSON.parse(stdout)` 取 `.text`。
43
43
  2. **降级 codeagent-wrapper**(BC fallback):plugin 未装 → fallback 到 Bash 调用,行为与 plugin 路径等价。
44
44
 
45
- **判定**:preflight `Bash` 跑 `node ~/.claude/.ccg/scripts/check-plugins.cjs`(解析 Claude Code 权威 `installed_plugins.json`)。exit `0` + stdout `{"codex":"<ver>","gemini":"<ver>"}` → 通道 A(plugin 默认);非 `0` → 通道 B(wrapper BC fallback)。
45
+ **判定**:preflight `Bash` 跑 `node ~/.claude/.ccg/scripts/check-plugins.cjs`(解析 Claude Code 权威 `installed_plugins.json`)。exit `0` + stdout `{"codex":"<ver>","gemini":"<ver>"}` → 通道 A(Bash 直调快路径,默认);非 `0` → 通道 B(wrapper BC fallback)。
46
46
 
47
- ⚠️ Analyze 命令在主线 context 内,**允许** `Agent(...)`——与 subagent "禁止嵌套 spawn" 约束不冲突。
47
+ ⚠️ Analyze 命令在主线 context 内执行,通道 A 走 Bash 直调(不再 spawn `Agent(...)`),无嵌套 spawn 顾虑。
48
48
 
49
49
  ---
50
50
 
@@ -57,28 +57,69 @@ CCG 把双模型并行通道从 `Bash(codeagent-wrapper)` **默认切换**为 pl
57
57
 
58
58
  **调用语法**(双通道):
59
59
 
60
- **通道 A — plugin spawn(默认)**:
60
+ **通道 A — Bash 直调 plugin 快路径(默认,绕开 sonnet wrapper + ACP 慢路径)**:
61
61
 
62
+ > 占位符 `{{CODEX_BASH_TASK}}` / `{{GEMINI_BASH_TASK}}` 由 install 时渲染为
63
+ > `node <ccgx-call-plugin.mjs 绝对路径> <vendor> --json`。LLM **只需把 prompt
64
+ > 写入 tmpfile、追加 `--prompt-file <tmpfile>`、运行**。helper 内部处理路径解析、
65
+ > spawn array args、shell escape 全部规避——LLM 不参与任何命令构造,也不写 `Agent(...)`。
66
+ > 这条 Bash 直调通道自动吃到 gemini-batch 29s 快路径,消除 `Agent→gemini-companion→ACP`
67
+ > 的 5+min 卡死与 sonnet wrapper silent-fallback(broker 故障时自答 fabricated 视角)。
68
+
69
+ ```
70
+ Step 1. 用 Write 把任务描述写到 tmpfile(≤2KB,只放任务说明 + 角色提示词路径,不塞大段代码/diff):
71
+ Write({
72
+ file_path: ".context/tmp/ccg-analyze-codex-$JOB.txt",
73
+ content: <下方"任务描述模板">
74
+ })
75
+ Write({ 同上,gemini 版本,file_path: ".context/tmp/ccg-analyze-gemini-$JOB.txt" })
76
+
77
+ Step 2. 用 Bash 调 helper(占位符已渲染;纯分析只读,加 `--no-write`;并行两个在同一 message 内 run_in_background: true):
78
+ Bash({
79
+ command: `{{CODEX_BASH_TASK}} --no-write --prompt-file .context/tmp/ccg-analyze-codex-$JOB.txt`,
80
+ description: "Analyze: backend (codex direct)",
81
+ run_in_background: true
82
+ })
83
+ Bash({
84
+ command: `{{GEMINI_BASH_TASK}} --no-write --prompt-file .context/tmp/ccg-analyze-gemini-$JOB.txt`,
85
+ description: "Analyze: frontend (gemini direct)",
86
+ run_in_background: true
87
+ })
88
+
89
+ Step 3. 等 task-notification 后 Read 各自 stdout,`JSON.parse(stdout)` 取 helper 扁平化后的
90
+ `.text` 字段(= 模型真实输出);`.threadId` / `.stats` 同层可读。
62
91
  ```
63
- Agent({
64
- subagent_type: "<codex:codex-rescue|gemini:gemini-rescue>",
65
- description: "Analyze: <backend|frontend>",
66
- prompt: `ROLE_FILE: <角色提示词路径>
67
92
 
68
- <TASK>
93
+ **任务描述模板**(写到 tmpfile 的内容;保持 ≤2KB):
94
+
95
+ ```
96
+ # 任务:技术分析
97
+
98
+ 工作目录:<工作目录绝对路径>(你已在此,可直接用 Bash/Read)
99
+ 角色定义见 <角色提示词路径>(codex 用 ~/.claude/.ccg/prompts/{{BACKEND_PRIMARY}}/analyzer.md,gemini 用 {{FRONTEND_PRIMARY}}/analyzer.md),**先用 Read 工具读取该文件再开始分析**。
100
+
101
+ ## 你要做的事(用你自己的工具)
102
+
69
103
  需求:<增强后的需求(如未增强则用 $ARGUMENTS)>
70
- 上下文:<前序阶段检索到的代码上下文>
71
- </TASK>
104
+ 上下文:<前序阶段检索到的关键文件路径 + 符号名,不塞大段源码,让你自己 Read>
72
105
 
73
- OUTPUT: 期望输出格式
74
- Return ≤200 token structured summary (plugin-native protocol).
75
- `
76
- })
106
+ - codex (backend):技术可行性、架构影响、性能考量、潜在风险
107
+ - gemini (frontend):UI/UX 影响、用户体验、视觉设计考量
108
+
109
+ ## 硬约束
110
+
111
+ - **必须前台执行,禁止 `--background` / `--wait`**(ccgx 编排层已用 Agent run_in_background 包裹,插件内再 background = 双重后台,stop-gate / status / cancel 全盲)。
112
+ - 对文件系统零写入,仅分析。
113
+
114
+ ## 输出(JSON)
115
+
116
+ { "feasibility": "...", "impacts": [...], "risks": [...], "recommendations": [...] }
117
+ 只输出 JSON,无其他文本。
77
118
  ```
78
119
 
79
- 并行**两个 Agent 在同一 message 内同时 spawn**。
120
+ **严禁**:在 prompt 里塞大段源码 / git diff(撞 OS argv ~32KB 上限);写 `Agent(subagent_type="gemini:gemini-rescue")`(走 ACP 慢路径 + sonnet wrapper silent-fallback);heredoc / `-p "..."` 内联;硬编码 plugin 路径。**唯一允许**:copy 占位符 + 追加 `--prompt-file <tmpfile>`(纯分析只读流另加 `--no-write`)。
80
121
 
81
- **通道 B — codeagent-wrapper fallback**(plugin 未装时降级,并行用 `run_in_background: true`):
122
+ **通道 B — codeagent-wrapper fallback**(plugin 未装时降级,并行用 `run_in_background: true`;wrapper 走 stdin pipe,无 ARG_MAX 限制,其 `ROLE_FILE:` 由 `invoke-model.mjs` 解析故保留):
82
123
 
83
124
  ```
84
125
  Bash({
@@ -96,7 +137,7 @@ EOF",
96
137
  })
97
138
  ```
98
139
 
99
- > ⚠️ 通道 B `codeagent-wrapper` 已标 **deprecated**。
140
+ > ⚠️ 通道 B `codeagent-wrapper` 已标 **deprecated**,仅 plugin 未装时使用。
100
141
 
101
142
  **角色提示词**:
102
143
 
@@ -110,7 +151,7 @@ EOF",
110
151
  1. 同 message 内 spawn 多个 `Bash(run_in_background: true)` 并行任务
111
152
  2. spawn 完后主线说明已启动 task-id,**直接 turn end**,**不调 TaskOutput**
112
153
  3. Claude Code 引擎在每个 task 完成时自动发 `<task-notification>` system-reminder 触发主线新 turn
113
- 4. 主线在新 turn 处理:从 `<output-file>` 路径 read stdout,按通道 schema parse 结果
154
+ 4. 主线在新 turn 处理:从 `<output-file>` 路径 read stdout,`JSON.parse(stdout)` helper 扁平化后的 `.text`(通道 A)/ `--progress` 行(通道 B)
114
155
  5. **必须等所有相关 task 都收到通知**才进入下一阶段(按 task-id 计数已收齐)
115
156
 
116
157
  ⛔ **禁止**:
@@ -142,14 +183,14 @@ EOF",
142
183
 
143
184
  `[模式:分析]`
144
185
 
145
- **⚠️ 必须发起两个并行 Bash 调用**(参照上方调用规范):
186
+ **⚠️ 必须发起两个并行 Bash 直调 helper 调用**(参照上方调用规范,先 Write tmpfile 再 `{{CODEX_BASH_TASK}}` / `{{GEMINI_BASH_TASK}}` + `--prompt-file`):
146
187
 
147
- 1. **{{BACKEND_PRIMARY}} 后端分析**:`Bash({ command: "...--backend {{BACKEND_PRIMARY}}...", run_in_background: true })`
148
- - ROLE_FILE: `~/.claude/.ccg/prompts/{{BACKEND_PRIMARY}}/analyzer.md`
188
+ 1. **{{BACKEND_PRIMARY}} 后端分析**:`{{CODEX_BASH_TASK}} --no-write --prompt-file <tmpfile>`(`run_in_background: true`)
189
+ - 角色:tmpfile 内写"角色定义见 `~/.claude/.ccg/prompts/{{BACKEND_PRIMARY}}/analyzer.md`,先用 Read 工具读取再开始"
149
190
  - OUTPUT:技术可行性、架构影响、性能考量
150
191
 
151
- 2. **{{FRONTEND_PRIMARY}} 前端分析**:`Bash({ command: "...--backend {{FRONTEND_PRIMARY}}...", run_in_background: true })`
152
- - ROLE_FILE: `~/.claude/.ccg/prompts/{{FRONTEND_PRIMARY}}/analyzer.md`
192
+ 2. **{{FRONTEND_PRIMARY}} 前端分析**:`{{GEMINI_BASH_TASK}} --no-write --prompt-file <tmpfile>`(`run_in_background: true`)
193
+ - 角色:tmpfile 内写"角色定义见 `~/.claude/.ccg/prompts/{{FRONTEND_PRIMARY}}/analyzer.md`,先用 Read 工具读取再开始"
153
194
  - OUTPUT:UI/UX 影响、用户体验、视觉设计考量
154
195
 
155
196
  事件驱动等待:spawn 完两个 Bash bg 后主线 turn end,等 task-notification 自动唤醒。**必须等所有模型返回后才能进入下一阶段**。