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.
- package/README.md +134 -277
- package/README.zh-CN.md +134 -272
- package/dist/chunks/version-build.mjs +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +709 -16
- package/dist/index.d.ts +709 -16
- package/dist/index.mjs +1061 -30
- package/dist/shared/{ccgx-workflow.j1spUsik.mjs → ccgx-workflow.CdHnJLak.mjs} +106 -22
- package/package.json +1 -1
- package/templates/commands/agents/code-fixer.md +6 -6
- package/templates/commands/agents/phase-runner.md +46 -14
- package/templates/commands/agents/plan-checker.md +10 -0
- package/templates/commands/analyze.md +66 -25
- package/templates/commands/autonomous.md +428 -225
- package/templates/commands/cancel.md +9 -0
- package/templates/commands/codex-exec.md +12 -11
- package/templates/commands/context.md +14 -0
- package/templates/commands/debate.md +10 -6
- package/templates/commands/execute.md +76 -28
- package/templates/commands/optimize.md +53 -25
- package/templates/commands/plan.md +78 -28
- package/templates/commands/review.md +26 -19
- package/templates/commands/spec-impl.md +68 -127
- package/templates/commands/spec-plan.md +61 -82
- package/templates/commands/spec-research.md +35 -92
- package/templates/commands/spec-review.md +34 -119
- package/templates/commands/status.md +1 -0
- package/templates/commands/team-exec.md +45 -13
- package/templates/commands/team.md +64 -167
- package/templates/commands/test.md +56 -34
- package/templates/commands/verify-work.md +36 -13
- package/templates/commands/verify.md +35 -0
- package/templates/commands/workflow.md +22 -37
- package/templates/hooks/ccg-loop-detector.cjs +39 -8
- package/templates/hooks/ccg-statusline.js +142 -2
- package/templates/hooks/ccg-stop-gate.cjs +248 -19
- package/templates/hooks/ccg-subagent-context.cjs +505 -0
- package/templates/scripts/ccg-state-lock.cjs +510 -0
- package/templates/scripts/ccg-team-schedule.cjs +328 -0
- package/templates/scripts/ccgx-call-plugin.mjs +494 -141
- package/templates/scripts/invoke-model.mjs +28 -1
- package/templates/scripts/task-store.cjs +614 -0
- package/templates/skills/tools/verify-change/SKILL.md +7 -0
- package/templates/skills/tools/verify-module/SKILL.md +7 -0
- package/templates/skills/tools/verify-quality/SKILL.md +7 -0
- 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.
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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(
|
|
4485
|
-
return stdout.includes(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
4695
|
+
await execAsync$1(`npx --yes ${PACKAGE_NAME}@latest init --force --skip-mcp --skip-prompt`, {
|
|
4618
4696
|
timeout: 3e5,
|
|
4619
|
-
// 5min —
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
5240
|
-
return stdout.includes(
|
|
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(
|
|
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.
|
|
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` |
|
|
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 (
|
|
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.
|
|
209
|
+
### Phase G. 多轮收敛(多轮模式:`--fix` Ralph auto-retry / `--fix --auto`)
|
|
210
210
|
|
|
211
|
-
`--auto`
|
|
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` →
|
|
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 路由
|
|
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
|
-
|
|
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` | `
|
|
43
|
-
| `frontend` | `
|
|
44
|
-
| `fullstack` | 串行:先 codex(schema
|
|
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
|
-
|
|
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
|
-
|
|
|
68
|
-
| Plugin 报告 partial / failed
|
|
69
|
-
| Plugin 超时 /
|
|
70
|
-
| 同一 phase
|
|
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
|
|
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`**:按"
|
|
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 时
|
|
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
|
|
40
|
+
CCG 把双模型并行通道从 `Bash(codeagent-wrapper)` **默认切换**为 Bash 直调 plugin 快路径:
|
|
41
41
|
|
|
42
|
-
1. **优先 plugin
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
74
|
-
|
|
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
|
-
|
|
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
|
|
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}} 后端分析**:`
|
|
148
|
-
-
|
|
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}} 前端分析**:`
|
|
152
|
-
-
|
|
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 自动唤醒。**必须等所有模型返回后才能进入下一阶段**。
|