cclaw-cli 0.51.11 → 0.51.13
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 +125 -45
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +3 -1
- package/dist/content/examples.js +5 -5
- package/dist/content/review-prompts.d.ts +1 -0
- package/dist/content/review-prompts.js +104 -0
- package/dist/content/skills.js +10 -6
- package/dist/content/state-contracts.d.ts +1 -0
- package/dist/content/state-contracts.js +63 -0
- package/dist/harness-adapters.js +2 -0
- package/dist/install.js +8 -0
- package/package.json +1 -1
package/dist/artifact-linter.js
CHANGED
|
@@ -348,35 +348,6 @@ function getMarkdownTableRows(sectionBody) {
|
|
|
348
348
|
}
|
|
349
349
|
return rows;
|
|
350
350
|
}
|
|
351
|
-
function getApproachRows(sectionBody) {
|
|
352
|
-
const tableRows = getMarkdownTableRows(sectionBody).map((row) => row.join(" "));
|
|
353
|
-
const headingRows = sectionBody
|
|
354
|
-
.split(/\r?\n/u)
|
|
355
|
-
.map((line) => line.trim())
|
|
356
|
-
.filter((line) => /^#{3,6}\s+\S/u.test(line))
|
|
357
|
-
.map((line) => line.replace(/^#{3,6}\s+/u, ""));
|
|
358
|
-
const bulletRows = sectionBody
|
|
359
|
-
.split(/\r?\n/u)
|
|
360
|
-
.map((line) => line.trim())
|
|
361
|
-
.filter((line) => /^(?:[-*]|\d+\.)\s+\S/u.test(line));
|
|
362
|
-
return [...tableRows, ...headingRows, ...bulletRows];
|
|
363
|
-
}
|
|
364
|
-
function hasSemanticChallenger(row) {
|
|
365
|
-
const normalized = row
|
|
366
|
-
.replace(/[_`*]/gu, " ")
|
|
367
|
-
.replace(/\s+/gu, " ")
|
|
368
|
-
.trim()
|
|
369
|
-
.toLowerCase();
|
|
370
|
-
const isChallenger = /\bchallenger\b/u.test(normalized);
|
|
371
|
-
if (!isChallenger)
|
|
372
|
-
return false;
|
|
373
|
-
return (/\bhigher[-\s]?upside\b/u.test(normalized) ||
|
|
374
|
-
/\bhigh[-\s]?upside\b/u.test(normalized) ||
|
|
375
|
-
/\bupside\s*:?\s*(?:high|higher|strong|large|meaningful)\b/u.test(normalized) ||
|
|
376
|
-
/\b(?:high|higher|strong|large|meaningful)\s+upside\b/u.test(normalized) ||
|
|
377
|
-
/\b(?:10-star|ten-star|ambitious|higher leverage|leverage)\b/u.test(normalized) ||
|
|
378
|
-
/\bhigh\b/u.test(normalized));
|
|
379
|
-
}
|
|
380
351
|
function parseBinaryFlag(value) {
|
|
381
352
|
const normalized = value.trim().toLowerCase();
|
|
382
353
|
if (/^(?:y|yes|true|1)$/u.test(normalized))
|
|
@@ -596,6 +567,114 @@ function validateScopeSummary(sectionBody) {
|
|
|
596
567
|
details: "Scope Summary names the selected mode and the next-stage handoff."
|
|
597
568
|
};
|
|
598
569
|
}
|
|
570
|
+
const APPROACH_ROLE_VALUES = ["baseline", "challenger", "wild-card"];
|
|
571
|
+
const APPROACH_UPSIDE_VALUES = ["low", "modest", "high", "higher"];
|
|
572
|
+
const REQUIREMENT_PRIORITY_VALUES = ["P0", "P1", "P2", "P3", "DROPPED"];
|
|
573
|
+
function normalizeTableToken(value) {
|
|
574
|
+
return value
|
|
575
|
+
.replace(/[`*_]/gu, "")
|
|
576
|
+
.trim()
|
|
577
|
+
.toLowerCase()
|
|
578
|
+
.replace(/\s+/gu, "-");
|
|
579
|
+
}
|
|
580
|
+
function columnIndex(header, expected) {
|
|
581
|
+
return header.findIndex((cell) => normalizeTableToken(cell) === expected);
|
|
582
|
+
}
|
|
583
|
+
function validateApproachesTaxonomy(sectionBody) {
|
|
584
|
+
const header = tableHeaderCells(sectionBody);
|
|
585
|
+
const rows = getMarkdownTableRows(sectionBody);
|
|
586
|
+
if (!header) {
|
|
587
|
+
return {
|
|
588
|
+
rowCount: 0,
|
|
589
|
+
roleUpsideOk: false,
|
|
590
|
+
challengerOk: false,
|
|
591
|
+
details: "Approaches must be a markdown table with canonical Role and Upside columns."
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
const roleIndex = columnIndex(header, "role");
|
|
595
|
+
const upsideIndex = columnIndex(header, "upside");
|
|
596
|
+
if (roleIndex < 0 || upsideIndex < 0) {
|
|
597
|
+
return {
|
|
598
|
+
rowCount: rows.length,
|
|
599
|
+
roleUpsideOk: false,
|
|
600
|
+
challengerOk: false,
|
|
601
|
+
details: "Approaches table must include canonical `Role` and `Upside` columns (Role: baseline | challenger | wild-card; Upside: low | modest | high | higher)."
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
let challengerRows = 0;
|
|
605
|
+
let challengerHasHighUpside = false;
|
|
606
|
+
for (const [index, row] of rows.entries()) {
|
|
607
|
+
const role = normalizeTableToken(row[roleIndex] ?? "");
|
|
608
|
+
const upside = normalizeTableToken(row[upsideIndex] ?? "");
|
|
609
|
+
if (!APPROACH_ROLE_VALUES.includes(role)) {
|
|
610
|
+
return {
|
|
611
|
+
rowCount: rows.length,
|
|
612
|
+
roleUpsideOk: false,
|
|
613
|
+
challengerOk: false,
|
|
614
|
+
details: `Approaches row ${index + 1} has invalid Role "${row[roleIndex] ?? ""}". Expected one of: ${APPROACH_ROLE_VALUES.join(", ")}.`
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
if (!APPROACH_UPSIDE_VALUES.includes(upside)) {
|
|
618
|
+
return {
|
|
619
|
+
rowCount: rows.length,
|
|
620
|
+
roleUpsideOk: false,
|
|
621
|
+
challengerOk: false,
|
|
622
|
+
details: `Approaches row ${index + 1} has invalid Upside "${row[upsideIndex] ?? ""}". Expected one of: ${APPROACH_UPSIDE_VALUES.join(", ")}.`
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
if (role === "challenger") {
|
|
626
|
+
challengerRows += 1;
|
|
627
|
+
if (upside === "high" || upside === "higher") {
|
|
628
|
+
challengerHasHighUpside = true;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
const challengerOk = challengerRows === 1 && challengerHasHighUpside;
|
|
633
|
+
return {
|
|
634
|
+
rowCount: rows.length,
|
|
635
|
+
roleUpsideOk: true,
|
|
636
|
+
challengerOk,
|
|
637
|
+
details: challengerOk
|
|
638
|
+
? "Approaches table uses canonical Role/Upside values and exactly one high/higher-upside challenger."
|
|
639
|
+
: `Approaches table must include exactly one challenger row with Upside high or higher. Found ${challengerRows} challenger row(s).`
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
function validateRequirementsTaxonomy(sectionBody) {
|
|
643
|
+
const header = tableHeaderCells(sectionBody);
|
|
644
|
+
if (!header) {
|
|
645
|
+
return {
|
|
646
|
+
ok: false,
|
|
647
|
+
details: "Requirements must be a markdown table with a Priority column."
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
const priorityIndex = columnIndex(header, "priority");
|
|
651
|
+
if (priorityIndex < 0) {
|
|
652
|
+
return {
|
|
653
|
+
ok: false,
|
|
654
|
+
details: "Requirements table must include a canonical `Priority` column."
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
const rows = getMarkdownTableRows(sectionBody);
|
|
658
|
+
if (rows.length === 0) {
|
|
659
|
+
return {
|
|
660
|
+
ok: false,
|
|
661
|
+
details: "Requirements table must include at least one requirement row."
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
for (const [index, row] of rows.entries()) {
|
|
665
|
+
const rawPriority = (row[priorityIndex] ?? "").replace(/[`*_]/gu, "").trim().toUpperCase();
|
|
666
|
+
if (!REQUIREMENT_PRIORITY_VALUES.includes(rawPriority)) {
|
|
667
|
+
return {
|
|
668
|
+
ok: false,
|
|
669
|
+
details: `Requirements row ${index + 1} has invalid Priority "${row[priorityIndex] ?? ""}". Expected one of: ${REQUIREMENT_PRIORITY_VALUES.join(", ")}.`
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
return {
|
|
674
|
+
ok: true,
|
|
675
|
+
details: "Requirements table uses canonical Priority values."
|
|
676
|
+
};
|
|
677
|
+
}
|
|
599
678
|
const INTERACTION_EDGE_CASE_REQUIREMENTS = [
|
|
600
679
|
{ label: "double-click", pattern: /\bdouble[\s-]?click\b/iu },
|
|
601
680
|
{
|
|
@@ -1322,6 +1401,9 @@ function validateSectionBody(sectionBody, rule, sectionName) {
|
|
|
1322
1401
|
if (sectionNameNormalized === "premise challenge") {
|
|
1323
1402
|
return validatePremiseChallenge(sectionBody);
|
|
1324
1403
|
}
|
|
1404
|
+
if (sectionNameNormalized === "requirements") {
|
|
1405
|
+
return validateRequirementsTaxonomy(sectionBody);
|
|
1406
|
+
}
|
|
1325
1407
|
if (sectionNameNormalized === "data flow") {
|
|
1326
1408
|
return validateInteractionEdgeCaseMatrix(sectionBody);
|
|
1327
1409
|
}
|
|
@@ -1533,31 +1615,29 @@ export async function lintArtifact(projectRoot, stage, track = "standard") {
|
|
|
1533
1615
|
}
|
|
1534
1616
|
const approachesBody = sectionBodyByName(sections, "Approaches");
|
|
1535
1617
|
if (approachesBody !== null) {
|
|
1536
|
-
const
|
|
1537
|
-
const bulletRows = approachesBody
|
|
1538
|
-
.split(/\r?\n/u)
|
|
1539
|
-
.map((line) => line.trim())
|
|
1540
|
-
.filter((line) => /^(?:[-*]|\d+\.)\s+\S/u.test(line));
|
|
1541
|
-
const rowCount = Math.max(tableRows.length, bulletRows.length);
|
|
1542
|
-
const approachRows = getApproachRows(approachesBody);
|
|
1543
|
-
const hasChallenger = approachRows.some(hasSemanticChallenger);
|
|
1618
|
+
const approachesTaxonomy = validateApproachesTaxonomy(approachesBody);
|
|
1544
1619
|
findings.push({
|
|
1545
1620
|
section: "Distinct Approaches Enforcement",
|
|
1546
1621
|
required: true,
|
|
1547
1622
|
rule: "Approaches section must document at least 2 distinct approaches so the Iron Law comparison is meaningful.",
|
|
1548
|
-
found: rowCount >= 2,
|
|
1549
|
-
details: rowCount >= 2
|
|
1550
|
-
? `Detected ${rowCount} approach row(s).`
|
|
1551
|
-
: `Detected ${rowCount} approach row(s); at least 2 required.`
|
|
1623
|
+
found: approachesTaxonomy.rowCount >= 2,
|
|
1624
|
+
details: approachesTaxonomy.rowCount >= 2
|
|
1625
|
+
? `Detected ${approachesTaxonomy.rowCount} approach row(s).`
|
|
1626
|
+
: `Detected ${approachesTaxonomy.rowCount} approach row(s); at least 2 required.`
|
|
1627
|
+
});
|
|
1628
|
+
findings.push({
|
|
1629
|
+
section: "Approaches Role/Upside Taxonomy",
|
|
1630
|
+
required: true,
|
|
1631
|
+
rule: "Approaches table must use canonical Role and Upside enum values.",
|
|
1632
|
+
found: approachesTaxonomy.roleUpsideOk,
|
|
1633
|
+
details: approachesTaxonomy.details
|
|
1552
1634
|
});
|
|
1553
1635
|
findings.push({
|
|
1554
1636
|
section: "Challenger Alternative Enforcement",
|
|
1555
1637
|
required: true,
|
|
1556
1638
|
rule: "Approaches must include one challenger option with explicit high/higher upside.",
|
|
1557
|
-
found:
|
|
1558
|
-
details:
|
|
1559
|
-
? "Semantic challenger with high/higher upside detected."
|
|
1560
|
-
: "Missing a challenger option with explicit high/higher upside. Example: `| C | challenger | high upside | More ambitious path with clear trade-offs |`."
|
|
1639
|
+
found: approachesTaxonomy.challengerOk,
|
|
1640
|
+
details: approachesTaxonomy.details
|
|
1561
1641
|
});
|
|
1562
1642
|
}
|
|
1563
1643
|
const reactionIndex = headingLineIndex(raw, "Approach Reaction");
|
package/dist/constants.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export declare const FLOW_VERSION = "1.0.0";
|
|
|
10
10
|
export declare const SHIP_FINALIZATION_MODES: readonly ["FINALIZE_MERGE_LOCAL", "FINALIZE_OPEN_PR", "FINALIZE_KEEP_BRANCH", "FINALIZE_DISCARD_BRANCH", "FINALIZE_NO_VCS"];
|
|
11
11
|
export type ShipFinalizationMode = (typeof SHIP_FINALIZATION_MODES)[number];
|
|
12
12
|
export declare const DEFAULT_HARNESSES: HarnessId[];
|
|
13
|
-
export declare const REQUIRED_DIRS: readonly [".cclaw", ".cclaw/commands", ".cclaw/skills", ".cclaw/templates", ".cclaw/artifacts", ".cclaw/state", ".cclaw/runs", ".cclaw/rules", ".cclaw/agents", ".cclaw/hooks"];
|
|
13
|
+
export declare const REQUIRED_DIRS: readonly [".cclaw", ".cclaw/commands", ".cclaw/skills", ".cclaw/templates", ".cclaw/templates/state-contracts", ".cclaw/artifacts", ".cclaw/state", ".cclaw/runs", ".cclaw/rules", ".cclaw/agents", ".cclaw/hooks", ".cclaw/skills/review-prompts"];
|
|
14
14
|
export declare const REQUIRED_GITIGNORE_PATTERNS: readonly ["# cclaw generated artifacts", ".cclaw/", ".claude/commands/cc-*.md", ".claude/commands/cc.md", ".cursor/commands/cc-*.md", ".cursor/commands/cc.md", ".opencode/commands/cc-*.md", ".opencode/commands/cc.md", ".agents/skills/cc/SKILL.md", ".agents/skills/cc-*/SKILL.md", ".claude/hooks/hooks.json", ".cursor/hooks.json", ".codex/hooks.json", ".opencode/plugins/cclaw-plugin.mjs", ".cursor/rules/cclaw-workflow.mdc"];
|
|
15
15
|
/**
|
|
16
16
|
* Canonical stage -> skill folder mapping.
|
package/dist/constants.js
CHANGED
|
@@ -57,12 +57,14 @@ export const REQUIRED_DIRS = [
|
|
|
57
57
|
`${RUNTIME_ROOT}/commands`,
|
|
58
58
|
`${RUNTIME_ROOT}/skills`,
|
|
59
59
|
`${RUNTIME_ROOT}/templates`,
|
|
60
|
+
`${RUNTIME_ROOT}/templates/state-contracts`,
|
|
60
61
|
`${RUNTIME_ROOT}/artifacts`,
|
|
61
62
|
`${RUNTIME_ROOT}/state`,
|
|
62
63
|
`${RUNTIME_ROOT}/runs`,
|
|
63
64
|
`${RUNTIME_ROOT}/rules`,
|
|
64
65
|
`${RUNTIME_ROOT}/agents`,
|
|
65
|
-
`${RUNTIME_ROOT}/hooks
|
|
66
|
+
`${RUNTIME_ROOT}/hooks`,
|
|
67
|
+
`${RUNTIME_ROOT}/skills/review-prompts`
|
|
66
68
|
];
|
|
67
69
|
export const REQUIRED_GITIGNORE_PATTERNS = [
|
|
68
70
|
"# cclaw generated artifacts",
|
package/dist/content/examples.js
CHANGED
|
@@ -31,11 +31,11 @@ const STAGE_EXAMPLES = {
|
|
|
31
31
|
|
|
32
32
|
## Approaches
|
|
33
33
|
|
|
34
|
-
| Approach | Role | Architecture | Trade-offs | Recommendation |
|
|
35
|
-
| --- | --- | --- | --- | --- |
|
|
36
|
-
| A: Reusable validation module | baseline | Shared TS module with typed validators, imported by CI scripts and local CLI. Existing \`pre-publish.sh\` calls the module. | Medium upfront effort, high reuse. Requires test coverage for the module. | **Recommended** — best balance of reuse and delivery speed. |
|
|
37
|
-
| B: Hardened shell scripts |
|
|
38
|
-
| C: Full release framework | challenger
|
|
34
|
+
| Approach | Role | Upside | Architecture | Trade-offs | Recommendation |
|
|
35
|
+
| --- | --- | --- | --- | --- | --- |
|
|
36
|
+
| A: Reusable validation module | baseline | high | Shared TS module with typed validators, imported by CI scripts and local CLI. Existing \`pre-publish.sh\` calls the module. | Medium upfront effort, high reuse. Requires test coverage for the module. | **Recommended** — best balance of reuse and delivery speed. |
|
|
37
|
+
| B: Hardened shell scripts | baseline | modest | Keep existing script approach, add stricter checks and error messages. | Lowest effort. Weak reuse, CI/local divergence risk grows over time. | Viable fallback if TS module is blocked. |
|
|
38
|
+
| C: Full release framework | challenger | higher | New release orchestrator with plugin system, config files, rollback commands. | Maximum flexibility. High risk, delivery delay, over-engineered for current needs. | Not recommended for v1. |
|
|
39
39
|
|
|
40
40
|
## Approach Reaction
|
|
41
41
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const REVIEW_PROMPTS: Record<string, string>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
export const REVIEW_PROMPTS = {
|
|
2
|
+
"brainstorm-self-review.md": `# Brainstorm Self-Review Prompt
|
|
3
|
+
|
|
4
|
+
Use this before asking the user to approve the brainstorm artifact.
|
|
5
|
+
|
|
6
|
+
## Calibration
|
|
7
|
+
|
|
8
|
+
Only flag issues that would cause a real downstream scope/design mistake:
|
|
9
|
+
wrong problem, no real alternative, hidden scope growth, missing user reaction,
|
|
10
|
+
or a recommendation that does not trace to the user's answer.
|
|
11
|
+
|
|
12
|
+
Do not flag prose style, wording preferences, section length, or missing detail
|
|
13
|
+
that would not change the scope/design decision.
|
|
14
|
+
|
|
15
|
+
## Checks
|
|
16
|
+
|
|
17
|
+
| Category | What to check |
|
|
18
|
+
|---|---|
|
|
19
|
+
| Premise | Is this the right problem and the direct path? |
|
|
20
|
+
| Alternatives | Are there 2-3 meaningfully different options, including exactly one challenger with high/higher upside? |
|
|
21
|
+
| User reaction | Does the selected direction trace to the user's reaction/concerns? |
|
|
22
|
+
| Scope protection | Does the Not Doing list prevent silent enlargement? |
|
|
23
|
+
| Handoff | Is the next-stage handoff explicit and track-aware? |
|
|
24
|
+
|
|
25
|
+
## Output
|
|
26
|
+
|
|
27
|
+
Write the result into \`## Self-Review Notes\`:
|
|
28
|
+
|
|
29
|
+
\`\`\`markdown
|
|
30
|
+
- Status: Approved | Issues Found
|
|
31
|
+
- Patches applied:
|
|
32
|
+
- <specific patch or None>
|
|
33
|
+
- Remaining concerns:
|
|
34
|
+
- <concern or None>
|
|
35
|
+
\`\`\`
|
|
36
|
+
`,
|
|
37
|
+
"scope-ceo-review.md": `# Scope CEO Review Prompt
|
|
38
|
+
|
|
39
|
+
Use this after drafting scope boundaries and before user approval.
|
|
40
|
+
|
|
41
|
+
## Calibration
|
|
42
|
+
|
|
43
|
+
Think like a founder reviewing whether this is the right product slice. Flag
|
|
44
|
+
only issues that would materially change scope, sequencing, leverage, or user
|
|
45
|
+
value. Do not nitpick wording.
|
|
46
|
+
|
|
47
|
+
## Checks
|
|
48
|
+
|
|
49
|
+
| Category | What to check |
|
|
50
|
+
|---|---|
|
|
51
|
+
| Premise | Are we solving the right problem now? |
|
|
52
|
+
| Leverage | Are we using existing code, constraints, and platform strengths? |
|
|
53
|
+
| 10-star delta | Is there a better high-leverage scope move worth cherry-picking? |
|
|
54
|
+
| Boundary | Are accepted, deferred, and excluded items unambiguous? |
|
|
55
|
+
| Mode fit | Does the selected mode match the evidence: SCOPE EXPANSION, SELECTIVE EXPANSION, HOLD SCOPE, or SCOPE REDUCTION? |
|
|
56
|
+
| Downstream refs | Are R-IDs and LD#hash anchors ready for design/spec/plan? |
|
|
57
|
+
|
|
58
|
+
## Output
|
|
59
|
+
|
|
60
|
+
Record in \`## Outside Voice Findings\` or \`## Spec Review Loop\`:
|
|
61
|
+
|
|
62
|
+
\`\`\`markdown
|
|
63
|
+
| ID | Dimension | Finding | Disposition | Rationale |
|
|
64
|
+
|---|---|---|---|---|
|
|
65
|
+
| CEO-1 | <dimension> | <issue> | accept/reject/defer | <why> |
|
|
66
|
+
\`\`\`
|
|
67
|
+
`,
|
|
68
|
+
"design-eng-review.md": `# Design Engineering Review Prompt
|
|
69
|
+
|
|
70
|
+
Use this after drafting design and before handing to spec.
|
|
71
|
+
|
|
72
|
+
## Calibration
|
|
73
|
+
|
|
74
|
+
Think like a senior engineer reviewing whether implementation can proceed
|
|
75
|
+
without hidden architecture risk. Flag only issues that would cause wrong code,
|
|
76
|
+
rework, missing failure behavior, or unverifiable acceptance criteria.
|
|
77
|
+
|
|
78
|
+
## Checks
|
|
79
|
+
|
|
80
|
+
| Category | What to check |
|
|
81
|
+
|---|---|
|
|
82
|
+
| Architecture | Are component boundaries concrete and aligned with scope? |
|
|
83
|
+
| Data flow | Are inputs, outputs, persistence, and async/sync edges explicit? |
|
|
84
|
+
| Failure modes | Does every meaningful failure have detection, rescue, and user-visible behavior? |
|
|
85
|
+
| Traceability | Do design decisions reference relevant R-IDs and LD#hash anchors? |
|
|
86
|
+
| Verification | Is each risky choice testable by spec/plan/TDD? |
|
|
87
|
+
| Overbuild | Is any architecture stronger than the locked scope actually needs? |
|
|
88
|
+
|
|
89
|
+
## Output
|
|
90
|
+
|
|
91
|
+
Record findings in the design artifact's review section:
|
|
92
|
+
|
|
93
|
+
\`\`\`markdown
|
|
94
|
+
## Engineering Review
|
|
95
|
+
**Status:** Approved | Issues Found
|
|
96
|
+
|
|
97
|
+
**Issues:**
|
|
98
|
+
- [R#/LD#hash]: <specific issue> — <why it matters>
|
|
99
|
+
|
|
100
|
+
**Recommendations:**
|
|
101
|
+
- <advisory item or None>
|
|
102
|
+
\`\`\`
|
|
103
|
+
`
|
|
104
|
+
};
|
package/dist/content/skills.js
CHANGED
|
@@ -30,16 +30,20 @@ Before execution:
|
|
|
30
30
|
2. Load active artifacts from \`.cclaw/artifacts/\`.
|
|
31
31
|
3. Load upstream artifacts required by this stage:
|
|
32
32
|
${readLines}
|
|
33
|
-
4.
|
|
33
|
+
4. Read the state contract for this stage from \`.cclaw/templates/state-contracts/<stage>.json\`.
|
|
34
|
+
Treat it as the machine-readable skeleton: required top-level fields,
|
|
35
|
+
closed taxonomies, and the derived markdown path. Do not validate natural-language
|
|
36
|
+
prose by regex; put semantic quality checks in the review prompts.
|
|
37
|
+
5. Extract upstream decisions, constraints, and open questions into the current
|
|
34
38
|
artifact's \`Upstream Handoff\` section when that section exists.
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
6. Before doing stage work, give a compact user-facing drift preamble: "Carrying forward: <1-3 bullets>. Drift since upstream: None / <specific drift>. Recommendation: continue / re-scope."
|
|
40
|
+
7. If you change an upstream decision, record an explicit drift reason in the
|
|
37
41
|
current artifact before continuing.
|
|
38
|
-
|
|
42
|
+
8. Confirm stage inputs:
|
|
39
43
|
${inputs}
|
|
40
|
-
|
|
44
|
+
9. Confirm required context:
|
|
41
45
|
${requiredContext}
|
|
42
|
-
|
|
46
|
+
10. Use the injected knowledge digest from session-start; only fall back to full
|
|
43
47
|
\`.cclaw/knowledge.jsonl\` when the digest is insufficient.
|
|
44
48
|
`;
|
|
45
49
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const STATE_CONTRACTS: Record<string, string>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { CCLAW_VERSION, RUNTIME_ROOT, SHIP_FINALIZATION_MODES } from "../constants.js";
|
|
2
|
+
import { FLOW_STAGES } from "../types.js";
|
|
3
|
+
const REQUIRED_TOP_LEVEL_FIELDS = {
|
|
4
|
+
brainstorm: ["stage", "selectedDirection", "approachTier", "approaches", "approval", "nextStageHandoff"],
|
|
5
|
+
scope: ["stage", "scopeMode", "requirements", "lockedDecisions", "scopeSummary", "nextStageHandoff"],
|
|
6
|
+
design: ["stage", "architecture", "dataFlow", "failureModes", "requirementRefs", "decisionRefs"],
|
|
7
|
+
spec: ["stage", "acceptanceCriteria", "requirementRefs", "designDecisionRefs"],
|
|
8
|
+
plan: ["stage", "tasks", "acceptanceCriteriaRefs", "requirementRefs", "decisionRefs", "verificationCommands"],
|
|
9
|
+
tdd: ["stage", "redEvidence", "greenEvidence", "acceptanceCriteriaRefs", "verificationCommands"],
|
|
10
|
+
review: ["stage", "finalVerdict", "findings", "acceptanceCriteriaRefs", "requirementRefs", "verificationCommands"],
|
|
11
|
+
ship: ["stage", "finalizationMode", "verificationSummary", "releaseNotesDraft"]
|
|
12
|
+
};
|
|
13
|
+
const STAGE_TAXONOMIES = {
|
|
14
|
+
brainstorm: {
|
|
15
|
+
approachTier: ["Lightweight", "Standard", "Deep"],
|
|
16
|
+
approachRole: ["baseline", "challenger", "wild-card"],
|
|
17
|
+
approachUpside: ["low", "modest", "high", "higher"]
|
|
18
|
+
},
|
|
19
|
+
scope: {
|
|
20
|
+
scopeMode: ["SCOPE EXPANSION", "SELECTIVE EXPANSION", "HOLD SCOPE", "SCOPE REDUCTION"],
|
|
21
|
+
priority: ["P0", "P1", "P2", "P3", "DROPPED"]
|
|
22
|
+
},
|
|
23
|
+
design: {
|
|
24
|
+
diagramTier: ["lightweight", "standard", "deep"],
|
|
25
|
+
edgeKind: ["sync", "async", "failure", "degraded"]
|
|
26
|
+
},
|
|
27
|
+
spec: {
|
|
28
|
+
priority: ["P0", "P1", "P2", "P3", "DROPPED"]
|
|
29
|
+
},
|
|
30
|
+
plan: {
|
|
31
|
+
taskStatus: ["pending", "in_progress", "blocked", "done", "dropped"]
|
|
32
|
+
},
|
|
33
|
+
tdd: {
|
|
34
|
+
cycleState: ["RED", "GREEN", "REFACTOR", "BLOCKED"]
|
|
35
|
+
},
|
|
36
|
+
review: {
|
|
37
|
+
finalVerdict: ["APPROVED", "APPROVED_WITH_CONCERNS", "BLOCKED"],
|
|
38
|
+
findingSeverity: ["Critical", "High", "Medium", "Low", "Info"]
|
|
39
|
+
},
|
|
40
|
+
ship: {
|
|
41
|
+
finalizationMode: [...SHIP_FINALIZATION_MODES]
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
function stateContract(stage) {
|
|
45
|
+
const stageIndex = FLOW_STAGES.indexOf(stage) + 1;
|
|
46
|
+
const stageNumber = String(stageIndex).padStart(2, "0");
|
|
47
|
+
return {
|
|
48
|
+
schemaVersion: 1,
|
|
49
|
+
contractId: `cclaw-${stage}-state`,
|
|
50
|
+
stage,
|
|
51
|
+
derivedMarkdownPath: `${RUNTIME_ROOT}/artifacts/${stageNumber}-${stage}.md`,
|
|
52
|
+
requiredTopLevelFields: REQUIRED_TOP_LEVEL_FIELDS[stage],
|
|
53
|
+
taxonomies: STAGE_TAXONOMIES[stage]
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export const STATE_CONTRACTS = Object.fromEntries(FLOW_STAGES.map((stage) => [
|
|
57
|
+
`${stage}.json`,
|
|
58
|
+
`${JSON.stringify({
|
|
59
|
+
...stateContract(stage),
|
|
60
|
+
generatedBy: "cclaw",
|
|
61
|
+
cclawVersion: CCLAW_VERSION
|
|
62
|
+
}, null, 2)}\n`
|
|
63
|
+
]));
|
package/dist/harness-adapters.js
CHANGED
|
@@ -210,6 +210,8 @@ When in doubt, prefer **non-trivial** — the quick track is opt-in and only saf
|
|
|
210
210
|
|
|
211
211
|
Knowledge capture and curation run automatically as part of stage completion
|
|
212
212
|
protocols via the internal \`learnings\` skill — no user-facing command.
|
|
213
|
+
Reusable entries land in \`.cclaw/knowledge.jsonl\` as strict JSONL with
|
|
214
|
+
\`type\`, \`trigger\`, \`action\`, and \`origin_run\` metadata.
|
|
213
215
|
|
|
214
216
|
**Stage order:** brainstorm > scope > design > spec > plan > tdd > review > ship, then closeout: retro > compound > archive.
|
|
215
217
|
\`/cc-next\` loads the right stage skill automatically and also drives post-ship closeout. Gates must pass before handoff.
|
package/dist/install.js
CHANGED
|
@@ -16,6 +16,8 @@ import { stageCompleteScript, startFlowScript, runHookCmdScript, opencodePluginJ
|
|
|
16
16
|
import { nodeHookRuntimeScript } from "./content/node-hooks.js";
|
|
17
17
|
import { META_SKILL_NAME, usingCclawSkillMarkdown } from "./content/meta-skill.js";
|
|
18
18
|
import { ARTIFACT_TEMPLATES, CURSOR_WORKFLOW_RULE_MDC, RULEBOOK_MARKDOWN, buildRulesJson } from "./content/templates.js";
|
|
19
|
+
import { STATE_CONTRACTS } from "./content/state-contracts.js";
|
|
20
|
+
import { REVIEW_PROMPTS } from "./content/review-prompts.js";
|
|
19
21
|
import { stageSkillFolder, stageSkillMarkdown } from "./content/skills.js";
|
|
20
22
|
import { LANGUAGE_RULE_PACK_DIR, LANGUAGE_RULE_PACK_FILES, LANGUAGE_RULE_PACK_GENERATORS, LEGACY_LANGUAGE_RULE_PACK_FOLDERS } from "./content/utility-skills.js";
|
|
21
23
|
import { RESEARCH_PLAYBOOKS } from "./content/research-playbooks.js";
|
|
@@ -357,6 +359,9 @@ async function writeArtifactTemplates(projectRoot) {
|
|
|
357
359
|
await Promise.all(Object.entries(ARTIFACT_TEMPLATES).map(async ([fileName, content]) => {
|
|
358
360
|
await writeFileSafe(runtimePath(projectRoot, "templates", fileName), content);
|
|
359
361
|
}));
|
|
362
|
+
await Promise.all(Object.entries(STATE_CONTRACTS).map(async ([fileName, content]) => {
|
|
363
|
+
await writeFileSafe(runtimePath(projectRoot, "templates", "state-contracts", fileName), content);
|
|
364
|
+
}));
|
|
360
365
|
}
|
|
361
366
|
async function writeSkills(projectRoot, config) {
|
|
362
367
|
const skillTrack = config?.defaultTrack ?? "standard";
|
|
@@ -379,6 +384,9 @@ async function writeSkills(projectRoot, config) {
|
|
|
379
384
|
for (const [fileName, markdown] of Object.entries(RESEARCH_PLAYBOOKS)) {
|
|
380
385
|
await writeFileSafe(runtimePath(projectRoot, "skills", "research", fileName), markdown);
|
|
381
386
|
}
|
|
387
|
+
for (const [fileName, markdown] of Object.entries(REVIEW_PROMPTS)) {
|
|
388
|
+
await writeFileSafe(runtimePath(projectRoot, "skills", "review-prompts", fileName), markdown);
|
|
389
|
+
}
|
|
382
390
|
// Language rule packs live under .cclaw/rules/lang/<pack>.md. They are opt-in:
|
|
383
391
|
// only the packs listed in config.languageRulePacks are materialised. Any
|
|
384
392
|
// legacy per-language skill folders from v0.7.0 (.cclaw/skills/language-*)
|