cclaw-cli 0.6.0 → 0.7.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/dist/cli.d.ts +4 -2
- package/dist/cli.js +33 -7
- package/dist/config.d.ts +11 -1
- package/dist/config.js +64 -4
- package/dist/content/learnings.js +70 -17
- package/dist/content/meta-skill.js +42 -5
- package/dist/content/stage-schema.d.ts +18 -1
- package/dist/content/stage-schema.js +25 -9
- package/dist/content/start-command.js +30 -7
- package/dist/content/status-command.js +28 -6
- package/dist/content/templates.js +28 -6
- package/dist/content/utility-skills.d.ts +11 -1
- package/dist/content/utility-skills.js +297 -7
- package/dist/delegation.d.ts +6 -1
- package/dist/delegation.js +3 -2
- package/dist/doctor.js +38 -1
- package/dist/install.d.ts +3 -1
- package/dist/install.js +82 -19
- package/dist/policy.js +2 -1
- package/dist/runs.d.ts +15 -0
- package/dist/runs.js +35 -1
- package/dist/types.d.ts +29 -0
- package/dist/types.js +20 -0
- package/package.json +1 -1
|
@@ -33,10 +33,22 @@ This is the **recommended way to start** working with cclaw. Use \`/cc-next\` fo
|
|
|
33
33
|
|
|
34
34
|
1. Read \`${flowPath}\`.
|
|
35
35
|
2. If flow already has completed stages beyond brainstorm, warn the user that starting a new brainstorm will reset progress. Ask for confirmation before proceeding.
|
|
36
|
-
3.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
3. **Track heuristic** — classify the idea text and **recommend** a track (the user can override before any state mutation):
|
|
37
|
+
- **quick** (\`spec → tdd → review → ship\`) — single-purpose work where the spec is essentially already known.
|
|
38
|
+
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\`.
|
|
39
|
+
- **standard** (full 8 stages — default) — anything that introduces a new capability, touches multiple modules, or has unclear scope.
|
|
40
|
+
Triggers: \`new feature\`, \`add\`, \`build\`, \`design\`, \`refactor\`, \`migration\`, \`platform\`, \`architecture\`, \`endpoint\`, \`schema\`, \`api\`, \`integrate\`, \`workflow\`, \`onboarding\`, or any prompt that does not match quick triggers.
|
|
41
|
+
- When triggers conflict (e.g. "small refactor that touches 5 modules") prefer **standard** — quick is opt-in and only safe when scope is genuinely tiny.
|
|
42
|
+
4. Present the recommendation as a single decision with explicit options:
|
|
43
|
+
> \`Recommended track: <quick|standard>\` because \`<one-line reason citing matched triggers>\`.
|
|
44
|
+
> Override? (A) keep \`<recommended>\` (B) switch to \`<other>\` (C) cancel.
|
|
45
|
+
If \`AskQuestion\`/\`AskUserQuestion\` is available, send exactly ONE question; on schema error, fall back to plain text.
|
|
46
|
+
5. Persist the chosen track to \`${flowPath}\` (\`track\` field). Compute \`skippedStages\` from the track and write that too. Use the **first stage of the chosen track** as \`currentStage\` (quick → \`spec\`, standard → \`brainstorm\`).
|
|
47
|
+
6. Write the prompt to \`.cclaw/artifacts/00-idea.md\` as the raw idea capture, and append a \`Track:\` line referencing the chosen track and the matched heuristic.
|
|
48
|
+
7. Load the **first-stage skill for the chosen track** and its command file:
|
|
49
|
+
- quick → \`.cclaw/skills/specification-authoring/SKILL.md\` + \`.cclaw/commands/spec.md\`
|
|
50
|
+
- standard → \`.cclaw/skills/brainstorming/SKILL.md\` + \`.cclaw/commands/brainstorm.md\`
|
|
51
|
+
8. Execute that stage with the prompt as initial context.
|
|
40
52
|
|
|
41
53
|
### Without prompt (\`/cc\`)
|
|
42
54
|
|
|
@@ -81,9 +93,20 @@ Do **not** silently discard an existing flow when the user provides a prompt. If
|
|
|
81
93
|
- Inform: "You have an active flow at stage **{currentStage}** with {N} completed stages. Starting a new brainstorm will reset progress."
|
|
82
94
|
- Ask: "Continue with reset? (A) Yes, start fresh (B) No, resume current flow"
|
|
83
95
|
- If (B) → switch to Path B behavior.
|
|
84
|
-
3.
|
|
85
|
-
|
|
86
|
-
|
|
96
|
+
3. **Classify the idea** using the heuristic below and present a single track recommendation. Wait for explicit confirmation or override before mutating any state.
|
|
97
|
+
|
|
98
|
+
**Track heuristic** (lowercase substring match against the user prompt):
|
|
99
|
+
|
|
100
|
+
| Track | Triggers | Use when |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| \`quick\` | \`bug\`, \`bugfix\`, \`fix\`, \`hotfix\`, \`patch\`, \`typo\`, \`regression\`, \`rename\`, \`bump\`, \`upgrade dep\`, \`docs only\`, \`comment\`, \`lint\`, \`format\`, \`small\`, \`tiny\`, \`one-liner\`, \`revert\`, \`copy change\` | Single-purpose, spec is essentially known, low blast radius |
|
|
103
|
+
| \`standard\` | \`new feature\`, \`add\`, \`build\`, \`design\`, \`refactor\`, \`migration\`, \`platform\`, \`architecture\`, \`endpoint\`, \`schema\`, \`api\`, \`integrate\`, \`workflow\`, \`onboarding\` (or no quick trigger matched) | Anything new, multi-module, or unclear scope |
|
|
104
|
+
|
|
105
|
+
- On conflict, prefer \`standard\` (quick is opt-in for genuinely tiny work).
|
|
106
|
+
- Always state the recommendation as a one-line reason citing the matched trigger.
|
|
107
|
+
4. Persist the chosen track in \`${flowPath}\` (\`track\` + \`skippedStages\`). Set \`currentStage\` to the first stage of the chosen track (\`quick\` → \`spec\`, \`standard\` → \`brainstorm\`). Reset gate catalog.
|
|
108
|
+
5. Write \`${RUNTIME_ROOT}/artifacts/00-idea.md\` with the user's prompt and an explicit \`Track:\` line capturing the heuristic decision.
|
|
109
|
+
6. Load and execute the **first stage skill of the chosen track** (\`brainstorming\` for standard, \`specification-authoring\` for quick) plus its matching command file.
|
|
87
110
|
|
|
88
111
|
### Path B: \`/cc\` (no arguments)
|
|
89
112
|
|
|
@@ -10,6 +10,15 @@ function delegationLogPath() {
|
|
|
10
10
|
function knowledgePath() {
|
|
11
11
|
return `${RUNTIME_ROOT}/knowledge.md`;
|
|
12
12
|
}
|
|
13
|
+
function contextModePath() {
|
|
14
|
+
return `${RUNTIME_ROOT}/state/context-mode.json`;
|
|
15
|
+
}
|
|
16
|
+
function checkpointPath() {
|
|
17
|
+
return `${RUNTIME_ROOT}/state/checkpoint.json`;
|
|
18
|
+
}
|
|
19
|
+
function stageActivityPath() {
|
|
20
|
+
return `${RUNTIME_ROOT}/state/stage-activity.jsonl`;
|
|
21
|
+
}
|
|
13
22
|
/**
|
|
14
23
|
* Command contract for /cc-status — a read-only snapshot command.
|
|
15
24
|
* Does not mutate state. Always safe to run.
|
|
@@ -39,9 +48,15 @@ time to answer "where are we?" without advancing the flow.
|
|
|
39
48
|
\`skippedStages\`, and per-stage gate catalog.
|
|
40
49
|
2. Read **\`${delegationPath}\`** — count delegated / completed / waived / pending entries
|
|
41
50
|
for the current stage's \`mandatoryDelegations\`.
|
|
42
|
-
3. Read
|
|
51
|
+
3. Read **\`${contextModePath()}\`** — surface \`activeMode\` (default if missing).
|
|
52
|
+
4. Compute **time in current stage** from the most recent stage-entry signal:
|
|
53
|
+
- Prefer \`${checkpointPath()}\`'s \`timestamp\` when its \`stage\` matches \`currentStage\`.
|
|
54
|
+
- Otherwise scan \`${stageActivityPath()}\` from the end for the first entry whose \`stage\` matches \`currentStage\` and use its \`ts\`.
|
|
55
|
+
- Compute the duration as \`now - signalTimestamp\` and render compactly: \`<X>m\`, \`<X>h<Y>m\`, or \`<X>d<Y>h\`.
|
|
56
|
+
- If no signal exists, render \`(unknown)\`.
|
|
57
|
+
5. Read the top of **\`${knowledgePath}\`** — surface up to 3 most recent entries
|
|
43
58
|
(by trailing timestamp or source marker).
|
|
44
|
-
|
|
59
|
+
6. Emit the status block described below. Do **not** load any stage skill.
|
|
45
60
|
|
|
46
61
|
## Status Block Format
|
|
47
62
|
|
|
@@ -49,6 +64,8 @@ time to answer "where are we?" without advancing the flow.
|
|
|
49
64
|
cclaw status
|
|
50
65
|
track: <quick|standard>
|
|
51
66
|
current stage: <stage> (<N>/<total> in track)
|
|
67
|
+
time in stage: <Xd Yh | Yh Zm | Zm | unknown>
|
|
68
|
+
context mode: <activeMode> (default | execution | review | incident | …)
|
|
52
69
|
completed stages: <list or "none">
|
|
53
70
|
skipped stages: <list or "none">
|
|
54
71
|
|
|
@@ -109,11 +126,16 @@ a read-only command.
|
|
|
109
126
|
|
|
110
127
|
1. Read \`${flowPath}\`. If missing → report **BLOCKED: flow state absent** and suggest \`cclaw init\`.
|
|
111
128
|
2. Read \`${delegationPath}\`. Missing → treat all mandatory delegations as pending.
|
|
112
|
-
3. Read \`${
|
|
113
|
-
4.
|
|
129
|
+
3. Read \`${contextModePath()}\` for \`activeMode\`. Missing → render \`activeMode = default\`.
|
|
130
|
+
4. Compute **time in stage**:
|
|
131
|
+
- Prefer \`${checkpointPath()}\` when \`stage === currentStage\` and \`timestamp\` parses as ISO 8601.
|
|
132
|
+
- Else scan \`${stageActivityPath()}\` from tail for the most recent entry whose \`stage === currentStage\`; use its \`ts\`.
|
|
133
|
+
- Render \`<X>d<Y>h\`, \`<X>h<Y>m\`, \`<X>m\`, or \`(unknown)\`.
|
|
134
|
+
5. Read \`${RUNTIME_ROOT}/knowledge.md\`. If missing or empty → knowledge highlights are \`(none recorded)\`.
|
|
135
|
+
6. For each gate in \`stageGateCatalog[currentStage].required\`:
|
|
114
136
|
- Satisfied if present in \`passed\` and absent from \`blocked\`.
|
|
115
|
-
|
|
116
|
-
|
|
137
|
+
7. Build and print the status block (see command contract for layout).
|
|
138
|
+
8. Suggest the next action:
|
|
117
139
|
- If current stage has unmet gates → \`/cc-next\` to resume.
|
|
118
140
|
- If current stage is complete → \`/cc-next\` to advance (or report "Flow complete" if terminal).
|
|
119
141
|
|
|
@@ -345,12 +345,34 @@ Execution rule: complete and verify each wave before starting the next wave.
|
|
|
345
345
|
- Reconciliation summary:
|
|
346
346
|
|
|
347
347
|
## Review Readiness Dashboard
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
-
|
|
352
|
-
-
|
|
353
|
-
-
|
|
348
|
+
|
|
349
|
+
| Pass | Status | Completed at (UTC) | Reviewer / source | Commit at review | Drift vs HEAD |
|
|
350
|
+
|---|---|---|---|---|---|
|
|
351
|
+
| Layer 1 — spec compliance | pass / fail / pending | <ISO 8601> | spec-reviewer | <short sha> | <files changed since> |
|
|
352
|
+
| Layer 2 — correctness | pass / fail / pending | <ISO 8601> | code-reviewer | <short sha> | <files changed since> |
|
|
353
|
+
| Layer 2 — security | pass / fail / pending | <ISO 8601> | security-reviewer | <short sha> | <files changed since> |
|
|
354
|
+
| Layer 2 — performance | pass / fail / pending | <ISO 8601> | code-reviewer | <short sha> | <files changed since> |
|
|
355
|
+
| Layer 2 — architecture | pass / fail / pending | <ISO 8601> | code-reviewer | <short sha> | <files changed since> |
|
|
356
|
+
| Adversarial review | pass / fail / n/a | <ISO 8601 or —> | adversarial-review skill | <short sha or —> | <drift or —> |
|
|
357
|
+
| Review army schema valid | pass / fail | <ISO 8601> | jsonschema | <short sha> | n/a |
|
|
358
|
+
|
|
359
|
+
### Delegation log snapshot (current run, current stage)
|
|
360
|
+
- Path: \`.cclaw/state/delegation-log.json\`
|
|
361
|
+
- Required: <list of mandatory specialists>
|
|
362
|
+
- Completed: <list with timestamps>
|
|
363
|
+
- Waived (with reason): <list or "none">
|
|
364
|
+
- Pending: <list or "none">
|
|
365
|
+
|
|
366
|
+
### Staleness signal
|
|
367
|
+
- Worktree commit at last review pass: \`<short sha>\`
|
|
368
|
+
- Worktree commit now: \`<short sha>\`
|
|
369
|
+
- Files changed since last review pass: \`<count>\` (run \`git diff --stat <sha>..HEAD\` to inspect)
|
|
370
|
+
- If drift > 0 lines, mark Layer 1 / Layer 2 results as **STALE — re-run before ship**.
|
|
371
|
+
|
|
372
|
+
### Headline
|
|
373
|
+
- Open critical blockers: <count>
|
|
374
|
+
- Adversarial review pass: pass / fail / n/a
|
|
375
|
+
- Ship recommendation: APPROVED | APPROVED_WITH_CONCERNS | BLOCKED
|
|
354
376
|
|
|
355
377
|
## Completeness Score
|
|
356
378
|
- AC coverage: <N>/<M> (<percent>%)
|
|
@@ -16,5 +16,15 @@ export declare function landscapeCheckSkill(): string;
|
|
|
16
16
|
export declare function knowledgeCurationSkill(): string;
|
|
17
17
|
export declare function securityAuditSkill(): string;
|
|
18
18
|
export declare function adversarialReviewSkill(): string;
|
|
19
|
-
export declare
|
|
19
|
+
export declare function retrospectiveSkill(): string;
|
|
20
|
+
export declare function languageTypescriptSkill(): string;
|
|
21
|
+
export declare function languagePythonSkill(): string;
|
|
22
|
+
export declare function languageGoSkill(): string;
|
|
23
|
+
export declare const LANGUAGE_RULE_PACK_FOLDERS: {
|
|
24
|
+
readonly typescript: "language-typescript";
|
|
25
|
+
readonly python: "language-python";
|
|
26
|
+
readonly go: "language-go";
|
|
27
|
+
};
|
|
28
|
+
export declare const LANGUAGE_RULE_PACK_GENERATORS: Record<string, () => string>;
|
|
29
|
+
export declare const UTILITY_SKILL_FOLDERS: readonly ["security", "debugging", "performance", "ci-cd", "docs", "executing-plans", "context-engineering", "source-driven-development", "frontend-accessibility", "landscape-check", "adversarial-review", "security-audit", "knowledge-curation", "retrospective"];
|
|
20
30
|
export declare const UTILITY_SKILL_MAP: Record<string, () => string>;
|
|
@@ -751,23 +751,22 @@ candidates exist).
|
|
|
751
751
|
export function knowledgeCurationSkill() {
|
|
752
752
|
return `---
|
|
753
753
|
name: knowledge-curation
|
|
754
|
-
description: "Read-only curation pass over .cclaw/knowledge.md. Surfaces stale, duplicate, or low-confidence entries and proposes a soft-archive plan; never deletes without explicit user approval."
|
|
754
|
+
description: "Read-only curation pass over .cclaw/knowledge.md and .cclaw/knowledge.jsonl. Surfaces stale, duplicate, or low-confidence entries and proposes a soft-archive plan; never deletes without explicit user approval."
|
|
755
755
|
---
|
|
756
756
|
|
|
757
757
|
# Knowledge Curation
|
|
758
758
|
|
|
759
759
|
## Quick Start
|
|
760
760
|
|
|
761
|
-
> 1. This is a **read-only audit** of \`.cclaw/knowledge.md\`. Never delete or rewrite entries here.
|
|
761
|
+
> 1. This is a **read-only audit** of \`.cclaw/knowledge.md\` and, when present, \`.cclaw/knowledge.jsonl\`. Never delete or rewrite entries here.
|
|
762
762
|
> 2. Surface candidates for soft-archive when the active file > 50 entries OR contains stale/duplicate/superseded entries.
|
|
763
763
|
> 3. Propose a single archive plan and require explicit user approval before any move.
|
|
764
764
|
|
|
765
765
|
## HARD-GATE
|
|
766
766
|
|
|
767
|
-
- Do not modify \`.cclaw/knowledge.md\` from this skill except via an explicit
|
|
768
|
-
user-approved archive plan that **moves** entries to
|
|
769
|
-
\`.cclaw/knowledge.archive.md\` (never deletes them).
|
|
767
|
+
- Do not modify \`.cclaw/knowledge.md\` or \`.cclaw/knowledge.jsonl\` from this skill except via an explicit user-approved archive plan that **moves** markdown entries to \`.cclaw/knowledge.archive.md\` and appends soft-archive lines (same title, \`archived: true\`) to the JSONL. Never physically removes entries.
|
|
770
768
|
- Do not silently rewrite or summarize entries — preserve original wording.
|
|
769
|
+
- Prefer the JSONL store for queries when present (faster, structured); use the markdown mirror as the human-readable source of truth for final user approval.
|
|
771
770
|
|
|
772
771
|
## When to run
|
|
773
772
|
|
|
@@ -1069,6 +1068,295 @@ Escalate to the main review-army under the matching severity (Critical / Importa
|
|
|
1069
1068
|
- Only playing the hostile-user role and skipping operator + maintainer.
|
|
1070
1069
|
`;
|
|
1071
1070
|
}
|
|
1071
|
+
export function retrospectiveSkill() {
|
|
1072
|
+
return `---
|
|
1073
|
+
name: retrospective
|
|
1074
|
+
description: "Post-ship retrospective lens. Use after a ship to extract durable lessons (rules, patterns, accelerators) before context fades. Distinct from the inline ship Compound Step — this is a deeper, optional sweep across the whole run."
|
|
1075
|
+
---
|
|
1076
|
+
|
|
1077
|
+
# Retrospective
|
|
1078
|
+
|
|
1079
|
+
## Quick Start
|
|
1080
|
+
|
|
1081
|
+
> 1. Run **after** the ship stage closes (PR merged or release tagged), while the run is still loaded in memory.
|
|
1082
|
+
> 2. Walk the four lenses below; harvest concrete entries for \`.cclaw/knowledge.md\`.
|
|
1083
|
+
> 3. Stop when you have at least one durable entry **or** an explicit "no new lesson this run".
|
|
1084
|
+
|
|
1085
|
+
## HARD-GATE
|
|
1086
|
+
|
|
1087
|
+
Do **not** run retrospective before ship gates pass. The goal is to learn from
|
|
1088
|
+
a *closed* loop, not to evaluate work-in-progress.
|
|
1089
|
+
Do **not** invent generic platitudes ("write more tests"). Every entry must cite
|
|
1090
|
+
a concrete moment in *this* run (file, decision, blocker, surprise).
|
|
1091
|
+
|
|
1092
|
+
## When to use
|
|
1093
|
+
|
|
1094
|
+
- Right after \`/cc-next\` reports the ship stage complete.
|
|
1095
|
+
- Before starting the next \`/cc <idea>\` — fresh context, lessons captured.
|
|
1096
|
+
- After an incident or surprise during ship (rollback, hotfix, regression).
|
|
1097
|
+
|
|
1098
|
+
## When NOT to use
|
|
1099
|
+
|
|
1100
|
+
- Mid-flow (use the per-stage Operational Self-Improvement block instead).
|
|
1101
|
+
- For trivial changes (typo fix, config bump) — the Compound Step in the
|
|
1102
|
+
ship template is enough.
|
|
1103
|
+
|
|
1104
|
+
## Four Lenses
|
|
1105
|
+
|
|
1106
|
+
For each lens, write either a knowledge entry **or** the explicit string
|
|
1107
|
+
"no new lesson". Skipping a lens silently is forbidden.
|
|
1108
|
+
|
|
1109
|
+
### 1. What surprised us?
|
|
1110
|
+
|
|
1111
|
+
- A bug that hid in a place no one suspected → \`[lesson]\`.
|
|
1112
|
+
- A test that passed but missed a real failure mode → \`[lesson]\`.
|
|
1113
|
+
- A library/API behavior that contradicted our mental model → \`[rule]\`.
|
|
1114
|
+
|
|
1115
|
+
### 2. What slowed us down?
|
|
1116
|
+
|
|
1117
|
+
- Repeated context loss between waves → \`[compound]\` accelerator.
|
|
1118
|
+
- Re-derivation of a fact already in upstream artifacts → \`[pattern]\` "re-read X first".
|
|
1119
|
+
- Tooling friction (slow test loop, flaky CI) → \`[compound]\` follow-up.
|
|
1120
|
+
|
|
1121
|
+
### 3. What worked unreasonably well?
|
|
1122
|
+
|
|
1123
|
+
- A refactor that unlocked the next 3 tasks → \`[pattern]\`.
|
|
1124
|
+
- A skill/agent invocation that nailed it on first try → \`[pattern]\` (record the prompt shape).
|
|
1125
|
+
- Adopting an existing solution instead of building → \`[rule]\` reinforcement.
|
|
1126
|
+
|
|
1127
|
+
### 4. What would we do differently next time?
|
|
1128
|
+
|
|
1129
|
+
- Architectural decision that aged poorly within the same run → \`[lesson]\`.
|
|
1130
|
+
- Scope mode chosen incorrectly → \`[rule]\` heuristic update.
|
|
1131
|
+
- Order-of-operations mistake (e.g. spec drift before tdd) → \`[pattern]\` ordering.
|
|
1132
|
+
|
|
1133
|
+
## Output protocol
|
|
1134
|
+
|
|
1135
|
+
For every harvested insight, append one entry to \`.cclaw/knowledge.md\` using
|
|
1136
|
+
the standard format (see \`learnings\` skill). Prefer:
|
|
1137
|
+
|
|
1138
|
+
- \`[compound]\` for process/speed accelerators.
|
|
1139
|
+
- \`[lesson]\` for "we learned this the hard way".
|
|
1140
|
+
- \`[pattern]\` for repeatable shapes that worked.
|
|
1141
|
+
- \`[rule]\` only for hard constraints that must always hold.
|
|
1142
|
+
|
|
1143
|
+
Then write a one-paragraph **Run Summary** at the top of the next
|
|
1144
|
+
\`/cc <idea>\` brainstorm context citing the lessons in scope.
|
|
1145
|
+
|
|
1146
|
+
## Anti-patterns
|
|
1147
|
+
|
|
1148
|
+
- Retrospective as performance review — frame is *system improvement*, not blame.
|
|
1149
|
+
- Harvesting only positive ("what worked") and skipping uncomfortable lessons.
|
|
1150
|
+
- Writing entries so generic they could apply to any project.
|
|
1151
|
+
- Letting the retrospective drift into a re-design of the shipped feature.
|
|
1152
|
+
`;
|
|
1153
|
+
}
|
|
1154
|
+
export function languageTypescriptSkill() {
|
|
1155
|
+
return `---
|
|
1156
|
+
name: language-typescript
|
|
1157
|
+
description: "TypeScript rule pack. Opt-in language lens. Use when reviewing or writing TypeScript/JavaScript diffs during tdd or review — enforces type-safety, runtime-boundary validation, and idiomatic patterns."
|
|
1158
|
+
---
|
|
1159
|
+
|
|
1160
|
+
# TypeScript Rule Pack
|
|
1161
|
+
|
|
1162
|
+
## Quick Start
|
|
1163
|
+
|
|
1164
|
+
> 1. Activate during tdd or review whenever the diff touches \`.ts\`, \`.tsx\`, \`.mts\`, \`.cts\`, or \`.js\` files.
|
|
1165
|
+
> 2. Walk the rule tiers in order. Tier-1 violations block merge. Tier-2 need a named follow-up.
|
|
1166
|
+
> 3. Cite each finding as \`file:line — <rule id> — <one-line remediation>\`.
|
|
1167
|
+
|
|
1168
|
+
## HARD-GATE
|
|
1169
|
+
|
|
1170
|
+
Do not approve a TypeScript change that ships \`any\`, \`@ts-ignore\`, or
|
|
1171
|
+
\`@ts-expect-error\` *without* (a) a comment explaining why, (b) a linked issue,
|
|
1172
|
+
and (c) an assertion that the blast radius is bounded to the current file.
|
|
1173
|
+
No exceptions in production code paths.
|
|
1174
|
+
|
|
1175
|
+
## Tier 1 — blocking rules
|
|
1176
|
+
|
|
1177
|
+
1. **No silent \`any\`.** Unknown inputs must be typed as \`unknown\` first, then narrowed.
|
|
1178
|
+
2. **Runtime validate trust boundaries.** HTTP bodies, env vars, file contents, and
|
|
1179
|
+
IPC payloads must be parsed through a schema validator (zod, valibot, io-ts) before
|
|
1180
|
+
being treated as typed data.
|
|
1181
|
+
3. **No \`as\` without a narrowing reason.** \`value as Foo\` is only acceptable when
|
|
1182
|
+
preceded by a runtime check that proves the shape (e.g. \`if ("id" in value)\`).
|
|
1183
|
+
4. **Exhaustive switches on discriminated unions.** Every \`switch\` on a tagged
|
|
1184
|
+
union must end with a \`default\` branch that assigns to \`never\` to surface
|
|
1185
|
+
missing cases at compile time.
|
|
1186
|
+
5. **Promise hygiene.** No unawaited promises in \`async\` functions; no
|
|
1187
|
+
\`void promise\` unless documented. Use \`@typescript-eslint/no-floating-promises\`.
|
|
1188
|
+
6. **Null-safety at the boundary.** Optional chaining (\`?.\`) and nullish
|
|
1189
|
+
coalescing (\`??\`) must only be used when the null path is handled, not as a
|
|
1190
|
+
silent default.
|
|
1191
|
+
|
|
1192
|
+
## Tier 2 — follow-up rules
|
|
1193
|
+
|
|
1194
|
+
7. Prefer \`readonly\` for arrays/object fields that are not mutated.
|
|
1195
|
+
8. Prefer \`type\` aliases for unions, \`interface\` for extendable object shapes.
|
|
1196
|
+
9. Name generic parameters descriptively once they carry semantic meaning (\`TEvent\`, \`TPayload\`).
|
|
1197
|
+
10. Avoid re-exporting entire namespaces; named re-exports keep bundle analysis tractable.
|
|
1198
|
+
11. Co-locate test fixtures with their types to keep drift visible.
|
|
1199
|
+
|
|
1200
|
+
## Anti-patterns
|
|
1201
|
+
|
|
1202
|
+
- "It compiles, ship it" — compilation is necessary, not sufficient. Runtime boundary validation is the gate.
|
|
1203
|
+
- Casting library return types to tighten them without reading the library's actual contract.
|
|
1204
|
+
- Wrapping every function in \`try/catch\` and swallowing the error — errors must either be rethrown typed or mapped to a Result/Either shape.
|
|
1205
|
+
- Using enums where a string-literal union would do (enums carry runtime cost and erase at tree-shaking time only when \`const\`).
|
|
1206
|
+
|
|
1207
|
+
## Review output shape
|
|
1208
|
+
|
|
1209
|
+
\`\`\`
|
|
1210
|
+
- **Rule:** T1-2 (runtime validate trust boundaries)
|
|
1211
|
+
- **File:line:** src/api/users.ts:42
|
|
1212
|
+
- **Finding:** POST body cast directly to \`UserCreateInput\`; no schema parse.
|
|
1213
|
+
- **Remediation:** Parse through \`userCreateSchema\` (zod) before passing to the service layer.
|
|
1214
|
+
\`\`\`
|
|
1215
|
+
`;
|
|
1216
|
+
}
|
|
1217
|
+
export function languagePythonSkill() {
|
|
1218
|
+
return `---
|
|
1219
|
+
name: language-python
|
|
1220
|
+
description: "Python rule pack. Opt-in language lens. Use when reviewing or writing Python diffs during tdd or review — enforces typing, exception hygiene, and idiomatic patterns."
|
|
1221
|
+
---
|
|
1222
|
+
|
|
1223
|
+
# Python Rule Pack
|
|
1224
|
+
|
|
1225
|
+
## Quick Start
|
|
1226
|
+
|
|
1227
|
+
> 1. Activate during tdd or review whenever the diff touches \`.py\` / \`.pyi\` files.
|
|
1228
|
+
> 2. Walk the rule tiers in order. Tier-1 violations block merge. Tier-2 need a named follow-up.
|
|
1229
|
+
> 3. Cite each finding as \`file:line — <rule id> — <one-line remediation>\`.
|
|
1230
|
+
|
|
1231
|
+
## HARD-GATE
|
|
1232
|
+
|
|
1233
|
+
Do not approve a Python change that catches bare \`except:\` or \`except Exception:\`
|
|
1234
|
+
in production code *without* (a) re-raising, (b) logging with \`logger.exception\`, or
|
|
1235
|
+
(c) a comment explaining the intentional swallow. Silent broad catches are the
|
|
1236
|
+
single biggest source of "works on my machine" bugs in Python services.
|
|
1237
|
+
|
|
1238
|
+
## Tier 1 — blocking rules
|
|
1239
|
+
|
|
1240
|
+
1. **Type hints on public APIs.** Every exported function, method, and dataclass
|
|
1241
|
+
must have full type hints. Use \`from __future__ import annotations\` or PEP 604 union syntax.
|
|
1242
|
+
2. **No mutable default arguments.** \`def f(x=[])\` is a bug. Use \`None\` + inline default.
|
|
1243
|
+
3. **Exception specificity.** Catch the narrowest exception class you actually handle.
|
|
1244
|
+
4. **Context managers for resources.** Files, sockets, DB sessions, locks — always \`with\`.
|
|
1245
|
+
5. **No bare \`assert\` in production code.** \`assert\` is stripped under \`python -O\`.
|
|
1246
|
+
For invariants, raise \`ValueError\`/\`RuntimeError\` explicitly.
|
|
1247
|
+
6. **Deterministic imports.** No conditional imports at module top level except for
|
|
1248
|
+
platform branches; no import-time side effects.
|
|
1249
|
+
|
|
1250
|
+
## Tier 2 — follow-up rules
|
|
1251
|
+
|
|
1252
|
+
7. Prefer \`@dataclass(slots=True, frozen=True)\` for value objects.
|
|
1253
|
+
8. Prefer \`pathlib.Path\` over \`os.path\` for new code.
|
|
1254
|
+
9. Use f-strings for interpolation; reserve \`%\` and \`.format\` for logger messages (lazy eval).
|
|
1255
|
+
10. Use \`logging.getLogger(__name__)\` per module; never the root logger.
|
|
1256
|
+
11. Pin dependency ranges in \`pyproject.toml\`; lock with \`uv lock\` / \`pip-compile\`.
|
|
1257
|
+
|
|
1258
|
+
## Async-specific
|
|
1259
|
+
|
|
1260
|
+
- Do not mix \`requests\`/sync I/O inside \`async def\`. Use \`httpx.AsyncClient\` / \`aiofiles\`.
|
|
1261
|
+
- \`asyncio.gather\` with \`return_exceptions=False\` cancels siblings on first failure — be explicit.
|
|
1262
|
+
- Every task created with \`asyncio.create_task\` must have its reference kept and awaited.
|
|
1263
|
+
|
|
1264
|
+
## Anti-patterns
|
|
1265
|
+
|
|
1266
|
+
- Using \`**kwargs\` to avoid writing a real signature.
|
|
1267
|
+
- Monkey-patching modules from tests without a \`contextlib.contextmanager\` cleanup.
|
|
1268
|
+
- Treating \`__init__.py\` as a place to run logic (imports only).
|
|
1269
|
+
- Re-inventing \`itertools\`/\`functools\` instead of using stdlib.
|
|
1270
|
+
|
|
1271
|
+
## Review output shape
|
|
1272
|
+
|
|
1273
|
+
\`\`\`
|
|
1274
|
+
- **Rule:** P1-3 (exception specificity)
|
|
1275
|
+
- **File:line:** users/service.py:88
|
|
1276
|
+
- **Finding:** \`except Exception\` around DB call silently drops integrity errors.
|
|
1277
|
+
- **Remediation:** Catch \`IntegrityError\` explicitly; re-raise everything else.
|
|
1278
|
+
\`\`\`
|
|
1279
|
+
`;
|
|
1280
|
+
}
|
|
1281
|
+
export function languageGoSkill() {
|
|
1282
|
+
return `---
|
|
1283
|
+
name: language-go
|
|
1284
|
+
description: "Go rule pack. Opt-in language lens. Use when reviewing or writing Go diffs during tdd or review — enforces error handling discipline, concurrency safety, and idiomatic patterns."
|
|
1285
|
+
---
|
|
1286
|
+
|
|
1287
|
+
# Go Rule Pack
|
|
1288
|
+
|
|
1289
|
+
## Quick Start
|
|
1290
|
+
|
|
1291
|
+
> 1. Activate during tdd or review whenever the diff touches \`.go\` files.
|
|
1292
|
+
> 2. Walk the rule tiers in order. Tier-1 violations block merge. Tier-2 need a named follow-up.
|
|
1293
|
+
> 3. Cite each finding as \`file:line — <rule id> — <one-line remediation>\`.
|
|
1294
|
+
|
|
1295
|
+
## HARD-GATE
|
|
1296
|
+
|
|
1297
|
+
Do not approve a Go change that discards an \`error\` return value with \`_ = ...\`
|
|
1298
|
+
in production code *without* a comment explaining why the error is provably
|
|
1299
|
+
irrelevant. Discarded errors are Go's #1 source of silent data loss.
|
|
1300
|
+
|
|
1301
|
+
## Tier 1 — blocking rules
|
|
1302
|
+
|
|
1303
|
+
1. **Every \`error\` is checked or explicitly wrapped with \`fmt.Errorf("%w", err)\`.**
|
|
1304
|
+
2. **No goroutine leaks.** Every \`go func()\` must have a stop condition visible in
|
|
1305
|
+
the diff: a \`context.Context\` cancellation, a \`done\` channel, or a bounded
|
|
1306
|
+
input channel that will close.
|
|
1307
|
+
3. **Context propagation.** Any function that does I/O, RPC, or long work must take
|
|
1308
|
+
\`ctx context.Context\` as the first parameter.
|
|
1309
|
+
4. **No mutex by value.** Fields of type \`sync.Mutex\` / \`sync.RWMutex\` must be
|
|
1310
|
+
pointers *or* the containing struct must be used only via pointer receivers.
|
|
1311
|
+
5. **Defer placement.** \`defer file.Close()\` must immediately follow a successful
|
|
1312
|
+
open, before any code path that can return early.
|
|
1313
|
+
6. **\`for range\` capture hygiene** (pre-Go 1.22): copy loop variables before
|
|
1314
|
+
capturing in goroutines or deferred functions. From Go 1.22+ the language fixes
|
|
1315
|
+
this, but confirm the repo's \`go\` directive in \`go.mod\`.
|
|
1316
|
+
|
|
1317
|
+
## Tier 2 — follow-up rules
|
|
1318
|
+
|
|
1319
|
+
7. Prefer small interfaces defined at the consumer site, not upstream.
|
|
1320
|
+
8. Prefer \`errors.Is\` / \`errors.As\` over string matching.
|
|
1321
|
+
9. Avoid \`init()\` except for registering with a framework.
|
|
1322
|
+
10. Use \`t.Helper()\` inside test helpers so failure lines point at the caller.
|
|
1323
|
+
11. Use \`//go:build\` tags for OS-specific code, not runtime \`runtime.GOOS\` checks.
|
|
1324
|
+
|
|
1325
|
+
## Concurrency-specific
|
|
1326
|
+
|
|
1327
|
+
- Buffered channels are a performance hint, not a correctness fix. Unbuffered first.
|
|
1328
|
+
- \`sync.WaitGroup\` \`Add\` must happen **before** \`go\`, not inside the goroutine.
|
|
1329
|
+
- \`atomic\` operations must be paired on the same variable — do not mix \`atomic.Load\`
|
|
1330
|
+
with plain reads of the same field.
|
|
1331
|
+
- Shared maps require a mutex or \`sync.Map\`; Go's race detector in CI is non-negotiable.
|
|
1332
|
+
|
|
1333
|
+
## Anti-patterns
|
|
1334
|
+
|
|
1335
|
+
- Returning \`interface{}\` / \`any\` to "keep options open" — narrow it now.
|
|
1336
|
+
- Building "smart" error types that lose the wrapped chain.
|
|
1337
|
+
- Using \`panic\` for control flow in library code (allowed only for unrecoverable invariants).
|
|
1338
|
+
- Ignoring \`go vet\` warnings because "the code works".
|
|
1339
|
+
|
|
1340
|
+
## Review output shape
|
|
1341
|
+
|
|
1342
|
+
\`\`\`
|
|
1343
|
+
- **Rule:** G1-2 (no goroutine leaks)
|
|
1344
|
+
- **File:line:** internal/worker/pool.go:57
|
|
1345
|
+
- **Finding:** \`go w.loop()\` has no stop condition; context is not threaded through.
|
|
1346
|
+
- **Remediation:** Accept \`ctx\` in \`Start\` and select on \`ctx.Done()\` inside \`loop\`.
|
|
1347
|
+
\`\`\`
|
|
1348
|
+
`;
|
|
1349
|
+
}
|
|
1350
|
+
export const LANGUAGE_RULE_PACK_FOLDERS = {
|
|
1351
|
+
typescript: "language-typescript",
|
|
1352
|
+
python: "language-python",
|
|
1353
|
+
go: "language-go"
|
|
1354
|
+
};
|
|
1355
|
+
export const LANGUAGE_RULE_PACK_GENERATORS = {
|
|
1356
|
+
"language-typescript": languageTypescriptSkill,
|
|
1357
|
+
"language-python": languagePythonSkill,
|
|
1358
|
+
"language-go": languageGoSkill
|
|
1359
|
+
};
|
|
1072
1360
|
export const UTILITY_SKILL_FOLDERS = [
|
|
1073
1361
|
"security",
|
|
1074
1362
|
"debugging",
|
|
@@ -1082,7 +1370,8 @@ export const UTILITY_SKILL_FOLDERS = [
|
|
|
1082
1370
|
"landscape-check",
|
|
1083
1371
|
"adversarial-review",
|
|
1084
1372
|
"security-audit",
|
|
1085
|
-
"knowledge-curation"
|
|
1373
|
+
"knowledge-curation",
|
|
1374
|
+
"retrospective"
|
|
1086
1375
|
];
|
|
1087
1376
|
export const UTILITY_SKILL_MAP = {
|
|
1088
1377
|
security: securityReviewSkill,
|
|
@@ -1097,5 +1386,6 @@ export const UTILITY_SKILL_MAP = {
|
|
|
1097
1386
|
"landscape-check": landscapeCheckSkill,
|
|
1098
1387
|
"adversarial-review": adversarialReviewSkill,
|
|
1099
1388
|
"security-audit": securityAuditSkill,
|
|
1100
|
-
"knowledge-curation": knowledgeCurationSkill
|
|
1389
|
+
"knowledge-curation": knowledgeCurationSkill,
|
|
1390
|
+
retrospective: retrospectiveSkill
|
|
1101
1391
|
};
|
package/dist/delegation.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { FlowStage } from "./types.js";
|
|
|
2
2
|
export type DelegationEntry = {
|
|
3
3
|
stage: string;
|
|
4
4
|
agent: string;
|
|
5
|
-
mode: "mandatory" | "proactive";
|
|
5
|
+
mode: "mandatory" | "proactive" | "conditional";
|
|
6
6
|
status: "scheduled" | "completed" | "failed" | "waived";
|
|
7
7
|
taskId?: string;
|
|
8
8
|
waiverReason?: string;
|
|
@@ -12,6 +12,11 @@ export type DelegationEntry = {
|
|
|
12
12
|
* consumers treat missing runId as unscoped (conservatively excluded from current-run checks).
|
|
13
13
|
*/
|
|
14
14
|
runId?: string;
|
|
15
|
+
/**
|
|
16
|
+
* For `conditional` rows: the trigger predicate that fired (e.g. `diff_lines_gt:100`).
|
|
17
|
+
* Recorded for audit so reviewers can see why the second pass was required.
|
|
18
|
+
*/
|
|
19
|
+
conditionTrigger?: string;
|
|
15
20
|
};
|
|
16
21
|
export type DelegationLedger = {
|
|
17
22
|
runId: string;
|
package/dist/delegation.js
CHANGED
|
@@ -14,7 +14,7 @@ function isDelegationEntry(value) {
|
|
|
14
14
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
15
15
|
return false;
|
|
16
16
|
const o = value;
|
|
17
|
-
const modeOk = o.mode === "mandatory" || o.mode === "proactive";
|
|
17
|
+
const modeOk = o.mode === "mandatory" || o.mode === "proactive" || o.mode === "conditional";
|
|
18
18
|
const statusOk = o.status === "scheduled" ||
|
|
19
19
|
o.status === "completed" ||
|
|
20
20
|
o.status === "failed" ||
|
|
@@ -26,7 +26,8 @@ function isDelegationEntry(value) {
|
|
|
26
26
|
typeof o.ts === "string" &&
|
|
27
27
|
(o.taskId === undefined || typeof o.taskId === "string") &&
|
|
28
28
|
(o.waiverReason === undefined || typeof o.waiverReason === "string") &&
|
|
29
|
-
(o.runId === undefined || typeof o.runId === "string")
|
|
29
|
+
(o.runId === undefined || typeof o.runId === "string") &&
|
|
30
|
+
(o.conditionTrigger === undefined || typeof o.conditionTrigger === "string"));
|
|
30
31
|
}
|
|
31
32
|
function parseLedger(raw, runId) {
|
|
32
33
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
package/dist/doctor.js
CHANGED
|
@@ -11,11 +11,13 @@ import { gitignoreHasRequiredPatterns } from "./gitignore.js";
|
|
|
11
11
|
import { HARNESS_ADAPTERS, CCLAW_MARKER_START, CCLAW_MARKER_END } from "./harness-adapters.js";
|
|
12
12
|
import { policyChecks } from "./policy.js";
|
|
13
13
|
import { readFlowState } from "./runs.js";
|
|
14
|
+
import { skippedStagesForTrack } from "./flow-state.js";
|
|
15
|
+
import { TRACK_STAGES } from "./types.js";
|
|
14
16
|
import { checkMandatoryDelegations } from "./delegation.js";
|
|
15
17
|
import { buildTraceMatrix } from "./trace-matrix.js";
|
|
16
18
|
import { reconcileAndWriteCurrentStageGateCatalog, verifyCompletedStagesGateClosure, verifyCurrentStageGateEvidence } from "./gate-evidence.js";
|
|
17
19
|
import { stageSkillFolder } from "./content/skills.js";
|
|
18
|
-
import { UTILITY_SKILL_FOLDERS } from "./content/utility-skills.js";
|
|
20
|
+
import { LANGUAGE_RULE_PACK_FOLDERS, UTILITY_SKILL_FOLDERS } from "./content/utility-skills.js";
|
|
19
21
|
import { CONTEXT_MODES, DEFAULT_CONTEXT_MODE } from "./content/contexts.js";
|
|
20
22
|
import { validateHookDocument } from "./hook-schema.js";
|
|
21
23
|
const execFileAsync = promisify(execFile);
|
|
@@ -406,6 +408,18 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
406
408
|
details: skillPath
|
|
407
409
|
});
|
|
408
410
|
}
|
|
411
|
+
// Opt-in language rule packs: only check presence for packs the user enabled.
|
|
412
|
+
for (const pack of parsedConfig?.languageRulePacks ?? []) {
|
|
413
|
+
const folder = LANGUAGE_RULE_PACK_FOLDERS[pack];
|
|
414
|
+
if (!folder)
|
|
415
|
+
continue;
|
|
416
|
+
const skillPath = path.join(projectRoot, RUNTIME_ROOT, "skills", folder, "SKILL.md");
|
|
417
|
+
checks.push({
|
|
418
|
+
name: `language_rule_pack:${pack}`,
|
|
419
|
+
ok: await exists(skillPath),
|
|
420
|
+
details: skillPath
|
|
421
|
+
});
|
|
422
|
+
}
|
|
409
423
|
// Agent definition files
|
|
410
424
|
for (const agent of CCLAW_AGENTS) {
|
|
411
425
|
const agentPath = path.join(projectRoot, RUNTIME_ROOT, "agents", `${agent.name}.md`);
|
|
@@ -743,6 +757,29 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
743
757
|
ok: activeRunId.length > 0,
|
|
744
758
|
details: `${RUNTIME_ROOT}/state/flow-state.json must include activeRunId`
|
|
745
759
|
});
|
|
760
|
+
const activeTrack = flowState.track ?? "standard";
|
|
761
|
+
const trackStageList = TRACK_STAGES[activeTrack];
|
|
762
|
+
const skippedFromState = Array.isArray(flowState.skippedStages) ? flowState.skippedStages : [];
|
|
763
|
+
const expectedSkipped = skippedStagesForTrack(activeTrack);
|
|
764
|
+
const skippedConsistent = expectedSkipped.length === skippedFromState.length &&
|
|
765
|
+
expectedSkipped.every((stage) => skippedFromState.includes(stage));
|
|
766
|
+
checks.push({
|
|
767
|
+
name: "flow_state:track",
|
|
768
|
+
ok: skippedConsistent,
|
|
769
|
+
details: skippedConsistent
|
|
770
|
+
? `active track "${activeTrack}" (${trackStageList.length}/${COMMAND_FILE_ORDER.length} stages: ${trackStageList.join(" → ")})${expectedSkipped.length > 0 ? `; skippedStages=${expectedSkipped.join(", ")}` : ""}`
|
|
771
|
+
: `track "${activeTrack}" expects skippedStages=[${expectedSkipped.join(", ")}] but flow-state has [${skippedFromState.join(", ")}] — run \`cclaw sync\` to repair`
|
|
772
|
+
});
|
|
773
|
+
checks.push({
|
|
774
|
+
name: "flow_state:track_completed_in_track",
|
|
775
|
+
ok: flowState.completedStages.every((stage) => trackStageList.includes(stage) || expectedSkipped.includes(stage)),
|
|
776
|
+
details: (() => {
|
|
777
|
+
const offTrack = flowState.completedStages.filter((stage) => !trackStageList.includes(stage) && !expectedSkipped.includes(stage));
|
|
778
|
+
return offTrack.length === 0
|
|
779
|
+
? `every completed stage belongs to track "${activeTrack}" or its skipped set`
|
|
780
|
+
: `completed stages contain entries outside track "${activeTrack}" and not in skipped set: ${offTrack.join(", ")}`;
|
|
781
|
+
})()
|
|
782
|
+
});
|
|
746
783
|
checks.push({
|
|
747
784
|
name: "artifacts:active_root",
|
|
748
785
|
ok: await exists(path.join(projectRoot, RUNTIME_ROOT, "artifacts")),
|
package/dist/install.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import type { FlowTrack, HarnessId } from "./types.js";
|
|
1
|
+
import type { FlowTrack, HarnessId, InitProfile } from "./types.js";
|
|
2
2
|
export interface InitOptions {
|
|
3
3
|
projectRoot: string;
|
|
4
4
|
harnesses?: HarnessId[];
|
|
5
5
|
track?: FlowTrack;
|
|
6
|
+
/** When set, pre-fills config defaults from the named profile before applying flag overrides. */
|
|
7
|
+
profile?: InitProfile;
|
|
6
8
|
}
|
|
7
9
|
export declare function initCclaw(options: InitOptions): Promise<void>;
|
|
8
10
|
export declare function syncCclaw(projectRoot: string): Promise<void>;
|