cclaw-cli 0.45.0 → 0.46.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 +1 -1
- package/dist/artifact-linter.js +82 -9
- package/dist/content/stages/design.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/artifact-linter.js
CHANGED
|
@@ -183,6 +183,42 @@ function getMarkdownTableRows(sectionBody) {
|
|
|
183
183
|
}
|
|
184
184
|
return rows;
|
|
185
185
|
}
|
|
186
|
+
const DIAGRAM_ARROW_PATTERN = /(?:<--?>|<?==?>|--?>|->>|=>|-\.->|→|⟶|↦)/u;
|
|
187
|
+
const DIAGRAM_FAILURE_EDGE_PATTERN = /\b(fail(?:ed|ure)?|error|timeout|fallback|degrad(?:e|ed|ation)|retry|backoff|circuit|unavailable|recover(?:y)?|rescue|mitigat(?:e|ion)|rollback|exception|abort|dead[\s-]?letter|dlq)\b/iu;
|
|
188
|
+
const DIAGRAM_GENERIC_NODE_PATTERN = /\b(service|component|module|system)\s*(?:[A-Z0-9])?\b/iu;
|
|
189
|
+
function diagramEdgeLines(sectionBody) {
|
|
190
|
+
return sectionBody
|
|
191
|
+
.split(/\r?\n/)
|
|
192
|
+
.map((line) => line.trim())
|
|
193
|
+
.filter((line) => line.length > 0)
|
|
194
|
+
.filter((line) => !line.startsWith("```"))
|
|
195
|
+
.filter((line) => !line.startsWith("%%"))
|
|
196
|
+
.filter((line) => DIAGRAM_ARROW_PATTERN.test(line));
|
|
197
|
+
}
|
|
198
|
+
function hasFailureEdgeInDiagram(sectionBody) {
|
|
199
|
+
const lines = diagramEdgeLines(sectionBody);
|
|
200
|
+
for (const line of lines) {
|
|
201
|
+
if (DIAGRAM_ARROW_PATTERN.test(line) && DIAGRAM_FAILURE_EDGE_PATTERN.test(line)) {
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
function hasLabeledDiagramArrow(lines) {
|
|
208
|
+
return lines.some((line) => /\|[^|]+\|/u.test(line) || /:\s*[A-Za-z]/u.test(line));
|
|
209
|
+
}
|
|
210
|
+
function hasAsyncDiagramEdge(lines) {
|
|
211
|
+
return lines.some((line) => /-\.->|-->>|~~>|\basync\b/iu.test(line));
|
|
212
|
+
}
|
|
213
|
+
function hasSyncDiagramEdge(lines) {
|
|
214
|
+
return lines.some((line) => {
|
|
215
|
+
if (/\bsync\b/iu.test(line))
|
|
216
|
+
return true;
|
|
217
|
+
if (!/(-->|->|=>|→|⟶|↦)/u.test(line))
|
|
218
|
+
return false;
|
|
219
|
+
return !/-\.->|-->>|~~>/u.test(line);
|
|
220
|
+
});
|
|
221
|
+
}
|
|
186
222
|
const LEARNING_TYPE_SET = new Set(["rule", "pattern", "lesson", "compound"]);
|
|
187
223
|
const LEARNING_CONFIDENCE_SET = new Set(["high", "medium", "low"]);
|
|
188
224
|
const LEARNING_UNIVERSALITY_SET = new Set(["project", "personal", "universal"]);
|
|
@@ -541,20 +577,57 @@ function validateSectionBody(sectionBody, rule, sectionName) {
|
|
|
541
577
|
};
|
|
542
578
|
}
|
|
543
579
|
}
|
|
544
|
-
const
|
|
545
|
-
if (
|
|
546
|
-
const
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
580
|
+
const sectionNameNormalized = normalizeHeadingTitle(sectionName).toLowerCase();
|
|
581
|
+
if (sectionNameNormalized === "architecture diagram") {
|
|
582
|
+
const edgeLines = diagramEdgeLines(sectionBody);
|
|
583
|
+
if (edgeLines.length === 0) {
|
|
584
|
+
return {
|
|
585
|
+
ok: false,
|
|
586
|
+
details: "Architecture Diagram must include at least one directional edge line (for example `A -->|action| B`)."
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
if (!hasLabeledDiagramArrow(edgeLines)) {
|
|
590
|
+
return {
|
|
591
|
+
ok: false,
|
|
592
|
+
details: "Architecture Diagram must label each edge with an action/message (for example `A -->|sync: persist| B`)."
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
const genericLine = edgeLines.find((line) => DIAGRAM_GENERIC_NODE_PATTERN.test(line));
|
|
596
|
+
if (genericLine) {
|
|
551
597
|
return {
|
|
552
598
|
ok: false,
|
|
553
|
-
details: `
|
|
599
|
+
details: `Architecture Diagram uses a generic node label in edge "${genericLine}". Use concrete component names instead of placeholders like Service/Component.`
|
|
554
600
|
};
|
|
555
601
|
}
|
|
602
|
+
if (!hasAsyncDiagramEdge(edgeLines) || !hasSyncDiagramEdge(edgeLines)) {
|
|
603
|
+
return {
|
|
604
|
+
ok: false,
|
|
605
|
+
details: "Architecture Diagram must distinguish sync vs async edges (for example solid + dotted arrows, or `sync:` and `async:` labels)."
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
if (!hasFailureEdgeInDiagram(sectionBody)) {
|
|
609
|
+
return {
|
|
610
|
+
ok: false,
|
|
611
|
+
details: "Architecture Diagram must include at least one failure-edge arrow with a failure keyword (for example: timeout, error, fallback, degraded, retry)."
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
if (sectionNameNormalized !== "architecture diagram") {
|
|
616
|
+
const keywords = extractRequiredKeywords(rule);
|
|
617
|
+
if (keywords.length > 0) {
|
|
618
|
+
const bodyLower = sectionBody.toLowerCase();
|
|
619
|
+
const found = keywords.filter((kw) => bodyLower.includes(kw.toLowerCase()));
|
|
620
|
+
const threshold = Math.ceil(keywords.length * 0.5);
|
|
621
|
+
if (found.length < threshold) {
|
|
622
|
+
const missing = keywords.filter((kw) => !bodyLower.includes(kw.toLowerCase()));
|
|
623
|
+
return {
|
|
624
|
+
ok: false,
|
|
625
|
+
details: `Rule expects keywords (${threshold}/${keywords.length} minimum): missing ${missing.join(", ")}.`
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
}
|
|
556
629
|
}
|
|
557
|
-
if (
|
|
630
|
+
if (sectionNameNormalized === "acceptance criteria" &&
|
|
558
631
|
/observable[\s,]*measurable[\s,]+(and )?falsifiable/iu.test(rule)) {
|
|
559
632
|
const rows = getMarkdownTableRows(sectionBody);
|
|
560
633
|
for (const row of rows) {
|
|
@@ -25,7 +25,7 @@ export const DESIGN = {
|
|
|
25
25
|
"Codebase Investigation — Before any design decision, read the actual code in the blast radius. List every file that will be touched, its current responsibilities, and existing patterns (error handling, naming, test style). Design must conform to discovered patterns, not impose new ones without justification.",
|
|
26
26
|
"Step 0: Scope Challenge — what existing code solves sub-problems? Minimum change set? Complexity check: 8+ files or 2+ new services = complexity smell → flag for possible scope reduction.",
|
|
27
27
|
"Search Before Building — For each technical choice (library, pattern, architecture), search for existing solutions. Label findings: Layer 1 (exact match), Layer 2 (partial match, needs adaptation), Layer 3 (inspiration only), EUREKA (unexpected perfect solution). Default to existing before custom.",
|
|
28
|
-
"Architecture Review — system design, component boundaries, data flow, scaling, security architecture. For each new codepath: one realistic production failure scenario. **Mandatory:** produce at least one architecture diagram (ASCII, Mermaid, or tool-generated) showing component boundaries and data flow direction. Apply the **Visual Communication rules** (see below) — an unlabeled or generic diagram is worse than no diagram, because it pretends to encode decisions it does not.",
|
|
28
|
+
"Architecture Review — system design, component boundaries, data flow, scaling, security architecture. For each new codepath: one realistic production failure scenario. **Mandatory:** produce at least one architecture diagram (ASCII, Mermaid, or tool-generated) showing component boundaries and data flow direction. Include at least one labeled failure edge, e.g. `API -->|timeout| FallbackCache -->|degraded response| User`. Apply the **Visual Communication rules** (see below) — an unlabeled or generic diagram is worse than no diagram, because it pretends to encode decisions it does not.",
|
|
29
29
|
"Code Quality Review — code organization, DRY violations, error handling patterns, over/under-engineering assessment.",
|
|
30
30
|
"Test Review — diagram every new flow, data path, error path. For each: what test type covers it? Does one exist? What is the gap? Produce test plan artifact.",
|
|
31
31
|
"Performance Review — N+1 queries, memory concerns, caching opportunities, slow code paths. What breaks at 10x load? At 100x?",
|
|
@@ -196,7 +196,7 @@ export const DESIGN = {
|
|
|
196
196
|
{ section: "Codebase Investigation", required: true, validationRule: "Must list blast-radius files with current responsibilities and discovered patterns." },
|
|
197
197
|
{ section: "Search Before Building", required: true, validationRule: "For each technical choice: Layer 1 (exact match), Layer 2 (partial match), Layer 3 (inspiration), EUREKA labels with reuse-first default." },
|
|
198
198
|
{ section: "Architecture Boundaries", required: true, validationRule: "Must list component boundaries with ownership." },
|
|
199
|
-
{ section: "Architecture Diagram", required: true, validationRule: "At least one diagram (ASCII, Mermaid, or image) showing component boundaries and data flow direction. Diagram must: (1) label every node with a concrete component name (no generic 'Service A/B'), (2) label every arrow with the action or message (no unlabeled arrows), (3) mark direction of data flow explicitly, (4) distinguish synchronous from asynchronous edges (e.g. solid vs dashed, or `sync:` / `async:` prefix), (5)
|
|
199
|
+
{ section: "Architecture Diagram", required: true, validationRule: "At least one diagram (ASCII, Mermaid, or image) showing component boundaries and data flow direction. Diagram must: (1) label every node with a concrete component name (no generic 'Service A/B'), (2) label every arrow with the action or message (no unlabeled arrows), (3) mark direction of data flow explicitly, (4) distinguish synchronous from asynchronous edges (e.g. solid vs dashed, or `sync:` / `async:` prefix), (5) include at least one failure/degraded edge line that contains an arrow plus a failure keyword (`timeout`, `error`, `fallback`, `degraded`, `retry`, etc.)." },
|
|
200
200
|
{ section: "Data Flow", required: true, validationRule: "Must include happy path, nil input, empty input, upstream error paths." },
|
|
201
201
|
{ section: "Failure Mode Table", required: true, validationRule: "Each failure mode has: trigger, detection, mitigation, user impact." },
|
|
202
202
|
{ section: "Test Strategy", required: true, validationRule: "Must define unit/integration/e2e expectations with coverage targets." },
|