ccgx-workflow 1.0.2 → 1.0.4
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/dist/cli.mjs +3 -1
- package/dist/index.mjs +5 -5
- package/dist/shared/{ccgx-workflow.Bq9vAaEw.mjs → ccgx-workflow.Bl0vlpC_.mjs} +70 -1
- package/package.json +1 -1
- package/templates/commands/agents/interface-auditor.md +30 -4
- package/templates/commands/review.md +38 -12
- package/templates/scripts/ccg-phase-runner-launcher.mjs +8 -2
- package/templates/scripts/repatch-gemini-plugin.mjs +10 -0
package/dist/cli.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import cac from 'cac';
|
|
3
3
|
import ansis from 'ansis';
|
|
4
|
-
import { d as diagnoseMcpConfig, i as isWindows, r as readClaudeCodeConfig, f as fixWindowsMcpConfig, w as writeClaudeCodeConfig, a as readCcgConfig, b as initI18n, c as i18n, s as showMainMenu, e as init, g as configMcp, v as version } from './shared/ccgx-workflow.
|
|
4
|
+
import { d as diagnoseMcpConfig, i as isWindows, r as readClaudeCodeConfig, f as fixWindowsMcpConfig, w as writeClaudeCodeConfig, a as readCcgConfig, b as initI18n, c as i18n, s as showMainMenu, e as init, g as configMcp, v as version } from './shared/ccgx-workflow.Bl0vlpC_.mjs';
|
|
5
5
|
import 'inquirer';
|
|
6
6
|
import 'ora';
|
|
7
7
|
import 'node:child_process';
|
|
@@ -11,6 +11,8 @@ import 'node:url';
|
|
|
11
11
|
import 'pathe';
|
|
12
12
|
import 'fs-extra';
|
|
13
13
|
import 'smol-toml';
|
|
14
|
+
import 'node:fs';
|
|
15
|
+
import 'node:path';
|
|
14
16
|
import 'i18next';
|
|
15
17
|
|
|
16
18
|
async function diagnoseMcp() {
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { h as collectSkills } from './shared/ccgx-workflow.
|
|
2
|
-
export { j as changeLanguage, F as checkForUpdates, H as collectInvocableSkills, G as compareVersions, l as createDefaultConfig, m as createDefaultRouting, I as generateCommandContent, n as getCcgDir, o as getConfigPath, D as getCurrentVersion, E as getLatestVersion, q as getWorkflowById, p as getWorkflowConfigs, c as i18n, e as init, b as initI18n, x as installAceTool, y as installAceToolRs, J as installSkillCommands, t as installWorkflows, B as migrateToV1_4_0, C as needsMigration, K as parseFrontmatter, a as readCcgConfig, s as showMainMenu, A as uninstallAceTool, z as uninstallWorkflows, u as update, k as writeCcgConfig } from './shared/ccgx-workflow.
|
|
1
|
+
import { h as collectSkills } from './shared/ccgx-workflow.Bl0vlpC_.mjs';
|
|
2
|
+
export { j as changeLanguage, F as checkForUpdates, H as collectInvocableSkills, G as compareVersions, l as createDefaultConfig, m as createDefaultRouting, I as generateCommandContent, n as getCcgDir, o as getConfigPath, D as getCurrentVersion, E as getLatestVersion, q as getWorkflowById, p as getWorkflowConfigs, c as i18n, e as init, b as initI18n, x as installAceTool, y as installAceToolRs, J as installSkillCommands, t as installWorkflows, B as migrateToV1_4_0, C as needsMigration, K as parseFrontmatter, a as readCcgConfig, s as showMainMenu, A as uninstallAceTool, z as uninstallWorkflows, u as update, k as writeCcgConfig } from './shared/ccgx-workflow.Bl0vlpC_.mjs';
|
|
3
3
|
import { existsSync, readFileSync, mkdirSync, writeFileSync, statSync, readdirSync } from 'node:fs';
|
|
4
4
|
import { join, dirname } from 'node:path';
|
|
5
5
|
import { homedir } from 'node:os';
|
|
@@ -986,9 +986,9 @@ function resolveQualityTier(input) {
|
|
|
986
986
|
return { tier: "triple", source: "default" };
|
|
987
987
|
}
|
|
988
988
|
const PHASE_RUNNER_BUDGET_USD = {
|
|
989
|
-
fast:
|
|
990
|
-
triple:
|
|
991
|
-
debate:
|
|
989
|
+
fast: 50,
|
|
990
|
+
triple: 100,
|
|
991
|
+
debate: 250
|
|
992
992
|
};
|
|
993
993
|
function shellSingleQuote(s) {
|
|
994
994
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
@@ -8,9 +8,11 @@ import { fileURLToPath } from 'node:url';
|
|
|
8
8
|
import { join, dirname, relative, sep, basename } from 'pathe';
|
|
9
9
|
import fs from 'fs-extra';
|
|
10
10
|
import { parse, stringify } from 'smol-toml';
|
|
11
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
12
|
+
import { join as join$1 } from 'node:path';
|
|
11
13
|
import i18next from 'i18next';
|
|
12
14
|
|
|
13
|
-
const version = "1.0.
|
|
15
|
+
const version = "1.0.4";
|
|
14
16
|
|
|
15
17
|
function cmd(id, order, category, name, nameEn, description, descriptionEn, cmdOverride) {
|
|
16
18
|
return {
|
|
@@ -291,6 +293,61 @@ function getMcpCommand(command) {
|
|
|
291
293
|
return [command];
|
|
292
294
|
}
|
|
293
295
|
|
|
296
|
+
const VENDOR_MARKETPLACE_KEYS = {
|
|
297
|
+
codex: "codex@openai-codex",
|
|
298
|
+
gemini: "gemini@google-gemini"
|
|
299
|
+
};
|
|
300
|
+
function discoverCompanion(vendor, homeDir = homedir()) {
|
|
301
|
+
const ssotPath = join$1(homeDir, ".claude", "plugins", "installed_plugins.json");
|
|
302
|
+
if (!existsSync(ssotPath)) return null;
|
|
303
|
+
let raw;
|
|
304
|
+
try {
|
|
305
|
+
raw = JSON.parse(readFileSync(ssotPath, "utf-8"));
|
|
306
|
+
} catch {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
const key = VENDOR_MARKETPLACE_KEYS[vendor];
|
|
310
|
+
const instances = raw?.plugins?.[key];
|
|
311
|
+
if (!Array.isArray(instances) || instances.length === 0) return null;
|
|
312
|
+
const inst = instances[0];
|
|
313
|
+
const installPath = inst?.installPath;
|
|
314
|
+
if (typeof installPath !== "string" || !installPath) return null;
|
|
315
|
+
const companionPath = join$1(installPath, "scripts", `${vendor}-companion.mjs`);
|
|
316
|
+
if (!existsSync(companionPath)) return null;
|
|
317
|
+
const version = typeof inst?.version === "string" ? inst.version : "unknown";
|
|
318
|
+
return { vendor, installPath, companionPath, version };
|
|
319
|
+
}
|
|
320
|
+
function shellQuotePosix(s) {
|
|
321
|
+
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
322
|
+
}
|
|
323
|
+
function buildBashCommand(loc, options = {}) {
|
|
324
|
+
const jsonOutput = options.jsonOutput ?? true;
|
|
325
|
+
const promptPlaceholder = options.promptPlaceholder ?? "%PROMPT%";
|
|
326
|
+
const heredocDelimiter = options.heredocDelimiter ?? "CCG_PROMPT_EOF";
|
|
327
|
+
const quotedPath = shellQuotePosix(loc.companionPath);
|
|
328
|
+
const flags = jsonOutput ? "--json" : "";
|
|
329
|
+
return [
|
|
330
|
+
`node ${quotedPath} task ${flags}-p "$(cat <<'${heredocDelimiter}'`,
|
|
331
|
+
promptPlaceholder,
|
|
332
|
+
heredocDelimiter,
|
|
333
|
+
`)"`
|
|
334
|
+
].join("\n").replace(/ -p/, " -p").replace(/ +/g, " ").trimEnd();
|
|
335
|
+
}
|
|
336
|
+
function buildPluginMissingFallback(vendor) {
|
|
337
|
+
const key = VENDOR_MARKETPLACE_KEYS[vendor];
|
|
338
|
+
return [
|
|
339
|
+
`# CCG: ${vendor} plugin (${key}) not installed at CCG install time.`,
|
|
340
|
+
`# Install with: claude plugin install ${key}`,
|
|
341
|
+
`# Then re-run: npx ccgx-workflow init --skip-prompt --skip-mcp`,
|
|
342
|
+
`echo 'CCG: ${vendor} plugin not available' >&2 && exit 1`
|
|
343
|
+
].join("\n");
|
|
344
|
+
}
|
|
345
|
+
function resolvePluginBashCommand(vendor, options = {}, homeDir) {
|
|
346
|
+
const loc = discoverCompanion(vendor, homeDir);
|
|
347
|
+
if (!loc) return buildPluginMissingFallback(vendor);
|
|
348
|
+
return buildBashCommand(loc, options);
|
|
349
|
+
}
|
|
350
|
+
|
|
294
351
|
const __filename$2 = fileURLToPath(import.meta.url);
|
|
295
352
|
const __dirname$2 = dirname(__filename$2);
|
|
296
353
|
function findPackageRoot$1(startDir) {
|
|
@@ -356,6 +413,18 @@ function injectConfigVariables(content, config) {
|
|
|
356
413
|
}
|
|
357
414
|
const liteModeFlag = config.liteMode ? "--lite " : "";
|
|
358
415
|
processed = processed.replace(/\{\{LITE_MODE_FLAG\}\}/g, liteModeFlag);
|
|
416
|
+
if (processed.includes("{{CODEX_BASH_TASK}}")) {
|
|
417
|
+
processed = processed.replace(/\{\{CODEX_BASH_TASK\}\}/g, resolvePluginBashCommand("codex"));
|
|
418
|
+
}
|
|
419
|
+
if (processed.includes("{{CODEX_BASH_TASK_TEXT}}")) {
|
|
420
|
+
processed = processed.replace(/\{\{CODEX_BASH_TASK_TEXT\}\}/g, resolvePluginBashCommand("codex", { jsonOutput: false }));
|
|
421
|
+
}
|
|
422
|
+
if (processed.includes("{{GEMINI_BASH_TASK}}")) {
|
|
423
|
+
processed = processed.replace(/\{\{GEMINI_BASH_TASK\}\}/g, resolvePluginBashCommand("gemini"));
|
|
424
|
+
}
|
|
425
|
+
if (processed.includes("{{GEMINI_BASH_TASK_TEXT}}")) {
|
|
426
|
+
processed = processed.replace(/\{\{GEMINI_BASH_TASK_TEXT\}\}/g, resolvePluginBashCommand("gemini", { jsonOutput: false }));
|
|
427
|
+
}
|
|
359
428
|
const mcpProvider = config.mcpProvider || "ace-tool";
|
|
360
429
|
if (mcpProvider === "skip") {
|
|
361
430
|
processed = processed.replace(/,\s*\{\{MCP_SEARCH_TOOL\}\}/g, "");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ccgx-workflow",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
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",
|
|
@@ -99,7 +99,32 @@ phase_files: [<本 phase 修改/新增的相对路径>]
|
|
|
99
99
|
[{severity: info, category: commit-diff-drift, message: "subject says 'add foo' but git stat 无新建 foo 路径文件 (best-effort 检测,可能误报)"}]
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
-
### 5.
|
|
102
|
+
### 5. Inline plugin Bash 命令拼接(critical,1.0.4 新增)
|
|
103
|
+
|
|
104
|
+
**目的**:检测模板里有没有手写 inline `node "$(ls .../codex-companion.mjs | head -1)" task -p ...` 命令——绕过 1.0.4 install-time codegen 占位符(`{{CODEX_BASH_TASK}}` / `{{GEMINI_BASH_TASK}}` / `{{CODEX_BASH_TASK_TEXT}}` / `{{GEMINI_BASH_TASK_TEXT}}`),重新引入 v4.4.1 同型的"flag 漂移 + 路径 glob hack"风险。
|
|
105
|
+
|
|
106
|
+
**为什么这是 critical**:
|
|
107
|
+
|
|
108
|
+
- inline 拼接给 LLM 自由发挥空间——LLM 看到示例后会**编造**未在示例中出现的 flag(与 v4.4.1 编造 `codex:rescue` 单前缀同型)
|
|
109
|
+
- `ls .../*-companion.mjs | head -1` 在 plugin 多版本 cache 下行为不可预测(installed_plugins.json 才是 SSoT)
|
|
110
|
+
- 跳过 install-time codegen 意味着 plugin 未装时模板**静默坏掉**而不是给出清晰错误
|
|
111
|
+
|
|
112
|
+
**怎么做**:
|
|
113
|
+
1. 本 phase commit 影响的 `.md` 文件中(仅扫 `templates/commands/**.md`)grep:
|
|
114
|
+
- `node\s+["'`].*?-companion\.mjs.*?\btask\b.*?-p\b` — inline 命令模式
|
|
115
|
+
- `\$\(ls\s+.*-companion\.mjs.*head\s+-1\)` — glob hack 模式
|
|
116
|
+
- `buildPluginBashCommand\s*\(` — TS-helper 伪代码模式(codex 审计提到的"helper opts 漂移"风险)
|
|
117
|
+
2. 命中即 critical,除非该出现位置是:
|
|
118
|
+
- 1.0.4+ CHANGELOG / migration doc 的"反例对照"段落
|
|
119
|
+
- `agents/interface-auditor.md` 自身(本 rule 说明)
|
|
120
|
+
- 测试 fixture(`__tests__/`、`fixtures/`、`*.test.*`)
|
|
121
|
+
|
|
122
|
+
**critical 例子**:
|
|
123
|
+
```
|
|
124
|
+
[{severity: critical, category: inline-plugin-bash, message: "review.md:58 inline `node ... codex-companion.mjs ... task -p` — 应改用 {{CODEX_BASH_TASK}} install-time codegen 占位符(1.0.4 起)"}]
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 6. Mock 与 ground truth schema 偏差(info/major)
|
|
103
128
|
|
|
104
129
|
**目的**:测试 mock 数据跟真实 schema 不一致(与 P28 fixtures 协作;本 agent 仅做轻量提示)。
|
|
105
130
|
|
|
@@ -123,14 +148,15 @@ phase_files: [<本 phase 修改/新增的相对路径>]
|
|
|
123
148
|
2. `git show <commit_hash> --name-only` → phase_files 验证;若 prompt 给的列表跟 git 不一致以 git 为准
|
|
124
149
|
3. 过滤掉非 `.ts` / `.md` / `package.json` 的文件(图片、bin 等不审)
|
|
125
150
|
|
|
126
|
-
### Step 2:
|
|
127
|
-
对每个 phase 修改文件分别跑
|
|
151
|
+
### Step 2: 六项检查并行思考
|
|
152
|
+
对每个 phase 修改文件分别跑 6 项检查的 grep。每条命中产出一个 Finding 候选。
|
|
128
153
|
|
|
129
154
|
### Step 3: 假阳性过滤
|
|
130
155
|
- SSoT 违反:排除测试文件、type union 同名、re-export
|
|
131
156
|
- 半成品:排除 default export、type-only re-export 到 index.ts
|
|
132
157
|
- magic string:排除 CCG 自家 agent 名(白名单)
|
|
133
158
|
- commit drift:用模糊匹配,命中率不高时降级 info
|
|
159
|
+
- inline-plugin-bash:排除 CHANGELOG/migration 反例段、interface-auditor.md 自身说明、测试 fixture
|
|
134
160
|
- mock drift:纯 best-effort,全部标 info severity
|
|
135
161
|
|
|
136
162
|
### Step 4: 输出 ≤200 token 摘要
|
|
@@ -139,7 +165,7 @@ phase_files: [<本 phase 修改/新增的相对路径>]
|
|
|
139
165
|
|
|
140
166
|
```
|
|
141
167
|
STATUS: complete | error
|
|
142
|
-
FINDINGS: [{severity: critical|major|info, category: ssot-violation|leftover|magic-string-mismatch|commit-diff-drift|mock-drift, message: "<具体证据 + 文件路径 + 行号>"}, ...]
|
|
168
|
+
FINDINGS: [{severity: critical|major|info, category: ssot-violation|leftover|magic-string-mismatch|commit-diff-drift|inline-plugin-bash|mock-drift, message: "<具体证据 + 文件路径 + 行号>"}, ...]
|
|
143
169
|
NOTES: <≤80 字一行总结>
|
|
144
170
|
```
|
|
145
171
|
|
|
@@ -51,25 +51,44 @@ argument-hint: "[代码或描述] [--adversarial] [--fix [--all] [--auto]] [--ro
|
|
|
51
51
|
|
|
52
52
|
**调用语法**(v4.4.2 起 review/verify 路径默认走 Bash 直调):
|
|
53
53
|
|
|
54
|
-
**通道 A — Bash 直调 plugin script
|
|
54
|
+
**通道 A — Bash 直调 plugin script(默认,绕开 sonnet wrapper)**:
|
|
55
|
+
|
|
56
|
+
> 1.0.4 起 Bash 命令字符串由 install 时直接渲染(基于 `~/.claude/plugins/installed_plugins.json`
|
|
57
|
+
> 真值源),LLM 只需 copy 整段 + 替换 `%PROMPT%` 即可。**禁止凭印象拼 `node "$(ls ...) | head -1"
|
|
58
|
+
> task -p ...` inline 命令** —— glob hack 在 plugin 多版本 cache 下行为不可预测,且参数漂移
|
|
59
|
+
> 与 v4.4.1 的 195 处错名 bug 同型。
|
|
55
60
|
|
|
56
61
|
```
|
|
62
|
+
# 后端审查(codex 视角)
|
|
57
63
|
Bash({
|
|
58
|
-
command: `
|
|
64
|
+
command: `{{CODEX_BASH_TASK}}`, ← install 时已渲染为完整命令,含 heredoc 安全 prompt 注入
|
|
59
65
|
description: "Review: backend (codex direct)",
|
|
60
66
|
run_in_background: true,
|
|
61
67
|
timeout: 3600000
|
|
62
68
|
})
|
|
63
69
|
|
|
70
|
+
# 前端审查(gemini 视角)
|
|
64
71
|
Bash({
|
|
65
|
-
command: `
|
|
72
|
+
command: `{{GEMINI_BASH_TASK}}`,
|
|
66
73
|
description: "Review: frontend (gemini direct)",
|
|
67
74
|
run_in_background: true,
|
|
68
75
|
timeout: 3600000
|
|
69
76
|
})
|
|
70
77
|
```
|
|
71
78
|
|
|
72
|
-
|
|
79
|
+
LLM 消费协议:把上面命令字符串里的 `%PROMPT%` 替换为完整 prompt 文本(含 ROLE_FILE 引用 +
|
|
80
|
+
TASK 描述 + OUTPUT 要求),**不要在外面加任何 escape**——heredoc `<<'CCG_PROMPT_EOF'`
|
|
81
|
+
的单引号 delimiter 已保证 `$` / `'` / `"` / `\` 全部按字面量处理。
|
|
82
|
+
|
|
83
|
+
⛔ **不要**用 `Agent(subagent_type="codex:codex-rescue"|"gemini:gemini-rescue")`:
|
|
84
|
+
|
|
85
|
+
review/verify 路径输出**直接落地**决策(PR merge / advance / revise / escalate),无下游兜底。
|
|
86
|
+
plugin 经由 `Agent(...)` spawn 时引擎启动 sonnet wrapper 扮演 codex/gemini 客户端,broker 故障 /
|
|
87
|
+
CLI 空答 / auth 过期时 wrapper 受 instruction-tuning 驱动**自答 fabricated cross-vendor 视角**
|
|
88
|
+
(silent fallback),主线无法察觉。Bash 直调消除 wrapper 层,stdout 即真实 plugin 输出。
|
|
89
|
+
|
|
90
|
+
详见 `src/utils/verify-orchestrator.ts:planVerifyWave` 的 `useDirectBashInvocation` 选项 +
|
|
91
|
+
`src/utils/plugin-bash-codegen.ts`(1.0.4 install-time codegen)。
|
|
73
92
|
|
|
74
93
|
主线接 stdout JSON(5-50KB),按 plugin --json schema 解析 `result.text` 字段,失败信号:
|
|
75
94
|
- exit code ≠ 0 → loud fail,触发 v1.7.87 标准 2-retry / 5s / 3-attempts 规则
|
|
@@ -165,11 +184,21 @@ EOF",
|
|
|
165
184
|
|
|
166
185
|
**仅当 `$ARGUMENTS` 含 `--adversarial` 字面量时启动**。否则跳过本阶段。
|
|
167
186
|
|
|
168
|
-
调用方式(
|
|
187
|
+
调用方式(Bash 直调,绕开 sonnet wrapper):
|
|
169
188
|
|
|
170
189
|
```
|
|
171
190
|
Bash({
|
|
172
|
-
command: `
|
|
191
|
+
command: `{{CODEX_BASH_TASK}}`, ← 同上,install 时渲染为完整命令
|
|
192
|
+
description: "Adversarial review (codex direct)",
|
|
193
|
+
run_in_background: true,
|
|
194
|
+
timeout: 3600000
|
|
195
|
+
})
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
把命令里的 `%PROMPT%` 替换为以下完整 prompt 文本(heredoc 已保证字面量传递,不需要 escape):
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
--adversarial-review
|
|
173
202
|
|
|
174
203
|
请对以下代码变更进行敌对视角审查:
|
|
175
204
|
|
|
@@ -184,14 +213,11 @@ Bash({
|
|
|
184
213
|
你的任务:
|
|
185
214
|
1. 找出前两轮**未发现或低估**的安全/性能/正确性漏洞
|
|
186
215
|
2. 假设代码作者刻意误导,挑刺
|
|
187
|
-
3. 输出格式:[Critical-Adversarial] / [Major-Adversarial] 列表,每条标
|
|
188
|
-
description: "Adversarial review (codex direct)",
|
|
189
|
-
run_in_background: true,
|
|
190
|
-
timeout: 3600000
|
|
191
|
-
})
|
|
216
|
+
3. 输出格式:[Critical-Adversarial] / [Major-Adversarial] 列表,每条标"为什么前两轮没发现"
|
|
192
217
|
```
|
|
193
218
|
|
|
194
|
-
⛔ 不用 `Agent(subagent_type="codex:codex-rescue")
|
|
219
|
+
⛔ 不用 `Agent(subagent_type="codex:codex-rescue")`:review/verify 路径输出直接落地,silent fallback
|
|
220
|
+
风险(sonnet wrapper 受 instruction-tuning 自答冒充 adversarial 视角)不可接受。详见前文「通道 A」段。
|
|
195
221
|
|
|
196
222
|
收到 stdout JSON 后解析 `result.text` 字段保留待阶段 3 综合。stdout 空或 exit≠0 → 走标准 2-retry 规则。
|
|
197
223
|
|
|
@@ -152,7 +152,7 @@ Required:
|
|
|
152
152
|
|
|
153
153
|
Optional:
|
|
154
154
|
--tier <fast|triple|debate> Quality tier; maps to --max-budget-usd
|
|
155
|
-
(fast=
|
|
155
|
+
(fast=50, triple=100, debate=250). Default: triple.
|
|
156
156
|
--max-budget-usd <N> Override per-call budget cap.
|
|
157
157
|
--grace-ms <N> SIGTERM->SIGKILL grace (default 5000).
|
|
158
158
|
|
|
@@ -193,7 +193,13 @@ function writeState(workdir, jobId, state) {
|
|
|
193
193
|
// production phase-runner spawn).
|
|
194
194
|
// ---------------------------------------------------------------------------
|
|
195
195
|
|
|
196
|
-
|
|
196
|
+
// v1.0.3: ×50 raise after user feedback. PoC D3 baseline (fast=$1 / triple=$2
|
|
197
|
+
// / debate=$5) was tuned for "p90 + 50% margin" of *single phase* spawns, but
|
|
198
|
+
// real autonomous runs hit the cap on edge cases ($1.034 over $1) — tight
|
|
199
|
+
// enough to surface as failures rather than runaway loops. Raising to 50/100/
|
|
200
|
+
// 250 keeps the runaway-loop guardrail intact (a stuck loop blows >$1000 fast)
|
|
201
|
+
// while removing the false-positive failure mode for legitimately complex phases.
|
|
202
|
+
const TIER_BUDGET = { fast: 50.0, triple: 100.0, debate: 250.0 }
|
|
197
203
|
|
|
198
204
|
function buildClaudeArgs({ promptFile, workdir, tier, maxBudgetUsd }) {
|
|
199
205
|
const budget = maxBudgetUsd ?? TIER_BUDGET[tier]
|
|
@@ -132,6 +132,16 @@ const PATCHES = [
|
|
|
132
132
|
match: /(spawnSync\(command,\s*\[name\],\s*\{\s*encoding:\s*"utf8",\s*stdio:\s*"pipe")(\s*\})/,
|
|
133
133
|
replace: '$1, windowsHide: true$2',
|
|
134
134
|
},
|
|
135
|
+
{
|
|
136
|
+
id: "P-9",
|
|
137
|
+
file: "lib/acp-client.mjs",
|
|
138
|
+
description: "JSON-RPC error swallowing (reject with bare {code,message} → caller sees '[object Object]')",
|
|
139
|
+
// Guard: any patched marker present
|
|
140
|
+
guard: /CCG P-9 patch/,
|
|
141
|
+
// Match: the bare reject(message.error) inside the response branch
|
|
142
|
+
match: /(if \(message\.error\) \{\s*\r?\n\s*)pending\.reject\(message\.error\);(\s*\r?\n\s*\} else \{)/,
|
|
143
|
+
replace: `$1// CCG P-9 patch: wrap JSON-RPC error object in Error instance.\n // Without this, callers doing \`e instanceof Error ? e.message : String(e)\`\n // get "[object Object]" — losing real error info (auth-expired, broker-dead,\n // parse-error, etc). See .ccg-migration/PLUGIN-PATCHES.md P-9.\n const _err = message.error;\n const _wrapped = Object.assign(\n new Error(typeof _err === "object" && _err !== null && _err.message\n ? String(_err.message)\n : String(_err)),\n {\n jsonrpcCode: typeof _err === "object" && _err !== null ? _err.code : undefined,\n jsonrpcData: typeof _err === "object" && _err !== null ? _err.data : undefined,\n },\n );\n pending.reject(_wrapped);$2`,
|
|
144
|
+
},
|
|
135
145
|
];
|
|
136
146
|
|
|
137
147
|
let applied = 0;
|