cclaw-cli 0.5.8 → 0.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/artifact-linter.js
CHANGED
|
@@ -118,6 +118,22 @@ function tokensFromRule(rule) {
|
|
|
118
118
|
}
|
|
119
119
|
return [];
|
|
120
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Extract required keywords from validation rules that contain comma-separated
|
|
123
|
+
* concept lists. Activates only for rules with structured enumerations like
|
|
124
|
+
* "failure modes, error surface, data-flow paths" — not for short rules.
|
|
125
|
+
*/
|
|
126
|
+
function extractRequiredKeywords(rule) {
|
|
127
|
+
const colonMatch = /:\s*(.+)$/u.exec(rule);
|
|
128
|
+
if (!colonMatch)
|
|
129
|
+
return [];
|
|
130
|
+
const tail = colonMatch[1];
|
|
131
|
+
const parts = tail.split(/,\s*(?:and\s+)?/u).map((p) => p.trim().replace(/\.$/u, ""));
|
|
132
|
+
const phrases = parts.filter((p) => p.length >= 4 && !/^(must|should|at least|if |or )/iu.test(p));
|
|
133
|
+
if (phrases.length < 3)
|
|
134
|
+
return [];
|
|
135
|
+
return phrases;
|
|
136
|
+
}
|
|
121
137
|
function validateSectionBody(sectionBody, rule) {
|
|
122
138
|
const bodyLines = sectionBody.split(/\r?\n/).map((line) => line.trim());
|
|
123
139
|
const meaningful = meaningfulLineCount(sectionBody);
|
|
@@ -185,6 +201,19 @@ function validateSectionBody(sectionBody, rule) {
|
|
|
185
201
|
}
|
|
186
202
|
}
|
|
187
203
|
}
|
|
204
|
+
const keywords = extractRequiredKeywords(rule);
|
|
205
|
+
if (keywords.length > 0) {
|
|
206
|
+
const bodyLower = sectionBody.toLowerCase();
|
|
207
|
+
const found = keywords.filter((kw) => bodyLower.includes(kw.toLowerCase()));
|
|
208
|
+
const threshold = Math.ceil(keywords.length * 0.5);
|
|
209
|
+
if (found.length < threshold) {
|
|
210
|
+
const missing = keywords.filter((kw) => !bodyLower.includes(kw.toLowerCase()));
|
|
211
|
+
return {
|
|
212
|
+
ok: false,
|
|
213
|
+
details: `Rule expects keywords (${threshold}/${keywords.length} minimum): missing ${missing.join(", ")}.`
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
188
217
|
return {
|
|
189
218
|
ok: true,
|
|
190
219
|
details: "Section heading and content satisfy lint heuristics."
|
package/dist/content/examples.js
CHANGED
|
@@ -73,6 +73,14 @@ The original premise (“add notifications”) was reframed to **“ensure users
|
|
|
73
73
|
| **12-MONTH IDEAL** | Unified notification center with reliable multi-channel fan-out and user-level routing preferences. |
|
|
74
74
|
| **Alignment verdict** | Aligned: this scope builds the durability foundation without prematurely committing to channel expansion. |
|
|
75
75
|
|
|
76
|
+
### Mode-Specific Analysis
|
|
77
|
+
|
|
78
|
+
**Selected mode:** SELECTIVE EXPANSION
|
|
79
|
+
|
|
80
|
+
- **Hold-scope baseline:** SSE live updates + REST fallback is the minimum that meets the "know when action is needed" reframe. Accepted as baseline.
|
|
81
|
+
- **Expansion evaluated — degraded-state UX (accepted):** Adding an explicit "live updates paused" banner and polling fallback turns a reliability gap into a visible, recoverable state. Low incremental effort (S), high user trust payoff.
|
|
82
|
+
- **Expansion evaluated — real-time channel upgrade (deferred):** WebSocket channel provides lower latency but requires new infra (connection pool, auth handshake). Not justified for current load; deferred to post-v1 validation.
|
|
83
|
+
|
|
76
84
|
### Implementation Alternatives
|
|
77
85
|
|
|
78
86
|
| Option | Summary | Effort (S/M/L/XL) | Risk | Pros | Cons | Reuses |
|
package/dist/content/observe.js
CHANGED
|
@@ -309,10 +309,15 @@ is_plan_mode_safe_tool() {
|
|
|
309
309
|
todowrite|todoread|todo_write|todo_read) return 0 ;;
|
|
310
310
|
webfetch|websearch|web_fetch|web_search|fetchmcpresource) return 0 ;;
|
|
311
311
|
switchmode|switch_mode) return 0 ;;
|
|
312
|
+
task|delegate) return 0 ;;
|
|
312
313
|
*) return 1 ;;
|
|
313
314
|
esac
|
|
314
315
|
}
|
|
315
316
|
|
|
317
|
+
is_cclaw_cli_payload() {
|
|
318
|
+
printf '%s' "$1" | grep -Eq '(cclaw |npx cclaw |/cc-|/cc[^[:alnum:]_-])'
|
|
319
|
+
}
|
|
320
|
+
|
|
316
321
|
is_preimplementation_stage() {
|
|
317
322
|
case "$1" in
|
|
318
323
|
brainstorm|scope|design|spec|plan) return 0 ;;
|
|
@@ -370,7 +375,7 @@ fi
|
|
|
370
375
|
|
|
371
376
|
if is_preimplementation_stage "$CURRENT_STAGE" && ! is_plan_mode_safe_tool "$TOOL_LOWER"; then
|
|
372
377
|
if ! is_mutating_tool "$TOOL_LOWER"; then
|
|
373
|
-
if ! printf '%s' "$PAYLOAD_LOWER" | grep -Eq '\.cclaw/'; then
|
|
378
|
+
if ! printf '%s' "$PAYLOAD_LOWER" | grep -Eq '\.cclaw/' && ! is_cclaw_cli_payload "$PAYLOAD_LOWER"; then
|
|
374
379
|
if [ -n "$REASONS" ]; then
|
|
375
380
|
REASONS="$REASONS,non_safe_tool_in_plan_stage_\${CURRENT_STAGE}"
|
|
376
381
|
else
|
|
@@ -393,9 +398,10 @@ fi
|
|
|
393
398
|
SHOULD_RECORD_FLOW_READ=0
|
|
394
399
|
case "$TOOL_LOWER" in
|
|
395
400
|
read|readfile|open|view|cat) SHOULD_RECORD_FLOW_READ=1 ;;
|
|
401
|
+
shell|runcommand|run_command|execcommand|exec_command|terminal) SHOULD_RECORD_FLOW_READ=1 ;;
|
|
396
402
|
esac
|
|
397
403
|
|
|
398
|
-
if [ "$SHOULD_RECORD_FLOW_READ" -eq 1 ] && printf '%s' "$PAYLOAD_LOWER" | grep -Eq '\.cclaw/state/flow-state\.json'; then
|
|
404
|
+
if [ "$SHOULD_RECORD_FLOW_READ" -eq 1 ] && printf '%s' "$PAYLOAD_LOWER" | grep -Eq '(\.cclaw/state/flow-state\.json|cclaw doctor|cclaw sync)'; then
|
|
399
405
|
TMP_STATE_FILE="$GUARD_STATE_FILE.tmp.$$"
|
|
400
406
|
if command -v jq >/dev/null 2>&1 && [ -f "$GUARD_STATE_FILE" ]; then
|
|
401
407
|
jq --arg ts "$TS" --argjson epoch "$NOW_EPOCH" '
|
package/dist/content/skills.js
CHANGED
|
@@ -143,6 +143,8 @@ function stageCompletionProtocol(schema) {
|
|
|
143
143
|
const gateIds = schema.requiredGates.map((g) => g.id);
|
|
144
144
|
const gateList = gateIds.map((id) => `\`${id}\``).join(", ");
|
|
145
145
|
const nextStage = schema.next === "done" ? null : schema.next;
|
|
146
|
+
const mandatory = schema.mandatoryDelegations;
|
|
147
|
+
const delegationLogRel = `${RUNTIME_ROOT}/state/delegation-log.json`;
|
|
146
148
|
const stateUpdate = nextStage
|
|
147
149
|
? ` - Set \`currentStage\` to \`"${nextStage}"\`
|
|
148
150
|
- Add \`"${stage}"\` to \`completedStages\` array
|
|
@@ -151,23 +153,33 @@ function stageCompletionProtocol(schema) {
|
|
|
151
153
|
: ` - Add \`"${stage}"\` to \`completedStages\` array
|
|
152
154
|
- Move all gate IDs for this stage (${gateList}) into \`stageGateCatalog.${stage}.passed\`
|
|
153
155
|
- Clear \`stageGateCatalog.${stage}.blocked\``;
|
|
156
|
+
const delegationBlock = mandatory.length > 0
|
|
157
|
+
? `0. **Delegation pre-flight** (BLOCKING):
|
|
158
|
+
- Mandatory agents for this stage: ${mandatory.map((a) => `\`${a}\``).join(", ")}.
|
|
159
|
+
- For each mandatory agent: confirm it was dispatched (via Task/delegate) and completed, OR record an explicit waiver with reason in \`${delegationLogRel}\`.
|
|
160
|
+
- Write a JSON entry per agent: \`{ "stage": "${stage}", "agent": "<name>", "mode": "mandatory", "status": "completed"|"waived", "waiverReason": "<if waived>", "ts": "<ISO timestamp>" }\`.
|
|
161
|
+
- If the harness does not support delegation, record status \`"waived"\` with reason \`"harness_limitation"\`.
|
|
162
|
+
- **Do NOT proceed to step 1 until every mandatory agent has an entry in the delegation log.**
|
|
163
|
+
`
|
|
164
|
+
: "";
|
|
154
165
|
let nextAction;
|
|
155
166
|
if (nextStage) {
|
|
156
167
|
const nextSchema = stageSchema(nextStage);
|
|
157
168
|
const nextDescription = nextSchema.skillDescription.charAt(0).toLowerCase() + nextSchema.skillDescription.slice(1);
|
|
158
|
-
nextAction = `
|
|
169
|
+
nextAction = `4. Tell the user:\n\n > **Stage \`${stage}\` complete.** Next: **${nextStage}** — ${nextDescription}\n >\n > Run \`/cc-next\` to continue.`;
|
|
159
170
|
}
|
|
160
171
|
else {
|
|
161
|
-
nextAction = `
|
|
172
|
+
nextAction = `4. Tell the user:\n\n > **Flow complete.** All stages finished. The project is ready for release.`;
|
|
162
173
|
}
|
|
163
174
|
return `## Stage Completion Protocol
|
|
164
175
|
|
|
165
176
|
When all required gates are satisfied and the artifact is written:
|
|
166
177
|
|
|
167
|
-
1. **Update \`${RUNTIME_ROOT}/state/flow-state.json\`:**
|
|
178
|
+
${delegationBlock}1. **Update \`${RUNTIME_ROOT}/state/flow-state.json\`:**
|
|
168
179
|
${stateUpdate}
|
|
169
180
|
- For each passed gate, add an entry to \`guardEvidence\`: \`"<gate_id>": "<artifact path or excerpt proving the gate>"\`. Do NOT leave \`guardEvidence\` empty.
|
|
170
181
|
2. **Persist artifact** at \`${RUNTIME_ROOT}/artifacts/${schema.artifactFile}\`. Do NOT manually copy into \`${RUNTIME_ROOT}/runs/\`; archival is handled by \`cclaw archive\`.
|
|
182
|
+
3. **Doctor pre-flight** — Run \`npx cclaw doctor\` (or the installed cclaw binary). If any check fails, resolve the issue (missing delegation entry, artifact section, gate evidence) and re-run until all checks pass. Do NOT proceed to the next step while doctor reports failures.
|
|
171
183
|
${nextAction}
|
|
172
184
|
|
|
173
185
|
**STOP.** Do not load the next stage skill yourself. The user will run \`/cc-next\` when ready (same session or new session).
|
|
@@ -352,12 +352,15 @@ const SCOPE = {
|
|
|
352
352
|
{ section: "Premise Challenge", required: true, validationRule: "Must contain explicit answers to: right problem? direct path? what if nothing?" },
|
|
353
353
|
{ section: "Implementation Alternatives", required: true, validationRule: "2-3 options with Name, Summary, Effort, Risk, Pros, Cons, and Reuses. Must include minimal viable and ideal architecture options." },
|
|
354
354
|
{ section: "Scope Mode", required: true, validationRule: "Must state selected mode and rationale with default heuristic justification." },
|
|
355
|
+
{ section: "Mode-Specific Analysis", required: true, validationRule: "Must document the analysis matching the selected scope mode: EXPAND (10x and delight opportunities), SELECTIVE (hold-scope baseline then cherry-picked expansions), HOLD (minimum-change-set hardening), REDUCE (ruthless cuts and follow-up split)." },
|
|
355
356
|
{ section: "In Scope / Out of Scope", required: true, validationRule: "Two separate explicit lists. Out-of-scope must not be empty." },
|
|
356
357
|
{ section: "Discretion Areas", required: true, validationRule: "Explicit list of implementer decision zones, or 'None' if scope is fully locked." },
|
|
357
358
|
{ section: "Deferred Items", required: true, validationRule: "Each item has one-line rationale. If empty, state 'None' explicitly." },
|
|
358
359
|
{ section: "Error & Rescue Registry", required: true, validationRule: "Each scoped capability has: failure mode, detection method, fallback decision." },
|
|
359
360
|
{ section: "Completion Dashboard", required: true, validationRule: "Lists checklist findings, count of resolved decisions, and unresolved decisions (or 'None')." },
|
|
360
|
-
{ section: "Scope Summary", required: true, validationRule: "Clean summary: mode, strongest challenges, recommended path, accepted scope, deferred, excluded." }
|
|
361
|
+
{ section: "Scope Summary", required: true, validationRule: "Clean summary: mode, strongest challenges, recommended path, accepted scope, deferred, excluded." },
|
|
362
|
+
{ section: "Dream State Mapping", required: false, validationRule: "If present (complex projects): CURRENT STATE, THIS PLAN, 12-MONTH IDEAL, and alignment verdict." },
|
|
363
|
+
{ section: "Temporal Interrogation", required: false, validationRule: "If present (complex projects): timeline simulation table with decision pressures and lock-now vs defer verdicts." }
|
|
361
364
|
],
|
|
362
365
|
namedAntiPattern: {
|
|
363
366
|
title: "Scope Is Obvious From Context",
|
|
@@ -76,6 +76,14 @@ export const ARTIFACT_TEMPLATES = {
|
|
|
76
76
|
- [ ] hold
|
|
77
77
|
- [ ] reduce
|
|
78
78
|
|
|
79
|
+
## Mode-Specific Analysis
|
|
80
|
+
- **Selected mode:**
|
|
81
|
+
- **Analysis:**
|
|
82
|
+
- (EXPAND: 10x opportunities, delight features)
|
|
83
|
+
- (SELECTIVE: hold-scope baseline, cherry-picked expansions)
|
|
84
|
+
- (HOLD: minimum-change-set hardening)
|
|
85
|
+
- (REDUCE: ruthless cuts, follow-up split)
|
|
86
|
+
|
|
79
87
|
## In Scope / Out of Scope
|
|
80
88
|
|
|
81
89
|
### In Scope
|