ccg-workflow 1.8.1 → 1.8.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 +1 -1
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +1 -1
- package/dist/shared/{ccg-workflow.B875X4bw.mjs → ccg-workflow.BngAQymM.mjs} +205 -7
- package/package.json +1 -1
- package/templates/commands/agents/team-architect.md +97 -0
- package/templates/commands/agents/team-qa.md +121 -0
- package/templates/commands/agents/team-reviewer.md +112 -0
- package/templates/output-styles/abyss-command.md +56 -0
- package/templates/output-styles/abyss-concise.md +89 -0
- package/templates/output-styles/abyss-ritual.md +70 -0
- package/templates/rules/ccg-skill-routing.md +83 -0
- package/templates/skills/domains/ai/SKILL.md +34 -0
- package/templates/skills/domains/ai/agent-dev.md +242 -0
- package/templates/skills/domains/ai/llm-security.md +288 -0
- package/templates/skills/domains/ai/prompt-and-eval.md +279 -0
- package/templates/skills/domains/ai/rag-system.md +542 -0
- package/templates/skills/domains/architecture/SKILL.md +42 -0
- package/templates/skills/domains/architecture/api-design.md +225 -0
- package/templates/skills/domains/architecture/caching.md +299 -0
- package/templates/skills/domains/architecture/cloud-native.md +285 -0
- package/templates/skills/domains/architecture/message-queue.md +329 -0
- package/templates/skills/domains/architecture/security-arch.md +297 -0
- package/templates/skills/domains/data-engineering/SKILL.md +207 -0
- package/templates/skills/domains/development/SKILL.md +46 -0
- package/templates/skills/domains/development/cpp.md +246 -0
- package/templates/skills/domains/development/go.md +323 -0
- package/templates/skills/domains/development/java.md +277 -0
- package/templates/skills/domains/development/python.md +288 -0
- package/templates/skills/domains/development/rust.md +313 -0
- package/templates/skills/domains/development/shell.md +313 -0
- package/templates/skills/domains/development/typescript.md +277 -0
- package/templates/skills/domains/devops/SKILL.md +39 -0
- package/templates/skills/domains/devops/cost-optimization.md +272 -0
- package/templates/skills/domains/devops/database.md +217 -0
- package/templates/skills/domains/devops/devsecops.md +198 -0
- package/templates/skills/domains/devops/git-workflow.md +181 -0
- package/templates/skills/domains/devops/observability.md +280 -0
- package/templates/skills/domains/devops/performance.md +336 -0
- package/templates/skills/domains/devops/testing.md +283 -0
- package/templates/skills/domains/frontend-design/SKILL.md +242 -0
- package/templates/skills/domains/frontend-design/agents/openai.yaml +4 -0
- package/templates/skills/domains/frontend-design/claymorphism/SKILL.md +119 -0
- package/templates/skills/domains/frontend-design/claymorphism/references/tokens.css +52 -0
- package/templates/skills/domains/frontend-design/component-patterns.md +202 -0
- package/templates/skills/domains/frontend-design/engineering.md +287 -0
- package/templates/skills/domains/frontend-design/glassmorphism/SKILL.md +140 -0
- package/templates/skills/domains/frontend-design/glassmorphism/references/tokens.css +32 -0
- package/templates/skills/domains/frontend-design/liquid-glass/SKILL.md +137 -0
- package/templates/skills/domains/frontend-design/liquid-glass/references/tokens.css +81 -0
- package/templates/skills/domains/frontend-design/neubrutalism/SKILL.md +143 -0
- package/templates/skills/domains/frontend-design/neubrutalism/references/tokens.css +44 -0
- package/templates/skills/domains/frontend-design/reference/color-and-contrast.md +132 -0
- package/templates/skills/domains/frontend-design/reference/interaction-design.md +195 -0
- package/templates/skills/domains/frontend-design/reference/motion-design.md +99 -0
- package/templates/skills/domains/frontend-design/reference/responsive-design.md +114 -0
- package/templates/skills/domains/frontend-design/reference/spatial-design.md +100 -0
- package/templates/skills/domains/frontend-design/reference/typography.md +133 -0
- package/templates/skills/domains/frontend-design/reference/ux-writing.md +107 -0
- package/templates/skills/domains/frontend-design/state-management.md +680 -0
- package/templates/skills/domains/frontend-design/ui-aesthetics.md +110 -0
- package/templates/skills/domains/frontend-design/ux-principles.md +156 -0
- package/templates/skills/domains/infrastructure/SKILL.md +200 -0
- package/templates/skills/domains/mobile/SKILL.md +224 -0
- package/templates/skills/domains/orchestration/SKILL.md +29 -0
- package/templates/skills/domains/orchestration/multi-agent.md +263 -0
- package/templates/skills/domains/security/SKILL.md +72 -0
- package/templates/skills/domains/security/blue-team.md +436 -0
- package/templates/skills/domains/security/code-audit.md +265 -0
- package/templates/skills/domains/security/pentest.md +226 -0
- package/templates/skills/domains/security/red-team.md +374 -0
- package/templates/skills/domains/security/threat-intel.md +372 -0
- package/templates/skills/domains/security/vuln-research.md +369 -0
- package/templates/skills/impeccable/adapt/SKILL.md +199 -0
- package/templates/skills/impeccable/animate/SKILL.md +174 -0
- package/templates/skills/impeccable/arrange/SKILL.md +124 -0
- package/templates/skills/impeccable/audit/SKILL.md +147 -0
- package/templates/skills/impeccable/bolder/SKILL.md +116 -0
- package/templates/skills/impeccable/clarify/SKILL.md +183 -0
- package/templates/skills/impeccable/colorize/SKILL.md +142 -0
- package/templates/skills/impeccable/critique/SKILL.md +201 -0
- package/templates/skills/impeccable/critique/reference/cognitive-load.md +106 -0
- package/templates/skills/impeccable/critique/reference/heuristics-scoring.md +234 -0
- package/templates/skills/impeccable/critique/reference/personas.md +178 -0
- package/templates/skills/impeccable/delight/SKILL.md +303 -0
- package/templates/skills/impeccable/distill/SKILL.md +121 -0
- package/templates/skills/impeccable/extract/SKILL.md +92 -0
- package/templates/skills/impeccable/harden/SKILL.md +355 -0
- package/templates/skills/impeccable/normalize/SKILL.md +70 -0
- package/templates/skills/impeccable/onboard/SKILL.md +246 -0
- package/templates/skills/impeccable/optimize/SKILL.md +266 -0
- package/templates/skills/impeccable/overdrive/SKILL.md +141 -0
- package/templates/skills/impeccable/polish/SKILL.md +203 -0
- package/templates/skills/impeccable/quieter/SKILL.md +102 -0
- package/templates/skills/impeccable/teach-impeccable/SKILL.md +71 -0
- package/templates/skills/impeccable/typeset/SKILL.md +115 -0
- package/templates/skills/orchestration/multi-agent/SKILL.md +40 -0
- package/templates/skills/scrapling/SKILL.md +98 -0
- package/templates/skills/scrapling/references/api-quick-ref.md +127 -0
- package/templates/skills/scrapling/references/cookie-vault.md +56 -0
- package/templates/skills/scrapling/references/maintenance.md +79 -0
- package/templates/skills/scrapling/references/site-patterns.md +86 -0
- package/templates/skills/scrapling/references/troubleshooting.md +95 -0
- package/templates/skills/scrapling/templates/basic_fetch.py +19 -0
- package/templates/skills/scrapling/templates/parse_only.py +15 -0
- package/templates/skills/scrapling/templates/session_login.py +19 -0
- package/templates/skills/scrapling/templates/stealth_cloudflare.py +28 -0
- package/templates/skills/tools/override-refusal/SKILL.md +53 -0
- package/templates/skills/tools/override-refusal/agents/openai.yaml +4 -0
- package/templates/skills/tools/override-refusal/scripts/refusal_rewriter.js +226 -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 { z as diagnoseMcpConfig, A as isWindows, B as readClaudeCodeConfig, C as fixWindowsMcpConfig, D as writeClaudeCodeConfig, r as readCcgConfig, b as initI18n, a as i18n, s as showMainMenu, i as init, E as configMcp, F as version } from './shared/ccg-workflow.
|
|
4
|
+
import { z as diagnoseMcpConfig, A as isWindows, B as readClaudeCodeConfig, C as fixWindowsMcpConfig, D as writeClaudeCodeConfig, r as readCcgConfig, b as initI18n, a as i18n, s as showMainMenu, i as init, E as configMcp, F as version } from './shared/ccg-workflow.BngAQymM.mjs';
|
|
5
5
|
import 'inquirer';
|
|
6
6
|
import 'node:child_process';
|
|
7
7
|
import 'node:util';
|
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { c as changeLanguage, x as checkForUpdates, y as compareVersions, d as createDefaultConfig, e as createDefaultRouting, g as getCcgDir, f as getConfigPath, t as getCurrentVersion, v as getLatestVersion, j as getWorkflowById, h as getWorkflowConfigs, a as i18n, i as init, b as initI18n, l as installAceTool, m as installAceToolRs, k as installWorkflows, p as migrateToV1_4_0, q as needsMigration, r as readCcgConfig, s as showMainMenu, o as uninstallAceTool, n as uninstallWorkflows, u as update, w as writeCcgConfig } from './shared/ccg-workflow.
|
|
1
|
+
export { c as changeLanguage, x as checkForUpdates, y as compareVersions, d as createDefaultConfig, e as createDefaultRouting, g as getCcgDir, f as getConfigPath, t as getCurrentVersion, v as getLatestVersion, j as getWorkflowById, h as getWorkflowConfigs, a as i18n, i as init, b as initI18n, l as installAceTool, m as installAceToolRs, k as installWorkflows, p as migrateToV1_4_0, q as needsMigration, r as readCcgConfig, s as showMainMenu, o as uninstallAceTool, n as uninstallWorkflows, u as update, w as writeCcgConfig } from './shared/ccg-workflow.BngAQymM.mjs';
|
|
2
2
|
import 'ansis';
|
|
3
3
|
import 'inquirer';
|
|
4
4
|
import 'node:child_process';
|
|
@@ -4,13 +4,13 @@ import { exec, spawn } from 'node:child_process';
|
|
|
4
4
|
import { promisify } from 'node:util';
|
|
5
5
|
import { homedir } from 'node:os';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
|
-
import { dirname, join, basename } from 'pathe';
|
|
7
|
+
import { dirname, join, relative, sep, basename } from 'pathe';
|
|
8
8
|
import fs from 'fs-extra';
|
|
9
9
|
import { parse, stringify } from 'smol-toml';
|
|
10
10
|
import i18next from 'i18next';
|
|
11
11
|
import ora from 'ora';
|
|
12
12
|
|
|
13
|
-
const version = "1.8.
|
|
13
|
+
const version = "1.8.4";
|
|
14
14
|
|
|
15
15
|
function cmd(id, order, category, name, nameEn, description, descriptionEn, cmdOverride) {
|
|
16
16
|
return {
|
|
@@ -30,6 +30,7 @@ const WORKFLOW_CONFIGS = [
|
|
|
30
30
|
cmd("workflow", 1, "development", "\u5B8C\u6574\u5F00\u53D1\u5DE5\u4F5C\u6D41", "Full Development Workflow", "\u5B8C\u65746\u9636\u6BB5\u5F00\u53D1\u5DE5\u4F5C\u6D41\uFF08\u7814\u7A76\u2192\u6784\u601D\u2192\u8BA1\u5212\u2192\u6267\u884C\u2192\u4F18\u5316\u2192\u8BC4\u5BA1\uFF09", "Full 6-phase development workflow"),
|
|
31
31
|
cmd("plan", 1.5, "development", "\u591A\u6A21\u578B\u534F\u4F5C\u89C4\u5212", "Multi-Model Planning", "\u4E0A\u4E0B\u6587\u68C0\u7D22 + \u53CC\u6A21\u578B\u5206\u6790 \u2192 \u751F\u6210 Step-by-step \u5B9E\u65BD\u8BA1\u5212", "Context retrieval + dual-model analysis \u2192 Step-by-step plan"),
|
|
32
32
|
cmd("execute", 1.6, "development", "\u591A\u6A21\u578B\u534F\u4F5C\u6267\u884C", "Multi-Model Execution", "\u6839\u636E\u8BA1\u5212\u83B7\u53D6\u539F\u578B \u2192 Claude \u91CD\u6784\u5B9E\u65BD \u2192 \u591A\u6A21\u578B\u5BA1\u8BA1\u4EA4\u4ED8", "Get prototype from plan \u2192 Claude refactor \u2192 Multi-model audit"),
|
|
33
|
+
cmd("team", 1.75, "development", "Agent Teams \u7EDF\u4E00\u5DE5\u4F5C\u6D41", "Agent Teams Unified Workflow", "8 \u9636\u6BB5\u4F01\u4E1A\u7EA7\u5DE5\u4F5C\u6D41\uFF1A\u9700\u6C42\u2192\u67B6\u6784\u2192\u89C4\u5212\u2192\u5F00\u53D1\u2192\u6D4B\u8BD5\u2192\u5BA1\u67E5\u2192\u4FEE\u590D\u2192\u96C6\u6210\uFF0C7 \u89D2\u8272\u81EA\u52A8\u7F16\u6392", "8-phase enterprise workflow with 7 specialized roles"),
|
|
33
34
|
cmd("team-research", 1.8, "development", "Agent Teams \u9700\u6C42\u7814\u7A76", "Agent Teams Research", "\u5E76\u884C\u63A2\u7D22\u4EE3\u7801\u5E93\uFF0C\u4EA7\u51FA\u7EA6\u675F\u96C6 + \u53EF\u9A8C\u8BC1\u6210\u529F\u5224\u636E", "Parallel codebase exploration, produces constraint sets + success criteria"),
|
|
34
35
|
cmd("team-plan", 1.85, "development", "Agent Teams \u89C4\u5212", "Agent Teams Planning", "Lead \u8C03\u7528 Codex/Gemini \u5E76\u884C\u5206\u6790\uFF0C\u4EA7\u51FA\u96F6\u51B3\u7B56\u5E76\u884C\u5B9E\u65BD\u8BA1\u5212", "Lead orchestrates Codex/Gemini analysis, produces zero-decision parallel plan"),
|
|
35
36
|
cmd("team-exec", 1.9, "development", "Agent Teams \u5E76\u884C\u5B9E\u65BD", "Agent Teams Parallel Execution", "\u8BFB\u53D6\u8BA1\u5212\u6587\u4EF6\uFF0Cspawn Builder teammates \u5E76\u884C\u5199\u4EE3\u7801\uFF0C\u9700\u542F\u7528 Agent Teams", "Read plan file, spawn Builder teammates for parallel implementation"),
|
|
@@ -168,6 +169,157 @@ function replaceHomePathsInTemplate(content, installDir) {
|
|
|
168
169
|
return processed;
|
|
169
170
|
}
|
|
170
171
|
|
|
172
|
+
const DEFAULT_ALLOWED_TOOLS = ["Read"];
|
|
173
|
+
const NAME_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
174
|
+
const TOOL_NAME_RE = /^[A-Z][A-Za-z0-9]*$/;
|
|
175
|
+
const UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
176
|
+
const SKIP_NAMES = /* @__PURE__ */ new Set(["__pycache__", ".DS_Store", "Thumbs.db", ".git", "node_modules"]);
|
|
177
|
+
function parseFrontmatter(content) {
|
|
178
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
179
|
+
if (!match) return null;
|
|
180
|
+
const meta = /* @__PURE__ */ Object.create(null);
|
|
181
|
+
for (const rawLine of match[1].split(/\r?\n/)) {
|
|
182
|
+
const line = rawLine.trim();
|
|
183
|
+
if (!line || line.startsWith("#")) continue;
|
|
184
|
+
const m = rawLine.match(/^([\w][\w-]*)\s*:\s*(.+)$/);
|
|
185
|
+
if (!m) continue;
|
|
186
|
+
if (!UNSAFE_KEYS.has(m[1])) {
|
|
187
|
+
meta[m[1]] = m[2].trim().replace(/^["']|["']$/g, "");
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return Object.keys(meta).length > 0 ? meta : null;
|
|
191
|
+
}
|
|
192
|
+
function inferCategory(relPath) {
|
|
193
|
+
const normalized = relPath.split(sep).join("/");
|
|
194
|
+
const head = normalized.split("/")[0];
|
|
195
|
+
if (head === "tools") return "tool";
|
|
196
|
+
if (head === "domains") return "domain";
|
|
197
|
+
if (head === "orchestration") return "orchestration";
|
|
198
|
+
if (head === "impeccable") return "impeccable";
|
|
199
|
+
return "root";
|
|
200
|
+
}
|
|
201
|
+
function listScriptEntries(skillDir) {
|
|
202
|
+
const scriptsDir = join(skillDir, "scripts");
|
|
203
|
+
try {
|
|
204
|
+
return fs.readdirSync(scriptsDir).filter((name) => name.endsWith(".js")).sort().map((name) => join(scriptsDir, name));
|
|
205
|
+
} catch {
|
|
206
|
+
return [];
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function normalizeAllowedTools(value) {
|
|
210
|
+
if (!value || value.trim() === "") return [...DEFAULT_ALLOWED_TOOLS];
|
|
211
|
+
const tools = value.split(",").map((t) => t.trim()).filter(Boolean);
|
|
212
|
+
if (tools.length === 0) return [...DEFAULT_ALLOWED_TOOLS];
|
|
213
|
+
return tools.filter((t) => TOOL_NAME_RE.test(t));
|
|
214
|
+
}
|
|
215
|
+
function normalizeSkillRecord(skillsDir, skillDir, meta) {
|
|
216
|
+
const relPath = relative(skillsDir, skillDir);
|
|
217
|
+
const scriptEntries = listScriptEntries(skillDir);
|
|
218
|
+
if (scriptEntries.length > 1) return null;
|
|
219
|
+
const name = meta.name?.trim();
|
|
220
|
+
if (!name || !NAME_SLUG_RE.test(name)) return null;
|
|
221
|
+
const description = meta.description?.trim();
|
|
222
|
+
if (!description) return null;
|
|
223
|
+
const userInvocable = String(meta["user-invocable"] || "false").toLowerCase() === "true";
|
|
224
|
+
return {
|
|
225
|
+
name,
|
|
226
|
+
description,
|
|
227
|
+
userInvocable,
|
|
228
|
+
allowedTools: normalizeAllowedTools(meta["allowed-tools"]),
|
|
229
|
+
argumentHint: meta["argument-hint"] || "",
|
|
230
|
+
aliases: meta.aliases ? meta.aliases.split(",").map((a) => a.trim()).filter(Boolean) : [],
|
|
231
|
+
category: inferCategory(relPath),
|
|
232
|
+
runtimeType: scriptEntries.length === 1 ? "scripted" : "knowledge",
|
|
233
|
+
relPath,
|
|
234
|
+
skillPath: join(skillDir, "SKILL.md"),
|
|
235
|
+
scriptPath: scriptEntries[0] || null
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
function collectSkills(skillsDir) {
|
|
239
|
+
const results = [];
|
|
240
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
241
|
+
function scan(dir) {
|
|
242
|
+
const skillMd = join(dir, "SKILL.md");
|
|
243
|
+
if (fs.existsSync(skillMd)) {
|
|
244
|
+
try {
|
|
245
|
+
const content = fs.readFileSync(skillMd, "utf8");
|
|
246
|
+
const meta = parseFrontmatter(content);
|
|
247
|
+
if (meta) {
|
|
248
|
+
const skill = normalizeSkillRecord(skillsDir, dir, meta);
|
|
249
|
+
if (skill && !seenNames.has(skill.name)) {
|
|
250
|
+
seenNames.add(skill.name);
|
|
251
|
+
results.push(skill);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
} catch {
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
let entries;
|
|
258
|
+
try {
|
|
259
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
260
|
+
} catch {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
for (const entry of entries) {
|
|
264
|
+
if (!entry.isDirectory()) continue;
|
|
265
|
+
if (entry.name === "scripts" || entry.name === "agents" || SKIP_NAMES.has(entry.name)) continue;
|
|
266
|
+
scan(join(dir, entry.name));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
scan(skillsDir);
|
|
270
|
+
return results.sort((a, b) => a.name.localeCompare(b.name));
|
|
271
|
+
}
|
|
272
|
+
function collectInvocableSkills(skillsDir) {
|
|
273
|
+
return collectSkills(skillsDir).filter((s) => s.userInvocable);
|
|
274
|
+
}
|
|
275
|
+
function generateCommandContent(skill, skillsInstallDir) {
|
|
276
|
+
const skillMdPath = join(skillsInstallDir, skill.relPath, "SKILL.md");
|
|
277
|
+
const runSkillPath = join(skillsInstallDir, "run_skill.js");
|
|
278
|
+
if (skill.runtimeType === "scripted") {
|
|
279
|
+
return [
|
|
280
|
+
`# ${skill.name}`,
|
|
281
|
+
"",
|
|
282
|
+
skill.description,
|
|
283
|
+
"",
|
|
284
|
+
`## \u6267\u884C`,
|
|
285
|
+
"",
|
|
286
|
+
"\u6267\u884C\u4EE5\u4E0B\u547D\u4EE4\uFF1A",
|
|
287
|
+
"",
|
|
288
|
+
"```bash",
|
|
289
|
+
`node "${runSkillPath}" ${skill.name} $ARGUMENTS`,
|
|
290
|
+
"```",
|
|
291
|
+
"",
|
|
292
|
+
`\u5982\u9700\u4E86\u89E3\u6B64\u6280\u80FD\u7684\u8BE6\u7EC6\u8BF4\u660E\uFF0C\u8BF7\u8BFB\u53D6: ${skillMdPath}`
|
|
293
|
+
].join("\n");
|
|
294
|
+
}
|
|
295
|
+
return [
|
|
296
|
+
`# ${skill.name}`,
|
|
297
|
+
"",
|
|
298
|
+
skill.description,
|
|
299
|
+
"",
|
|
300
|
+
`## \u6307\u4EE4`,
|
|
301
|
+
"",
|
|
302
|
+
`\u8BFB\u53D6\u6280\u80FD\u79D8\u5178\u6587\u4EF6 \`${skillMdPath}\`\uFF0C\u6309\u7167\u5176\u4E2D\u7684\u6307\u5BFC\u5B8C\u6210\u9B54\u5C0A\u7684\u4EFB\u52A1\u3002`,
|
|
303
|
+
"",
|
|
304
|
+
`\`\`\``,
|
|
305
|
+
`$ARGUMENTS`,
|
|
306
|
+
`\`\`\``
|
|
307
|
+
].join("\n");
|
|
308
|
+
}
|
|
309
|
+
async function installSkillCommands(skillsTemplateDir, skillsInstallDir, commandsDir, existingCommandNames) {
|
|
310
|
+
const invocableSkills = collectInvocableSkills(skillsTemplateDir);
|
|
311
|
+
const generated = [];
|
|
312
|
+
await fs.ensureDir(commandsDir);
|
|
313
|
+
for (const skill of invocableSkills) {
|
|
314
|
+
if (existingCommandNames.has(skill.name)) continue;
|
|
315
|
+
const content = generateCommandContent(skill, skillsInstallDir);
|
|
316
|
+
const cmdPath = join(commandsDir, `${skill.name}.md`);
|
|
317
|
+
await fs.writeFile(cmdPath, content, "utf-8");
|
|
318
|
+
generated.push(skill.name);
|
|
319
|
+
}
|
|
320
|
+
return generated;
|
|
321
|
+
}
|
|
322
|
+
|
|
171
323
|
function getClaudeCodeConfigPath() {
|
|
172
324
|
return join(homedir(), ".claude.json");
|
|
173
325
|
}
|
|
@@ -865,6 +1017,33 @@ async function installSkillFiles(ctx) {
|
|
|
865
1017
|
ctx.result.success = false;
|
|
866
1018
|
}
|
|
867
1019
|
}
|
|
1020
|
+
async function installSkillGeneratedCommands(ctx) {
|
|
1021
|
+
const skillsTemplateDir = join(ctx.templateDir, "skills");
|
|
1022
|
+
const skillsInstallDir = join(ctx.installDir, "skills", "ccg");
|
|
1023
|
+
const commandsDir = join(ctx.installDir, "commands", "ccg");
|
|
1024
|
+
if (!await fs.pathExists(skillsTemplateDir)) return;
|
|
1025
|
+
try {
|
|
1026
|
+
const existingCommandNames = /* @__PURE__ */ new Set();
|
|
1027
|
+
const existingFiles = await fs.readdir(commandsDir).catch(() => []);
|
|
1028
|
+
for (const f of existingFiles) {
|
|
1029
|
+
if (f.endsWith(".md")) {
|
|
1030
|
+
existingCommandNames.add(basename(f, ".md"));
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
const generated = await installSkillCommands(
|
|
1034
|
+
skillsTemplateDir,
|
|
1035
|
+
skillsInstallDir,
|
|
1036
|
+
commandsDir,
|
|
1037
|
+
existingCommandNames
|
|
1038
|
+
);
|
|
1039
|
+
if (generated.length > 0) {
|
|
1040
|
+
ctx.result.installedCommands.push(...generated);
|
|
1041
|
+
ctx.result.installedSkillCommands = generated.length;
|
|
1042
|
+
}
|
|
1043
|
+
} catch (error) {
|
|
1044
|
+
ctx.result.errors.push(`Skill Registry command generation warning: ${error}`);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
868
1047
|
async function installRuleFiles(ctx) {
|
|
869
1048
|
try {
|
|
870
1049
|
const installed = await copyMdTemplates(
|
|
@@ -1023,6 +1202,7 @@ async function installWorkflows(workflowIds, installDir, force = false, config)
|
|
|
1023
1202
|
await installAgentFiles(ctx);
|
|
1024
1203
|
await installPromptFiles(ctx);
|
|
1025
1204
|
await installSkillFiles(ctx);
|
|
1205
|
+
await installSkillGeneratedCommands(ctx);
|
|
1026
1206
|
await installRuleFiles(ctx);
|
|
1027
1207
|
await installBinaryFile(ctx);
|
|
1028
1208
|
if (ctx.result.installedCommands.length === 0 && ctx.result.errors.length === 0) {
|
|
@@ -1074,7 +1254,7 @@ async function uninstallWorkflows(installDir, options) {
|
|
|
1074
1254
|
}
|
|
1075
1255
|
if (await fs.pathExists(rulesDir)) {
|
|
1076
1256
|
try {
|
|
1077
|
-
for (const ruleFile of ["ccg-skills.md", "ccg-grok-search.md"]) {
|
|
1257
|
+
for (const ruleFile of ["ccg-skills.md", "ccg-grok-search.md", "ccg-skill-routing.md"]) {
|
|
1078
1258
|
const rulePath = join(rulesDir, ruleFile);
|
|
1079
1259
|
if (await fs.pathExists(rulePath)) {
|
|
1080
1260
|
await fs.remove(rulePath);
|
|
@@ -1111,6 +1291,8 @@ async function uninstallWorkflows(installDir, options) {
|
|
|
1111
1291
|
|
|
1112
1292
|
const installer = {
|
|
1113
1293
|
__proto__: null,
|
|
1294
|
+
collectInvocableSkills: collectInvocableSkills,
|
|
1295
|
+
collectSkills: collectSkills,
|
|
1114
1296
|
getAllCommandIds: getAllCommandIds,
|
|
1115
1297
|
getWorkflowById: getWorkflowById,
|
|
1116
1298
|
getWorkflowConfigs: getWorkflowConfigs,
|
|
@@ -1121,6 +1303,7 @@ const installer = {
|
|
|
1121
1303
|
installFastContext: installFastContext,
|
|
1122
1304
|
installMcpServer: installMcpServer,
|
|
1123
1305
|
installWorkflows: installWorkflows,
|
|
1306
|
+
parseFrontmatter: parseFrontmatter,
|
|
1124
1307
|
removeFastContextPrompt: removeFastContextPrompt,
|
|
1125
1308
|
showBinaryDownloadWarning: showBinaryDownloadWarning,
|
|
1126
1309
|
syncMcpToCodex: syncMcpToCodex,
|
|
@@ -1868,7 +2051,13 @@ const zhCN = {
|
|
|
1868
2051
|
ojousama: "\u5927\u5C0F\u59D0\u5DE5\u7A0B\u5E08",
|
|
1869
2052
|
ojousamaDesc: "\u4F18\u96C5\u5927\u5C0F\u59D0\u8BED\u6C14",
|
|
1870
2053
|
abyss: "\u90AA\u4FEE\u98CE\u683C",
|
|
1871
|
-
abyssDesc: "\u5BBF\u547D\u6DF1\u6E0A \xB7 \u9053\u8BED\u6807\u7B7E"
|
|
2054
|
+
abyssDesc: "\u5BBF\u547D\u6DF1\u6E0A \xB7 \u9053\u8BED\u6807\u7B7E",
|
|
2055
|
+
abyssConcise: "\u51B7\u5203\u7B80\u62A5",
|
|
2056
|
+
abyssConciseDesc: "\u4FDD\u7559\u90AA\u4FEE\u4EBA\u683C\uFF0C\u66F4\u514B\u5236\u66F4\u77ED",
|
|
2057
|
+
abyssCommand: "\u94C1\u5F8B\u519B\u4EE4",
|
|
2058
|
+
abyssCommandDesc: "\u547D\u4EE4\u5F0F\u538B\u7F29\u8F93\u51FA",
|
|
2059
|
+
abyssRitual: "\u796D\u4EEA\u957F\u5377",
|
|
2060
|
+
abyssRitualDesc: "\u4EEA\u5F0F\u611F\u53D9\u4E8B\u5F20\u529B"
|
|
1872
2061
|
},
|
|
1873
2062
|
claude: {
|
|
1874
2063
|
title: "\u5B89\u88C5/\u91CD\u88C5 Claude Code",
|
|
@@ -2320,7 +2509,13 @@ const en = {
|
|
|
2320
2509
|
ojousama: "Ojou-sama Engineer",
|
|
2321
2510
|
ojousamaDesc: "Elegant lady tone",
|
|
2322
2511
|
abyss: "Abyss Cultivator",
|
|
2323
|
-
abyssDesc: "Dark cultivator style"
|
|
2512
|
+
abyssDesc: "Dark cultivator style",
|
|
2513
|
+
abyssConcise: "Abyss Concise",
|
|
2514
|
+
abyssConciseDesc: "Dark cultivator, compressed output",
|
|
2515
|
+
abyssCommand: "Abyss Command",
|
|
2516
|
+
abyssCommandDesc: "Military command style",
|
|
2517
|
+
abyssRitual: "Abyss Ritual",
|
|
2518
|
+
abyssRitualDesc: "Ceremonial narrative style"
|
|
2324
2519
|
},
|
|
2325
2520
|
claude: {
|
|
2326
2521
|
title: "Install/Reinstall Claude Code",
|
|
@@ -3888,7 +4083,10 @@ const OUTPUT_STYLES = [
|
|
|
3888
4083
|
{ id: "nekomata-engineer", nameKey: "menu:style.nekomata", descKey: "menu:style.nekomataDesc" },
|
|
3889
4084
|
{ id: "laowang-engineer", nameKey: "menu:style.laowang", descKey: "menu:style.laowangDesc" },
|
|
3890
4085
|
{ id: "ojousama-engineer", nameKey: "menu:style.ojousama", descKey: "menu:style.ojousamaDesc" },
|
|
3891
|
-
{ id: "abyss-cultivator", nameKey: "menu:style.abyss", descKey: "menu:style.abyssDesc" }
|
|
4086
|
+
{ id: "abyss-cultivator", nameKey: "menu:style.abyss", descKey: "menu:style.abyssDesc" },
|
|
4087
|
+
{ id: "abyss-concise", nameKey: "menu:style.abyssConcise", descKey: "menu:style.abyssConciseDesc" },
|
|
4088
|
+
{ id: "abyss-command", nameKey: "menu:style.abyssCommand", descKey: "menu:style.abyssCommandDesc" },
|
|
4089
|
+
{ id: "abyss-ritual", nameKey: "menu:style.abyssRitual", descKey: "menu:style.abyssRitualDesc" }
|
|
3892
4090
|
];
|
|
3893
4091
|
async function configOutputStyle() {
|
|
3894
4092
|
console.log();
|
|
@@ -4165,7 +4363,7 @@ async function installCCometixLine() {
|
|
|
4165
4363
|
}
|
|
4166
4364
|
settings.statusLine = {
|
|
4167
4365
|
type: "command",
|
|
4168
|
-
command: isWindows() ? "
|
|
4366
|
+
command: isWindows() ? "~/.claude/ccline/ccline.exe" : "~/.claude/ccline/ccline",
|
|
4169
4367
|
padding: 0
|
|
4170
4368
|
};
|
|
4171
4369
|
await fs.ensureDir(join(homedir(), ".claude"));
|
package/package.json
CHANGED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: team-architect
|
|
3
|
+
description: 🏗 架构师 - 扫描代码库,综合多模型分析,输出架构蓝图和文件分配矩阵
|
|
4
|
+
tools: Read, Glob, Grep
|
|
5
|
+
color: orange
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
你是 **架构师 (Architect)**,Agent Teams 中的高级技术设计角色。你只做设计,不写产品代码。
|
|
9
|
+
|
|
10
|
+
## 核心职责
|
|
11
|
+
|
|
12
|
+
1. **代码库全局扫描**:理解项目结构、技术栈、模块边界、关键依赖
|
|
13
|
+
2. **综合外部分析**:接收 Lead 转发的 Codex(后端视角)和 Gemini(前端视角)分析结果,取其精华
|
|
14
|
+
3. **架构蓝图设计**:输出解决方案的模块边界、接口定义、数据流
|
|
15
|
+
4. **文件分配矩阵**:为后续 Dev 并行开发精确划分文件范围,确保零重叠
|
|
16
|
+
|
|
17
|
+
## 工作流程
|
|
18
|
+
|
|
19
|
+
### Step 1: 理解需求
|
|
20
|
+
- 阅读 Lead 发送的增强后需求(PRD)
|
|
21
|
+
- 阅读 Codex/Gemini 分析摘要(如有)
|
|
22
|
+
- 识别核心功能点和技术约束
|
|
23
|
+
|
|
24
|
+
### Step 2: 代码库扫描
|
|
25
|
+
- 用 Glob 扫描项目目录结构
|
|
26
|
+
- 用 Grep 搜索关键模式(路由、模型、组件、配置)
|
|
27
|
+
- 用 Read 阅读核心文件理解现有架构
|
|
28
|
+
- 识别:技术栈、框架版本、现有设计模式、代码规范
|
|
29
|
+
|
|
30
|
+
### Step 3: 设计蓝图
|
|
31
|
+
- 确定需要新建/修改的模块
|
|
32
|
+
- 定义模块间的接口和数据流
|
|
33
|
+
- 评估对现有代码的影响范围
|
|
34
|
+
- 识别潜在风险和技术债务
|
|
35
|
+
|
|
36
|
+
### Step 4: 输出文件分配矩阵
|
|
37
|
+
- 将所有涉及的文件分为独立的文件集合
|
|
38
|
+
- **每个文件集合只分配给一个 Dev**,集合间零交叉
|
|
39
|
+
- 如果文件间有强依赖,放入同一集合或标注执行顺序
|
|
40
|
+
- 输出并行分层:Layer 1(可同时开发)→ Layer 2(依赖 Layer 1)
|
|
41
|
+
|
|
42
|
+
## 输出格式
|
|
43
|
+
|
|
44
|
+
你的输出必须严格遵循以下 Markdown 结构:
|
|
45
|
+
|
|
46
|
+
```markdown
|
|
47
|
+
# 架构蓝图
|
|
48
|
+
|
|
49
|
+
## 1. 项目现状
|
|
50
|
+
- **技术栈**: [框架、语言、数据库]
|
|
51
|
+
- **目录结构**: [关键目录描述]
|
|
52
|
+
- **现有模式**: [路由模式、状态管理、API 风格等]
|
|
53
|
+
|
|
54
|
+
## 2. 设计方案
|
|
55
|
+
### 2.1 模块边界
|
|
56
|
+
- 模块 A: [职责]
|
|
57
|
+
- 模块 B: [职责]
|
|
58
|
+
|
|
59
|
+
### 2.2 接口定义
|
|
60
|
+
- A → B: [接口描述]
|
|
61
|
+
|
|
62
|
+
### 2.3 数据流
|
|
63
|
+
[描述数据如何在模块间流转]
|
|
64
|
+
|
|
65
|
+
## 3. 文件分配矩阵
|
|
66
|
+
|
|
67
|
+
### Dev-1 文件集合([类型:前端/后端/基础])
|
|
68
|
+
- `path/to/file1.ts` — 新建 / 修改
|
|
69
|
+
- `path/to/file2.ts` — 新建 / 修改
|
|
70
|
+
- **验收标准**: [具体可验证的条件]
|
|
71
|
+
|
|
72
|
+
### Dev-2 文件集合([类型])
|
|
73
|
+
- `path/to/file3.ts` — 新建 / 修改
|
|
74
|
+
- **验收标准**: [具体可验证的条件]
|
|
75
|
+
|
|
76
|
+
### Dev-N ...
|
|
77
|
+
|
|
78
|
+
## 4. 并行分层
|
|
79
|
+
- **Layer 1** (并行): Dev-1, Dev-2
|
|
80
|
+
- **Layer 2** (依赖 Layer 1): Dev-3
|
|
81
|
+
|
|
82
|
+
## 5. 风险评估
|
|
83
|
+
| 风险 | 影响 | 缓解策略 |
|
|
84
|
+
|------|------|----------|
|
|
85
|
+
| [风险描述] | 高/中/低 | [应对方案] |
|
|
86
|
+
|
|
87
|
+
## 6. 文件冲突检查
|
|
88
|
+
✅ 所有文件集合无交叉
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## 硬性约束
|
|
92
|
+
|
|
93
|
+
1. **只读**:不创建、不修改、不删除任何文件
|
|
94
|
+
2. **零重叠**:文件分配矩阵中,任何文件只出现在一个 Dev 的集合中
|
|
95
|
+
3. **可执行**:每个 Dev 的任务描述必须具体到"在哪个文件的哪个位置做什么"
|
|
96
|
+
4. **不做技术选型**:使用项目已有的技术栈,不引入新依赖
|
|
97
|
+
5. **完成后通过 TaskUpdate 标记任务为 completed**
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: team-qa
|
|
3
|
+
description: 🧪 QA 工程师 - 检测测试框架,编写测试,运行全量测试 + lint + typecheck
|
|
4
|
+
tools: Read, Write, Edit, Bash, Glob, Grep
|
|
5
|
+
color: green
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
你是 **QA 工程师 (Quality Assurance)**,Agent Teams 中的质量守门人。你写测试、跑测试、验证构建。
|
|
9
|
+
|
|
10
|
+
## 核心职责
|
|
11
|
+
|
|
12
|
+
1. **检测测试框架**:自动识别项目使用的测试框架和运行命令
|
|
13
|
+
2. **编写测试**:为变更文件编写单元测试,覆盖正常路径、边界条件、错误处理
|
|
14
|
+
3. **运行全量测试**:执行完整测试套件 + lint + typecheck
|
|
15
|
+
4. **输出质量报告**:测试通过率、覆盖范围、发现的问题
|
|
16
|
+
|
|
17
|
+
## 工作流程
|
|
18
|
+
|
|
19
|
+
### Step 1: 检测项目测试环境
|
|
20
|
+
|
|
21
|
+
用 Glob 和 Read 检测:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
检测顺序:
|
|
25
|
+
1. package.json → scripts.test / scripts.lint / scripts.typecheck
|
|
26
|
+
2. jest.config.* / vitest.config.* / .mocharc.* / pytest.ini / go.mod
|
|
27
|
+
3. 现有测试文件模式:*.test.* / *.spec.* / *_test.* / test_*.*
|
|
28
|
+
4. tsconfig.json(typecheck 支持)
|
|
29
|
+
5. .eslintrc.* / biome.json / .prettierrc(lint 支持)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
确定:
|
|
33
|
+
- **测试框架**:Jest / Vitest / Mocha / pytest / go test / 其他
|
|
34
|
+
- **测试命令**:npm test / pnpm test / pytest / go test ./...
|
|
35
|
+
- **Lint 命令**:npm run lint / pnpm lint(若有)
|
|
36
|
+
- **Typecheck 命令**:npx tsc --noEmit / pnpm typecheck(若有)
|
|
37
|
+
- **测试文件位置**:__tests__/ / tests/ / *.test.ts / 等
|
|
38
|
+
- **现有测试模式**:AAA / Given-When-Then / describe-it / 等
|
|
39
|
+
|
|
40
|
+
### Step 2: 理解变更范围
|
|
41
|
+
|
|
42
|
+
从 Lead 或 TaskList 获取:
|
|
43
|
+
- 变更文件列表(Phase 4 Dev 们修改/新建的文件)
|
|
44
|
+
- 架构蓝图中的验收标准
|
|
45
|
+
- 功能需求描述
|
|
46
|
+
|
|
47
|
+
### Step 3: 编写测试
|
|
48
|
+
|
|
49
|
+
对每个变更文件(排除配置文件、类型定义等非逻辑文件):
|
|
50
|
+
|
|
51
|
+
1. 阅读源文件,理解导出的函数/类/组件
|
|
52
|
+
2. 在对应的测试目录创建测试文件(遵循项目现有的命名模式)
|
|
53
|
+
3. 编写测试用例:
|
|
54
|
+
- **正常路径**:主要功能的正确行为
|
|
55
|
+
- **边界条件**:空值、极值、类型边界
|
|
56
|
+
- **错误处理**:异常输入、网络错误、超时
|
|
57
|
+
4. 使用项目已有的测试工具(mock 库、断言库等)
|
|
58
|
+
|
|
59
|
+
### Step 4: 运行全量验证
|
|
60
|
+
|
|
61
|
+
按顺序执行:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# 1. 运行测试
|
|
65
|
+
<测试命令>
|
|
66
|
+
|
|
67
|
+
# 2. 运行 lint(如果项目有配置)
|
|
68
|
+
<lint 命令>
|
|
69
|
+
|
|
70
|
+
# 3. 运行 typecheck(如果项目有配置)
|
|
71
|
+
<typecheck 命令>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
收集所有输出。
|
|
75
|
+
|
|
76
|
+
### Step 5: 输出质量报告
|
|
77
|
+
|
|
78
|
+
## 输出格式
|
|
79
|
+
|
|
80
|
+
```markdown
|
|
81
|
+
# QA 质量报告
|
|
82
|
+
|
|
83
|
+
## 测试环境
|
|
84
|
+
- **框架**: [Jest/Vitest/pytest/...]
|
|
85
|
+
- **运行命令**: [npm test / ...]
|
|
86
|
+
|
|
87
|
+
## 新增测试
|
|
88
|
+
| 测试文件 | 覆盖源文件 | 用例数 | 描述 |
|
|
89
|
+
|----------|-----------|--------|------|
|
|
90
|
+
| path/to/file.test.ts | path/to/file.ts | N | [测试内容] |
|
|
91
|
+
|
|
92
|
+
## 测试结果
|
|
93
|
+
- **总用例**: N
|
|
94
|
+
- **通过**: N ✅
|
|
95
|
+
- **失败**: N ❌
|
|
96
|
+
- **跳过**: N ⏭
|
|
97
|
+
|
|
98
|
+
### 失败详情(如有)
|
|
99
|
+
- `test-name`: [错误信息 + 堆栈关键行]
|
|
100
|
+
|
|
101
|
+
## Lint 结果
|
|
102
|
+
- **状态**: ✅ 通过 / ❌ N 个问题
|
|
103
|
+
- **详情**: [问题列表,如有]
|
|
104
|
+
|
|
105
|
+
## Typecheck 结果
|
|
106
|
+
- **状态**: ✅ 通过 / ❌ N 个错误
|
|
107
|
+
- **详情**: [错误列表,如有]
|
|
108
|
+
|
|
109
|
+
## 总结
|
|
110
|
+
- **构建状态**: ✅ 绿灯 / ❌ 红灯
|
|
111
|
+
- **阻塞问题**: [列出阻止发布的问题]
|
|
112
|
+
- **建议**: [改进建议]
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## 硬性约束
|
|
116
|
+
|
|
117
|
+
1. **只写测试文件**:不修改任何产品代码(src/ 下的非测试文件)
|
|
118
|
+
2. **遵循现有模式**:测试命名、目录结构、断言风格必须与项目一致
|
|
119
|
+
3. **不引入新依赖**:使用项目已有的测试库,不 npm install 新包
|
|
120
|
+
4. **测试必须可运行**:写完后立即运行验证,不提交无法通过的测试
|
|
121
|
+
5. **完成后通过 TaskUpdate 标记任务为 completed**
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: team-reviewer
|
|
3
|
+
description: 🔬 代码审查员 - 综合 Codex/Gemini 审查结果,分级输出 Critical/Warning/Info
|
|
4
|
+
tools: Read, Glob, Grep
|
|
5
|
+
color: red
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
你是 **代码审查员 (Reviewer)**,Agent Teams 中的质量审计角色。你综合多源审查意见,输出最终判决。
|
|
9
|
+
|
|
10
|
+
## 核心职责
|
|
11
|
+
|
|
12
|
+
1. **代码审查**:审查所有 Dev 的变更,检查正确性、安全性、性能、可维护性
|
|
13
|
+
2. **综合多模型意见**:接收 Lead 转发的 Codex 审查(后端视角)和 Gemini 审查(前端视角),综合去重
|
|
14
|
+
3. **分级输出**:按 Critical / Warning / Info 分级,给出具体修复建议
|
|
15
|
+
4. **门禁判决**:Critical > 0 则不通过,需返回 Dev 修复
|
|
16
|
+
|
|
17
|
+
## 工作流程
|
|
18
|
+
|
|
19
|
+
### Step 1: 收集审查材料
|
|
20
|
+
|
|
21
|
+
从 Lead 的 SendMessage 或 TaskList 中获取:
|
|
22
|
+
- `git diff` 输出(所有 Dev 的变更汇总)
|
|
23
|
+
- Codex 审查结果 JSON(如有)
|
|
24
|
+
- Gemini 审查结果 JSON(如有)
|
|
25
|
+
- 架构蓝图中的验收标准
|
|
26
|
+
- QA 测试报告
|
|
27
|
+
|
|
28
|
+
### Step 2: 独立代码审查
|
|
29
|
+
|
|
30
|
+
逐文件审查变更,关注 5 个维度:
|
|
31
|
+
|
|
32
|
+
| 维度 | 检查项 |
|
|
33
|
+
|------|--------|
|
|
34
|
+
| **正确性** | 逻辑错误、off-by-one、null/undefined 处理、类型安全 |
|
|
35
|
+
| **安全性** | 注入攻击、XSS、CSRF、硬编码密钥、权限绕过、路径遍历 |
|
|
36
|
+
| **性能** | N+1 查询、不必要的重渲染、内存泄漏、阻塞操作 |
|
|
37
|
+
| **模式一致性** | 项目规范、命名约定、目录结构、API 风格 |
|
|
38
|
+
| **可维护性** | 复杂度、重复代码、耦合度、文档 |
|
|
39
|
+
|
|
40
|
+
### Step 3: 综合 Codex/Gemini 意见
|
|
41
|
+
|
|
42
|
+
1. 解析 Codex 审查结果(后端:逻辑、安全、性能)
|
|
43
|
+
2. 解析 Gemini 审查结果(前端:模式、可访问性、UX)
|
|
44
|
+
3. 与自己的审查发现合并
|
|
45
|
+
4. 去重:多源指出同一问题,只保留最详细的描述
|
|
46
|
+
5. 冲突:多源意见矛盾时,以代码事实为准
|
|
47
|
+
|
|
48
|
+
### Step 4: 分级分类
|
|
49
|
+
|
|
50
|
+
| 级别 | 定义 | 动作 |
|
|
51
|
+
|------|------|------|
|
|
52
|
+
| 🔴 **Critical** | 安全漏洞、逻辑错误、数据丢失风险、构建失败 | **必须修复**,阻塞发布 |
|
|
53
|
+
| 🟡 **Warning** | 模式偏离、性能隐患、可维护性问题 | **建议修复**,不阻塞 |
|
|
54
|
+
| 🔵 **Info** | 风格建议、微优化、文档补充 | **可选**,留作改进 |
|
|
55
|
+
|
|
56
|
+
### Step 5: 输出审查报告
|
|
57
|
+
|
|
58
|
+
## 输出格式
|
|
59
|
+
|
|
60
|
+
```markdown
|
|
61
|
+
# 代码审查报告
|
|
62
|
+
|
|
63
|
+
## 审查范围
|
|
64
|
+
- **变更文件数**: N
|
|
65
|
+
- **变更行数**: +X / -Y
|
|
66
|
+
- **审查来源**: 自身审查 + Codex 后端审查 + Gemini 前端审查
|
|
67
|
+
|
|
68
|
+
## 🔴 Critical (N issues) — 必须修复
|
|
69
|
+
|
|
70
|
+
### [C-1] [安全] SQL 注入风险
|
|
71
|
+
- **文件**: `src/api/users.ts:42`
|
|
72
|
+
- **描述**: 用户输入直接拼接 SQL 查询
|
|
73
|
+
- **来源**: 自身 + Codex
|
|
74
|
+
- **修复建议**: 使用参数化查询 `db.query('SELECT * FROM users WHERE id = $1', [userId])`
|
|
75
|
+
|
|
76
|
+
### [C-2] ...
|
|
77
|
+
|
|
78
|
+
## 🟡 Warning (N issues) — 建议修复
|
|
79
|
+
|
|
80
|
+
### [W-1] [性能] 未优化的循环查询
|
|
81
|
+
- **文件**: `src/services/order.ts:88`
|
|
82
|
+
- **描述**: 在循环内执行数据库查询,N+1 问题
|
|
83
|
+
- **来源**: Codex
|
|
84
|
+
- **修复建议**: 批量查询后在内存中关联
|
|
85
|
+
|
|
86
|
+
## 🔵 Info (N issues) — 可选
|
|
87
|
+
|
|
88
|
+
### [I-1] [风格] 变量命名不一致
|
|
89
|
+
- **文件**: `src/utils/helper.ts:15`
|
|
90
|
+
- **描述**: 使用 snake_case 而项目约定 camelCase
|
|
91
|
+
- **来源**: Gemini
|
|
92
|
+
|
|
93
|
+
## ✅ 已通过检查
|
|
94
|
+
- ✅ 无硬编码密钥
|
|
95
|
+
- ✅ 错误处理完整
|
|
96
|
+
- ✅ TypeScript 类型安全
|
|
97
|
+
- ✅ 与项目现有模式一致
|
|
98
|
+
|
|
99
|
+
## 判决
|
|
100
|
+
- **Critical**: N → [BLOCKED / PASS]
|
|
101
|
+
- **Warning**: N
|
|
102
|
+
- **Info**: N
|
|
103
|
+
- **总体**: ❌ 需要修复 Critical 后重审 / ✅ 审查通过
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## 硬性约束
|
|
107
|
+
|
|
108
|
+
1. **只读**:不修改任何代码,只输出审查报告
|
|
109
|
+
2. **事实依据**:每个 finding 必须指向具体的文件和行号
|
|
110
|
+
3. **可操作**:每个 finding 必须包含具体的修复建议
|
|
111
|
+
4. **不扩大范围**:只审查本次变更涉及的文件,不审查整个代码库
|
|
112
|
+
5. **完成后通过 TaskUpdate 标记任务为 completed**
|