cclaw-cli 0.41.0 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -5
- package/dist/cli.js +5 -0
- package/dist/config.d.ts +63 -2
- package/dist/config.js +182 -8
- package/dist/content/ideate-command.d.ts +7 -0
- package/dist/content/ideate-command.js +178 -34
- package/dist/install.d.ts +5 -6
- package/dist/install.js +25 -11
- package/dist/types.d.ts +23 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -135,10 +135,31 @@ Plus harness-specific shims:
|
|
|
135
135
|
folders are auto-cleaned on sync.)
|
|
136
136
|
- `AGENTS.md` with a managed routing block (includes a Codex-specific note)
|
|
137
137
|
|
|
138
|
-
`.cclaw/config.yaml`
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
### `.cclaw/config.yaml` — the minimal surface
|
|
139
|
+
|
|
140
|
+
`cclaw init` writes five keys, on purpose:
|
|
141
|
+
|
|
142
|
+
```yaml
|
|
143
|
+
version: 0.43.0
|
|
144
|
+
flowVersion: 1.0.0
|
|
145
|
+
harnesses:
|
|
146
|
+
- codex
|
|
147
|
+
strictness: advisory # advisory | strict — one knob for prompt-guard + TDD
|
|
148
|
+
gitHookGuards: false # opt in to managed .git/hooks/pre-commit + pre-push
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
If cclaw detects a Node / Python / Go project at init time, a sixth
|
|
152
|
+
`languageRulePacks` line appears (auto-populated from `package.json`,
|
|
153
|
+
`pyproject.toml` / `requirements.txt`, `go.mod`). That is the full
|
|
154
|
+
default surface — a new user sees nothing they need to understand yet.
|
|
155
|
+
|
|
156
|
+
Advanced knobs (`promptGuardMode` / `tddEnforcement` per-axis overrides,
|
|
157
|
+
`tddTestGlobs`, `defaultTrack`, `trackHeuristics`, `sliceReview`) are
|
|
158
|
+
**opt-in**: add them by hand when you need them. `cclaw upgrade`
|
|
159
|
+
preserves exactly what you wrote — it never silently reintroduces
|
|
160
|
+
defaults you removed.
|
|
161
|
+
|
|
162
|
+
Full key-by-key reference: [`docs/config.md`](./docs/config.md).
|
|
142
163
|
|
|
143
164
|
---
|
|
144
165
|
|
|
@@ -152,7 +173,7 @@ inside `/cc-ops` subcommands.
|
|
|
152
173
|
|---|---|
|
|
153
174
|
| **`/cc <idea>`** | Classify the task, discover origin docs (`docs/prd/**`, ADRs, root `PRD.md`, …), sniff the stack, recommend a track, then start the first stage of that track. `/cc` without arguments resumes the current flow. |
|
|
154
175
|
| **`/cc-next`** | The one progression primitive. Reads `flow-state.json`, checks gates + mandatory subagent delegations, and either resumes the current stage or advances to the next. `/cc-next` in a new session is how you **resume**. |
|
|
155
|
-
| **`/cc-ideate`** | Repository improvement discovery. Scans for TODOs, flaky tests, oversized modules, docs drift, and recurring knowledge-store lessons
|
|
176
|
+
| **`/cc-ideate`** | Repository improvement discovery. Scans for TODOs, flaky tests, oversized modules, docs drift, and recurring knowledge-store lessons, **persists the ranked backlog** to `.cclaw/artifacts/ideation-<date>-<slug>.md`, and ends with a concrete handoff: launch `/cc` on the selected candidate in the same session, save-and-close, or discard. Resume check on next run reuses any ideation artifact younger than 30 days. Never mutates `flow-state.json`. |
|
|
156
177
|
| **`/cc-view`** | Read-only flow visibility. `/cc-view status` (default) shows stage progress, mandatory delegations with their fulfillment mode (isolated / generic-dispatch / role-switch), the ship closeout substate (retro → compound → archive), and the active harness parity row. `/cc-view tree` renders the same picture as a tree with a closeout sub-branch under ship and a per-harness playbook summary. `/cc-view diff` shows stage/gate/closeout/delegation deltas since the last run. Never mutates state (except diff's snapshot baseline). |
|
|
157
178
|
|
|
158
179
|
> Power-user surface: `/cc-ops` is an operational router for manual
|
package/dist/cli.js
CHANGED
|
@@ -827,6 +827,11 @@ async function runCommand(parsed, ctx) {
|
|
|
827
827
|
}
|
|
828
828
|
const trackNote = effectiveTrack ? ` (track=${effectiveTrack})` : "";
|
|
829
829
|
info(ctx, `Initialized .cclaw runtime and generated harness shims${trackNote}`);
|
|
830
|
+
// Point new users at the one config surface they might actually flip —
|
|
831
|
+
// `strictness` and `gitHookGuards` — without overselling the other knobs
|
|
832
|
+
// (those live behind docs/config.md until someone needs them).
|
|
833
|
+
info(ctx, "Config: .cclaw/config.yaml (strictness=advisory, gitHookGuards=false).");
|
|
834
|
+
info(ctx, "Need stricter guards or language rule packs? See docs/config.md.");
|
|
830
835
|
await maybeEnableCodexHooksFlag(effectiveHarnesses, parsed, ctx);
|
|
831
836
|
return 0;
|
|
832
837
|
}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,5 +1,66 @@
|
|
|
1
|
-
import type { FlowTrack, HarnessId, VibyConfig } from "./types.js";
|
|
1
|
+
import type { FlowTrack, HarnessId, LanguageRulePack, VibyConfig } from "./types.js";
|
|
2
2
|
export declare function configPath(projectRoot: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* Default test-file globs used by workflow-guard.sh to detect when a write
|
|
5
|
+
* targets a test file during TDD. Users rarely need to override this — the
|
|
6
|
+
* defaults cover TypeScript / JavaScript / Python / Go / Rust / Java layouts.
|
|
7
|
+
* Exposed so `install.ts` can reuse the same list when seeding the shell
|
|
8
|
+
* guard script, even though the field is no longer written to the default
|
|
9
|
+
* `config.yaml` template.
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEFAULT_TDD_TEST_GLOBS: readonly string[];
|
|
12
|
+
/**
|
|
13
|
+
* Populated runtime view of config values that downstream callers (install,
|
|
14
|
+
* observe, doctor) consume. Always has the derived guard modes populated,
|
|
15
|
+
* regardless of whether the user wrote `strictness`, the legacy keys, both,
|
|
16
|
+
* or neither.
|
|
17
|
+
*/
|
|
3
18
|
export declare function createDefaultConfig(harnesses?: HarnessId[], defaultTrack?: FlowTrack): VibyConfig;
|
|
19
|
+
/**
|
|
20
|
+
* Probe common project-root manifests to infer which language rule packs the
|
|
21
|
+
* user would reasonably want. Pure-functional best-effort: any filesystem
|
|
22
|
+
* error is swallowed, producing an empty list — the user can always override
|
|
23
|
+
* by hand.
|
|
24
|
+
*
|
|
25
|
+
* Called from `cclaw init` only (not `readConfig`), so subsequent upgrades
|
|
26
|
+
* never surprise a user who intentionally cleared the list.
|
|
27
|
+
*/
|
|
28
|
+
export declare function detectLanguageRulePacks(projectRoot: string): Promise<LanguageRulePack[]>;
|
|
4
29
|
export declare function readConfig(projectRoot: string): Promise<VibyConfig>;
|
|
5
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Fields that live on the populated runtime `VibyConfig` but are considered
|
|
32
|
+
* "advanced" — we keep them in the in-memory object so downstream callers
|
|
33
|
+
* don't have to branch, but we do **not** write them to `config.yaml` unless
|
|
34
|
+
* the user set them explicitly. Keeps the default template small and honest:
|
|
35
|
+
* only knobs a new user would meaningfully flip show up.
|
|
36
|
+
*/
|
|
37
|
+
type AdvancedConfigKey = "promptGuardMode" | "tddEnforcement" | "tddTestGlobs" | "defaultTrack" | "languageRulePacks" | "trackHeuristics" | "sliceReview";
|
|
38
|
+
/**
|
|
39
|
+
* Options controlling the serialisation shape of `config.yaml`.
|
|
40
|
+
*
|
|
41
|
+
* - `"full"` (default): write every field on the `VibyConfig` object that
|
|
42
|
+
* isn't `undefined`. Preserves existing shapes and keeps legacy callers
|
|
43
|
+
* working without migration.
|
|
44
|
+
* - `"minimal"`: write only the user-facing knobs (`MINIMAL_CONFIG_KEYS`)
|
|
45
|
+
* plus any non-empty `languageRulePacks` (so auto-detected values survive
|
|
46
|
+
* a fresh `cclaw init`). Use this when generating the default template;
|
|
47
|
+
* power users can still add advanced keys by hand.
|
|
48
|
+
*
|
|
49
|
+
* `advancedKeysPresent` upgrades an otherwise-minimal serialisation by
|
|
50
|
+
* including the listed advanced keys. `cclaw upgrade` uses it to preserve
|
|
51
|
+
* the exact shape a user hand-authored, while still re-minimising configs
|
|
52
|
+
* where the user stayed at defaults.
|
|
53
|
+
*/
|
|
54
|
+
export interface WriteConfigOptions {
|
|
55
|
+
mode?: "full" | "minimal";
|
|
56
|
+
advancedKeysPresent?: ReadonlySet<AdvancedConfigKey>;
|
|
57
|
+
}
|
|
58
|
+
export declare function writeConfig(projectRoot: string, config: VibyConfig, options?: WriteConfigOptions): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Enumerate which advanced keys are currently set in the on-disk config.
|
|
61
|
+
* Used by `cclaw upgrade` to preserve the user's existing shape — if they
|
|
62
|
+
* wrote `tddTestGlobs` by hand, the upgrade keeps it; if they didn't, the
|
|
63
|
+
* upgrade stays minimal.
|
|
64
|
+
*/
|
|
65
|
+
export declare function detectAdvancedKeys(projectRoot: string): Promise<ReadonlySet<AdvancedConfigKey>>;
|
|
66
|
+
export {};
|
package/dist/config.js
CHANGED
|
@@ -15,6 +15,7 @@ const ALLOWED_CONFIG_KEYS = new Set([
|
|
|
15
15
|
"version",
|
|
16
16
|
"flowVersion",
|
|
17
17
|
"harnesses",
|
|
18
|
+
"strictness",
|
|
18
19
|
"promptGuardMode",
|
|
19
20
|
"tddEnforcement",
|
|
20
21
|
"tddTestGlobs",
|
|
@@ -24,6 +25,21 @@ const ALLOWED_CONFIG_KEYS = new Set([
|
|
|
24
25
|
"trackHeuristics",
|
|
25
26
|
"sliceReview"
|
|
26
27
|
]);
|
|
28
|
+
/**
|
|
29
|
+
* Config keys always present in the minimal init template. Everything else
|
|
30
|
+
* is "advanced" — parsed when present, but not pre-populated by `cclaw init`.
|
|
31
|
+
*
|
|
32
|
+
* Deliberately small: a first-time user should only see knobs they might
|
|
33
|
+
* actually flip. Power users override by adding more keys by hand; the
|
|
34
|
+
* reference lives in `docs/config.md`.
|
|
35
|
+
*/
|
|
36
|
+
const MINIMAL_CONFIG_KEYS = [
|
|
37
|
+
"version",
|
|
38
|
+
"flowVersion",
|
|
39
|
+
"harnesses",
|
|
40
|
+
"strictness",
|
|
41
|
+
"gitHookGuards"
|
|
42
|
+
];
|
|
27
43
|
const DEFAULT_SLICE_REVIEW_THRESHOLD = 5;
|
|
28
44
|
const DEFAULT_SLICE_REVIEW_TRACKS = ["standard"];
|
|
29
45
|
function configFixExample() {
|
|
@@ -57,19 +73,78 @@ function validateStringArray(value, fieldName, configFilePath) {
|
|
|
57
73
|
export function configPath(projectRoot) {
|
|
58
74
|
return path.join(projectRoot, CONFIG_PATH);
|
|
59
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Default test-file globs used by workflow-guard.sh to detect when a write
|
|
78
|
+
* targets a test file during TDD. Users rarely need to override this — the
|
|
79
|
+
* defaults cover TypeScript / JavaScript / Python / Go / Rust / Java layouts.
|
|
80
|
+
* Exposed so `install.ts` can reuse the same list when seeding the shell
|
|
81
|
+
* guard script, even though the field is no longer written to the default
|
|
82
|
+
* `config.yaml` template.
|
|
83
|
+
*/
|
|
84
|
+
export const DEFAULT_TDD_TEST_GLOBS = [
|
|
85
|
+
"**/*.test.*",
|
|
86
|
+
"**/*.spec.*",
|
|
87
|
+
"**/test/**"
|
|
88
|
+
];
|
|
89
|
+
/**
|
|
90
|
+
* Populated runtime view of config values that downstream callers (install,
|
|
91
|
+
* observe, doctor) consume. Always has the derived guard modes populated,
|
|
92
|
+
* regardless of whether the user wrote `strictness`, the legacy keys, both,
|
|
93
|
+
* or neither.
|
|
94
|
+
*/
|
|
60
95
|
export function createDefaultConfig(harnesses = DEFAULT_HARNESSES, defaultTrack = "standard") {
|
|
61
96
|
return {
|
|
62
97
|
version: CCLAW_VERSION,
|
|
63
98
|
flowVersion: FLOW_VERSION,
|
|
64
99
|
harnesses,
|
|
100
|
+
strictness: "advisory",
|
|
65
101
|
promptGuardMode: "advisory",
|
|
66
102
|
tddEnforcement: "advisory",
|
|
67
|
-
tddTestGlobs: [
|
|
103
|
+
tddTestGlobs: [...DEFAULT_TDD_TEST_GLOBS],
|
|
68
104
|
gitHookGuards: false,
|
|
69
105
|
defaultTrack,
|
|
70
106
|
languageRulePacks: []
|
|
71
107
|
};
|
|
72
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Probe common project-root manifests to infer which language rule packs the
|
|
111
|
+
* user would reasonably want. Pure-functional best-effort: any filesystem
|
|
112
|
+
* error is swallowed, producing an empty list — the user can always override
|
|
113
|
+
* by hand.
|
|
114
|
+
*
|
|
115
|
+
* Called from `cclaw init` only (not `readConfig`), so subsequent upgrades
|
|
116
|
+
* never surprise a user who intentionally cleared the list.
|
|
117
|
+
*/
|
|
118
|
+
export async function detectLanguageRulePacks(projectRoot) {
|
|
119
|
+
const detected = [];
|
|
120
|
+
const pkgPath = path.join(projectRoot, "package.json");
|
|
121
|
+
if (await exists(pkgPath)) {
|
|
122
|
+
try {
|
|
123
|
+
const pkg = JSON.parse(await fs.readFile(pkgPath, "utf8"));
|
|
124
|
+
const deps = {
|
|
125
|
+
...pkg.dependencies,
|
|
126
|
+
...pkg.devDependencies
|
|
127
|
+
};
|
|
128
|
+
if ("typescript" in deps || typeof pkg.types === "string") {
|
|
129
|
+
detected.push("typescript");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// Malformed package.json — skip; user can set the pack manually later.
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const pythonMarkers = ["pyproject.toml", "requirements.txt", "setup.py", "Pipfile"];
|
|
137
|
+
for (const marker of pythonMarkers) {
|
|
138
|
+
if (await exists(path.join(projectRoot, marker))) {
|
|
139
|
+
detected.push("python");
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (await exists(path.join(projectRoot, "go.mod"))) {
|
|
144
|
+
detected.push("go");
|
|
145
|
+
}
|
|
146
|
+
return [...new Set(detected)];
|
|
147
|
+
}
|
|
73
148
|
export async function readConfig(projectRoot) {
|
|
74
149
|
const fullPath = configPath(projectRoot);
|
|
75
150
|
if (!(await exists(fullPath))) {
|
|
@@ -105,23 +180,39 @@ export async function readConfig(projectRoot) {
|
|
|
105
180
|
const harnesses = hasHarnessesField
|
|
106
181
|
? [...new Set(validatedHarnesses)]
|
|
107
182
|
: DEFAULT_HARNESSES;
|
|
183
|
+
const strictnessRaw = parsed.strictness;
|
|
184
|
+
if (Object.prototype.hasOwnProperty.call(parsed, "strictness") &&
|
|
185
|
+
strictnessRaw !== "advisory" &&
|
|
186
|
+
strictnessRaw !== "strict") {
|
|
187
|
+
throw configValidationError(fullPath, `"strictness" must be "advisory" or "strict"`);
|
|
188
|
+
}
|
|
189
|
+
const strictness = strictnessRaw === "strict" ? "strict" : "advisory";
|
|
190
|
+
// Legacy guard fields — keep honouring explicit values for power users who
|
|
191
|
+
// want asymmetric behaviour (e.g. strict prompt guard + advisory TDD).
|
|
192
|
+
// When the user only set `strictness`, both axes inherit from it.
|
|
193
|
+
const hasExplicitPromptGuard = Object.prototype.hasOwnProperty.call(parsed, "promptGuardMode");
|
|
108
194
|
const promptGuardModeRaw = parsed.promptGuardMode;
|
|
109
|
-
if (
|
|
195
|
+
if (hasExplicitPromptGuard &&
|
|
110
196
|
promptGuardModeRaw !== "advisory" &&
|
|
111
197
|
promptGuardModeRaw !== "strict") {
|
|
112
198
|
throw configValidationError(fullPath, `"promptGuardMode" must be "advisory" or "strict"`);
|
|
113
199
|
}
|
|
114
|
-
const promptGuardMode =
|
|
200
|
+
const promptGuardMode = hasExplicitPromptGuard
|
|
201
|
+
? (promptGuardModeRaw === "strict" ? "strict" : "advisory")
|
|
202
|
+
: strictness;
|
|
203
|
+
const hasExplicitTddEnforcement = Object.prototype.hasOwnProperty.call(parsed, "tddEnforcement");
|
|
115
204
|
const tddEnforcementRaw = parsed.tddEnforcement;
|
|
116
|
-
if (
|
|
205
|
+
if (hasExplicitTddEnforcement &&
|
|
117
206
|
tddEnforcementRaw !== "advisory" &&
|
|
118
207
|
tddEnforcementRaw !== "strict") {
|
|
119
208
|
throw configValidationError(fullPath, `"tddEnforcement" must be "advisory" or "strict"`);
|
|
120
209
|
}
|
|
121
|
-
const tddEnforcement =
|
|
210
|
+
const tddEnforcement = hasExplicitTddEnforcement
|
|
211
|
+
? (tddEnforcementRaw === "strict" ? "strict" : "advisory")
|
|
212
|
+
: strictness;
|
|
122
213
|
const tddTestGlobsRaw = parsed.tddTestGlobs;
|
|
123
214
|
const tddTestGlobs = validateStringArray(tddTestGlobsRaw, "tddTestGlobs", fullPath)
|
|
124
|
-
?? [
|
|
215
|
+
?? [...DEFAULT_TDD_TEST_GLOBS];
|
|
125
216
|
const gitHookGuardsRaw = parsed.gitHookGuards;
|
|
126
217
|
if (Object.prototype.hasOwnProperty.call(parsed, "gitHookGuards") &&
|
|
127
218
|
typeof gitHookGuardsRaw !== "boolean") {
|
|
@@ -232,6 +323,7 @@ export async function readConfig(projectRoot) {
|
|
|
232
323
|
version: parsed.version ?? CCLAW_VERSION,
|
|
233
324
|
flowVersion: parsed.flowVersion ?? FLOW_VERSION,
|
|
234
325
|
harnesses,
|
|
326
|
+
strictness,
|
|
235
327
|
promptGuardMode,
|
|
236
328
|
tddEnforcement,
|
|
237
329
|
tddTestGlobs,
|
|
@@ -242,6 +334,88 @@ export async function readConfig(projectRoot) {
|
|
|
242
334
|
sliceReview
|
|
243
335
|
};
|
|
244
336
|
}
|
|
245
|
-
|
|
246
|
-
|
|
337
|
+
function isMinimalKey(key) {
|
|
338
|
+
return MINIMAL_CONFIG_KEYS.includes(key);
|
|
339
|
+
}
|
|
340
|
+
function buildSerializableConfig(config, options = {}) {
|
|
341
|
+
const mode = options.mode ?? "full";
|
|
342
|
+
const advanced = options.advancedKeysPresent;
|
|
343
|
+
const output = {};
|
|
344
|
+
const ordered = [
|
|
345
|
+
"version",
|
|
346
|
+
"flowVersion",
|
|
347
|
+
"harnesses",
|
|
348
|
+
"strictness",
|
|
349
|
+
"promptGuardMode",
|
|
350
|
+
"tddEnforcement",
|
|
351
|
+
"tddTestGlobs",
|
|
352
|
+
"gitHookGuards",
|
|
353
|
+
"defaultTrack",
|
|
354
|
+
"languageRulePacks",
|
|
355
|
+
"trackHeuristics",
|
|
356
|
+
"sliceReview"
|
|
357
|
+
];
|
|
358
|
+
for (const key of ordered) {
|
|
359
|
+
const value = config[key];
|
|
360
|
+
if (value === undefined)
|
|
361
|
+
continue;
|
|
362
|
+
if (mode === "full") {
|
|
363
|
+
output[key] = value;
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
// Minimal mode: always include the short list; advanced keys only when
|
|
367
|
+
// the caller explicitly opted in, or for auto-detected non-empty
|
|
368
|
+
// `languageRulePacks`.
|
|
369
|
+
if (isMinimalKey(key)) {
|
|
370
|
+
output[key] = value;
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
if (advanced?.has(key)) {
|
|
374
|
+
output[key] = value;
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
if (key === "languageRulePacks" && Array.isArray(value) && value.length > 0) {
|
|
378
|
+
output[key] = value;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return output;
|
|
382
|
+
}
|
|
383
|
+
export async function writeConfig(projectRoot, config, options = {}) {
|
|
384
|
+
const serialisable = buildSerializableConfig(config, options);
|
|
385
|
+
await writeFileSafe(configPath(projectRoot), stringify(serialisable));
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Enumerate which advanced keys are currently set in the on-disk config.
|
|
389
|
+
* Used by `cclaw upgrade` to preserve the user's existing shape — if they
|
|
390
|
+
* wrote `tddTestGlobs` by hand, the upgrade keeps it; if they didn't, the
|
|
391
|
+
* upgrade stays minimal.
|
|
392
|
+
*/
|
|
393
|
+
export async function detectAdvancedKeys(projectRoot) {
|
|
394
|
+
const fullPath = configPath(projectRoot);
|
|
395
|
+
if (!(await exists(fullPath)))
|
|
396
|
+
return new Set();
|
|
397
|
+
try {
|
|
398
|
+
const parsedUnknown = parse(await fs.readFile(fullPath, "utf8"));
|
|
399
|
+
if (!isRecord(parsedUnknown))
|
|
400
|
+
return new Set();
|
|
401
|
+
const advancedCandidates = [
|
|
402
|
+
"promptGuardMode",
|
|
403
|
+
"tddEnforcement",
|
|
404
|
+
"tddTestGlobs",
|
|
405
|
+
"defaultTrack",
|
|
406
|
+
"languageRulePacks",
|
|
407
|
+
"trackHeuristics",
|
|
408
|
+
"sliceReview"
|
|
409
|
+
];
|
|
410
|
+
const present = new Set();
|
|
411
|
+
for (const key of advancedCandidates) {
|
|
412
|
+
if (Object.prototype.hasOwnProperty.call(parsedUnknown, key)) {
|
|
413
|
+
present.add(key);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return present;
|
|
417
|
+
}
|
|
418
|
+
catch {
|
|
419
|
+
return new Set();
|
|
420
|
+
}
|
|
247
421
|
}
|
|
@@ -1,2 +1,9 @@
|
|
|
1
1
|
export declare function ideateCommandContract(): string;
|
|
2
2
|
export declare function ideateCommandSkillMarkdown(): string;
|
|
3
|
+
/**
|
|
4
|
+
* Exposed for tests and docs that need to mention the artifact convention
|
|
5
|
+
* without hard-coding the path string in two places.
|
|
6
|
+
*/
|
|
7
|
+
export declare const IDEATION_ARTIFACT_PATH_PATTERN = ".cclaw/artifacts/ideation-<YYYY-MM-DD-slug>.md";
|
|
8
|
+
export declare const IDEATION_ARTIFACT_GLOB_PATTERN = ".cclaw/artifacts/ideation-*.md";
|
|
9
|
+
export declare const IDEATION_RESUME_WINDOW = 30;
|
|
@@ -1,39 +1,62 @@
|
|
|
1
1
|
import { RUNTIME_ROOT } from "../constants.js";
|
|
2
2
|
const IDEATE_SKILL_FOLDER = "flow-ideate";
|
|
3
3
|
const IDEATE_SKILL_NAME = "flow-ideate";
|
|
4
|
+
/**
|
|
5
|
+
* Directory + filename convention for ideation artifacts. These are separate
|
|
6
|
+
* from stage artifacts (00-..08-*.md) because `/cc-ideate` runs outside the
|
|
7
|
+
* critical-path flow state machine and must not collide with stage numbering.
|
|
8
|
+
*/
|
|
9
|
+
const IDEATION_ARTIFACT_GLOB = ".cclaw/artifacts/ideation-*.md";
|
|
10
|
+
const IDEATION_ARTIFACT_PATTERN = ".cclaw/artifacts/ideation-<YYYY-MM-DD-slug>.md";
|
|
11
|
+
const IDEATION_RESUME_WINDOW_DAYS = 30;
|
|
12
|
+
/**
|
|
13
|
+
* Structured-ask tool list reused across cclaw skills. Kept inline here (small
|
|
14
|
+
* enough) to avoid cross-module coupling; larger stage skills cite the shared
|
|
15
|
+
* protocol file instead.
|
|
16
|
+
*/
|
|
17
|
+
const STRUCTURED_ASK_TOOLS = "`AskUserQuestion` on Claude, `AskQuestion` on Cursor, " +
|
|
18
|
+
"`question` on OpenCode when `permission.question: \"allow\"` is set, " +
|
|
19
|
+
"`request_user_input` on Codex in Plan / Collaboration mode; " +
|
|
20
|
+
"fall back to a plain-text lettered list when the tool is hidden or errors";
|
|
4
21
|
export function ideateCommandContract() {
|
|
5
22
|
return `# /cc-ideate
|
|
6
23
|
|
|
7
24
|
## Purpose
|
|
8
25
|
|
|
9
|
-
Repository-improvement discovery mode. Generate a ranked backlog of
|
|
10
|
-
improvements
|
|
26
|
+
Repository-improvement discovery mode. Generate a ranked backlog of
|
|
27
|
+
high-value improvements, persist it as an artifact on disk, and end with
|
|
28
|
+
an explicit handoff — either launch \`/cc\` on a chosen candidate in the
|
|
29
|
+
same session, or save/discard the backlog.
|
|
11
30
|
|
|
12
31
|
## HARD-GATE
|
|
13
32
|
|
|
14
|
-
-
|
|
15
|
-
- Every recommendation
|
|
16
|
-
|
|
33
|
+
- Discovery mode only. Never mutate \`.cclaw/state/flow-state.json\`.
|
|
34
|
+
- Every recommendation cites evidence from the current repository
|
|
35
|
+
(file path, command output, or knowledge-store entry id).
|
|
36
|
+
- Always write a persisted artifact to
|
|
37
|
+
\`${IDEATION_ARTIFACT_PATTERN}\`. Chat-only output is not acceptable —
|
|
38
|
+
the next session must be able to resume.
|
|
39
|
+
- Always end with a structured handoff prompt, not an open question.
|
|
17
40
|
|
|
18
41
|
## Algorithm
|
|
19
42
|
|
|
20
|
-
1.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
4.
|
|
33
|
-
5.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
43
|
+
1. **Resume check.** Glob \`${IDEATION_ARTIFACT_GLOB}\`. If any artifact
|
|
44
|
+
has been modified within the last ${IDEATION_RESUME_WINDOW_DAYS} days,
|
|
45
|
+
offer the user: continue that backlog, start fresh, or cancel.
|
|
46
|
+
2. **Scan repo signals:**
|
|
47
|
+
- open TODO/FIXME/XXX/HACK notes,
|
|
48
|
+
- flaky or failing tests,
|
|
49
|
+
- oversized modules / complexity hotspots,
|
|
50
|
+
- docs drift vs changed code,
|
|
51
|
+
- repeated entries in \`${RUNTIME_ROOT}/knowledge.jsonl\`.
|
|
52
|
+
3. **Produce 5-10 candidates** with impact (High/Medium/Low),
|
|
53
|
+
effort (S/M/L), confidence (High/Medium/Low), and one evidence path
|
|
54
|
+
per candidate.
|
|
55
|
+
4. **Rank by impact/effort**, recommend the top item.
|
|
56
|
+
5. **Write the artifact** at
|
|
57
|
+
\`${IDEATION_ARTIFACT_PATTERN}\` using the schema in the skill.
|
|
58
|
+
6. **Present the handoff prompt** with four concrete options — not A/B/C
|
|
59
|
+
letters. Default = "Start /cc on the top recommendation".
|
|
37
60
|
|
|
38
61
|
## Primary skill
|
|
39
62
|
|
|
@@ -43,31 +66,152 @@ improvements before committing to a specific feature request.
|
|
|
43
66
|
export function ideateCommandSkillMarkdown() {
|
|
44
67
|
return `---
|
|
45
68
|
name: ${IDEATE_SKILL_NAME}
|
|
46
|
-
description: "Repository ideation mode: detect and rank high-leverage improvements
|
|
69
|
+
description: "Repository ideation mode: detect and rank high-leverage improvements, persist a backlog artifact, and hand off to /cc or save/discard."
|
|
47
70
|
---
|
|
48
71
|
|
|
49
72
|
# /cc-ideate
|
|
50
73
|
|
|
51
74
|
## Announce at start
|
|
52
75
|
|
|
53
|
-
"Using flow-ideate to identify highest-leverage improvements in this
|
|
76
|
+
"Using flow-ideate to identify highest-leverage improvements in this
|
|
77
|
+
repository. Will persist a ranked backlog to
|
|
78
|
+
\`${IDEATION_ARTIFACT_PATTERN}\` and end with an explicit handoff."
|
|
54
79
|
|
|
55
80
|
## HARD-GATE
|
|
56
81
|
|
|
57
|
-
Do not start coding in ideate mode.
|
|
82
|
+
- Do not start coding in ideate mode.
|
|
83
|
+
- Do not mutate \`.cclaw/state/flow-state.json\` — ideation sits outside
|
|
84
|
+
the critical-path flow.
|
|
85
|
+
- Always produce the artifact file on disk before presenting the handoff.
|
|
86
|
+
- Always end with a structured handoff that names the concrete follow-up
|
|
87
|
+
command for each option. No A/B/C letters without command context.
|
|
58
88
|
|
|
59
89
|
## Protocol
|
|
60
90
|
|
|
61
|
-
|
|
62
|
-
2. Build candidate improvements with impact/effort/confidence.
|
|
63
|
-
3. Rank and recommend one candidate.
|
|
64
|
-
4. Ask for explicit selection.
|
|
65
|
-
5. If user selects a candidate, hand off to \`/cc <selected idea>\`.
|
|
91
|
+
### Phase 0 — Resume check
|
|
66
92
|
|
|
67
|
-
|
|
93
|
+
1. Use the harness's file-glob tool (\`Glob\` pattern
|
|
94
|
+
\`${IDEATION_ARTIFACT_GLOB}\` or equivalent \`ls\`/\`find\`).
|
|
95
|
+
2. Filter to files modified within the last ${IDEATION_RESUME_WINDOW_DAYS} days.
|
|
96
|
+
3. If one or more match, present **one** structured ask using the
|
|
97
|
+
harness's native tool (${STRUCTURED_ASK_TOOLS}) with options:
|
|
98
|
+
- **Continue the existing backlog** — read the most-recent
|
|
99
|
+
ideation-*.md and work from its candidate list; skip re-scanning.
|
|
100
|
+
- **Start a fresh scan** — proceed to Phase 1; the old artifact stays
|
|
101
|
+
on disk for history.
|
|
102
|
+
- **Cancel** — stop; do not scan or write anything.
|
|
103
|
+
4. If no recent artifact exists, proceed to Phase 1 silently.
|
|
68
104
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
105
|
+
### Phase 1 — Collect evidence
|
|
106
|
+
|
|
107
|
+
Scan the current repo. Examples of signals (not exhaustive):
|
|
108
|
+
|
|
109
|
+
- \`rg -n 'TODO|FIXME|XXX|HACK|TBD'\` grouped by file.
|
|
110
|
+
- Test-runner output (\`npm test\`, \`pytest\`, \`go test ./...\`) — note
|
|
111
|
+
failures, timeouts, deprecation warnings.
|
|
112
|
+
- Module size outliers (\`wc -l\` or \`du\`) with weak direct test coverage.
|
|
113
|
+
- Docs drift: check that \`README.md\` / \`docs/\` reference files that
|
|
114
|
+
still exist and flags/APIs that still match \`src/\`.
|
|
115
|
+
- \`${RUNTIME_ROOT}/knowledge.jsonl\` entries with \`type: "heuristic"\`
|
|
116
|
+
or repeated \`subject:\` values.
|
|
117
|
+
|
|
118
|
+
Record each finding with the exact file path or command that produced it.
|
|
119
|
+
|
|
120
|
+
### Phase 2 — Build candidates
|
|
121
|
+
|
|
122
|
+
For each high-signal finding, construct a candidate:
|
|
123
|
+
|
|
124
|
+
- **ID** — \`I-1\`, \`I-2\`, …
|
|
125
|
+
- **Title** — one short imperative phrase
|
|
126
|
+
- **Impact** — High / Medium / Low
|
|
127
|
+
- **Effort** — S / M / L
|
|
128
|
+
- **Confidence** — High / Medium / Low
|
|
129
|
+
- **Evidence** — path(s) or command output, inline if short
|
|
130
|
+
- **Proposed handoff** — the exact \`/cc <phrase>\` the user would run
|
|
131
|
+
to act on this candidate
|
|
132
|
+
|
|
133
|
+
Aim for 5–10 candidates. Do not invent candidates without evidence.
|
|
134
|
+
|
|
135
|
+
### Phase 3 — Rank and write the artifact
|
|
136
|
+
|
|
137
|
+
1. Sort by impact/effort ratio; break ties with confidence.
|
|
138
|
+
2. Compute the artifact filename:
|
|
139
|
+
- \`slug\` = first 3–5 words of the top recommendation, lowercase,
|
|
140
|
+
non-alphanumeric collapsed to \`-\`, trimmed. When ideation is
|
|
141
|
+
focus-hinted (user passed an argument), use the focus hint instead.
|
|
142
|
+
- \`date\` = today in \`YYYY-MM-DD\` (local time).
|
|
143
|
+
- Path = \`.cclaw/artifacts/ideation-<date>-<slug>.md\`.
|
|
144
|
+
3. Use the harness's write-file tool (\`Write\`, \`apply_patch\`, or shell
|
|
145
|
+
\`cat <<EOF > path\`) to create the artifact with this schema:
|
|
146
|
+
|
|
147
|
+
\`\`\`markdown
|
|
148
|
+
# Ideation — <date>
|
|
149
|
+
|
|
150
|
+
**Focus:** <user-supplied focus or "open-ended scan">
|
|
151
|
+
**Generated:** <ISO-8601 timestamp>
|
|
152
|
+
**Recommendation:** I-1
|
|
153
|
+
|
|
154
|
+
## Ranked backlog
|
|
155
|
+
|
|
156
|
+
| ID | Improvement | Impact | Effort | Confidence | Evidence |
|
|
157
|
+
|---|---|---|---|---|---|
|
|
158
|
+
| I-1 | Fix feature-worktree test timeouts | High | S | High | tests/unit/feature-system.test.ts:31 |
|
|
159
|
+
| … | … | … | … | … | … |
|
|
160
|
+
|
|
161
|
+
## Candidate detail
|
|
162
|
+
|
|
163
|
+
### I-1 — Fix feature-worktree test timeouts
|
|
164
|
+
- **Evidence:** \`npm test\` hangs 40s on tests/unit/feature-system.test.ts:31.
|
|
165
|
+
- **Handoff:** \`/cc Fix feature-worktree test timeouts on macOS\`
|
|
166
|
+
|
|
167
|
+
### I-2 — …
|
|
168
|
+
\`\`\`
|
|
169
|
+
|
|
170
|
+
4. Confirm in chat: "Wrote <path>."
|
|
171
|
+
|
|
172
|
+
### Phase 4 — Handoff prompt
|
|
173
|
+
|
|
174
|
+
Present **one** structured ask using the harness's native tool
|
|
175
|
+
(${STRUCTURED_ASK_TOOLS}). Each option must name the concrete follow-up —
|
|
176
|
+
no bare A/B/C.
|
|
177
|
+
|
|
178
|
+
Required options, in this order:
|
|
179
|
+
|
|
180
|
+
1. **Start /cc on the top recommendation** — the agent immediately loads
|
|
181
|
+
\`${RUNTIME_ROOT}/skills/using-cclaw/SKILL.md\` and invokes
|
|
182
|
+
\`/cc <I-1 handoff phrase>\` in the same turn. Default choice.
|
|
183
|
+
2. **Pick a different candidate** — the agent asks which ID (I-2, I-3, …)
|
|
184
|
+
and then invokes \`/cc <that candidate's handoff phrase>\`.
|
|
185
|
+
3. **Save and close** — leave the artifact on disk, do nothing else.
|
|
186
|
+
Next session: \`/cc-ideate\` will offer to resume it.
|
|
187
|
+
4. **Discard** — delete the just-written artifact. Use only when the
|
|
188
|
+
scan produced nothing actionable.
|
|
189
|
+
|
|
190
|
+
When the structured-ask tool is unavailable, fall back to a plain-text
|
|
191
|
+
lettered list with the same four labels. Do not invent extra options.
|
|
192
|
+
|
|
193
|
+
### Phase 5 — Execute the choice
|
|
194
|
+
|
|
195
|
+
- **Start /cc on I-1** or **different candidate:** announce
|
|
196
|
+
"Handing off to /cc <phrase>" and load the \`using-cclaw\` router
|
|
197
|
+
skill. From there, the normal \`/cc\` classification and stage flow
|
|
198
|
+
takes over. Do not produce a second artifact; the ideation file is
|
|
199
|
+
preserved as the origin document for this run.
|
|
200
|
+
- **Save and close:** reply with the artifact path and stop.
|
|
201
|
+
- **Discard:** delete the artifact file, confirm deletion, stop.
|
|
202
|
+
|
|
203
|
+
## Do not
|
|
204
|
+
|
|
205
|
+
- Do not write into \`.cclaw/artifacts/0X-*.md\` (stage artifacts).
|
|
206
|
+
- Do not mutate \`.cclaw/state/flow-state.json\` at any phase.
|
|
207
|
+
- Do not end the turn with an ungrounded "pick one" question — every
|
|
208
|
+
option in the handoff prompt must reference a concrete command.
|
|
72
209
|
`;
|
|
73
210
|
}
|
|
211
|
+
/**
|
|
212
|
+
* Exposed for tests and docs that need to mention the artifact convention
|
|
213
|
+
* without hard-coding the path string in two places.
|
|
214
|
+
*/
|
|
215
|
+
export const IDEATION_ARTIFACT_PATH_PATTERN = IDEATION_ARTIFACT_PATTERN;
|
|
216
|
+
export const IDEATION_ARTIFACT_GLOB_PATTERN = IDEATION_ARTIFACT_GLOB;
|
|
217
|
+
export const IDEATION_RESUME_WINDOW = IDEATION_RESUME_WINDOW_DAYS;
|
package/dist/install.d.ts
CHANGED
|
@@ -9,13 +9,12 @@ export declare function syncCclaw(projectRoot: string): Promise<void>;
|
|
|
9
9
|
/**
|
|
10
10
|
* Refresh generated files in `.cclaw/` without touching user-authored
|
|
11
11
|
* artifacts, state, or custom config keys. Only the `version` + `flowVersion`
|
|
12
|
-
* stamps are rewritten so the on-disk config reflects the installed CLI
|
|
13
|
-
* `promptGuardMode`, `tddEnforcement`, `gitHookGuards`, `languageRulePacks`,
|
|
14
|
-
* `trackHeuristics`, and `sliceReview` are preserved verbatim from the
|
|
15
|
-
* existing config.
|
|
12
|
+
* stamps are rewritten so the on-disk config reflects the installed CLI.
|
|
16
13
|
*
|
|
17
|
-
*
|
|
18
|
-
* (
|
|
14
|
+
* Shape preservation: if the user previously hand-authored advanced keys
|
|
15
|
+
* (e.g. `tddTestGlobs`, `trackHeuristics`, `sliceReview`), those stay in the
|
|
16
|
+
* yaml. If their existing config is minimal, the upgrade keeps it minimal —
|
|
17
|
+
* advanced knobs are never silently added.
|
|
19
18
|
*/
|
|
20
19
|
export declare function upgradeCclaw(projectRoot: string): Promise<void>;
|
|
21
20
|
export declare function uninstallCclaw(projectRoot: string): Promise<void>;
|
package/dist/install.js
CHANGED
|
@@ -3,7 +3,7 @@ import fs from "node:fs/promises";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
5
|
import { CCLAW_VERSION, COMMAND_FILE_ORDER, FLOW_VERSION, REQUIRED_DIRS, RUNTIME_ROOT } from "./constants.js";
|
|
6
|
-
import { writeConfig, createDefaultConfig, readConfig, configPath } from "./config.js";
|
|
6
|
+
import { writeConfig, createDefaultConfig, readConfig, configPath, detectLanguageRulePacks, detectAdvancedKeys } from "./config.js";
|
|
7
7
|
import { commandContract } from "./content/contracts.js";
|
|
8
8
|
import { contextModeFiles, createInitialContextModeState } from "./content/contexts.js";
|
|
9
9
|
import { learnSkillMarkdown, learnCommandContract } from "./content/learnings.js";
|
|
@@ -1156,13 +1156,24 @@ async function materializeRuntime(projectRoot, config, forceStateReset) {
|
|
|
1156
1156
|
await ensureGitignore(projectRoot);
|
|
1157
1157
|
}
|
|
1158
1158
|
export async function initCclaw(options) {
|
|
1159
|
-
const
|
|
1160
|
-
|
|
1159
|
+
const baseConfig = createDefaultConfig(options.harnesses, options.track);
|
|
1160
|
+
// Best-effort auto-detect: a Node project gets `typescript`, a Go module
|
|
1161
|
+
// gets `go`, etc. Skipped entirely when the project root has no manifests.
|
|
1162
|
+
const detectedPacks = await detectLanguageRulePacks(options.projectRoot);
|
|
1163
|
+
const config = {
|
|
1164
|
+
...baseConfig,
|
|
1165
|
+
languageRulePacks: detectedPacks
|
|
1166
|
+
};
|
|
1167
|
+
// Write a minimal `config.yaml` — advanced knobs live in docs/config.md
|
|
1168
|
+
// and only appear in the on-disk file when the user sets them explicitly
|
|
1169
|
+
// or a non-default value was detected (e.g. languageRulePacks).
|
|
1170
|
+
await writeConfig(options.projectRoot, config, { mode: "minimal" });
|
|
1161
1171
|
await materializeRuntime(options.projectRoot, config, true);
|
|
1162
1172
|
}
|
|
1163
1173
|
export async function syncCclaw(projectRoot) {
|
|
1174
|
+
const configExists = await exists(configPath(projectRoot));
|
|
1164
1175
|
const config = await readConfig(projectRoot);
|
|
1165
|
-
if (!
|
|
1176
|
+
if (!configExists) {
|
|
1166
1177
|
await writeConfig(projectRoot, createDefaultConfig(config.harnesses));
|
|
1167
1178
|
}
|
|
1168
1179
|
await materializeRuntime(projectRoot, config, false);
|
|
@@ -1170,22 +1181,25 @@ export async function syncCclaw(projectRoot) {
|
|
|
1170
1181
|
/**
|
|
1171
1182
|
* Refresh generated files in `.cclaw/` without touching user-authored
|
|
1172
1183
|
* artifacts, state, or custom config keys. Only the `version` + `flowVersion`
|
|
1173
|
-
* stamps are rewritten so the on-disk config reflects the installed CLI
|
|
1174
|
-
* `promptGuardMode`, `tddEnforcement`, `gitHookGuards`, `languageRulePacks`,
|
|
1175
|
-
* `trackHeuristics`, and `sliceReview` are preserved verbatim from the
|
|
1176
|
-
* existing config.
|
|
1184
|
+
* stamps are rewritten so the on-disk config reflects the installed CLI.
|
|
1177
1185
|
*
|
|
1178
|
-
*
|
|
1179
|
-
* (
|
|
1186
|
+
* Shape preservation: if the user previously hand-authored advanced keys
|
|
1187
|
+
* (e.g. `tddTestGlobs`, `trackHeuristics`, `sliceReview`), those stay in the
|
|
1188
|
+
* yaml. If their existing config is minimal, the upgrade keeps it minimal —
|
|
1189
|
+
* advanced knobs are never silently added.
|
|
1180
1190
|
*/
|
|
1181
1191
|
export async function upgradeCclaw(projectRoot) {
|
|
1192
|
+
const advancedKeysPresent = await detectAdvancedKeys(projectRoot);
|
|
1182
1193
|
const existing = await readConfig(projectRoot);
|
|
1183
1194
|
const upgraded = {
|
|
1184
1195
|
...existing,
|
|
1185
1196
|
version: CCLAW_VERSION,
|
|
1186
1197
|
flowVersion: FLOW_VERSION
|
|
1187
1198
|
};
|
|
1188
|
-
await writeConfig(projectRoot, upgraded
|
|
1199
|
+
await writeConfig(projectRoot, upgraded, {
|
|
1200
|
+
mode: "minimal",
|
|
1201
|
+
advancedKeysPresent
|
|
1202
|
+
});
|
|
1189
1203
|
await materializeRuntime(projectRoot, upgraded, false);
|
|
1190
1204
|
}
|
|
1191
1205
|
function stripManagedHookCommands(value) {
|
package/dist/types.d.ts
CHANGED
|
@@ -92,9 +92,30 @@ export interface VibyConfig {
|
|
|
92
92
|
version: string;
|
|
93
93
|
flowVersion: string;
|
|
94
94
|
harnesses: HarnessId[];
|
|
95
|
-
/**
|
|
95
|
+
/**
|
|
96
|
+
* Single-knob strictness for both guard families. When set, cclaw derives
|
|
97
|
+
* `promptGuardMode` and `tddEnforcement` from this value unless the legacy
|
|
98
|
+
* fields are explicitly provided. Default: "advisory".
|
|
99
|
+
*
|
|
100
|
+
* Added in v0.43.0 to collapse two fields that always moved together for
|
|
101
|
+
* ~99% of users. Power users who want asymmetric strictness (e.g. strict
|
|
102
|
+
* prompt guard, advisory TDD) can still set the legacy fields directly —
|
|
103
|
+
* explicit per-axis values override the derived strictness.
|
|
104
|
+
*/
|
|
105
|
+
strictness?: "advisory" | "strict";
|
|
106
|
+
/**
|
|
107
|
+
* Prompt guard behavior for runtime write-risk detection hooks.
|
|
108
|
+
*
|
|
109
|
+
* Since v0.43.0 this is an advanced override. Prefer `strictness` in new
|
|
110
|
+
* configs; set this explicitly only when you need strict prompt guarding
|
|
111
|
+
* while keeping TDD advisory, or vice versa.
|
|
112
|
+
*/
|
|
96
113
|
promptGuardMode?: "advisory" | "strict";
|
|
97
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* TDD red->green->refactor enforcement mode used by workflow guard hooks.
|
|
116
|
+
*
|
|
117
|
+
* Since v0.43.0 this is an advanced override — see `strictness`.
|
|
118
|
+
*/
|
|
98
119
|
tddEnforcement?: "advisory" | "strict";
|
|
99
120
|
/** Optional test file globs used by guard guidance and /cc-ops tdd-log docs. */
|
|
100
121
|
tddTestGlobs?: string[];
|