cclaw-cli 0.37.0 → 0.38.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 +11 -8
- package/dist/config.js +5 -25
- package/dist/content/start-command.js +2 -2
- package/dist/track-heuristics.d.ts +8 -1
- package/dist/track-heuristics.js +14 -29
- package/dist/types.d.ts +28 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -229,27 +229,30 @@ Each critical-path stage produces a dated artifact under
|
|
|
229
229
|
bundle into `.cclaw/runs/<YYYY-MM-DD-slug>/` and resets the active flow
|
|
230
230
|
for the next feature.
|
|
231
231
|
|
|
232
|
-
### Track heuristics are configurable
|
|
232
|
+
### Track heuristics are configurable (advisory)
|
|
233
233
|
|
|
234
234
|
Every team has its own vocabulary. Override the built-in trigger lists in
|
|
235
235
|
`.cclaw/config.yaml`:
|
|
236
236
|
|
|
237
237
|
```yaml
|
|
238
238
|
trackHeuristics:
|
|
239
|
-
priority: [standard, medium, quick]
|
|
240
239
|
fallback: standard
|
|
241
240
|
tracks:
|
|
242
241
|
quick:
|
|
243
242
|
triggers: [hotfix, rollback, prod-incident]
|
|
244
|
-
veto: [schema, migration] # never route quick even if
|
|
243
|
+
veto: [schema, migration] # never route quick even if a trigger hits
|
|
245
244
|
standard:
|
|
246
|
-
|
|
247
|
-
- "^epic:"
|
|
248
|
-
- "platform-team|core-infra"
|
|
245
|
+
triggers: [epic, platform-team, core-infra]
|
|
249
246
|
```
|
|
250
247
|
|
|
251
|
-
|
|
252
|
-
|
|
248
|
+
Honest caveat: this config is **advisory**. cclaw surfaces these lists in
|
|
249
|
+
the `/cc` skill and contract prose so the LLM applies them during
|
|
250
|
+
classification — there is no Node-level router that mechanically enforces
|
|
251
|
+
the outcome. That is why the knobs are deliberately minimal: per-track
|
|
252
|
+
`triggers` + `veto` on top of defaults, plus `fallback`. Evaluation order is
|
|
253
|
+
fixed (`standard -> medium -> quick`, narrow-to-broad); regex `patterns`
|
|
254
|
+
and a `priority` override were removed in v0.38.0 because nothing in
|
|
255
|
+
runtime consumed them.
|
|
253
256
|
|
|
254
257
|
### Mid-flow reclassification
|
|
255
258
|
|
package/dist/config.js
CHANGED
|
@@ -160,17 +160,8 @@ export async function readConfig(projectRoot) {
|
|
|
160
160
|
if (fallbackRaw !== undefined && (typeof fallbackRaw !== "string" || !FLOW_TRACK_SET.has(fallbackRaw))) {
|
|
161
161
|
throw configValidationError(fullPath, `"trackHeuristics.fallback" must be one of: ${SUPPORTED_TRACKS_TEXT}`);
|
|
162
162
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if (priorityRaw !== undefined) {
|
|
166
|
-
if (!Array.isArray(priorityRaw)) {
|
|
167
|
-
throw configValidationError(fullPath, `"trackHeuristics.priority" must be an array`);
|
|
168
|
-
}
|
|
169
|
-
const invalidPriority = priorityRaw.filter((value) => typeof value !== "string" || !FLOW_TRACK_SET.has(value));
|
|
170
|
-
if (invalidPriority.length > 0) {
|
|
171
|
-
throw configValidationError(fullPath, `"trackHeuristics.priority" must contain only: ${SUPPORTED_TRACKS_TEXT}`);
|
|
172
|
-
}
|
|
173
|
-
priority = [...new Set(priorityRaw)];
|
|
163
|
+
if (Object.prototype.hasOwnProperty.call(trackHeuristicsRaw, "priority")) {
|
|
164
|
+
throw configValidationError(fullPath, `"trackHeuristics.priority" is no longer supported (removed in v0.38.0). Track evaluation order is always standard -> medium -> quick. Remove the field to upgrade.`);
|
|
174
165
|
}
|
|
175
166
|
const tracksRaw = trackHeuristicsRaw.tracks;
|
|
176
167
|
let tracks = undefined;
|
|
@@ -186,30 +177,19 @@ export async function readConfig(projectRoot) {
|
|
|
186
177
|
if (!isRecord(ruleRaw)) {
|
|
187
178
|
throw configValidationError(fullPath, `"trackHeuristics.tracks.${trackName}" must be an object`);
|
|
188
179
|
}
|
|
180
|
+
if (Object.prototype.hasOwnProperty.call(ruleRaw, "patterns")) {
|
|
181
|
+
throw configValidationError(fullPath, `"trackHeuristics.tracks.${trackName}.patterns" is no longer supported (removed in v0.38.0). Regex patterns were never wired into runtime routing. Move the intent into "triggers" (substrings) or "veto".`);
|
|
182
|
+
}
|
|
189
183
|
const triggers = validateStringArray(ruleRaw.triggers, `trackHeuristics.tracks.${trackName}.triggers`, fullPath);
|
|
190
|
-
const patterns = validateStringArray(ruleRaw.patterns, `trackHeuristics.tracks.${trackName}.patterns`, fullPath);
|
|
191
184
|
const veto = validateStringArray(ruleRaw.veto, `trackHeuristics.tracks.${trackName}.veto`, fullPath);
|
|
192
|
-
if (patterns) {
|
|
193
|
-
for (const pattern of patterns) {
|
|
194
|
-
try {
|
|
195
|
-
// eslint-disable-next-line no-new
|
|
196
|
-
new RegExp(pattern, "iu");
|
|
197
|
-
}
|
|
198
|
-
catch {
|
|
199
|
-
throw configValidationError(fullPath, `"trackHeuristics.tracks.${trackName}.patterns" contains invalid regex "${pattern}"`);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
185
|
tracks[trackName] = {
|
|
204
186
|
triggers,
|
|
205
|
-
patterns,
|
|
206
187
|
veto
|
|
207
188
|
};
|
|
208
189
|
}
|
|
209
190
|
}
|
|
210
191
|
trackHeuristics = {
|
|
211
192
|
fallback: fallbackRaw,
|
|
212
|
-
priority,
|
|
213
193
|
tracks
|
|
214
194
|
};
|
|
215
195
|
}
|
|
@@ -65,7 +65,7 @@ This is the **recommended way to start** working with cclaw. Use \`/cc-next\` fo
|
|
|
65
65
|
4. Read \`${flowPath}\`.
|
|
66
66
|
5. If flow already has completed stages beyond brainstorm, warn the user that starting a new brainstorm will reset progress. Ask for confirmation before proceeding.
|
|
67
67
|
6. **Track heuristic** — classify the idea text and **recommend** a track (the user can override before any state mutation):
|
|
68
|
-
- First, load \`${RUNTIME_ROOT}/config.yaml\`. If \`trackHeuristics\` is defined, apply those per-track
|
|
68
|
+
- First, load \`${RUNTIME_ROOT}/config.yaml\`. If \`trackHeuristics\` is defined, apply those per-track vocabulary hints (\`fallback\`, \`tracks.<id>.{triggers,veto}\`) on top of the built-in defaults. Evaluation order is always \`standard -> medium -> quick\` (narrow-to-broad).
|
|
69
69
|
- **quick** (\`spec → tdd → review → ship\`) — single-purpose work where the spec is essentially already known.
|
|
70
70
|
Triggers (case-insensitive substring or close variant): \`bug\`, \`bugfix\`, \`fix\`, \`hotfix\`, \`patch\`, \`typo\`, \`regression\`, \`copy change\`, \`rename\`, \`bump\`, \`upgrade dep\`, \`config tweak\`, \`docs only\`, \`comment\`, \`lint\`, \`format\`, \`small\`, \`tiny\`, \`one-liner\`, \`revert\`.
|
|
71
71
|
- **medium** (\`brainstorm → spec → plan → tdd → review → ship\`) — additive work that fits existing architecture and still needs product framing.
|
|
@@ -141,7 +141,7 @@ Do **not** silently discard an existing flow when the user provides a prompt. If
|
|
|
141
141
|
- Ask: "Continue with reset? (A) Yes, start fresh (B) No, resume current flow"
|
|
142
142
|
- If (B) → switch to Path B behavior.
|
|
143
143
|
6. **Classify the idea** using the heuristic below and present a single track recommendation. Wait for explicit confirmation or override before mutating any state.
|
|
144
|
-
- If \`${RUNTIME_ROOT}/config.yaml\` defines \`trackHeuristics\`, apply
|
|
144
|
+
- If \`${RUNTIME_ROOT}/config.yaml\` defines \`trackHeuristics\`, apply those vocabulary hints (\`fallback\`, \`tracks.<id>.{triggers,veto}\`) on top of built-in defaults. Evaluation order is fixed: \`standard -> medium -> quick\`. (Honest note: this is advisory prose; the LLM applies it, not a Node-level router.)
|
|
145
145
|
|
|
146
146
|
**Track heuristic** (lowercase substring match against the user prompt):
|
|
147
147
|
|
|
@@ -4,9 +4,16 @@ export interface TrackResolution {
|
|
|
4
4
|
reason: string;
|
|
5
5
|
matchedTokens: string[];
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Reference implementation of the track classifier the /cc skill prose
|
|
9
|
+
* describes. Tests pin its behavior so the built-in defaults stay honest.
|
|
10
|
+
* This function is not called from cclaw runtime — `/cc` routing happens in
|
|
11
|
+
* the LLM. If you wire this in later, update README to drop the
|
|
12
|
+
* "advisory" language.
|
|
13
|
+
*/
|
|
7
14
|
export declare function resolveTrackFromPrompt(prompt: string, config: TrackHeuristicsConfig | undefined): TrackResolution;
|
|
8
15
|
export declare const TRACK_HEURISTICS_DEFAULTS: {
|
|
9
16
|
readonly fallback: "standard";
|
|
10
|
-
readonly
|
|
17
|
+
readonly evaluationOrder: readonly ("quick" | "medium" | "standard")[];
|
|
11
18
|
readonly tracks: Record<"quick" | "medium" | "standard", TrackHeuristicRule>;
|
|
12
19
|
};
|
package/dist/track-heuristics.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { FLOW_TRACKS } from "./types.js";
|
|
2
|
+
// Built-in vocabulary per track. Kept in one place so tests, docs, and the
|
|
3
|
+
// /cc skill prose can snapshot the exact same strings.
|
|
2
4
|
const DEFAULT_RULES = {
|
|
3
5
|
quick: {
|
|
4
6
|
triggers: [
|
|
@@ -48,7 +50,9 @@ const DEFAULT_RULES = {
|
|
|
48
50
|
]
|
|
49
51
|
}
|
|
50
52
|
};
|
|
51
|
-
|
|
53
|
+
// Fixed evaluation order: narrow-to-broad. Overriding this was never wired
|
|
54
|
+
// into runtime, so cclaw stopped offering the knob in v0.38.0.
|
|
55
|
+
const EVALUATION_ORDER = ["standard", "medium", "quick"];
|
|
52
56
|
const DEFAULT_FALLBACK = "standard";
|
|
53
57
|
function hasToken(promptLower, token) {
|
|
54
58
|
return promptLower.includes(token.toLowerCase());
|
|
@@ -62,17 +66,6 @@ function matchRule(promptLower, rule) {
|
|
|
62
66
|
matches.push(trigger);
|
|
63
67
|
}
|
|
64
68
|
}
|
|
65
|
-
for (const pattern of rule.patterns ?? []) {
|
|
66
|
-
try {
|
|
67
|
-
const regex = new RegExp(pattern, "iu");
|
|
68
|
-
if (regex.test(promptLower)) {
|
|
69
|
-
matches.push(`/${pattern}/`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
// Ignore invalid custom regex entries; config validation should catch these.
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
69
|
return [...new Set(matches)];
|
|
77
70
|
}
|
|
78
71
|
function isValidTrack(value) {
|
|
@@ -89,34 +82,26 @@ function mergeRules(base, overrides) {
|
|
|
89
82
|
continue;
|
|
90
83
|
merged[track] = {
|
|
91
84
|
triggers: rule.triggers ?? merged[track].triggers,
|
|
92
|
-
patterns: rule.patterns ?? merged[track].patterns,
|
|
93
85
|
veto: rule.veto ?? merged[track].veto
|
|
94
86
|
};
|
|
95
87
|
}
|
|
96
88
|
return merged;
|
|
97
89
|
}
|
|
98
|
-
function resolvePriority(config) {
|
|
99
|
-
const configured = config?.priority ?? [];
|
|
100
|
-
const filtered = configured.filter((track) => isValidTrack(track));
|
|
101
|
-
const unique = [...new Set(filtered)];
|
|
102
|
-
if (unique.length === 0)
|
|
103
|
-
return [...DEFAULT_PRIORITY];
|
|
104
|
-
// Ensure all tracks are still represented in deterministic order.
|
|
105
|
-
for (const track of FLOW_TRACKS) {
|
|
106
|
-
if (!unique.includes(track))
|
|
107
|
-
unique.push(track);
|
|
108
|
-
}
|
|
109
|
-
return unique;
|
|
110
|
-
}
|
|
111
90
|
function resolveFallback(config) {
|
|
112
91
|
return config?.fallback && isValidTrack(config.fallback) ? config.fallback : DEFAULT_FALLBACK;
|
|
113
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Reference implementation of the track classifier the /cc skill prose
|
|
95
|
+
* describes. Tests pin its behavior so the built-in defaults stay honest.
|
|
96
|
+
* This function is not called from cclaw runtime — `/cc` routing happens in
|
|
97
|
+
* the LLM. If you wire this in later, update README to drop the
|
|
98
|
+
* "advisory" language.
|
|
99
|
+
*/
|
|
114
100
|
export function resolveTrackFromPrompt(prompt, config) {
|
|
115
101
|
const promptLower = prompt.toLowerCase();
|
|
116
102
|
const rules = mergeRules(DEFAULT_RULES, config);
|
|
117
|
-
const priority = resolvePriority(config);
|
|
118
103
|
const fallback = resolveFallback(config);
|
|
119
|
-
for (const track of
|
|
104
|
+
for (const track of EVALUATION_ORDER) {
|
|
120
105
|
const rule = rules[track];
|
|
121
106
|
const vetoes = rule.veto ?? [];
|
|
122
107
|
if (vetoes.some((token) => hasToken(promptLower, token))) {
|
|
@@ -139,6 +124,6 @@ export function resolveTrackFromPrompt(prompt, config) {
|
|
|
139
124
|
}
|
|
140
125
|
export const TRACK_HEURISTICS_DEFAULTS = {
|
|
141
126
|
fallback: DEFAULT_FALLBACK,
|
|
142
|
-
|
|
127
|
+
evaluationOrder: EVALUATION_ORDER,
|
|
143
128
|
tracks: DEFAULT_RULES
|
|
144
129
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -25,20 +25,38 @@ export type HarnessId = (typeof HARNESS_IDS)[number];
|
|
|
25
25
|
*/
|
|
26
26
|
export declare const LANGUAGE_RULE_PACKS: readonly ["typescript", "python", "go"];
|
|
27
27
|
export type LanguageRulePack = (typeof LANGUAGE_RULE_PACKS)[number];
|
|
28
|
+
/**
|
|
29
|
+
* Per-track vocabulary hints the LLM applies when classifying a /cc prompt.
|
|
30
|
+
*
|
|
31
|
+
* Intentionally minimal:
|
|
32
|
+
* - `triggers`: additional substrings that push a prompt toward this track.
|
|
33
|
+
* - `veto`: substrings that forbid this track even if a trigger matches.
|
|
34
|
+
*
|
|
35
|
+
* Removed in v0.38.0:
|
|
36
|
+
* - `patterns` (regex): no runtime ever consumed them; kept authors honest
|
|
37
|
+
* about what cclaw actually enforces.
|
|
38
|
+
*/
|
|
28
39
|
export interface TrackHeuristicRule {
|
|
29
40
|
triggers?: string[];
|
|
30
|
-
patterns?: string[];
|
|
31
41
|
veto?: string[];
|
|
32
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Optional prompt-to-track overrides for /cc classification.
|
|
45
|
+
*
|
|
46
|
+
* Honesty note: this config is **advisory**. cclaw surfaces these lists in
|
|
47
|
+
* the /cc skill and contract prose so the LLM can apply them when picking a
|
|
48
|
+
* track. There is no Node-level routing layer that mechanically enforces the
|
|
49
|
+
* result — which is why we only ship `triggers`, `veto`, and `fallback`, not
|
|
50
|
+
* regex patterns or priority overrides.
|
|
51
|
+
*
|
|
52
|
+
* Removed in v0.38.0:
|
|
53
|
+
* - `priority`: track evaluation order is always `standard -> medium -> quick`
|
|
54
|
+
* (narrow-to-broad matching). Overriding it was never wired.
|
|
55
|
+
*/
|
|
33
56
|
export interface TrackHeuristicsConfig {
|
|
34
|
-
/** Track used when no trigger
|
|
57
|
+
/** Track used when no trigger matches. Defaults to `standard`. */
|
|
35
58
|
fallback?: FlowTrack;
|
|
36
|
-
/**
|
|
37
|
-
* Track evaluation order. First matching track wins.
|
|
38
|
-
* Example: ["standard", "medium", "quick"].
|
|
39
|
-
*/
|
|
40
|
-
priority?: FlowTrack[];
|
|
41
|
-
/** Per-track matching rules. */
|
|
59
|
+
/** Per-track vocabulary hints. */
|
|
42
60
|
tracks?: Partial<Record<FlowTrack, TrackHeuristicRule>>;
|
|
43
61
|
}
|
|
44
62
|
/**
|
|
@@ -92,7 +110,8 @@ export interface VibyConfig {
|
|
|
92
110
|
*/
|
|
93
111
|
languageRulePacks?: LanguageRulePack[];
|
|
94
112
|
/**
|
|
95
|
-
* Optional prompt-to-track
|
|
113
|
+
* Optional prompt-to-track vocabulary overrides for /cc classification.
|
|
114
|
+
* Advisory (surfaced in the /cc skill prose), not machine-enforced.
|
|
96
115
|
* If omitted, cclaw uses built-in defaults.
|
|
97
116
|
*/
|
|
98
117
|
trackHeuristics?: TrackHeuristicsConfig;
|