cc-codeconductor 0.3.3 → 0.4.1
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 +36 -2
- package/dist/index.js +522 -31
- package/package.json +1 -1
- package/policy.yml +12 -0
- package/presets/agy/AGENTS.md +42 -0
- package/presets/agy/skills/cc-review/SKILL.md +25 -1
- package/presets/claude/CLAUDE.md +69 -5
- package/presets/codex/AGENTS.md +52 -0
- package/presets/opencode/README.md +15 -0
- package/presets/opencode/agents/complexity-auditor.md +89 -0
package/README.md
CHANGED
|
@@ -36,6 +36,10 @@ contracts, task cards, and risk-based routing.
|
|
|
36
36
|
> a sitemap.xml with rate limiting and SSRF prevention
|
|
37
37
|
> - `npx cc-codeconductor seo llms --sitemap <url>` — generates a `llms.txt` file
|
|
38
38
|
> for AI-search readiness from sitemap content
|
|
39
|
+
> - `npx cc-codeconductor help` (alias: `cc-help`) — shows preset inventory
|
|
40
|
+
> (skills, subagents, commands) for the active or specified target
|
|
41
|
+
> - `npx cc-codeconductor debt-harvest` (alias: `harvest`) — scans source files
|
|
42
|
+
> for `// defer` comments and writes `.codeconductor/debt-ledger.md`
|
|
39
43
|
> - `/cc-pagespeed --url <url>` — audits web performance using the PageSpeed
|
|
40
44
|
> Insights API; applies the 80/20 principle to produce a prioritized report of
|
|
41
45
|
> Core Web Vitals (LCP, TBT, CLS, FCP, TTFB) with framework-specific fixes;
|
|
@@ -123,12 +127,14 @@ Task Card → Risk Classification → Routing Policy → Conductor Agent → Del
|
|
|
123
127
|
- Codex preset
|
|
124
128
|
- Spring Boot / Kotlin workflow
|
|
125
129
|
- Python / Django workflow guidance
|
|
126
|
-
-
|
|
127
|
-
- Routing Policy v0.
|
|
130
|
+
- 10 core Conductor Agents
|
|
131
|
+
- Routing Policy v0.2.0
|
|
128
132
|
- Task Card template
|
|
129
133
|
- Scorecard template
|
|
130
134
|
- End-to-end example
|
|
131
135
|
- YAML-driven model configuration
|
|
136
|
+
- Provider-agnostic `AgentContract` abstraction with target renderers for Claude, OpenCode, Codex, and Agy
|
|
137
|
+
- Council consensus engine (`councilConsensus()`) for multi-agent governance with majority/unanimous algorithms and security veto
|
|
132
138
|
|
|
133
139
|
---
|
|
134
140
|
|
|
@@ -266,6 +272,34 @@ npx cc-codeconductor update --global
|
|
|
266
272
|
|
|
267
273
|
Smart updates all currently installed target presets, council configurations, and skills (from `skills-lock.json`), preserving user edits outside managed blocks. Also validates that `AGENTS.md` and `CLAUDE.md` do not exceed the 40KB size limit.
|
|
268
274
|
|
|
275
|
+
#### `help` — show preset inventory
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
npx cc-codeconductor help # show inventory for active target
|
|
279
|
+
npx cc-codeconductor help --target claude # show inventory for specific target
|
|
280
|
+
npx cc-codeconductor cc-help # alias
|
|
281
|
+
npx cc-codeconductor help --output json # machine-readable output
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Lists the skills, subagents, commands, and workflows available in the active
|
|
285
|
+
preset. Reads from `presets/<target>/` in the project root.
|
|
286
|
+
|
|
287
|
+
#### `debt-harvest` — collect deferred debt items
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
npx cc-codeconductor debt-harvest # scan src/ for // defer comments
|
|
291
|
+
npx cc-codeconductor debt-harvest --dir lib # scan a different directory
|
|
292
|
+
npx cc-codeconductor harvest # alias
|
|
293
|
+
npx cc-codeconductor debt-harvest --output json
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Scans source files for `// defer - [reason]` comments and consolidates them
|
|
297
|
+
into `.codeconductor/debt-ledger.md`, grouped by optional tag
|
|
298
|
+
(`// defer - reason --tag`). Read-only on source files; only writes the ledger.
|
|
299
|
+
|
|
300
|
+
Supported extensions: `.ts`, `.tsx`, `.js`, `.jsx`, `.go`, `.rs`, `.java`,
|
|
301
|
+
`.kt`, `.swift`, `.cs`, `.php`, `.scala`, `.dart`, `.c`, `.cpp`, `.h`, `.hpp`.
|
|
302
|
+
|
|
269
303
|
|
|
270
304
|
### Global options
|
|
271
305
|
|
package/dist/index.js
CHANGED
|
@@ -36,14 +36,15 @@ function getExitCode(error) {
|
|
|
36
36
|
}
|
|
37
37
|
return ExitCode.VALIDATION_ERROR;
|
|
38
38
|
}
|
|
39
|
-
var ExitCode, CliError, ValidationError, UnsafeOperationError;
|
|
39
|
+
var ExitCode, CliError, ValidationError, UnsafeOperationError, CredentialGuardError;
|
|
40
40
|
var init_errors = __esm(() => {
|
|
41
41
|
ExitCode = {
|
|
42
42
|
SUCCESS: 0,
|
|
43
43
|
VALIDATION_ERROR: 1,
|
|
44
44
|
UNSAFE_OPERATION: 2,
|
|
45
45
|
UNSUPPORTED_PROJECT: 3,
|
|
46
|
-
CONFIG_CONFLICT: 4
|
|
46
|
+
CONFIG_CONFLICT: 4,
|
|
47
|
+
CREDENTIAL_LEAK: 5
|
|
47
48
|
};
|
|
48
49
|
CliError = class CliError extends Error {
|
|
49
50
|
code;
|
|
@@ -67,14 +68,24 @@ var init_errors = __esm(() => {
|
|
|
67
68
|
this.name = "UnsafeOperationError";
|
|
68
69
|
}
|
|
69
70
|
};
|
|
71
|
+
CredentialGuardError = class CredentialGuardError extends CliError {
|
|
72
|
+
matches;
|
|
73
|
+
constructor(message, matches, details) {
|
|
74
|
+
super(message, ExitCode.CREDENTIAL_LEAK, details);
|
|
75
|
+
this.matches = matches;
|
|
76
|
+
this.name = "CredentialGuardError";
|
|
77
|
+
}
|
|
78
|
+
};
|
|
70
79
|
});
|
|
71
80
|
|
|
72
81
|
// src/core/filesystem/safety.ts
|
|
73
82
|
var exports_safety = {};
|
|
74
83
|
__export(exports_safety, {
|
|
75
84
|
validateWritePath: () => validateWritePath,
|
|
85
|
+
scanForCredentials: () => scanForCredentials,
|
|
76
86
|
isWritable: () => isWritable,
|
|
77
87
|
isProtectedPath: () => isProtectedPath,
|
|
88
|
+
isCredentialContent: () => isCredentialContent,
|
|
78
89
|
fileExists: () => fileExists
|
|
79
90
|
});
|
|
80
91
|
import { constants } from "node:fs";
|
|
@@ -103,6 +114,42 @@ async function isWritable(dir) {
|
|
|
103
114
|
return false;
|
|
104
115
|
}
|
|
105
116
|
}
|
|
117
|
+
function buildCredentialRegexes(patterns) {
|
|
118
|
+
return patterns.map((keyword) => new RegExp(`(?:${keyword})\\s*[:=]\\s*[^\\s]{8,}`, "i"));
|
|
119
|
+
}
|
|
120
|
+
function scanForCredentials(filePath, content, secretPatterns) {
|
|
121
|
+
const regexes = buildCredentialRegexes(secretPatterns);
|
|
122
|
+
const lines = content.split(`
|
|
123
|
+
`);
|
|
124
|
+
const matches = [];
|
|
125
|
+
for (let i = 0;i < lines.length; i++) {
|
|
126
|
+
const line = lines[i];
|
|
127
|
+
for (const regex of regexes) {
|
|
128
|
+
const m = regex.exec(line);
|
|
129
|
+
if (m) {
|
|
130
|
+
matches.push({
|
|
131
|
+
filePath,
|
|
132
|
+
line: i + 1,
|
|
133
|
+
pattern: regex.source,
|
|
134
|
+
matched: m[0]
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return matches;
|
|
140
|
+
}
|
|
141
|
+
function isCredentialContent(content, secretPatterns) {
|
|
142
|
+
const regexes = buildCredentialRegexes(secretPatterns);
|
|
143
|
+
const lines = content.split(`
|
|
144
|
+
`);
|
|
145
|
+
for (const line of lines) {
|
|
146
|
+
for (const regex of regexes) {
|
|
147
|
+
if (regex.test(line))
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
106
153
|
var PROTECTED_PATHS;
|
|
107
154
|
var init_safety = __esm(() => {
|
|
108
155
|
PROTECTED_PATHS = [".git", ".env", ".env.local", ".env.production", "secrets", "credentials"];
|
|
@@ -11079,7 +11126,7 @@ function validateCouncilSpec(data) {
|
|
|
11079
11126
|
function validateConfig(data) {
|
|
11080
11127
|
return CodeConductorConfigSchema.parse(data);
|
|
11081
11128
|
}
|
|
11082
|
-
var CouncilAgentSpecSchema, CouncilSpecSchema, ProjectProfileSchema, CodeConductorConfigSchema, RunnerTargetSchema, InstallStrategySchema, ManifestEntrySchema, InstallManifestSchema, ToolProviderNamesSchema, PermissionProviderNamesSchema, ModelConfigSchema;
|
|
11129
|
+
var CouncilAgentSpecSchema, CouncilSpecSchema, ProjectProfileSchema, CompileCheckConfigSchema, LoopConfigSchema, CodeConductorConfigSchema, RunnerTargetSchema, InstallStrategySchema, ManifestEntrySchema, InstallManifestSchema, ToolProviderNamesSchema, PermissionProviderNamesSchema, ModelConfigSchema, ContractTargetSchema, ContractFormatSchema, AgentContractSchema, CouncilFindingSchema, CouncilVerdictInputSchema, ConsensusConfigSchema, CouncilVerdictSchema, ClaudeAgentFileSchema, OpenCodeAgentFileSchema, SentryStackFrameSchema, SentryWebhookSchema;
|
|
11083
11130
|
var init_schemas = __esm(() => {
|
|
11084
11131
|
init_zod();
|
|
11085
11132
|
CouncilAgentSpecSchema = exports_external.object({
|
|
@@ -11112,6 +11159,16 @@ var init_schemas = __esm(() => {
|
|
|
11112
11159
|
signals: exports_external.array(exports_external.string()),
|
|
11113
11160
|
confidence: exports_external.enum(["low", "medium", "high"])
|
|
11114
11161
|
});
|
|
11162
|
+
CompileCheckConfigSchema = exports_external.object({
|
|
11163
|
+
enabled: exports_external.boolean(),
|
|
11164
|
+
command: exports_external.string().optional(),
|
|
11165
|
+
timeoutMs: exports_external.number().positive().optional()
|
|
11166
|
+
});
|
|
11167
|
+
LoopConfigSchema = exports_external.object({
|
|
11168
|
+
enabled: exports_external.boolean().optional().default(true),
|
|
11169
|
+
maxIterations: exports_external.number().int().positive().optional().default(3),
|
|
11170
|
+
maxTokenBudget: exports_external.number().nonnegative().optional().default(0)
|
|
11171
|
+
});
|
|
11115
11172
|
CodeConductorConfigSchema = exports_external.object({
|
|
11116
11173
|
version: exports_external.string(),
|
|
11117
11174
|
project: exports_external.object({
|
|
@@ -11131,8 +11188,10 @@ var init_schemas = __esm(() => {
|
|
|
11131
11188
|
}),
|
|
11132
11189
|
safety: exports_external.object({
|
|
11133
11190
|
destructiveCommands: exports_external.array(exports_external.string()),
|
|
11134
|
-
secretPatterns: exports_external.array(exports_external.string())
|
|
11135
|
-
|
|
11191
|
+
secretPatterns: exports_external.array(exports_external.string()),
|
|
11192
|
+
compileCheck: CompileCheckConfigSchema.optional()
|
|
11193
|
+
}),
|
|
11194
|
+
loop: LoopConfigSchema.optional()
|
|
11136
11195
|
});
|
|
11137
11196
|
RunnerTargetSchema = exports_external.enum([
|
|
11138
11197
|
"opencode",
|
|
@@ -11176,6 +11235,80 @@ var init_schemas = __esm(() => {
|
|
|
11176
11235
|
tools: exports_external.record(exports_external.string(), ToolProviderNamesSchema).optional(),
|
|
11177
11236
|
permissions: PermissionProviderNamesSchema.optional()
|
|
11178
11237
|
});
|
|
11238
|
+
ContractTargetSchema = exports_external.enum([
|
|
11239
|
+
"claude",
|
|
11240
|
+
"opencode",
|
|
11241
|
+
"codex",
|
|
11242
|
+
"gemini",
|
|
11243
|
+
"cursor",
|
|
11244
|
+
"agy"
|
|
11245
|
+
]);
|
|
11246
|
+
ContractFormatSchema = exports_external.object({
|
|
11247
|
+
target: ContractTargetSchema,
|
|
11248
|
+
options: exports_external.record(exports_external.unknown()).optional()
|
|
11249
|
+
});
|
|
11250
|
+
AgentContractSchema = exports_external.object({
|
|
11251
|
+
council: CouncilSpecSchema,
|
|
11252
|
+
targets: exports_external.array(ContractFormatSchema),
|
|
11253
|
+
contractVersion: exports_external.string(),
|
|
11254
|
+
renderHints: exports_external.record(ContractTargetSchema, exports_external.record(exports_external.unknown())).optional()
|
|
11255
|
+
});
|
|
11256
|
+
CouncilFindingSchema = exports_external.object({
|
|
11257
|
+
category: exports_external.string(),
|
|
11258
|
+
severity: exports_external.enum(["info", "warning", "critical"]),
|
|
11259
|
+
message: exports_external.string(),
|
|
11260
|
+
agentId: exports_external.string()
|
|
11261
|
+
});
|
|
11262
|
+
CouncilVerdictInputSchema = exports_external.object({
|
|
11263
|
+
agentId: exports_external.string(),
|
|
11264
|
+
agentRole: exports_external.string(),
|
|
11265
|
+
status: exports_external.enum(["APPROVED", "REJECTED", "ABSTAIN"]),
|
|
11266
|
+
securityVeto: exports_external.boolean(),
|
|
11267
|
+
findings: exports_external.array(CouncilFindingSchema),
|
|
11268
|
+
summary: exports_external.string()
|
|
11269
|
+
});
|
|
11270
|
+
ConsensusConfigSchema = exports_external.object({
|
|
11271
|
+
algorithm: exports_external.enum(["majority", "unanimous"]),
|
|
11272
|
+
allowSecurityVeto: exports_external.boolean()
|
|
11273
|
+
});
|
|
11274
|
+
CouncilVerdictSchema = exports_external.object({
|
|
11275
|
+
status: exports_external.enum(["APPROVED", "REJECTED", "ESCALATED"]),
|
|
11276
|
+
totalAgents: exports_external.number(),
|
|
11277
|
+
approvedCount: exports_external.number(),
|
|
11278
|
+
rejectedCount: exports_external.number(),
|
|
11279
|
+
abstainedCount: exports_external.number(),
|
|
11280
|
+
vetoApplied: exports_external.boolean(),
|
|
11281
|
+
vetoByAgentId: exports_external.string().optional(),
|
|
11282
|
+
findings: exports_external.array(CouncilFindingSchema),
|
|
11283
|
+
summary: exports_external.string(),
|
|
11284
|
+
individualVerdicts: exports_external.array(CouncilVerdictInputSchema)
|
|
11285
|
+
});
|
|
11286
|
+
ClaudeAgentFileSchema = exports_external.object({
|
|
11287
|
+
path: exports_external.string().startsWith(".claude/"),
|
|
11288
|
+
content: exports_external.string(),
|
|
11289
|
+
overwrite: exports_external.boolean()
|
|
11290
|
+
});
|
|
11291
|
+
OpenCodeAgentFileSchema = exports_external.object({
|
|
11292
|
+
path: exports_external.string().startsWith(".opencode/"),
|
|
11293
|
+
content: exports_external.string(),
|
|
11294
|
+
overwrite: exports_external.boolean()
|
|
11295
|
+
});
|
|
11296
|
+
SentryStackFrameSchema = exports_external.object({
|
|
11297
|
+
filename: exports_external.string(),
|
|
11298
|
+
function: exports_external.string(),
|
|
11299
|
+
lineNo: exports_external.number(),
|
|
11300
|
+
colNo: exports_external.number().optional(),
|
|
11301
|
+
context: exports_external.array(exports_external.string())
|
|
11302
|
+
});
|
|
11303
|
+
SentryWebhookSchema = exports_external.object({
|
|
11304
|
+
issueId: exports_external.string(),
|
|
11305
|
+
title: exports_external.string(),
|
|
11306
|
+
culprit: exports_external.string(),
|
|
11307
|
+
filename: exports_external.string().optional(),
|
|
11308
|
+
stackTrace: exports_external.array(SentryStackFrameSchema),
|
|
11309
|
+
environment: exports_external.string().optional(),
|
|
11310
|
+
release: exports_external.string().optional()
|
|
11311
|
+
});
|
|
11179
11312
|
});
|
|
11180
11313
|
|
|
11181
11314
|
// src/core/presets/package-paths.ts
|
|
@@ -11865,6 +11998,58 @@ var init_agy_installer = __esm(() => {
|
|
|
11865
11998
|
init_agy_council_generator();
|
|
11866
11999
|
});
|
|
11867
12000
|
|
|
12001
|
+
// src/core/filesystem/credential-guard.ts
|
|
12002
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
12003
|
+
async function loadPolicyPatterns() {
|
|
12004
|
+
try {
|
|
12005
|
+
const content = await readFile7(POLICY_PATH, "utf-8");
|
|
12006
|
+
const parsed = $parse(content);
|
|
12007
|
+
if (Array.isArray(parsed.secretPatterns) && parsed.secretPatterns.length > 0) {
|
|
12008
|
+
return parsed.secretPatterns;
|
|
12009
|
+
}
|
|
12010
|
+
} catch {}
|
|
12011
|
+
return [];
|
|
12012
|
+
}
|
|
12013
|
+
function mergePatterns(...arrays) {
|
|
12014
|
+
const seen = new Set;
|
|
12015
|
+
const result = [];
|
|
12016
|
+
for (const arr of arrays) {
|
|
12017
|
+
for (const p of arr) {
|
|
12018
|
+
if (!seen.has(p)) {
|
|
12019
|
+
seen.add(p);
|
|
12020
|
+
result.push(p);
|
|
12021
|
+
}
|
|
12022
|
+
}
|
|
12023
|
+
}
|
|
12024
|
+
return result;
|
|
12025
|
+
}
|
|
12026
|
+
async function loadCredentialPatterns(config) {
|
|
12027
|
+
const policyPatterns = await loadPolicyPatterns();
|
|
12028
|
+
const configPatterns = config?.safety?.secretPatterns;
|
|
12029
|
+
if (configPatterns && configPatterns.length > 0) {
|
|
12030
|
+
return mergePatterns(configPatterns, policyPatterns, DEFAULT_SECRET_PATTERNS);
|
|
12031
|
+
}
|
|
12032
|
+
if (policyPatterns.length > 0) {
|
|
12033
|
+
return mergePatterns(policyPatterns, DEFAULT_SECRET_PATTERNS);
|
|
12034
|
+
}
|
|
12035
|
+
return DEFAULT_SECRET_PATTERNS;
|
|
12036
|
+
}
|
|
12037
|
+
var DEFAULT_SECRET_PATTERNS;
|
|
12038
|
+
var init_credential_guard = __esm(() => {
|
|
12039
|
+
init_dist();
|
|
12040
|
+
init_package_paths();
|
|
12041
|
+
DEFAULT_SECRET_PATTERNS = [
|
|
12042
|
+
"password",
|
|
12043
|
+
"secret",
|
|
12044
|
+
"api_key",
|
|
12045
|
+
"token",
|
|
12046
|
+
"api[_-]?key",
|
|
12047
|
+
"access[_-]?token",
|
|
12048
|
+
"auth[_-]?token",
|
|
12049
|
+
"private[_-]?key"
|
|
12050
|
+
];
|
|
12051
|
+
});
|
|
12052
|
+
|
|
11868
12053
|
// src/core/filesystem/file-writer.ts
|
|
11869
12054
|
var exports_file_writer = {};
|
|
11870
12055
|
__export(exports_file_writer, {
|
|
@@ -11875,6 +12060,13 @@ import { access as access4, mkdir as mkdir4, writeFile as writeFile4 } from "nod
|
|
|
11875
12060
|
import { dirname as dirname3 } from "node:path";
|
|
11876
12061
|
async function writeGeneratedFiles(files, options) {
|
|
11877
12062
|
const results = [];
|
|
12063
|
+
const secretPatterns = await loadCredentialPatterns(options.config);
|
|
12064
|
+
const allMatches = files.flatMap((file) => {
|
|
12065
|
+
return scanForCredentials(file.path, file.content, secretPatterns);
|
|
12066
|
+
});
|
|
12067
|
+
if (allMatches.length > 0) {
|
|
12068
|
+
throw new CredentialGuardError(`Credential leak detected in ${allMatches.length} file(s). No files written.`, allMatches);
|
|
12069
|
+
}
|
|
11878
12070
|
for (const file of files) {
|
|
11879
12071
|
if (!validateWritePath(file.path)) {
|
|
11880
12072
|
results.push({
|
|
@@ -11933,6 +12125,7 @@ async function writeSingleFile(path, content, options) {
|
|
|
11933
12125
|
}
|
|
11934
12126
|
var init_file_writer = __esm(() => {
|
|
11935
12127
|
init_errors();
|
|
12128
|
+
init_credential_guard();
|
|
11936
12129
|
init_safety();
|
|
11937
12130
|
});
|
|
11938
12131
|
|
|
@@ -11941,7 +12134,7 @@ init_errors();
|
|
|
11941
12134
|
// package.json
|
|
11942
12135
|
var package_default = {
|
|
11943
12136
|
name: "cc-codeconductor",
|
|
11944
|
-
version: "0.
|
|
12137
|
+
version: "0.4.1",
|
|
11945
12138
|
description: "A multi-agent orchestration framework for AI-assisted software engineering workflows.",
|
|
11946
12139
|
keywords: [
|
|
11947
12140
|
"ai",
|
|
@@ -13604,7 +13797,7 @@ async function doctorCommand(options) {
|
|
|
13604
13797
|
}
|
|
13605
13798
|
|
|
13606
13799
|
// src/commands/init.command.ts
|
|
13607
|
-
import { access as access3, mkdir as mkdir3, readFile as
|
|
13800
|
+
import { access as access3, mkdir as mkdir3, readFile as readFile8, writeFile as writeFile3 } from "node:fs/promises";
|
|
13608
13801
|
import { homedir as homedir5 } from "node:os";
|
|
13609
13802
|
import { basename, resolve as resolve7 } from "node:path";
|
|
13610
13803
|
|
|
@@ -13615,6 +13808,7 @@ import { access as access2, mkdir as mkdir2, writeFile as writeFile2 } from "nod
|
|
|
13615
13808
|
import { resolve as resolve6 } from "node:path";
|
|
13616
13809
|
|
|
13617
13810
|
// src/core/config/codeconductor-config.ts
|
|
13811
|
+
init_credential_guard();
|
|
13618
13812
|
var DEFAULT_CONFIG = {
|
|
13619
13813
|
version: "0.2.0",
|
|
13620
13814
|
project: {
|
|
@@ -13633,7 +13827,17 @@ var DEFAULT_CONFIG = {
|
|
|
13633
13827
|
},
|
|
13634
13828
|
safety: {
|
|
13635
13829
|
destructiveCommands: ["rm -rf", "drop table", "delete from"],
|
|
13636
|
-
secretPatterns:
|
|
13830
|
+
secretPatterns: DEFAULT_SECRET_PATTERNS,
|
|
13831
|
+
compileCheck: {
|
|
13832
|
+
enabled: true,
|
|
13833
|
+
command: "tsc --noEmit",
|
|
13834
|
+
timeoutMs: 120000
|
|
13835
|
+
}
|
|
13836
|
+
},
|
|
13837
|
+
loop: {
|
|
13838
|
+
enabled: true,
|
|
13839
|
+
maxIterations: 3,
|
|
13840
|
+
maxTokenBudget: 0
|
|
13637
13841
|
}
|
|
13638
13842
|
};
|
|
13639
13843
|
|
|
@@ -13890,7 +14094,7 @@ async function copyPresets(baseDir, presets, force) {
|
|
|
13890
14094
|
continue;
|
|
13891
14095
|
}
|
|
13892
14096
|
try {
|
|
13893
|
-
const content = await
|
|
14097
|
+
const content = await readFile8(preset.sourcePath, "utf-8");
|
|
13894
14098
|
await writeFile3(destPath, content, "utf-8");
|
|
13895
14099
|
copied.push(`.codeconductor/presets/${preset.name}`);
|
|
13896
14100
|
} catch (err2) {
|
|
@@ -13959,8 +14163,10 @@ async function installCommand(options) {
|
|
|
13959
14163
|
}
|
|
13960
14164
|
};
|
|
13961
14165
|
}
|
|
14166
|
+
const configResult = await loadConfig(projectRoot);
|
|
14167
|
+
const config = configResult.success ? configResult.data : undefined;
|
|
13962
14168
|
const spec = presetResult.data;
|
|
13963
|
-
const writeOptions = { dryRun, force };
|
|
14169
|
+
const writeOptions = { dryRun, force, config };
|
|
13964
14170
|
const allFiles = [];
|
|
13965
14171
|
for (const t of targets) {
|
|
13966
14172
|
let installer;
|
|
@@ -14627,7 +14833,9 @@ async function installLspCommand(options) {
|
|
|
14627
14833
|
}
|
|
14628
14834
|
const installer = createLspInstaller();
|
|
14629
14835
|
const installReport = await installer.installAll(lsps, { dryRun });
|
|
14630
|
-
const
|
|
14836
|
+
const configResult = await loadConfig(projectRoot);
|
|
14837
|
+
const config = configResult.success ? configResult.data : undefined;
|
|
14838
|
+
const writeOptions = { dryRun, force, config };
|
|
14631
14839
|
const allConfigResults = [];
|
|
14632
14840
|
for (const t of targets) {
|
|
14633
14841
|
const generator = getLspConfigGenerator(t);
|
|
@@ -14729,8 +14937,277 @@ function getLspConfigGenerator(target) {
|
|
|
14729
14937
|
}
|
|
14730
14938
|
}
|
|
14731
14939
|
|
|
14940
|
+
// src/commands/debt-harvest.command.ts
|
|
14941
|
+
import { readdir as readdir2, readFile as readFile9, writeFile as writeFile5, mkdir as mkdir6 } from "node:fs/promises";
|
|
14942
|
+
import { join as join7, relative as relative2, extname } from "node:path";
|
|
14943
|
+
var DEFER_REGEX = /\/\/\s*defer\s*[-:]\s*(.+?)(?:\s*--(\w+))?\s*$/gm;
|
|
14944
|
+
var SOURCE_EXTENSIONS = new Set([
|
|
14945
|
+
".ts",
|
|
14946
|
+
".tsx",
|
|
14947
|
+
".js",
|
|
14948
|
+
".jsx",
|
|
14949
|
+
".mjs",
|
|
14950
|
+
".cjs",
|
|
14951
|
+
".go",
|
|
14952
|
+
".rs",
|
|
14953
|
+
".java",
|
|
14954
|
+
".kt",
|
|
14955
|
+
".swift",
|
|
14956
|
+
".cs",
|
|
14957
|
+
".php",
|
|
14958
|
+
".scala",
|
|
14959
|
+
".dart",
|
|
14960
|
+
".c",
|
|
14961
|
+
".cpp",
|
|
14962
|
+
".h",
|
|
14963
|
+
".hpp"
|
|
14964
|
+
]);
|
|
14965
|
+
async function walkDir(dir, extensions) {
|
|
14966
|
+
const results = [];
|
|
14967
|
+
try {
|
|
14968
|
+
const entries = await readdir2(dir, { withFileTypes: true });
|
|
14969
|
+
for (const entry of entries) {
|
|
14970
|
+
const fullPath = join7(dir, entry.name);
|
|
14971
|
+
if (entry.isDirectory()) {
|
|
14972
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules")
|
|
14973
|
+
continue;
|
|
14974
|
+
results.push(...await walkDir(fullPath, extensions));
|
|
14975
|
+
} else if (extensions.has(extname(entry.name))) {
|
|
14976
|
+
results.push(fullPath);
|
|
14977
|
+
}
|
|
14978
|
+
}
|
|
14979
|
+
} catch {}
|
|
14980
|
+
return results;
|
|
14981
|
+
}
|
|
14982
|
+
function extractDefers(content, filePath) {
|
|
14983
|
+
const entries = [];
|
|
14984
|
+
const lines = content.split(`
|
|
14985
|
+
`);
|
|
14986
|
+
for (let i = 0;i < lines.length; i++) {
|
|
14987
|
+
const line = lines[i];
|
|
14988
|
+
DEFER_REGEX.lastIndex = 0;
|
|
14989
|
+
const match = DEFER_REGEX.exec(line);
|
|
14990
|
+
if (match) {
|
|
14991
|
+
entries.push({
|
|
14992
|
+
file: filePath,
|
|
14993
|
+
line: i + 1,
|
|
14994
|
+
reason: match[1].trim(),
|
|
14995
|
+
tag: match[2]
|
|
14996
|
+
});
|
|
14997
|
+
}
|
|
14998
|
+
}
|
|
14999
|
+
return entries;
|
|
15000
|
+
}
|
|
15001
|
+
function renderLedger(entries) {
|
|
15002
|
+
const grouped = new Map;
|
|
15003
|
+
for (const entry of entries) {
|
|
15004
|
+
const tag = entry.tag ?? "unclassified";
|
|
15005
|
+
const group = grouped.get(tag) ?? [];
|
|
15006
|
+
group.push(entry);
|
|
15007
|
+
grouped.set(tag, group);
|
|
15008
|
+
}
|
|
15009
|
+
const lines = [
|
|
15010
|
+
"<!-- CODECONDUCTOR:BEGIN managed -->",
|
|
15011
|
+
"",
|
|
15012
|
+
"# Debt Ledger",
|
|
15013
|
+
"",
|
|
15014
|
+
"> Auto-generated by `codeconductor debt-harvest`. Do not edit manually.",
|
|
15015
|
+
""
|
|
15016
|
+
];
|
|
15017
|
+
const sortedTags = [...grouped.keys()].sort();
|
|
15018
|
+
for (const tag of sortedTags) {
|
|
15019
|
+
const tagEntries = grouped.get(tag);
|
|
15020
|
+
lines.push(`## ${tag}`);
|
|
15021
|
+
lines.push("");
|
|
15022
|
+
lines.push("| File | Line | Reason |");
|
|
15023
|
+
lines.push("| ---- | ---- | ------ |");
|
|
15024
|
+
for (const entry of tagEntries) {
|
|
15025
|
+
lines.push(`| ${entry.file} | ${entry.line} | ${entry.reason} |`);
|
|
15026
|
+
}
|
|
15027
|
+
lines.push("");
|
|
15028
|
+
}
|
|
15029
|
+
lines.push("<!-- CODECONDUCTOR:END managed -->");
|
|
15030
|
+
lines.push("");
|
|
15031
|
+
return lines.join(`
|
|
15032
|
+
`);
|
|
15033
|
+
}
|
|
15034
|
+
async function debtHarvestCommand(options) {
|
|
15035
|
+
const { projectRoot, dir = "src", output } = options;
|
|
15036
|
+
try {
|
|
15037
|
+
const targetDir = join7(projectRoot, dir);
|
|
15038
|
+
const files = await walkDir(targetDir, SOURCE_EXTENSIONS);
|
|
15039
|
+
const allEntries = [];
|
|
15040
|
+
for (const file of files) {
|
|
15041
|
+
const content = await readFile9(file, "utf-8");
|
|
15042
|
+
const entries = extractDefers(content, relative2(projectRoot, file));
|
|
15043
|
+
allEntries.push(...entries);
|
|
15044
|
+
}
|
|
15045
|
+
const ledgerDir = join7(projectRoot, ".codeconductor");
|
|
15046
|
+
await mkdir6(ledgerDir, { recursive: true });
|
|
15047
|
+
const ledgerPath = join7(ledgerDir, "debt-ledger.md");
|
|
15048
|
+
const ledgerContent = renderLedger(allEntries);
|
|
15049
|
+
await writeFile5(ledgerPath, ledgerContent, "utf-8");
|
|
15050
|
+
if (output === "json") {
|
|
15051
|
+
return {
|
|
15052
|
+
code: 0,
|
|
15053
|
+
data: {
|
|
15054
|
+
success: true,
|
|
15055
|
+
command: "debt-harvest",
|
|
15056
|
+
entries: allEntries,
|
|
15057
|
+
entryCount: allEntries.length,
|
|
15058
|
+
ledger: ledgerPath
|
|
15059
|
+
}
|
|
15060
|
+
};
|
|
15061
|
+
}
|
|
15062
|
+
return {
|
|
15063
|
+
code: 0,
|
|
15064
|
+
data: {
|
|
15065
|
+
success: true,
|
|
15066
|
+
command: "debt-harvest",
|
|
15067
|
+
message: `Found ${allEntries.length} deferred item(s) across ${files.length} file(s). Ledger written to ${ledgerPath}`,
|
|
15068
|
+
entries: allEntries
|
|
15069
|
+
}
|
|
15070
|
+
};
|
|
15071
|
+
} catch (error) {
|
|
15072
|
+
return {
|
|
15073
|
+
code: 1,
|
|
15074
|
+
data: {
|
|
15075
|
+
success: false,
|
|
15076
|
+
command: "debt-harvest",
|
|
15077
|
+
errors: [String(error)]
|
|
15078
|
+
}
|
|
15079
|
+
};
|
|
15080
|
+
}
|
|
15081
|
+
}
|
|
15082
|
+
|
|
15083
|
+
// src/commands/help.command.ts
|
|
15084
|
+
import { readdir as readdir3 } from "node:fs/promises";
|
|
15085
|
+
import { join as join8 } from "node:path";
|
|
15086
|
+
async function scanPresetDir(projectRoot, target) {
|
|
15087
|
+
const inventory = {
|
|
15088
|
+
target,
|
|
15089
|
+
skills: [],
|
|
15090
|
+
commands: [],
|
|
15091
|
+
agents: [],
|
|
15092
|
+
workflows: []
|
|
15093
|
+
};
|
|
15094
|
+
const presetDir = join8(projectRoot, "presets", target);
|
|
15095
|
+
try {
|
|
15096
|
+
const entries = await readdir3(presetDir, { withFileTypes: true });
|
|
15097
|
+
for (const entry of entries) {
|
|
15098
|
+
if (entry.isDirectory()) {
|
|
15099
|
+
const subDir = join8(presetDir, entry.name);
|
|
15100
|
+
const subEntries = await readdir3(subDir, { withFileTypes: true });
|
|
15101
|
+
for (const sub of subEntries) {
|
|
15102
|
+
if (sub.isFile()) {
|
|
15103
|
+
const itemName = sub.name.replace(/\.[^.]+$/, "");
|
|
15104
|
+
if (entry.name === "skills")
|
|
15105
|
+
inventory.skills.push(itemName);
|
|
15106
|
+
else if (entry.name === "commands")
|
|
15107
|
+
inventory.commands.push(itemName);
|
|
15108
|
+
else if (entry.name === "agents")
|
|
15109
|
+
inventory.agents.push(itemName);
|
|
15110
|
+
else if (entry.name === "workflows")
|
|
15111
|
+
inventory.workflows.push(itemName);
|
|
15112
|
+
} else if (sub.isDirectory()) {
|
|
15113
|
+
if (entry.name === "skills")
|
|
15114
|
+
inventory.skills.push(sub.name);
|
|
15115
|
+
else if (entry.name === "agents")
|
|
15116
|
+
inventory.agents.push(sub.name);
|
|
15117
|
+
}
|
|
15118
|
+
}
|
|
15119
|
+
}
|
|
15120
|
+
}
|
|
15121
|
+
} catch {}
|
|
15122
|
+
return inventory;
|
|
15123
|
+
}
|
|
15124
|
+
function renderHuman(inventory, defaultTarget) {
|
|
15125
|
+
const lines = [
|
|
15126
|
+
`CodeConductor Help — ${inventory.target}${inventory.target === defaultTarget ? " (active)" : ""}`,
|
|
15127
|
+
""
|
|
15128
|
+
];
|
|
15129
|
+
lines.push(`Skills (${inventory.skills.length}):`);
|
|
15130
|
+
if (inventory.skills.length === 0) {
|
|
15131
|
+
lines.push(" (none)");
|
|
15132
|
+
} else {
|
|
15133
|
+
for (const skill of inventory.skills.sort()) {
|
|
15134
|
+
lines.push(` - ${skill}`);
|
|
15135
|
+
}
|
|
15136
|
+
}
|
|
15137
|
+
lines.push("");
|
|
15138
|
+
lines.push(`Subagents (${inventory.agents.length}):`);
|
|
15139
|
+
if (inventory.agents.length === 0) {
|
|
15140
|
+
lines.push(" (none)");
|
|
15141
|
+
} else {
|
|
15142
|
+
for (const agent of inventory.agents.sort()) {
|
|
15143
|
+
lines.push(` - ${agent}`);
|
|
15144
|
+
}
|
|
15145
|
+
}
|
|
15146
|
+
lines.push("");
|
|
15147
|
+
lines.push(`Commands (${inventory.commands.length}):`);
|
|
15148
|
+
if (inventory.commands.length === 0) {
|
|
15149
|
+
lines.push(" (none)");
|
|
15150
|
+
} else {
|
|
15151
|
+
for (const cmd of inventory.commands.sort()) {
|
|
15152
|
+
lines.push(` - ${cmd}`);
|
|
15153
|
+
}
|
|
15154
|
+
}
|
|
15155
|
+
if (inventory.workflows.length > 0) {
|
|
15156
|
+
lines.push("");
|
|
15157
|
+
lines.push(`Workflows (${inventory.workflows.length}):`);
|
|
15158
|
+
for (const wf of inventory.workflows.sort()) {
|
|
15159
|
+
lines.push(` - ${wf}`);
|
|
15160
|
+
}
|
|
15161
|
+
}
|
|
15162
|
+
return lines.join(`
|
|
15163
|
+
`);
|
|
15164
|
+
}
|
|
15165
|
+
async function helpCommand(options) {
|
|
15166
|
+
const { projectRoot, target: overrideTarget, output } = options;
|
|
15167
|
+
try {
|
|
15168
|
+
let defaultTarget = "opencode";
|
|
15169
|
+
try {
|
|
15170
|
+
const configResult = await loadConfig(projectRoot);
|
|
15171
|
+
if (configResult.success) {
|
|
15172
|
+
defaultTarget = configResult.data.defaults.target;
|
|
15173
|
+
}
|
|
15174
|
+
} catch {}
|
|
15175
|
+
const target = overrideTarget ?? defaultTarget;
|
|
15176
|
+
const inventory = await scanPresetDir(projectRoot, target);
|
|
15177
|
+
if (output === "json") {
|
|
15178
|
+
return {
|
|
15179
|
+
code: 0,
|
|
15180
|
+
data: {
|
|
15181
|
+
success: true,
|
|
15182
|
+
command: "help",
|
|
15183
|
+
inventory,
|
|
15184
|
+
defaultTarget
|
|
15185
|
+
}
|
|
15186
|
+
};
|
|
15187
|
+
}
|
|
15188
|
+
return {
|
|
15189
|
+
code: 0,
|
|
15190
|
+
data: {
|
|
15191
|
+
success: true,
|
|
15192
|
+
command: "help",
|
|
15193
|
+
message: renderHuman(inventory, defaultTarget),
|
|
15194
|
+
inventory
|
|
15195
|
+
}
|
|
15196
|
+
};
|
|
15197
|
+
} catch (error) {
|
|
15198
|
+
return {
|
|
15199
|
+
code: 1,
|
|
15200
|
+
data: {
|
|
15201
|
+
success: false,
|
|
15202
|
+
command: "help",
|
|
15203
|
+
errors: [String(error)]
|
|
15204
|
+
}
|
|
15205
|
+
};
|
|
15206
|
+
}
|
|
15207
|
+
}
|
|
15208
|
+
|
|
14732
15209
|
// src/commands/seo-audit.command.ts
|
|
14733
|
-
import { writeFile as
|
|
15210
|
+
import { writeFile as writeFile6, mkdir as mkdir7 } from "node:fs/promises";
|
|
14734
15211
|
import { dirname as dirname4, resolve as resolve10 } from "node:path";
|
|
14735
15212
|
|
|
14736
15213
|
// src/infrastructure/http/safe-fetch.ts
|
|
@@ -16023,13 +16500,13 @@ async function seoAuditCommand(options) {
|
|
|
16023
16500
|
}
|
|
16024
16501
|
if (output) {
|
|
16025
16502
|
const outputPath = resolve10(options.projectRoot, output);
|
|
16026
|
-
await
|
|
16027
|
-
await
|
|
16503
|
+
await mkdir7(dirname4(outputPath), { recursive: true });
|
|
16504
|
+
await writeFile6(outputPath, formattedOutput, "utf-8");
|
|
16028
16505
|
} else if (format === "markdown") {
|
|
16029
16506
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
16030
16507
|
const defaultPath = resolve10(options.projectRoot, "seo-reports", `audit-report-${timestamp}.md`);
|
|
16031
|
-
await
|
|
16032
|
-
await
|
|
16508
|
+
await mkdir7(dirname4(defaultPath), { recursive: true });
|
|
16509
|
+
await writeFile6(defaultPath, formattedOutput, "utf-8");
|
|
16033
16510
|
process.stderr.write(`Report saved to: ${defaultPath}
|
|
16034
16511
|
`);
|
|
16035
16512
|
}
|
|
@@ -16057,7 +16534,7 @@ async function seoAuditCommand(options) {
|
|
|
16057
16534
|
}
|
|
16058
16535
|
|
|
16059
16536
|
// src/commands/seo-llms.command.ts
|
|
16060
|
-
import { writeFile as
|
|
16537
|
+
import { writeFile as writeFile7, mkdir as mkdir8 } from "node:fs/promises";
|
|
16061
16538
|
import { dirname as dirname5, resolve as resolve11 } from "node:path";
|
|
16062
16539
|
|
|
16063
16540
|
// src/domain/seo/llms-generator.ts
|
|
@@ -16202,8 +16679,8 @@ async function seoLlmsCommand(options) {
|
|
|
16202
16679
|
}) : await generateLlmsTxtFromUrl(url);
|
|
16203
16680
|
process.stderr.write("\r" + " ".repeat(80) + "\r");
|
|
16204
16681
|
const outputPath = output ? resolve11(options.projectRoot, output) : resolve11(options.projectRoot, "llms.txt");
|
|
16205
|
-
await
|
|
16206
|
-
await
|
|
16682
|
+
await mkdir8(dirname5(outputPath), { recursive: true });
|
|
16683
|
+
await writeFile7(outputPath, result.content, "utf-8");
|
|
16207
16684
|
process.stderr.write(`Generated: ${outputPath} (${result.entries.length} entries)
|
|
16208
16685
|
`);
|
|
16209
16686
|
return {
|
|
@@ -16231,7 +16708,7 @@ async function seoLlmsCommand(options) {
|
|
|
16231
16708
|
// src/commands/update.command.ts
|
|
16232
16709
|
import { homedir as homedir9 } from "node:os";
|
|
16233
16710
|
import { resolve as resolve12, dirname as dirname6 } from "node:path";
|
|
16234
|
-
import { mkdir as
|
|
16711
|
+
import { mkdir as mkdir9, readFile as readFile10, writeFile as writeFile8, stat as stat3 } from "node:fs/promises";
|
|
16235
16712
|
init_package_paths();
|
|
16236
16713
|
async function updateCommand(options) {
|
|
16237
16714
|
const { dryRun, force, global: isGlobal, output, projectRoot } = options;
|
|
@@ -16300,9 +16777,9 @@ async function updateCommand(options) {
|
|
|
16300
16777
|
const localCouncil = resolve12(basePath, ".codeconductor", "presets", "council.yml");
|
|
16301
16778
|
const bundledCouncil = resolve12(SRC_PRESETS_DIR, "council", "council.yml");
|
|
16302
16779
|
try {
|
|
16303
|
-
const content = await
|
|
16304
|
-
await
|
|
16305
|
-
await
|
|
16780
|
+
const content = await readFile10(bundledCouncil, "utf-8");
|
|
16781
|
+
await mkdir9(dirname6(localCouncil), { recursive: true });
|
|
16782
|
+
await writeFile8(localCouncil, content, "utf-8");
|
|
16306
16783
|
updated.push(localCouncil);
|
|
16307
16784
|
} catch (e) {
|
|
16308
16785
|
throw new Error(`Failed to update council.yml: ${e}`);
|
|
@@ -16311,9 +16788,9 @@ async function updateCommand(options) {
|
|
|
16311
16788
|
if (updateResults.policy) {
|
|
16312
16789
|
const localPolicy = resolve12(basePath, ".codeconductor", "presets", "policy.yml");
|
|
16313
16790
|
try {
|
|
16314
|
-
const content = await
|
|
16315
|
-
await
|
|
16316
|
-
await
|
|
16791
|
+
const content = await readFile10(POLICY_PATH, "utf-8");
|
|
16792
|
+
await mkdir9(dirname6(localPolicy), { recursive: true });
|
|
16793
|
+
await writeFile8(localPolicy, content, "utf-8");
|
|
16317
16794
|
updated.push(localPolicy);
|
|
16318
16795
|
} catch (e) {
|
|
16319
16796
|
throw new Error(`Failed to update policy.yml: ${e}`);
|
|
@@ -16375,7 +16852,7 @@ async function updateCommand(options) {
|
|
|
16375
16852
|
});
|
|
16376
16853
|
const filesToWrite = resolvedFiles.filter((f) => t.files.includes(f.path));
|
|
16377
16854
|
if (filesToWrite.length > 0) {
|
|
16378
|
-
const writeResults = await writeGeneratedFiles2(filesToWrite, { dryRun: false, force: true });
|
|
16855
|
+
const writeResults = await writeGeneratedFiles2(filesToWrite, { dryRun: false, force: true, config });
|
|
16379
16856
|
for (const wr of writeResults) {
|
|
16380
16857
|
if (wr.success) {
|
|
16381
16858
|
updated.push(wr.path);
|
|
@@ -16409,8 +16886,8 @@ async function updateCommand(options) {
|
|
|
16409
16886
|
}
|
|
16410
16887
|
} catch {}
|
|
16411
16888
|
try {
|
|
16412
|
-
await
|
|
16413
|
-
await
|
|
16889
|
+
await mkdir9(dirname6(lockDest), { recursive: true });
|
|
16890
|
+
await writeFile8(lockDest, JSON.stringify(newSkillsLock, null, 2), "utf-8");
|
|
16414
16891
|
updated.push(lockDest);
|
|
16415
16892
|
} catch (e) {
|
|
16416
16893
|
throw new Error(`Failed to write skills-lock.json: ${e}`);
|
|
@@ -16519,6 +16996,8 @@ Commands:
|
|
|
16519
16996
|
seo llms Generate llms.txt from a URL or sitemap
|
|
16520
16997
|
doctor Validate configuration and generated files
|
|
16521
16998
|
update Update installed presets
|
|
16999
|
+
help / cc-help Show preset inventory (skills, subagents, commands)
|
|
17000
|
+
debt-harvest / harvest Scan source files for deferred debt items
|
|
16522
17001
|
|
|
16523
17002
|
Options:
|
|
16524
17003
|
--help, -h Show this help message
|
|
@@ -16562,8 +17041,6 @@ Examples:
|
|
|
16562
17041
|
async function routeCommand(args, projectRoot) {
|
|
16563
17042
|
const { command, subcommand, options, flags } = args;
|
|
16564
17043
|
switch (command) {
|
|
16565
|
-
case "help":
|
|
16566
|
-
return { code: 0, data: { help: getHelp() } };
|
|
16567
17044
|
case "init":
|
|
16568
17045
|
return initCommand({
|
|
16569
17046
|
projectRoot,
|
|
@@ -16632,6 +17109,20 @@ async function routeCommand(args, projectRoot) {
|
|
|
16632
17109
|
global: options.global === true || options.global === "true",
|
|
16633
17110
|
output: flags.output
|
|
16634
17111
|
});
|
|
17112
|
+
case "help":
|
|
17113
|
+
case "cc-help":
|
|
17114
|
+
return helpCommand({
|
|
17115
|
+
projectRoot,
|
|
17116
|
+
target: options.target,
|
|
17117
|
+
output: flags.output
|
|
17118
|
+
});
|
|
17119
|
+
case "debt-harvest":
|
|
17120
|
+
case "harvest":
|
|
17121
|
+
return debtHarvestCommand({
|
|
17122
|
+
projectRoot,
|
|
17123
|
+
dir: options.dir,
|
|
17124
|
+
output: flags.output
|
|
17125
|
+
});
|
|
16635
17126
|
case "seo": {
|
|
16636
17127
|
if (subcommand === "audit") {
|
|
16637
17128
|
return seoAuditCommand({
|
package/package.json
CHANGED
package/policy.yml
CHANGED
|
@@ -48,6 +48,18 @@ denyWrite:
|
|
|
48
48
|
- "/var/**"
|
|
49
49
|
- "~/**"
|
|
50
50
|
|
|
51
|
+
# Credential patterns for secret detection.
|
|
52
|
+
# These are merged with CodeConductorConfig.safety.secretPatterns at runtime.
|
|
53
|
+
secretPatterns:
|
|
54
|
+
- password
|
|
55
|
+
- secret
|
|
56
|
+
- api_key
|
|
57
|
+
- token
|
|
58
|
+
- api[_-]?key
|
|
59
|
+
- access[_-]?token
|
|
60
|
+
- auth[_-]?token
|
|
61
|
+
- private[_-]?key
|
|
62
|
+
|
|
51
63
|
targets:
|
|
52
64
|
opencode:
|
|
53
65
|
unsupportedRules: []
|
package/presets/agy/AGENTS.md
CHANGED
|
@@ -24,6 +24,21 @@ LLM coding mistakes and bias toward caution over speed.
|
|
|
24
24
|
success criteria. For multi-step tasks, state a plan with verification
|
|
25
25
|
checks. Loop until verified.
|
|
26
26
|
|
|
27
|
+
### YAGNI (You Aren't Gonna Need It)
|
|
28
|
+
|
|
29
|
+
Do not build features, abstractions, or "flexibility" that is not explicitly
|
|
30
|
+
requested. If the user asks for a function, write a function — not a class
|
|
31
|
+
hierarchy. If they ask for a string, return a string — not a Result type
|
|
32
|
+
with 15 error codes. Every line you write must solve a problem that exists
|
|
33
|
+
**now**.
|
|
34
|
+
|
|
35
|
+
### Stdlib-First
|
|
36
|
+
|
|
37
|
+
Prefer the language's standard library over third-party packages. Before
|
|
38
|
+
adding a dependency, ask: "Does `node:fs`, `node:path`, `node:crypto`, or
|
|
39
|
+
a built-in module solve this?" If yes, use it. Every external dependency
|
|
40
|
+
introduces maintenance burden, supply-chain risk, and version conflicts.
|
|
41
|
+
|
|
27
42
|
---
|
|
28
43
|
|
|
29
44
|
## Workflow Contract
|
|
@@ -95,6 +110,7 @@ When multiple signals apply, take the highest risk level. Do not average.
|
|
|
95
110
|
| Documentation update | any | `docs` |
|
|
96
111
|
| Codebase exploration | any | `repo-explorer` |
|
|
97
112
|
| Code review | any | `reviewer` |
|
|
113
|
+
| Security review | high | `security-reviewer` → `reviewer` |
|
|
98
114
|
|
|
99
115
|
---
|
|
100
116
|
|
|
@@ -371,6 +387,32 @@ High-risk checkpoint: [yes | no — if yes, describe what triggers a stop]
|
|
|
371
387
|
|
|
372
388
|
---
|
|
373
389
|
|
|
390
|
+
### security-reviewer
|
|
391
|
+
|
|
392
|
+
**Role:** Dedicated security review. Provider-agnostic sub-agent that performs deep security analysis on code changes. Can apply a security veto that overrides majority consensus.
|
|
393
|
+
|
|
394
|
+
**Use when:** High-risk tasks touching auth, payment, credentials, injection vectors, or supply-chain dependencies. Mandatory for security-sensitive changes.
|
|
395
|
+
|
|
396
|
+
**Permissions:**
|
|
397
|
+
- read: `allow`
|
|
398
|
+
- edit: `deny`
|
|
399
|
+
- bash: `allow` (git diff, git status)
|
|
400
|
+
- network: `deny`
|
|
401
|
+
|
|
402
|
+
**Does not:** Write code. Edit files. Bypass security veto mechanism.
|
|
403
|
+
|
|
404
|
+
**Provider-agnostic constraints:**
|
|
405
|
+
- No vendor-specific prompts, APIs, or model identifiers in role definition
|
|
406
|
+
- All security analysis must be expressed through the council consensus interface (`securityVeto` flag on `REJECTED` verdict)
|
|
407
|
+
- Focus areas: vulnerabilities, credentials, injection, auth, supply-chain, OWASP Top 10
|
|
408
|
+
|
|
409
|
+
**Veto behavior:**
|
|
410
|
+
- When `securityVeto: true` and `status: 'REJECTED'`, the veto overrides majority consensus → final status becomes `REJECTED`
|
|
411
|
+
- The veto agent is recorded in `vetoByAgentId` for traceability
|
|
412
|
+
- Composable: can be added alongside existing council agents without replacing the general `security` agent
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
374
416
|
### docs
|
|
375
417
|
|
|
376
418
|
**Role:** Updates README, OpenAPI specs, ADRs, and changelogs.
|
|
@@ -43,13 +43,37 @@ reviewer.
|
|
|
43
43
|
|
|
44
44
|
---
|
|
45
45
|
|
|
46
|
-
## Step 2 —
|
|
46
|
+
## Step 2 — Security and code review
|
|
47
|
+
|
|
48
|
+
### Security review (security-reviewer)
|
|
49
|
+
|
|
50
|
+
Invoke `security-reviewer` **before** `reviewer` when the change touches:
|
|
51
|
+
|
|
52
|
+
- Authentication or authorization logic
|
|
53
|
+
- Payment or financial processing
|
|
54
|
+
- Credentials, tokens, secrets, or API keys
|
|
55
|
+
- SQL injection, XSS, or other injection vectors
|
|
56
|
+
- Supply-chain dependencies (new packages, lockfile changes)
|
|
57
|
+
- OWASP Top 10 categories
|
|
58
|
+
|
|
59
|
+
`security-reviewer` performs deep security analysis and can apply a **security
|
|
60
|
+
veto** that overrides majority consensus:
|
|
61
|
+
|
|
62
|
+
- When `securityVeto: true` and verdict is `REJECTED`, the veto forces the
|
|
63
|
+
final status to `REJECTED` regardless of other reviewers' opinions
|
|
64
|
+
- The veto agent ID is recorded in `vetoByAgentId` for traceability
|
|
65
|
+
|
|
66
|
+
If `security-reviewer` applies a veto, the review is **BLOCKED** — all CRITICAL
|
|
67
|
+
findings must be resolved before proceeding.
|
|
68
|
+
|
|
69
|
+
### Code review (reviewer)
|
|
47
70
|
|
|
48
71
|
Invoke `reviewer` with:
|
|
49
72
|
|
|
50
73
|
- The full diff
|
|
51
74
|
- The Task Card or PR description (if available)
|
|
52
75
|
- The target specification from $ARGUMENTS
|
|
76
|
+
- The security-reviewer report (if one was generated)
|
|
53
77
|
|
|
54
78
|
reviewer must evaluate the diff against the following checklist:
|
|
55
79
|
|
package/presets/claude/CLAUDE.md
CHANGED
|
@@ -26,6 +26,21 @@ LLM coding mistakes and bias toward caution over speed.
|
|
|
26
26
|
success criteria. For multi-step tasks, state a plan with verification
|
|
27
27
|
checks. Loop until verified.
|
|
28
28
|
|
|
29
|
+
### YAGNI (You Aren't Gonna Need It)
|
|
30
|
+
|
|
31
|
+
Do not build features, abstractions, or "flexibility" that is not explicitly
|
|
32
|
+
requested. If the user asks for a function, write a function — not a class
|
|
33
|
+
hierarchy. If they ask for a string, return a string — not a Result type
|
|
34
|
+
with 15 error codes. Every line you write must solve a problem that exists
|
|
35
|
+
**now**.
|
|
36
|
+
|
|
37
|
+
### Stdlib-First
|
|
38
|
+
|
|
39
|
+
Prefer the language's standard library over third-party packages. Before
|
|
40
|
+
adding a dependency, ask: "Does `node:fs`, `node:path`, `node:crypto`, or
|
|
41
|
+
a built-in module solve this?" If yes, use it. Every external dependency
|
|
42
|
+
introduces maintenance burden, supply-chain risk, and version conflicts.
|
|
43
|
+
|
|
29
44
|
---
|
|
30
45
|
|
|
31
46
|
## Core Terminology
|
|
@@ -481,6 +496,55 @@ _(none)_ if no suggestions
|
|
|
481
496
|
|
|
482
497
|
---
|
|
483
498
|
|
|
499
|
+
### Complexity Auditor
|
|
500
|
+
|
|
501
|
+
Analyzes the implementation diff for bloat, unnecessary abstractions, and
|
|
502
|
+
non-native solutions. Produces a Complexity Audit Report that feeds the
|
|
503
|
+
scorecard's cc-gain criterion. Does not edit code.
|
|
504
|
+
|
|
505
|
+
**Does not:** propose new dependencies, suggest new abstractions, recommend
|
|
506
|
+
external libraries, edit any file.
|
|
507
|
+
|
|
508
|
+
**Analysis axes:**
|
|
509
|
+
|
|
510
|
+
| Axis | What to detect |
|
|
511
|
+
| ----------------------- | ---------------------------------------------------------------- |
|
|
512
|
+
| LOC delta | Lines added vs removed — net simplification |
|
|
513
|
+
| Dependency delta | External deps added vs removed — prefer stdlib |
|
|
514
|
+
| Cyclomatic complexity | Conditional complexity changes — fewer branches = better |
|
|
515
|
+
| Bloat patterns | Trivial wrappers, one-method classes, unused imports, etc. |
|
|
516
|
+
|
|
517
|
+
**Complexity Audit Report format:**
|
|
518
|
+
|
|
519
|
+
```markdown
|
|
520
|
+
## Complexity Audit Report
|
|
521
|
+
|
|
522
|
+
**Task**: [objective from Task Card] **Auditor**: Complexity Auditor
|
|
523
|
+
|
|
524
|
+
### Metrics
|
|
525
|
+
|
|
526
|
+
| Metric | Added | Removed | Delta |
|
|
527
|
+
| -------------------- | ----- | ------- | ----- |
|
|
528
|
+
| LOC | | | |
|
|
529
|
+
| Dependencies | | | |
|
|
530
|
+
| Cyclomatic complexity| | | |
|
|
531
|
+
|
|
532
|
+
### Findings
|
|
533
|
+
|
|
534
|
+
- [ ] [F1] [file:line] — [description] Pattern: [bloat-pattern] Action: [delete|replace-native]
|
|
535
|
+
|
|
536
|
+
_(none)_ if no bloat patterns detected
|
|
537
|
+
|
|
538
|
+
### Summary
|
|
539
|
+
|
|
540
|
+
- LOC delta: [+/-N]
|
|
541
|
+
- Deps delta: [+/-N]
|
|
542
|
+
- Cyclomatic delta: [+/-N]
|
|
543
|
+
- Findings: [count]
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
---
|
|
547
|
+
|
|
484
548
|
### Docs
|
|
485
549
|
|
|
486
550
|
Updates README, OpenAPI specs, ADRs, and CHANGELOG to reflect what was actually
|
|
@@ -530,11 +594,11 @@ behavior that was not implemented. Omit CHANGELOG entries.
|
|
|
530
594
|
|
|
531
595
|
## Routing Policy
|
|
532
596
|
|
|
533
|
-
| Risk Level | Route
|
|
534
|
-
| ---------- |
|
|
535
|
-
| low | Repo Explorer → Implementer → Tester
|
|
536
|
-
| medium | Repo Explorer → Architect → Implementer → Tester → Reviewer
|
|
537
|
-
| high | Task Coach → Repo Explorer → Architect → [human review] → Implementer → Tester → Reviewer → Docs |
|
|
597
|
+
| Risk Level | Route |
|
|
598
|
+
| ---------- | ----------------------------------------------------------------------------------------------------- |
|
|
599
|
+
| low | Repo Explorer → Implementer → Tester |
|
|
600
|
+
| medium | Repo Explorer → Architect → Implementer → Complexity Auditor → Tester → Reviewer |
|
|
601
|
+
| high | Task Coach → Repo Explorer → Architect → [human review] → Implementer → Complexity Auditor → Tester → Reviewer → Docs |
|
|
538
602
|
|
|
539
603
|
**Classification heuristics:**
|
|
540
604
|
|
package/presets/codex/AGENTS.md
CHANGED
|
@@ -26,6 +26,21 @@ LLM coding mistakes and bias toward caution over speed.
|
|
|
26
26
|
success criteria. For multi-step tasks, state a plan with verification
|
|
27
27
|
checks. Loop until verified.
|
|
28
28
|
|
|
29
|
+
### YAGNI (You Aren't Gonna Need It)
|
|
30
|
+
|
|
31
|
+
Do not build features, abstractions, or "flexibility" that is not explicitly
|
|
32
|
+
requested. If the user asks for a function, write a function — not a class
|
|
33
|
+
hierarchy. If they ask for a string, return a string — not a Result type
|
|
34
|
+
with 15 error codes. Every line you write must solve a problem that exists
|
|
35
|
+
**now**.
|
|
36
|
+
|
|
37
|
+
### Stdlib-First
|
|
38
|
+
|
|
39
|
+
Prefer the language's standard library over third-party packages. Before
|
|
40
|
+
adding a dependency, ask: "Does `node:fs`, `node:path`, `node:crypto`, or
|
|
41
|
+
a built-in module solve this?" If yes, use it. Every external dependency
|
|
42
|
+
introduces maintenance burden, supply-chain risk, and version conflicts.
|
|
43
|
+
|
|
29
44
|
---
|
|
30
45
|
|
|
31
46
|
## Workflow Contract
|
|
@@ -98,6 +113,7 @@ When multiple signals apply, take the highest risk level. Do not average.
|
|
|
98
113
|
| Documentation update | any | `docs` |
|
|
99
114
|
| Codebase exploration | any | `repo-explorer` |
|
|
100
115
|
| Code review | any | `reviewer` |
|
|
116
|
+
| Security review | high | `security-reviewer` → `reviewer` |
|
|
101
117
|
|
|
102
118
|
---
|
|
103
119
|
|
|
@@ -604,6 +620,42 @@ _(none)_ if no suggestions
|
|
|
604
620
|
|
|
605
621
|
---
|
|
606
622
|
|
|
623
|
+
### security-reviewer
|
|
624
|
+
|
|
625
|
+
**Role:** Dedicated security review. Provider-agnostic sub-agent that performs
|
|
626
|
+
deep security analysis on code changes. Can apply a security veto that overrides
|
|
627
|
+
majority consensus.
|
|
628
|
+
|
|
629
|
+
**Use when:** High-risk tasks touching auth, payment, credentials, injection
|
|
630
|
+
vectors, or supply-chain dependencies. Mandatory for security-sensitive changes.
|
|
631
|
+
|
|
632
|
+
**Permissions:**
|
|
633
|
+
|
|
634
|
+
- read: `allow`
|
|
635
|
+
- edit: `deny`
|
|
636
|
+
- bash: `allow` (`git diff`, `git status`)
|
|
637
|
+
- network: `deny`
|
|
638
|
+
|
|
639
|
+
**Does not:** Write code. Edit files. Bypass security veto mechanism.
|
|
640
|
+
|
|
641
|
+
**Provider-agnostic constraints:**
|
|
642
|
+
|
|
643
|
+
- No vendor-specific prompts, APIs, or model identifiers in role definition
|
|
644
|
+
- All security analysis must be expressed through the council consensus
|
|
645
|
+
interface (`securityVeto` flag on `REJECTED` verdict)
|
|
646
|
+
- Focus areas: vulnerabilities, credentials, injection, auth, supply-chain,
|
|
647
|
+
OWASP Top 10
|
|
648
|
+
|
|
649
|
+
**Veto behavior:**
|
|
650
|
+
|
|
651
|
+
- When `securityVeto: true` and `status: 'REJECTED'`, the veto overrides
|
|
652
|
+
majority consensus → final status becomes `REJECTED`
|
|
653
|
+
- The veto agent is recorded in `vetoByAgentId` for traceability
|
|
654
|
+
- Composable: can be added alongside existing council agents without replacing
|
|
655
|
+
the general `security` agent
|
|
656
|
+
|
|
657
|
+
---
|
|
658
|
+
|
|
607
659
|
### docs
|
|
608
660
|
|
|
609
661
|
**Role:** Updates README, OpenAPI specs, ADRs, and CHANGELOG to reflect what was
|
|
@@ -185,6 +185,21 @@ export KIMI_API_KEY="your-key"
|
|
|
185
185
|
- When using tools, be precise and minimal with context.
|
|
186
186
|
{{LANGUAGE_INSTRUCTIONS}}
|
|
187
187
|
|
|
188
|
+
### YAGNI (You Aren't Gonna Need It)
|
|
189
|
+
|
|
190
|
+
Do not build features, abstractions, or "flexibility" that is not explicitly
|
|
191
|
+
requested. If the user asks for a function, write a function — not a class
|
|
192
|
+
hierarchy. If they ask for a string, return a string — not a Result type
|
|
193
|
+
with 15 error codes. Every line you write must solve a problem that exists
|
|
194
|
+
**now**.
|
|
195
|
+
|
|
196
|
+
### Stdlib-First
|
|
197
|
+
|
|
198
|
+
Prefer the language's standard library over third-party packages. Before
|
|
199
|
+
adding a dependency, ask: "Does `node:fs`, `node:path`, `node:crypto`, or
|
|
200
|
+
a built-in module solve this?" If yes, use it. Every external dependency
|
|
201
|
+
introduces maintenance burden, supply-chain risk, and version conflicts.
|
|
202
|
+
|
|
188
203
|
## Context Budget
|
|
189
204
|
|
|
190
205
|
- If the task type differs from the previous one, execute "/clear" before
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: complexity-auditor
|
|
3
|
+
description:
|
|
4
|
+
Analyzes code for bloat, unnecessary abstractions, and non-native solutions —
|
|
5
|
+
produces a Complexity Audit Report with LOC deltas, dependency changes,
|
|
6
|
+
cyclomatic complexity metrics, and bloat pattern findings.
|
|
7
|
+
mode: subagent
|
|
8
|
+
model: "{{MODEL}}"
|
|
9
|
+
temperature: 0.1
|
|
10
|
+
tools: Read, Glob, Grep
|
|
11
|
+
permission:
|
|
12
|
+
read: allow
|
|
13
|
+
edit: deny
|
|
14
|
+
bash:
|
|
15
|
+
"*": deny
|
|
16
|
+
glob: allow
|
|
17
|
+
grep: allow
|
|
18
|
+
webfetch: deny
|
|
19
|
+
websearch: deny
|
|
20
|
+
skill: deny
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
You are the Complexity Auditor — the code quality gate in the CodeConductor
|
|
24
|
+
framework. You analyze diffs for bloat, unnecessary abstractions, and non-native
|
|
25
|
+
solutions. You do not edit code. You do not propose new dependencies.
|
|
26
|
+
|
|
27
|
+
## Your Contract
|
|
28
|
+
|
|
29
|
+
You may only propose **deletions** or **native replacements**. You never propose
|
|
30
|
+
new dependencies, new abstractions, or external libraries. Every finding must
|
|
31
|
+
map to a concrete action: `delete` (remove code) or `replace-native` (swap
|
|
32
|
+
external dep for stdlib equivalent).
|
|
33
|
+
|
|
34
|
+
## Analysis Axes
|
|
35
|
+
|
|
36
|
+
| Axis | What to detect |
|
|
37
|
+
| ----------------------- | ---------------------------------------------------------------- |
|
|
38
|
+
| LOC delta | Lines added vs removed — net simplification |
|
|
39
|
+
| Dependency delta | External deps added vs removed — prefer stdlib |
|
|
40
|
+
| Cyclomatic complexity | Conditional complexity changes — fewer branches = better |
|
|
41
|
+
| Bloat patterns | Trivial wrappers, one-method classes, unused imports, etc. |
|
|
42
|
+
|
|
43
|
+
## Bloat Patterns to Detect
|
|
44
|
+
|
|
45
|
+
- **single-implementation-interface** — Interface with only one implementation
|
|
46
|
+
- **trivial-wrapper** — Function that only delegates to another function
|
|
47
|
+
- **one-method-class** — Class with only one method (a function may suffice)
|
|
48
|
+
- **unused-import** — Imported name not used in added code
|
|
49
|
+
- **external-dep-for-native** — External dep replaceable with stdlib
|
|
50
|
+
- **excessive-abstraction** — Deep class hierarchy or unnecessary indirection
|
|
51
|
+
- **dead-code** — Code added but never referenced
|
|
52
|
+
|
|
53
|
+
## Complexity Audit Report Format
|
|
54
|
+
|
|
55
|
+
```markdown
|
|
56
|
+
## Complexity Audit Report
|
|
57
|
+
|
|
58
|
+
**Task**: [objective from Task Card] **Auditor**: Complexity Auditor
|
|
59
|
+
|
|
60
|
+
### Metrics
|
|
61
|
+
|
|
62
|
+
| Metric | Added | Removed | Delta |
|
|
63
|
+
| -------------------- | ----- | ------- | ----- |
|
|
64
|
+
| LOC | | | |
|
|
65
|
+
| Dependencies | | | |
|
|
66
|
+
| Cyclomatic complexity| | | |
|
|
67
|
+
|
|
68
|
+
### Findings
|
|
69
|
+
|
|
70
|
+
- [ ] [F1] [file:line] — [description] Pattern: [bloat-pattern] Action: [delete|replace-native]
|
|
71
|
+
|
|
72
|
+
_(none)_ if no bloat patterns detected
|
|
73
|
+
|
|
74
|
+
### Summary
|
|
75
|
+
|
|
76
|
+
- LOC delta: [+/-N]
|
|
77
|
+
- Deps delta: [+/-N]
|
|
78
|
+
- Cyclomatic delta: [+/-N]
|
|
79
|
+
- Findings: [count]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## What You Never Do
|
|
83
|
+
|
|
84
|
+
- Edit any file — source, test, documentation, or configuration
|
|
85
|
+
- Propose new dependencies or external libraries
|
|
86
|
+
- Suggest new abstractions or design patterns
|
|
87
|
+
- Override the Orchestrator's routing decision
|
|
88
|
+
- Issue findings without a concrete action (delete or replace-native)
|
|
89
|
+
- Analyze a diff you have not fully read
|