cclaw-cli 0.7.0 → 0.7.1
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/content/contracts.js +1 -1
- package/dist/content/hooks.js +6 -6
- package/dist/content/learnings.d.ts +5 -0
- package/dist/content/learnings.js +88 -104
- package/dist/content/meta-skill.js +20 -11
- package/dist/content/session-hooks.js +2 -2
- package/dist/content/skills.js +2 -2
- package/dist/content/stage-schema.js +1 -1
- package/dist/content/status-command.js +2 -2
- package/dist/content/templates.js +1 -1
- package/dist/content/utility-skills.d.ts +21 -4
- package/dist/content/utility-skills.js +63 -40
- package/dist/doctor.js +33 -9
- package/dist/install.js +21 -7
- package/dist/policy.js +3 -2
- package/dist/runs.d.ts +4 -5
- package/dist/runs.js +19 -11
- package/dist/types.d.ts +4 -4
- package/package.json +1 -1
|
@@ -34,7 +34,7 @@ ${schema.hardGate}
|
|
|
34
34
|
2. Resolve active artifact root: \`.cclaw/artifacts/\`.
|
|
35
35
|
3. Load required upstream artifacts for this stage:
|
|
36
36
|
${hydrationLines}
|
|
37
|
-
4.
|
|
37
|
+
4. Stream \`.cclaw/knowledge.jsonl\` and apply relevant JSON-line entries (strict schema: type, trigger, action, confidence, domain, stage, created, project).
|
|
38
38
|
5. Write stage output to ${writeStepPaths}.
|
|
39
39
|
6. Do NOT copy artifacts into \`.cclaw/runs/\`; archival is handled only by \`cclaw archive\`.
|
|
40
40
|
|
package/dist/content/hooks.js
CHANGED
|
@@ -51,7 +51,7 @@ SUGGESTION_MEMORY_FILE="$ROOT/${RUNTIME_ROOT}/state/suggestion-memory.json"
|
|
|
51
51
|
CONTEXT_WARNINGS_FILE="$ROOT/${RUNTIME_ROOT}/state/context-warnings.jsonl"
|
|
52
52
|
CONTEXT_MODE_FILE="$ROOT/${RUNTIME_ROOT}/state/context-mode.json"
|
|
53
53
|
CONTEXTS_DIR="$ROOT/${RUNTIME_ROOT}/contexts"
|
|
54
|
-
KNOWLEDGE_FILE="$ROOT/${RUNTIME_ROOT}/knowledge.
|
|
54
|
+
KNOWLEDGE_FILE="$ROOT/${RUNTIME_ROOT}/knowledge.jsonl"
|
|
55
55
|
META_SKILL="$ROOT/${RUNTIME_ROOT}/skills/${META_SKILL_NAME}/SKILL.md"
|
|
56
56
|
|
|
57
57
|
# --- Read flow state ---
|
|
@@ -309,7 +309,7 @@ if [ -f "$META_SKILL" ]; then
|
|
|
309
309
|
META_CONTENT=$(cat "$META_SKILL" 2>/dev/null || echo "")
|
|
310
310
|
fi
|
|
311
311
|
|
|
312
|
-
# --- Load knowledge snapshot (
|
|
312
|
+
# --- Load knowledge snapshot (canonical JSONL tail) ---
|
|
313
313
|
KNOWLEDGE_SUMMARY=""
|
|
314
314
|
if [ -f "$KNOWLEDGE_FILE" ] && [ -s "$KNOWLEDGE_FILE" ]; then
|
|
315
315
|
KNOWLEDGE_SUMMARY=$(tail -n 30 "$KNOWLEDGE_FILE" 2>/dev/null || echo "")
|
|
@@ -593,7 +593,7 @@ RUN_SYNC_NOTE="Run metadata sync removed; active artifacts stay in ${RUNTIME_ROO
|
|
|
593
593
|
|
|
594
594
|
# --- Escape for JSON ---
|
|
595
595
|
${ESCAPE_FN}
|
|
596
|
-
MSG=$(escape_json "Cclaw: session ending (stage=$STAGE, run=$ACTIVE_RUN). $CHECKPOINT_NOTE $RUN_SYNC_NOTE Before stopping: (1) confirm flow-state reflects reality, (2) ensure artifact changes match current feature intent, (3) if you discovered a non-obvious rule/pattern, append
|
|
596
|
+
MSG=$(escape_json "Cclaw: session ending (stage=$STAGE, run=$ACTIVE_RUN). $CHECKPOINT_NOTE $RUN_SYNC_NOTE Before stopping: (1) confirm flow-state reflects reality, (2) ensure artifact changes match current feature intent, (3) if you discovered a non-obvious rule/pattern, append one strict-schema JSON line to ${RUNTIME_ROOT}/knowledge.jsonl, (4) commit or revert pending changes.")
|
|
597
597
|
|
|
598
598
|
# --- Output harness-specific JSON ---
|
|
599
599
|
case "$HARNESS" in
|
|
@@ -631,7 +631,7 @@ INPUT=$(cat 2>/dev/null || echo '{}')
|
|
|
631
631
|
STATE_DIR="$ROOT/${RUNTIME_ROOT}/state"
|
|
632
632
|
STATE_FILE="$STATE_DIR/flow-state.json"
|
|
633
633
|
DELEGATION_FILE="$STATE_DIR/delegation-log.json"
|
|
634
|
-
KNOWLEDGE_FILE="$ROOT/${RUNTIME_ROOT}/knowledge.
|
|
634
|
+
KNOWLEDGE_FILE="$ROOT/${RUNTIME_ROOT}/knowledge.jsonl"
|
|
635
635
|
DIGEST_FILE="$STATE_DIR/session-digest.md"
|
|
636
636
|
DIGEST_TMP="$STATE_DIR/session-digest.md.tmp.$$"
|
|
637
637
|
|
|
@@ -786,7 +786,7 @@ export default function cclawPlugin(ctx) {
|
|
|
786
786
|
const contextModePath = join(stateDir, "context-mode.json");
|
|
787
787
|
const contextsDir = join(runtimeDir, "contexts");
|
|
788
788
|
const sessionDigestPath = join(stateDir, "session-digest.md");
|
|
789
|
-
const knowledgePath = join(runtimeDir, "knowledge.
|
|
789
|
+
const knowledgePath = join(runtimeDir, "knowledge.jsonl");
|
|
790
790
|
const metaSkillPath = join(runtimeDir, "skills/${META_SKILL_NAME}/SKILL.md");
|
|
791
791
|
|
|
792
792
|
function ensureRuntimeDirs() {
|
|
@@ -923,7 +923,7 @@ export default function cclawPlugin(ctx) {
|
|
|
923
923
|
if (knowledge.length > 0) parts.push("Knowledge snapshot (latest entries):", ...knowledge);
|
|
924
924
|
|
|
925
925
|
parts.push(
|
|
926
|
-
"If you discover a non-obvious rule or pattern, append
|
|
926
|
+
"If you discover a non-obvious rule or pattern, append one strict-schema JSON line to .cclaw/knowledge.jsonl using type: rule, pattern, lesson, or compound."
|
|
927
927
|
);
|
|
928
928
|
|
|
929
929
|
const meta = readFileText(metaSkillPath).trim();
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical JSONL field order (matches the reference spec).
|
|
3
|
+
* Exported for tests and any programmatic writer that wants the exact shape.
|
|
4
|
+
*/
|
|
5
|
+
export declare const KNOWLEDGE_JSONL_FIELDS: readonly ["type", "trigger", "action", "confidence", "domain", "stage", "created", "project"];
|
|
1
6
|
export declare function learnSkillMarkdown(): string;
|
|
2
7
|
export declare function learnCommandContract(): string;
|
|
3
8
|
export declare function selfImprovementBlock(stageName: string): string;
|
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
2
|
// Knowledge store content for /cc-learn and stage self-improvement prompts.
|
|
3
|
+
//
|
|
4
|
+
// The knowledge store is a single canonical JSONL file. Each line is one
|
|
5
|
+
// self-contained JSON object matching the strict schema in this module.
|
|
6
|
+
// There is no markdown mirror — cclaw is JSONL-native.
|
|
3
7
|
// ---------------------------------------------------------------------------
|
|
4
|
-
const KNOWLEDGE_PATH = ".cclaw/knowledge.
|
|
5
|
-
const
|
|
8
|
+
const KNOWLEDGE_PATH = ".cclaw/knowledge.jsonl";
|
|
9
|
+
const KNOWLEDGE_ARCHIVE_PATH = ".cclaw/knowledge.archive.jsonl";
|
|
6
10
|
const LEARN_SKILL_NAME = "learnings";
|
|
7
|
-
const LEARN_SKILL_DESCRIPTION = "Project-scoped knowledge store:
|
|
11
|
+
const LEARN_SKILL_DESCRIPTION = "Project-scoped knowledge store: append and query rule/pattern/lesson/compound entries in the canonical JSONL file at .cclaw/knowledge.jsonl. Strict schema, append-only, machine-queryable.";
|
|
12
|
+
/**
|
|
13
|
+
* Canonical JSONL field order (matches the reference spec).
|
|
14
|
+
* Exported for tests and any programmatic writer that wants the exact shape.
|
|
15
|
+
*/
|
|
16
|
+
export const KNOWLEDGE_JSONL_FIELDS = [
|
|
17
|
+
"type",
|
|
18
|
+
"trigger",
|
|
19
|
+
"action",
|
|
20
|
+
"confidence",
|
|
21
|
+
"domain",
|
|
22
|
+
"stage",
|
|
23
|
+
"created",
|
|
24
|
+
"project"
|
|
25
|
+
];
|
|
8
26
|
export function learnSkillMarkdown() {
|
|
9
27
|
return `---
|
|
10
28
|
name: ${LEARN_SKILL_NAME}
|
|
@@ -15,113 +33,81 @@ description: "${LEARN_SKILL_DESCRIPTION}"
|
|
|
15
33
|
|
|
16
34
|
## Overview
|
|
17
35
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
- \`${KNOWLEDGE_PATH}\` — human-readable, append-only markdown (the reading view).
|
|
21
|
-
- \`${KNOWLEDGE_JSONL_PATH}\` — canonical, machine-queryable JSONL (one JSON object per line). Used by the curator, /cc-status, and future analytics.
|
|
22
|
-
|
|
23
|
-
Every \`/cc-learn add\` appends to **both** files. \`/cc-learn search\` prefers the JSONL store if it exists; otherwise it falls back to the markdown file.
|
|
36
|
+
The project knowledge store is **one canonical JSONL file**: \`${KNOWLEDGE_PATH}\`.
|
|
37
|
+
Each line is one self-contained JSON object. Append-only. Machine-queryable.
|
|
24
38
|
|
|
25
39
|
Use the store to keep durable knowledge that should survive sessions:
|
|
26
|
-
- **rule**: hard constraint to follow every time
|
|
27
|
-
- **pattern**: repeatable way that works well in this project
|
|
28
|
-
- **lesson**: non-obvious outcome from a failure or trade-off
|
|
29
|
-
- **compound**: post-ship insight about how to make the *next* feature faster (process accelerator, not domain rule)
|
|
40
|
+
- **rule**: hard constraint to follow every time.
|
|
41
|
+
- **pattern**: repeatable way that works well in this project.
|
|
42
|
+
- **lesson**: non-obvious outcome from a failure or trade-off.
|
|
43
|
+
- **compound**: post-ship insight about how to make the *next* feature faster (process accelerator, not domain rule).
|
|
30
44
|
|
|
31
45
|
## HARD-GATE
|
|
32
46
|
|
|
33
|
-
Under \`/cc-learn\`, only modify
|
|
34
|
-
|
|
35
|
-
|
|
47
|
+
Under \`/cc-learn\`, only modify \`${KNOWLEDGE_PATH}\`, \`${KNOWLEDGE_ARCHIVE_PATH}\`,
|
|
48
|
+
or an explicitly user-approved summary file. Do not modify application code here.
|
|
49
|
+
Do not invent alternate stores (no markdown mirror, no SQLite, no per-stage files).
|
|
36
50
|
|
|
37
|
-
|
|
38
|
-
### 2026-04-14T12:00:00Z [pattern] short-title
|
|
39
|
-
- Stage: design
|
|
40
|
-
- Context: one short line
|
|
41
|
-
- Insight: one short line
|
|
42
|
-
- Reuse: one short line
|
|
43
|
-
- Confidence: high | medium | low (optional)
|
|
44
|
-
- Domain: api | infra | ui | testing | … (optional)
|
|
45
|
-
- Project: <repo or scope name> (optional)
|
|
46
|
-
\`\`\`
|
|
51
|
+
## Entry format — strict JSONL schema
|
|
47
52
|
|
|
48
|
-
|
|
53
|
+
Exactly one JSON object per line. Fields must appear in the order:
|
|
54
|
+
\`type, trigger, action, confidence, domain, stage, created, project\`.
|
|
49
55
|
|
|
50
56
|
\`\`\`json
|
|
51
|
-
{"type":"pattern","
|
|
57
|
+
{"type":"pattern","trigger":"when reviewing external payloads","action":"parse through zod before touching service layer","confidence":"high","domain":"api","stage":"review","created":"2026-04-14T12:00:00Z","project":"cclaw"}
|
|
52
58
|
\`\`\`
|
|
53
59
|
|
|
54
|
-
Schema:
|
|
55
|
-
|
|
56
60
|
| field | type | required | notes |
|
|
57
61
|
|---|---|---|---|
|
|
58
62
|
| \`type\` | \`"rule" \\| "pattern" \\| "lesson" \\| "compound"\` | yes | Lowercase. |
|
|
59
|
-
| \`
|
|
60
|
-
| \`
|
|
61
|
-
| \`
|
|
62
|
-
| \`
|
|
63
|
-
| \`
|
|
64
|
-
| \`created\` | ISO 8601 UTC string | yes |
|
|
65
|
-
| \`
|
|
66
|
-
| \`domain\` | string | optional | Free-form taxonomy (\`api\`, \`infra\`, \`ui\`, …). |
|
|
67
|
-
| \`project\` | string | optional | Repo or scope name when the entry crosses features. |
|
|
68
|
-
| \`supersedes\` | string \\| null | optional | Title of the entry this one replaces. |
|
|
69
|
-
| \`superseded\` | boolean | optional | \`true\` when a newer entry replaces this one. |
|
|
70
|
-
| \`archived\` | boolean | optional | \`true\` once the curator soft-archives the entry. |
|
|
63
|
+
| \`trigger\` | string | yes | The concrete situation that must be recognized. Start with a verb or \`when …\`. |
|
|
64
|
+
| \`action\` | string | yes | The concrete move to take when the trigger fires. One sentence. |
|
|
65
|
+
| \`confidence\` | \`"high" \\| "medium" \\| "low"\` | yes | Write \`medium\` when unsure; do not omit. |
|
|
66
|
+
| \`domain\` | string \\| null | yes | Free-form taxonomy (\`api\`, \`infra\`, \`ui\`, \`security\`, \`testing\`, …). Use \`null\` when cross-cutting. |
|
|
67
|
+
| \`stage\` | \`FlowStage\` \\| null | yes | One of brainstorm / scope / design / spec / plan / tdd / review / ship, or \`null\` when cross-stage. |
|
|
68
|
+
| \`created\` | ISO 8601 UTC string | yes | \`date -u +%Y-%m-%dT%H:%M:%SZ\`. |
|
|
69
|
+
| \`project\` | string \\| null | yes | Repo or scope name. Use \`null\` when the entry crosses projects. |
|
|
71
70
|
|
|
72
71
|
Rules:
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
## Backward-compat migration (markdown → JSONL)
|
|
79
|
-
|
|
80
|
-
Run \`/cc-learn migrate\` once per repo when \`${KNOWLEDGE_JSONL_PATH}\` is missing:
|
|
81
|
-
|
|
82
|
-
1. Parse \`${KNOWLEDGE_PATH}\`. Each entry starts with \`### <ISO8601> [<type>] <title>\` and is followed by \`- <Field>: <value>\` lines until the next \`###\` or EOF.
|
|
83
|
-
2. Map fields to JSONL schema:
|
|
84
|
-
- Heading timestamp → \`created\`; heading \`[type]\` → \`type\`; heading title → \`title\`.
|
|
85
|
-
- Bullet \`Stage:\`, \`Context:\`, \`Insight:\`, \`Reuse:\`, \`Confidence:\`, \`Domain:\`, \`Project:\` → matching fields.
|
|
86
|
-
- A \`Supersedes:\` prefix line becomes \`"supersedes": "<old-title>"\`.
|
|
87
|
-
3. Emit one JSON object per line to \`${KNOWLEDGE_JSONL_PATH}\` preserving the original order. Set defaults: \`confidence = "medium"\`, \`superseded = false\`, \`archived = false\`, missing optional fields = \`null\`.
|
|
88
|
-
4. Do **not** rewrite \`${KNOWLEDGE_PATH}\`. The markdown stays as the human-readable mirror; new additions continue to write both files.
|
|
89
|
-
5. After migration, \`/cc-learn search\` reads the JSONL store first; if absent, it continues to parse the markdown file (so users who never migrate still work).
|
|
72
|
+
- No other fields. Extra keys are forbidden and MUST be rejected by any writer.
|
|
73
|
+
- Every required-null field must be emitted explicitly as \`null\` (not omitted). This keeps the file grep-friendly.
|
|
74
|
+
- Append-only: never rewrite or delete a historical line. Corrections are new
|
|
75
|
+
entries whose \`trigger\` clearly supersedes the earlier one.
|
|
76
|
+
- Keep each entry one line. No pretty-printing. No trailing commas.
|
|
90
77
|
|
|
91
78
|
## Curation policy (target: ≤ 50 active entries)
|
|
92
79
|
|
|
93
|
-
The
|
|
94
|
-
|
|
95
|
-
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
See the **knowledge-curation** utility skill for the full curation protocol.
|
|
80
|
+
- The file is append-only — entries are never physically deleted.
|
|
81
|
+
- When the canonical file exceeds 50 lines, \`/cc-learn curate\` proposes
|
|
82
|
+
soft-archiving: the approved lines are **moved** to \`${KNOWLEDGE_ARCHIVE_PATH}\`
|
|
83
|
+
verbatim (same JSONL shape). The working file stays lean.
|
|
84
|
+
- See the **knowledge-curation** utility skill for the full curation protocol.
|
|
99
85
|
|
|
100
86
|
## Subcommands
|
|
101
87
|
|
|
102
88
|
### \`/cc-learn\` (default)
|
|
103
|
-
-
|
|
104
|
-
|
|
89
|
+
- Read \`${KNOWLEDGE_PATH}\`. Stream the last 30 lines; pretty-print each
|
|
90
|
+
line's \`type\` / \`trigger\` / \`action\` for human review.
|
|
91
|
+
- If file is missing or empty, report that clearly and suggest \`/cc-learn add\`.
|
|
105
92
|
|
|
106
93
|
### \`/cc-learn search <query>\`
|
|
107
|
-
-
|
|
108
|
-
|
|
109
|
-
- Return matched
|
|
94
|
+
- Stream \`${KNOWLEDGE_PATH}\`, JSON.parse each line, filter where any of
|
|
95
|
+
\`trigger\`, \`action\`, \`domain\`, \`project\` contains \`<query>\` (case-insensitive).
|
|
96
|
+
- Return the matched lines pretty-printed (do not mutate the file).
|
|
110
97
|
|
|
111
98
|
### \`/cc-learn add\`
|
|
112
|
-
- Ask for: \`type\`, \`
|
|
113
|
-
-
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
-
|
|
117
|
-
|
|
118
|
-
### \`/cc-learn migrate\`
|
|
119
|
-
- Parse \`${KNOWLEDGE_PATH}\` and emit \`${KNOWLEDGE_JSONL_PATH}\` per the Backward-compat migration protocol above.
|
|
120
|
-
- Safe to re-run: if JSONL already exists, report the current entry count and exit (no destructive rewrite).
|
|
99
|
+
- Ask for required fields in order: \`type\`, \`trigger\`, \`action\`, \`confidence\`, \`domain\`, \`stage\`, \`project\`.
|
|
100
|
+
- \`confidence\` must be one of \`high\`, \`medium\`, \`low\`. Default to \`medium\` if the user declines to set it.
|
|
101
|
+
- \`domain\`, \`stage\`, and \`project\` may be explicitly \`null\`.
|
|
102
|
+
- \`created\` is set automatically to the current UTC ISO timestamp.
|
|
103
|
+
- Append exactly one JSON line to \`${KNOWLEDGE_PATH}\` with the field order from the schema table above.
|
|
104
|
+
- Re-read the file tail to confirm the new line is valid JSON and parses back to the same object.
|
|
121
105
|
|
|
122
106
|
### \`/cc-learn curate\`
|
|
123
107
|
- Hand off to the **knowledge-curation** skill (read-only audit + soft-archive plan).
|
|
124
|
-
- Never deletes
|
|
108
|
+
- Never deletes. Soft-archive means **moving** full JSON lines from
|
|
109
|
+
\`${KNOWLEDGE_PATH}\` to \`${KNOWLEDGE_ARCHIVE_PATH}\` as part of a
|
|
110
|
+
user-approved curation pass.
|
|
125
111
|
`;
|
|
126
112
|
}
|
|
127
113
|
export function learnCommandContract() {
|
|
@@ -129,23 +115,23 @@ export function learnCommandContract() {
|
|
|
129
115
|
|
|
130
116
|
## Purpose
|
|
131
117
|
|
|
132
|
-
Manage the project knowledge store.
|
|
133
|
-
- \`${KNOWLEDGE_PATH}\` —
|
|
134
|
-
- \`${
|
|
118
|
+
Manage the project knowledge store. One canonical file, strict JSONL:
|
|
119
|
+
- \`${KNOWLEDGE_PATH}\` — append-only JSONL, one entry per line.
|
|
120
|
+
- \`${KNOWLEDGE_ARCHIVE_PATH}\` — soft-archive target written only by curate.
|
|
135
121
|
|
|
136
122
|
## HARD-GATE
|
|
137
123
|
|
|
138
|
-
Do not edit source code from this command. Only operate on \`${KNOWLEDGE_PATH}\`,
|
|
124
|
+
Do not edit source code from this command. Only operate on \`${KNOWLEDGE_PATH}\`,
|
|
125
|
+
\`${KNOWLEDGE_ARCHIVE_PATH}\`, or user-approved summary output.
|
|
139
126
|
|
|
140
127
|
## Subcommands
|
|
141
128
|
|
|
142
129
|
| subcommand | args | description |
|
|
143
130
|
|---|---|---|
|
|
144
|
-
| (default) | — | Show recent knowledge entries (tail
|
|
145
|
-
| \`search\` | \`<query>\` |
|
|
146
|
-
| \`add\` | — | Append
|
|
147
|
-
| \`
|
|
148
|
-
| \`curate\` | — | Hand off to the **knowledge-curation** skill: read-only audit + soft-archive plan when the active file exceeds the curation threshold. |
|
|
131
|
+
| (default) | — | Show recent knowledge entries (tail of JSONL, pretty-printed). |
|
|
132
|
+
| \`search\` | \`<query>\` | Stream-filter the JSONL for matching \`trigger\`, \`action\`, \`domain\`, \`project\`. |
|
|
133
|
+
| \`add\` | — | Append one JSON line (\`rule\` / \`pattern\` / \`lesson\` / \`compound\`) with the strict 8-field schema. |
|
|
134
|
+
| \`curate\` | — | Hand off to the **knowledge-curation** skill: read-only audit + soft-archive plan when the file exceeds the curation threshold. |
|
|
149
135
|
`;
|
|
150
136
|
}
|
|
151
137
|
export function selfImprovementBlock(stageName) {
|
|
@@ -155,36 +141,34 @@ After this stage, ask:
|
|
|
155
141
|
- Did I discover a non-obvious reusable **rule** or **pattern**?
|
|
156
142
|
- Did a failure reveal a reusable **lesson**?
|
|
157
143
|
|
|
158
|
-
If yes, append one concise
|
|
144
|
+
If yes, append one concise JSON line to the canonical knowledge store
|
|
145
|
+
(\`${KNOWLEDGE_PATH}\`) using the strict 8-field schema:
|
|
159
146
|
|
|
160
147
|
\`\`\`bash
|
|
161
148
|
TS="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
162
|
-
|
|
163
|
-
### $TS [pattern] short-title
|
|
164
|
-
- Stage: ${stageName}
|
|
165
|
-
- Context: what situation triggered this
|
|
166
|
-
- Insight: what should be remembered
|
|
167
|
-
- Reuse: how to apply this next time
|
|
168
|
-
EOF
|
|
169
|
-
printf '%s\\n' '{"type":"pattern","title":"short-title","stage":"${stageName}","context":"what situation triggered this","insight":"what should be remembered","reuse":"how to apply this next time","created":"'"$TS"'","confidence":"medium","domain":null,"project":null,"supersedes":null,"superseded":false,"archived":false}' >> ${KNOWLEDGE_JSONL_PATH}
|
|
149
|
+
printf '%s\\n' '{"type":"pattern","trigger":"when <situation>","action":"<concrete move>","confidence":"medium","domain":null,"stage":"${stageName}","created":"'"$TS"'","project":null}' >> ${KNOWLEDGE_PATH}
|
|
170
150
|
\`\`\`
|
|
171
151
|
|
|
172
152
|
Type must be exactly one of: \`rule\`, \`pattern\`, \`lesson\`, \`compound\`.
|
|
153
|
+
Fields must appear in the order: \`type, trigger, action, confidence, domain, stage, created, project\`.
|
|
154
|
+
Missing optional values must be emitted as \`null\`, never omitted.
|
|
173
155
|
`;
|
|
174
156
|
}
|
|
175
157
|
export function learningsSearchPreamble(stage) {
|
|
176
158
|
return `## Prior Knowledge (load at stage start)
|
|
177
159
|
|
|
178
|
-
Before stage work,
|
|
179
|
-
|
|
180
|
-
If the file is empty, continue normally.
|
|
160
|
+
Before stage work, stream \`${KNOWLEDGE_PATH}\` and filter for entries relevant to
|
|
161
|
+
this stage (\`${stage}\`), affected domains, and key constraints. Apply matching
|
|
162
|
+
entries explicitly. If the file is empty, continue normally.
|
|
181
163
|
`;
|
|
182
164
|
}
|
|
183
165
|
export function learningsAgentsMdBlock() {
|
|
184
166
|
return `### Knowledge Store
|
|
185
167
|
|
|
186
|
-
\`${KNOWLEDGE_PATH}\` — append-only
|
|
187
|
-
|
|
188
|
-
|
|
168
|
+
\`${KNOWLEDGE_PATH}\` — append-only JSONL memory with entry types \`rule\`, \`pattern\`, \`lesson\`, \`compound\`.
|
|
169
|
+
Strict 8-field schema: \`type, trigger, action, confidence, domain, stage, created, project\`.
|
|
170
|
+
At session start and stage transitions, tail the file and apply relevant entries.
|
|
171
|
+
If a non-obvious reusable rule/pattern/lesson is discovered, append a new line
|
|
172
|
+
through \`/cc-learn add\` (never hand-edit).
|
|
189
173
|
`;
|
|
190
174
|
}
|
|
@@ -96,15 +96,22 @@ review lenses can enable opt-in rule packs in \`.cclaw/config.yaml\`:
|
|
|
96
96
|
|
|
97
97
|
\`\`\`yaml
|
|
98
98
|
languageRulePacks:
|
|
99
|
-
- typescript # →
|
|
100
|
-
- python # →
|
|
101
|
-
- go # →
|
|
99
|
+
- typescript # → .cclaw/rules/lang/typescript.md
|
|
100
|
+
- python # → .cclaw/rules/lang/python.md
|
|
101
|
+
- go # → .cclaw/rules/lang/go.md
|
|
102
102
|
\`\`\`
|
|
103
103
|
|
|
104
|
-
After editing the list, run \`cclaw sync\` to materialize the enabled
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
After editing the list, run \`cclaw sync\` to materialize the enabled packs
|
|
105
|
+
under \`.cclaw/rules/lang/\` (one \`<language>.md\` file per pack, each with
|
|
106
|
+
YAML frontmatter declaring \`stages\` and \`triggers\`). Packs activate during
|
|
107
|
+
\`tdd\` and \`review\` when the diff touches files in their language. They are
|
|
108
|
+
additive lenses — Tier-1 rules block merge, Tier-2 rules require a named
|
|
109
|
+
follow-up. Never silently override them.
|
|
110
|
+
|
|
111
|
+
\`cclaw sync\` and \`cclaw doctor\` also refuse the legacy v0.7.0 location
|
|
112
|
+
\`.cclaw/skills/language-*/\` — if a project still has those folders,
|
|
113
|
+
\`sync\` removes them on the next run and \`doctor\` surfaces the drift until
|
|
114
|
+
they are gone.
|
|
108
115
|
|
|
109
116
|
## Custom Skills (project-owned, sync-safe)
|
|
110
117
|
|
|
@@ -189,10 +196,12 @@ Watch for these anti-patterns:
|
|
|
189
196
|
|
|
190
197
|
## Knowledge Integration
|
|
191
198
|
|
|
192
|
-
At session start and stage transitions,
|
|
193
|
-
-
|
|
194
|
-
-
|
|
199
|
+
At session start and stage transitions, stream \`.cclaw/knowledge.jsonl\` (the canonical strict-JSONL knowledge store) and apply relevant entries:
|
|
200
|
+
- Each line is one JSON object with fields \`type, trigger, action, confidence, domain, stage, created, project\`.
|
|
201
|
+
- Review recent entries and apply relevant rules/patterns to the current task.
|
|
202
|
+
- If you discover a non-obvious reusable rule or pattern, append one new JSON line via \`/cc-learn add\` with type \`rule\`, \`pattern\`, \`lesson\`, or \`compound\`.
|
|
195
203
|
|
|
196
|
-
Knowledge capture is append-only and
|
|
204
|
+
Knowledge capture is append-only and strict-schema. Never rewrite or delete
|
|
205
|
+
historical entries; corrections are new lines whose \`trigger\` supersedes the earlier one.
|
|
197
206
|
`;
|
|
198
207
|
}
|
|
@@ -26,7 +26,7 @@ These are prompt-discipline guidelines that complement the real hooks cclaw gene
|
|
|
26
26
|
When a new session begins in any harness:
|
|
27
27
|
|
|
28
28
|
1. **Read flow state:** Load \`.cclaw/state/flow-state.json\` to find the current stage and completed stages.
|
|
29
|
-
2. **Load knowledge:**
|
|
29
|
+
2. **Load knowledge:** Stream the tail of \`.cclaw/knowledge.jsonl\` (strict JSONL store) and surface the most relevant rules/patterns.
|
|
30
30
|
3. **Check for in-progress work:** If the last stage is incomplete, remind the user and offer to resume.
|
|
31
31
|
4. **Load suggestion memory:** Read \`.cclaw/state/suggestion-memory.json\` and honor \`enabled=false\` opt-out.
|
|
32
32
|
5. **Read AGENTS.md:** The cclaw block contains routing and rules — follow them.
|
|
@@ -45,7 +45,7 @@ Before ending a session or when context is full:
|
|
|
45
45
|
|
|
46
46
|
1. **Verify no pending changes:** All modified files must be either committed or explicitly reverted.
|
|
47
47
|
2. **Update flow state:** Mark the current stage as its actual status (DONE / DONE_WITH_CONCERNS / BLOCKED).
|
|
48
|
-
3. **Write knowledge:** If any non-obvious reusable insight appears, append to \`.cclaw/knowledge.
|
|
48
|
+
3. **Write knowledge:** If any non-obvious reusable insight appears, append one strict-schema JSON line to \`.cclaw/knowledge.jsonl\` with type \`rule\`, \`pattern\`, \`lesson\`, or \`compound\`.
|
|
49
49
|
4. **Create checkpoint:** Write a brief status note to the current artifact or as a comment in flow-state.json.
|
|
50
50
|
|
|
51
51
|
### Stop conditions (agent must halt and report)
|
package/dist/content/skills.js
CHANGED
|
@@ -81,7 +81,7 @@ Before starting stage execution:
|
|
|
81
81
|
2. Resolve active artifact root: \`.cclaw/artifacts/\`.
|
|
82
82
|
3. Load upstream artifacts required by this stage:
|
|
83
83
|
${readLines}
|
|
84
|
-
4.
|
|
84
|
+
4. Stream \`.cclaw/knowledge.jsonl\` (strict-JSONL knowledge store) and apply relevant entries before making decisions.
|
|
85
85
|
`;
|
|
86
86
|
}
|
|
87
87
|
function whenNotToUseBlock(stage) {
|
|
@@ -236,7 +236,7 @@ function progressiveDisclosureBlock(stage) {
|
|
|
236
236
|
- Primary stage procedure (this file): \`.cclaw/skills/${schema.skillFolder}/SKILL.md\`
|
|
237
237
|
- Orchestrator contract (gate language and handoff): \`.cclaw/commands/${stage}.md\`
|
|
238
238
|
- Artifact structure baseline: \`.cclaw/templates/${schema.artifactFile}\`
|
|
239
|
-
- Runtime state truth source: \`.cclaw/state/flow-state.json\` + \`.cclaw/artifacts/\` + \`.cclaw/knowledge.
|
|
239
|
+
- Runtime state truth source: \`.cclaw/state/flow-state.json\` + \`.cclaw/artifacts/\` + \`.cclaw/knowledge.jsonl\`
|
|
240
240
|
|
|
241
241
|
### See also
|
|
242
242
|
- Meta routing and activation rules: \`.cclaw/skills/using-cclaw/SKILL.md\`
|
|
@@ -1455,7 +1455,7 @@ const SHIP = {
|
|
|
1455
1455
|
{ section: "Monitoring", required: false, validationRule: "If applicable: what metrics/logs to watch post-deploy. Risk note if no monitoring." },
|
|
1456
1456
|
{ section: "Finalization", required: true, validationRule: "Exactly one finalization enum token selected. Execution result documented. Worktree cleaned if applicable." },
|
|
1457
1457
|
{ section: "Completion Status", required: false, validationRule: "If present: exactly one of SHIPPED, SHIPPED_WITH_EXCEPTIONS, BLOCKED. Exceptions documented when applicable." },
|
|
1458
|
-
{ section: "Compound Step", required: false, validationRule: "Optional retrospective: at least one bullet of the form 'Insight: ... | Action: append [compound] entry to .cclaw/knowledge.
|
|
1458
|
+
{ section: "Compound Step", required: false, validationRule: "Optional retrospective: at least one bullet of the form 'Insight: ... | Action: append [compound] entry to .cclaw/knowledge.jsonl', or an explicit 'No compound insight this run.' line." }
|
|
1459
1459
|
],
|
|
1460
1460
|
namedAntiPattern: {
|
|
1461
1461
|
title: "Green CI Means Safe to Merge",
|
|
@@ -8,7 +8,7 @@ function delegationLogPath() {
|
|
|
8
8
|
return `${RUNTIME_ROOT}/state/delegation-log.json`;
|
|
9
9
|
}
|
|
10
10
|
function knowledgePath() {
|
|
11
|
-
return `${RUNTIME_ROOT}/knowledge.
|
|
11
|
+
return `${RUNTIME_ROOT}/knowledge.jsonl`;
|
|
12
12
|
}
|
|
13
13
|
function contextModePath() {
|
|
14
14
|
return `${RUNTIME_ROOT}/state/context-mode.json`;
|
|
@@ -131,7 +131,7 @@ a read-only command.
|
|
|
131
131
|
- Prefer \`${checkpointPath()}\` when \`stage === currentStage\` and \`timestamp\` parses as ISO 8601.
|
|
132
132
|
- Else scan \`${stageActivityPath()}\` from tail for the most recent entry whose \`stage === currentStage\`; use its \`ts\`.
|
|
133
133
|
- Render \`<X>d<Y>h\`, \`<X>h<Y>m\`, \`<X>m\`, or \`(unknown)\`.
|
|
134
|
-
5. Read \`${RUNTIME_ROOT}/knowledge.
|
|
134
|
+
5. Read \`${RUNTIME_ROOT}/knowledge.jsonl\`. If missing or empty → knowledge highlights are \`(none recorded)\`. Parse each line as JSON and surface its \`trigger\`/\`action\`.
|
|
135
135
|
6. For each gate in \`stageGateCatalog[currentStage].required\`:
|
|
136
136
|
- Satisfied if present in \`passed\` and absent from \`blocked\`.
|
|
137
137
|
7. Build and print the status block (see command contract for layout).
|
|
@@ -446,7 +446,7 @@ Execution rule: complete and verify each wave before starting the next wave.
|
|
|
446
446
|
_Optional retrospective. The goal is to make the **next** feature faster, not to evaluate this one._
|
|
447
447
|
_If you have nothing to add, write the explicit line: \`No compound insight this run.\`_
|
|
448
448
|
- Insight: <one short line about what should accelerate the next run>
|
|
449
|
-
- Action: append \`
|
|
449
|
+
- Action: append one strict-schema JSON line with \`"type":"compound"\` to \`.cclaw/knowledge.jsonl\` capturing the insight (fields: type, trigger, action, confidence, domain, stage, created, project)
|
|
450
450
|
`
|
|
451
451
|
};
|
|
452
452
|
export const RULEBOOK_MARKDOWN = `# Cclaw Rulebook
|
|
@@ -20,11 +20,28 @@ export declare function retrospectiveSkill(): string;
|
|
|
20
20
|
export declare function languageTypescriptSkill(): string;
|
|
21
21
|
export declare function languagePythonSkill(): string;
|
|
22
22
|
export declare function languageGoSkill(): string;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Language rule packs live under `.cclaw/rules/lang/<pack>.md`. They are NOT
|
|
25
|
+
* skills (no folder, no `SKILL.md`) — they are opt-in **rule files** that the
|
|
26
|
+
* meta-skill router and stage hooks consult when the corresponding language
|
|
27
|
+
* appears in a diff. The pack id doubles as the on-disk filename stem.
|
|
28
|
+
*/
|
|
29
|
+
export declare const LANGUAGE_RULE_PACK_FILES: {
|
|
30
|
+
readonly typescript: "typescript.md";
|
|
31
|
+
readonly python: "python.md";
|
|
32
|
+
readonly go: "go.md";
|
|
27
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* Folder (relative to runtime root) that holds every enabled language rule
|
|
36
|
+
* pack. A single folder keeps discovery trivial for hooks and for `doctor`.
|
|
37
|
+
*/
|
|
38
|
+
export declare const LANGUAGE_RULE_PACK_DIR: readonly ["rules", "lang"];
|
|
28
39
|
export declare const LANGUAGE_RULE_PACK_GENERATORS: Record<string, () => string>;
|
|
40
|
+
/**
|
|
41
|
+
* Legacy per-language folders under `.cclaw/skills/` used in v0.7.0. Listed
|
|
42
|
+
* here so `cclaw sync` and `doctor` can surface drift and the installer can
|
|
43
|
+
* clean them up after the move to `.cclaw/rules/lang/`.
|
|
44
|
+
*/
|
|
45
|
+
export declare const LEGACY_LANGUAGE_RULE_PACK_FOLDERS: readonly ["language-typescript", "language-python", "language-go"];
|
|
29
46
|
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"];
|
|
30
47
|
export declare const UTILITY_SKILL_MAP: Record<string, () => string>;
|
|
@@ -751,22 +751,22 @@ candidates exist).
|
|
|
751
751
|
export function knowledgeCurationSkill() {
|
|
752
752
|
return `---
|
|
753
753
|
name: knowledge-curation
|
|
754
|
-
description: "Read-only curation pass over
|
|
754
|
+
description: "Read-only curation pass over the canonical strict-JSONL knowledge store at .cclaw/knowledge.jsonl. Surfaces stale, duplicate, or low-confidence entries and proposes a soft-archive plan that moves approved lines to .cclaw/knowledge.archive.jsonl. 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.
|
|
761
|
+
> 1. This is a **read-only audit** of \`.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.
|
|
768
|
-
- Do not silently rewrite or summarize entries — preserve original
|
|
769
|
-
-
|
|
767
|
+
- Do not modify \`.cclaw/knowledge.jsonl\` from this skill except via an explicit user-approved archive plan that **moves** full JSON lines verbatim to \`.cclaw/knowledge.archive.jsonl\`. Never physically delete history that is already archived — the archive file is append-only too.
|
|
768
|
+
- Do not silently rewrite or summarize entries — preserve the original JSON line byte-for-byte.
|
|
769
|
+
- Operate only on the canonical JSONL store. If you see a stray \`.cclaw/knowledge.md\`, report it as a drift signal; do **not** read or rewrite it.
|
|
770
770
|
|
|
771
771
|
## When to run
|
|
772
772
|
|
|
@@ -776,28 +776,28 @@ description: "Read-only curation pass over .cclaw/knowledge.md and .cclaw/knowle
|
|
|
776
776
|
|
|
777
777
|
## Audit dimensions
|
|
778
778
|
|
|
779
|
-
For each
|
|
779
|
+
For each JSON line in \`.cclaw/knowledge.jsonl\` produce a row with:
|
|
780
780
|
|
|
781
781
|
| Field | Source |
|
|
782
782
|
|---|---|
|
|
783
|
-
|
|
|
784
|
-
| Type | \`rule\` / \`pattern\` / \`lesson\` / \`compound\` |
|
|
785
|
-
| Stage | \`
|
|
786
|
-
| Age | days since
|
|
787
|
-
| Confidence | \`
|
|
788
|
-
| Domain | \`
|
|
789
|
-
|
|
|
783
|
+
| # | 1-based line number in the JSONL file |
|
|
784
|
+
| Type | \`type\` field (\`rule\` / \`pattern\` / \`lesson\` / \`compound\`) |
|
|
785
|
+
| Stage | \`stage\` field (or \`null\`) |
|
|
786
|
+
| Age | days since \`created\` |
|
|
787
|
+
| Confidence | \`confidence\` field |
|
|
788
|
+
| Domain | \`domain\` field (or \`null\`) |
|
|
789
|
+
| Trigger | \`trigger\` field, truncated to 60 chars |
|
|
790
790
|
| Status hint | one of: keep / supersede-candidate / archive-candidate / duplicate |
|
|
791
791
|
|
|
792
792
|
### Status rules
|
|
793
793
|
|
|
794
|
-
- **supersede-candidate**:
|
|
795
|
-
- **duplicate**:
|
|
794
|
+
- **supersede-candidate**: a newer line shares the same \`trigger\` (case-insensitive) and a different \`action\`.
|
|
795
|
+
- **duplicate**: \`trigger\` ≈ another line's AND \`action\` ≈ the same (caller's judgment).
|
|
796
796
|
- **archive-candidate**:
|
|
797
|
-
-
|
|
798
|
-
-
|
|
799
|
-
-
|
|
800
|
-
- Total active entries > 50 and entry has lowest reuse signal.
|
|
797
|
+
- \`type=lesson\` AND age > 180 days AND no newer line references the same \`trigger\`; OR
|
|
798
|
+
- \`stage=brainstorm\` AND age > 90 days; OR
|
|
799
|
+
- \`confidence=low\` AND age > 60 days; OR
|
|
800
|
+
- Total active entries > 50 and entry has the lowest estimated reuse signal.
|
|
801
801
|
- **keep**: everything else.
|
|
802
802
|
|
|
803
803
|
## Output format
|
|
@@ -807,7 +807,7 @@ Produce two artifacts as **chat output only** (do not write files):
|
|
|
807
807
|
### 1. Audit table
|
|
808
808
|
|
|
809
809
|
\`\`\`markdown
|
|
810
|
-
| # |
|
|
810
|
+
| # | Type | Stage | Age | Confidence | Trigger | Status hint |
|
|
811
811
|
|---|---|---|---|---|---|---|
|
|
812
812
|
| 1 | … | … | … | … | … | … |
|
|
813
813
|
\`\`\`
|
|
@@ -820,14 +820,15 @@ Produce two artifacts as **chat output only** (do not write files):
|
|
|
820
820
|
Threshold reasoning: <why entries below were selected>
|
|
821
821
|
|
|
822
822
|
Entries to archive:
|
|
823
|
-
1. <
|
|
824
|
-
2. <
|
|
823
|
+
1. line #<N> — <trigger> — reason
|
|
824
|
+
2. line #<N> — <trigger> — reason
|
|
825
825
|
|
|
826
826
|
Action plan if approved:
|
|
827
|
-
1.
|
|
828
|
-
2. Move (cut/paste) selected
|
|
829
|
-
|
|
830
|
-
|
|
827
|
+
1. Ensure \`.cclaw/knowledge.archive.jsonl\` exists (create empty if missing).
|
|
828
|
+
2. Move (cut/paste) the selected JSON lines verbatim from
|
|
829
|
+
\`.cclaw/knowledge.jsonl\` into \`.cclaw/knowledge.archive.jsonl\`,
|
|
830
|
+
preserving byte order within each file.
|
|
831
|
+
3. Do not rewrite, re-order, or pretty-print any remaining line in the active file.
|
|
831
832
|
|
|
832
833
|
After approval: ask the user to run the move themselves, or — if they explicitly grant write access — perform the move atomically and report the new active count.
|
|
833
834
|
\`\`\`
|
|
@@ -1079,7 +1080,7 @@ description: "Post-ship retrospective lens. Use after a ship to extract durable
|
|
|
1079
1080
|
## Quick Start
|
|
1080
1081
|
|
|
1081
1082
|
> 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.
|
|
1083
|
+
> 2. Walk the four lenses below; harvest concrete entries for \`.cclaw/knowledge.jsonl\`.
|
|
1083
1084
|
> 3. Stop when you have at least one durable entry **or** an explicit "no new lesson this run".
|
|
1084
1085
|
|
|
1085
1086
|
## HARD-GATE
|
|
@@ -1132,13 +1133,14 @@ For each lens, write either a knowledge entry **or** the explicit string
|
|
|
1132
1133
|
|
|
1133
1134
|
## Output protocol
|
|
1134
1135
|
|
|
1135
|
-
For every harvested insight, append one
|
|
1136
|
-
|
|
1136
|
+
For every harvested insight, append one strict-schema JSON line to
|
|
1137
|
+
\`.cclaw/knowledge.jsonl\` (fields: \`type, trigger, action, confidence, domain, stage, created, project\`).
|
|
1138
|
+
See the \`learnings\` skill for the canonical shape. Choose \`type\`:
|
|
1137
1139
|
|
|
1138
|
-
- \`
|
|
1139
|
-
- \`
|
|
1140
|
-
- \`
|
|
1141
|
-
- \`
|
|
1140
|
+
- \`compound\` for process/speed accelerators.
|
|
1141
|
+
- \`lesson\` for "we learned this the hard way".
|
|
1142
|
+
- \`pattern\` for repeatable shapes that worked.
|
|
1143
|
+
- \`rule\` only for hard constraints that must always hold.
|
|
1142
1144
|
|
|
1143
1145
|
Then write a one-paragraph **Run Summary** at the top of the next
|
|
1144
1146
|
\`/cc <idea>\` brainstorm context citing the lessons in scope.
|
|
@@ -1347,16 +1349,37 @@ irrelevant. Discarded errors are Go's #1 source of silent data loss.
|
|
|
1347
1349
|
\`\`\`
|
|
1348
1350
|
`;
|
|
1349
1351
|
}
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1352
|
+
/**
|
|
1353
|
+
* Language rule packs live under `.cclaw/rules/lang/<pack>.md`. They are NOT
|
|
1354
|
+
* skills (no folder, no `SKILL.md`) — they are opt-in **rule files** that the
|
|
1355
|
+
* meta-skill router and stage hooks consult when the corresponding language
|
|
1356
|
+
* appears in a diff. The pack id doubles as the on-disk filename stem.
|
|
1357
|
+
*/
|
|
1358
|
+
export const LANGUAGE_RULE_PACK_FILES = {
|
|
1359
|
+
typescript: "typescript.md",
|
|
1360
|
+
python: "python.md",
|
|
1361
|
+
go: "go.md"
|
|
1354
1362
|
};
|
|
1363
|
+
/**
|
|
1364
|
+
* Folder (relative to runtime root) that holds every enabled language rule
|
|
1365
|
+
* pack. A single folder keeps discovery trivial for hooks and for `doctor`.
|
|
1366
|
+
*/
|
|
1367
|
+
export const LANGUAGE_RULE_PACK_DIR = ["rules", "lang"];
|
|
1355
1368
|
export const LANGUAGE_RULE_PACK_GENERATORS = {
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1369
|
+
typescript: languageTypescriptSkill,
|
|
1370
|
+
python: languagePythonSkill,
|
|
1371
|
+
go: languageGoSkill
|
|
1359
1372
|
};
|
|
1373
|
+
/**
|
|
1374
|
+
* Legacy per-language folders under `.cclaw/skills/` used in v0.7.0. Listed
|
|
1375
|
+
* here so `cclaw sync` and `doctor` can surface drift and the installer can
|
|
1376
|
+
* clean them up after the move to `.cclaw/rules/lang/`.
|
|
1377
|
+
*/
|
|
1378
|
+
export const LEGACY_LANGUAGE_RULE_PACK_FOLDERS = [
|
|
1379
|
+
"language-typescript",
|
|
1380
|
+
"language-python",
|
|
1381
|
+
"language-go"
|
|
1382
|
+
];
|
|
1360
1383
|
export const UTILITY_SKILL_FOLDERS = [
|
|
1361
1384
|
"security",
|
|
1362
1385
|
"debugging",
|
package/dist/doctor.js
CHANGED
|
@@ -17,7 +17,7 @@ import { checkMandatoryDelegations } from "./delegation.js";
|
|
|
17
17
|
import { buildTraceMatrix } from "./trace-matrix.js";
|
|
18
18
|
import { reconcileAndWriteCurrentStageGateCatalog, verifyCompletedStagesGateClosure, verifyCurrentStageGateEvidence } from "./gate-evidence.js";
|
|
19
19
|
import { stageSkillFolder } from "./content/skills.js";
|
|
20
|
-
import {
|
|
20
|
+
import { LANGUAGE_RULE_PACK_DIR, LANGUAGE_RULE_PACK_FILES, LEGACY_LANGUAGE_RULE_PACK_FOLDERS, UTILITY_SKILL_FOLDERS } from "./content/utility-skills.js";
|
|
21
21
|
import { CONTEXT_MODES, DEFAULT_CONTEXT_MODE } from "./content/contexts.js";
|
|
22
22
|
import { validateHookDocument } from "./hook-schema.js";
|
|
23
23
|
const execFileAsync = promisify(execFile);
|
|
@@ -409,15 +409,29 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
409
409
|
});
|
|
410
410
|
}
|
|
411
411
|
// Opt-in language rule packs: only check presence for packs the user enabled.
|
|
412
|
+
// Canonical location is .cclaw/rules/lang/<pack>.md.
|
|
412
413
|
for (const pack of parsedConfig?.languageRulePacks ?? []) {
|
|
413
|
-
const
|
|
414
|
-
if (!
|
|
414
|
+
const fileName = LANGUAGE_RULE_PACK_FILES[pack];
|
|
415
|
+
if (!fileName)
|
|
415
416
|
continue;
|
|
416
|
-
const
|
|
417
|
+
const packPath = path.join(projectRoot, RUNTIME_ROOT, ...LANGUAGE_RULE_PACK_DIR, fileName);
|
|
417
418
|
checks.push({
|
|
418
419
|
name: `language_rule_pack:${pack}`,
|
|
419
|
-
ok: await exists(
|
|
420
|
-
details:
|
|
420
|
+
ok: await exists(packPath),
|
|
421
|
+
details: packPath
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
// Drift: legacy per-language skill folders from v0.7.0 must not coexist with
|
|
425
|
+
// the new rules/lang/ layout. `cclaw sync` removes them on the next run.
|
|
426
|
+
for (const legacyFolder of LEGACY_LANGUAGE_RULE_PACK_FOLDERS) {
|
|
427
|
+
const legacyPath = path.join(projectRoot, RUNTIME_ROOT, "skills", legacyFolder);
|
|
428
|
+
const legacyPresent = await exists(legacyPath);
|
|
429
|
+
checks.push({
|
|
430
|
+
name: `language_rule_pack:no_legacy:${legacyFolder}`,
|
|
431
|
+
ok: !legacyPresent,
|
|
432
|
+
details: legacyPresent
|
|
433
|
+
? `legacy ${legacyPath} must be removed — language packs moved to ${RUNTIME_ROOT}/${LANGUAGE_RULE_PACK_DIR.join("/")}/. Run \`cclaw sync\`.`
|
|
434
|
+
: `no legacy ${legacyFolder} skill folder`
|
|
421
435
|
});
|
|
422
436
|
}
|
|
423
437
|
// Agent definition files
|
|
@@ -680,11 +694,21 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
680
694
|
ok: true,
|
|
681
695
|
details: hasPython ? "python3 available" : "warning: python3 not found, jq/node paths must stay healthy"
|
|
682
696
|
});
|
|
683
|
-
// Knowledge store exists
|
|
697
|
+
// Knowledge store exists (canonical JSONL, no markdown mirror)
|
|
684
698
|
checks.push({
|
|
685
699
|
name: "knowledge:store_exists",
|
|
686
|
-
ok: await exists(path.join(projectRoot, RUNTIME_ROOT, "knowledge.
|
|
687
|
-
details: `${RUNTIME_ROOT}/knowledge.
|
|
700
|
+
ok: await exists(path.join(projectRoot, RUNTIME_ROOT, "knowledge.jsonl")),
|
|
701
|
+
details: `${RUNTIME_ROOT}/knowledge.jsonl must exist`
|
|
702
|
+
});
|
|
703
|
+
// There must be NO legacy markdown knowledge store — JSONL is the only store.
|
|
704
|
+
const legacyKnowledgeMdPath = path.join(projectRoot, RUNTIME_ROOT, "knowledge.md");
|
|
705
|
+
const legacyExists = await exists(legacyKnowledgeMdPath);
|
|
706
|
+
checks.push({
|
|
707
|
+
name: "knowledge:no_legacy_markdown",
|
|
708
|
+
ok: !legacyExists,
|
|
709
|
+
details: legacyExists
|
|
710
|
+
? `legacy ${RUNTIME_ROOT}/knowledge.md must be removed — cclaw is JSONL-native`
|
|
711
|
+
: `no legacy markdown store present`
|
|
688
712
|
});
|
|
689
713
|
checks.push({
|
|
690
714
|
name: "state:checkpoint_exists",
|
package/dist/install.js
CHANGED
|
@@ -17,7 +17,7 @@ import { contextMonitorScript, promptGuardScript, workflowGuardScript } from "./
|
|
|
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
19
|
import { stageSkillFolder, stageSkillMarkdown } from "./content/skills.js";
|
|
20
|
-
import {
|
|
20
|
+
import { LANGUAGE_RULE_PACK_DIR, LANGUAGE_RULE_PACK_FILES, LANGUAGE_RULE_PACK_GENERATORS, LEGACY_LANGUAGE_RULE_PACK_FOLDERS, UTILITY_SKILL_FOLDERS, UTILITY_SKILL_MAP } from "./content/utility-skills.js";
|
|
21
21
|
import { createInitialFlowState } from "./flow-state.js";
|
|
22
22
|
import { ensureDir, exists, writeFileSafe } from "./fs-utils.js";
|
|
23
23
|
import { ensureGitignore, removeGitignorePatterns } from "./gitignore.js";
|
|
@@ -183,13 +183,23 @@ async function writeSkills(projectRoot, config) {
|
|
|
183
183
|
const generator = UTILITY_SKILL_MAP[folder];
|
|
184
184
|
await writeFileSafe(runtimePath(projectRoot, "skills", folder, "SKILL.md"), generator());
|
|
185
185
|
}
|
|
186
|
+
// Language rule packs live under .cclaw/rules/lang/<pack>.md. They are opt-in:
|
|
187
|
+
// only the packs listed in config.languageRulePacks are materialised. Any
|
|
188
|
+
// legacy per-language skill folders from v0.7.0 (.cclaw/skills/language-*)
|
|
189
|
+
// are cleaned up below so the new rules/lang layout is the only truth.
|
|
186
190
|
const enabledPacks = config?.languageRulePacks ?? [];
|
|
187
191
|
for (const pack of enabledPacks) {
|
|
188
|
-
const
|
|
189
|
-
const generator = LANGUAGE_RULE_PACK_GENERATORS[
|
|
190
|
-
if (!
|
|
192
|
+
const fileName = LANGUAGE_RULE_PACK_FILES[pack];
|
|
193
|
+
const generator = LANGUAGE_RULE_PACK_GENERATORS[pack];
|
|
194
|
+
if (!fileName || !generator)
|
|
191
195
|
continue;
|
|
192
|
-
await writeFileSafe(runtimePath(projectRoot,
|
|
196
|
+
await writeFileSafe(runtimePath(projectRoot, ...LANGUAGE_RULE_PACK_DIR, fileName), generator());
|
|
197
|
+
}
|
|
198
|
+
for (const legacyFolder of LEGACY_LANGUAGE_RULE_PACK_FOLDERS) {
|
|
199
|
+
const legacyPath = runtimePath(projectRoot, "skills", legacyFolder);
|
|
200
|
+
if (await exists(legacyPath)) {
|
|
201
|
+
await fs.rm(legacyPath, { recursive: true, force: true });
|
|
202
|
+
}
|
|
193
203
|
}
|
|
194
204
|
}
|
|
195
205
|
async function writeUtilityCommands(projectRoot) {
|
|
@@ -550,9 +560,13 @@ async function writeHooks(projectRoot, config) {
|
|
|
550
560
|
}
|
|
551
561
|
}
|
|
552
562
|
async function ensureKnowledgeStore(projectRoot) {
|
|
553
|
-
const storePath = runtimePath(projectRoot, "knowledge.
|
|
563
|
+
const storePath = runtimePath(projectRoot, "knowledge.jsonl");
|
|
554
564
|
if (!(await exists(storePath))) {
|
|
555
|
-
await writeFileSafe(storePath, "
|
|
565
|
+
await writeFileSafe(storePath, "");
|
|
566
|
+
}
|
|
567
|
+
const legacyMdPath = runtimePath(projectRoot, "knowledge.md");
|
|
568
|
+
if (await exists(legacyMdPath)) {
|
|
569
|
+
await fs.rm(legacyMdPath, { force: true });
|
|
556
570
|
}
|
|
557
571
|
}
|
|
558
572
|
async function ensureCustomSkillsScaffold(projectRoot) {
|
package/dist/policy.js
CHANGED
|
@@ -85,8 +85,9 @@ export async function policyChecks(projectRoot, options = {}) {
|
|
|
85
85
|
// --- utility skill checks ---
|
|
86
86
|
const runtimeFile = (relativePath) => `${RUNTIME_ROOT}/${relativePath}`;
|
|
87
87
|
const utilitySkillChecks = [
|
|
88
|
-
{ file: runtimeFile("skills/learnings/SKILL.md"), needle: "
|
|
89
|
-
{ file: runtimeFile("skills/learnings/SKILL.md"), needle: "knowledge.jsonl", name: "utility_skill:learnings:
|
|
88
|
+
{ file: runtimeFile("skills/learnings/SKILL.md"), needle: "strict JSONL schema", name: "utility_skill:learnings:jsonl_schema" },
|
|
89
|
+
{ file: runtimeFile("skills/learnings/SKILL.md"), needle: "knowledge.jsonl", name: "utility_skill:learnings:jsonl_store" },
|
|
90
|
+
{ file: runtimeFile("skills/learnings/SKILL.md"), needle: "type, trigger, action, confidence, domain, stage, created, project", name: "utility_skill:learnings:field_order" },
|
|
90
91
|
{ file: runtimeFile("skills/learnings/SKILL.md"), needle: "## Subcommands", name: "utility_skill:learnings:subcommands" },
|
|
91
92
|
{ file: runtimeFile("skills/learnings/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:learnings:hard_gate" },
|
|
92
93
|
{ file: runtimeFile("commands/learn.md"), needle: "## Subcommands", name: "utility_command:learn:subcommands" },
|
package/dist/runs.d.ts
CHANGED
|
@@ -56,11 +56,10 @@ export declare function ensureRunSystem(projectRoot: string, _options?: EnsureRu
|
|
|
56
56
|
export declare function listRuns(projectRoot: string): Promise<CclawRunMeta[]>;
|
|
57
57
|
export declare function archiveRun(projectRoot: string, featureName?: string): Promise<ArchiveRunResult>;
|
|
58
58
|
/**
|
|
59
|
-
* Counts
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* deliberate — the curator reads the file directly to make the soft-archive plan.
|
|
59
|
+
* Counts entries in the canonical JSONL knowledge store. An "active" entry is one
|
|
60
|
+
* non-empty line that parses as JSON with the required `type` field belonging to the
|
|
61
|
+
* allowed set. Malformed lines are ignored (not counted) but do not throw so that a
|
|
62
|
+
* hand-edited file cannot break doctor/archive flows.
|
|
64
63
|
*/
|
|
65
64
|
export declare function countActiveKnowledgeEntries(text: string): number;
|
|
66
65
|
export {};
|
package/dist/runs.js
CHANGED
|
@@ -407,7 +407,7 @@ export async function archiveRun(projectRoot, featureName) {
|
|
|
407
407
|
}
|
|
408
408
|
const KNOWLEDGE_SOFT_THRESHOLD = 50;
|
|
409
409
|
async function readKnowledgeStats(projectRoot) {
|
|
410
|
-
const knowledgePath = path.join(projectRoot, RUNTIME_ROOT, "knowledge.
|
|
410
|
+
const knowledgePath = path.join(projectRoot, RUNTIME_ROOT, "knowledge.jsonl");
|
|
411
411
|
let activeEntryCount = 0;
|
|
412
412
|
if (await exists(knowledgePath)) {
|
|
413
413
|
const text = await fs.readFile(knowledgePath, "utf8");
|
|
@@ -417,22 +417,30 @@ async function readKnowledgeStats(projectRoot) {
|
|
|
417
417
|
activeEntryCount,
|
|
418
418
|
softThreshold: KNOWLEDGE_SOFT_THRESHOLD,
|
|
419
419
|
overThreshold: activeEntryCount > KNOWLEDGE_SOFT_THRESHOLD,
|
|
420
|
-
knowledgePath: `${RUNTIME_ROOT}/knowledge.
|
|
420
|
+
knowledgePath: `${RUNTIME_ROOT}/knowledge.jsonl`
|
|
421
421
|
};
|
|
422
422
|
}
|
|
423
423
|
/**
|
|
424
|
-
* Counts
|
|
425
|
-
*
|
|
426
|
-
*
|
|
427
|
-
*
|
|
428
|
-
* deliberate — the curator reads the file directly to make the soft-archive plan.
|
|
424
|
+
* Counts entries in the canonical JSONL knowledge store. An "active" entry is one
|
|
425
|
+
* non-empty line that parses as JSON with the required `type` field belonging to the
|
|
426
|
+
* allowed set. Malformed lines are ignored (not counted) but do not throw so that a
|
|
427
|
+
* hand-edited file cannot break doctor/archive flows.
|
|
429
428
|
*/
|
|
430
429
|
export function countActiveKnowledgeEntries(text) {
|
|
431
|
-
const
|
|
430
|
+
const allowed = new Set(["rule", "pattern", "lesson", "compound"]);
|
|
432
431
|
let count = 0;
|
|
433
|
-
for (const
|
|
434
|
-
|
|
435
|
-
|
|
432
|
+
for (const raw of text.split(/\r?\n/)) {
|
|
433
|
+
const line = raw.trim();
|
|
434
|
+
if (line.length === 0)
|
|
435
|
+
continue;
|
|
436
|
+
try {
|
|
437
|
+
const parsed = JSON.parse(line);
|
|
438
|
+
if (typeof parsed.type === "string" && allowed.has(parsed.type)) {
|
|
439
|
+
count += 1;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
catch {
|
|
443
|
+
// Skip malformed lines silently; curation surfaces them separately.
|
|
436
444
|
}
|
|
437
445
|
}
|
|
438
446
|
return count;
|
package/dist/types.d.ts
CHANGED
|
@@ -48,10 +48,10 @@ export interface VibyConfig {
|
|
|
48
48
|
/** Default flow track for new runs (quick = shortened path, standard = full pipeline). */
|
|
49
49
|
defaultTrack?: FlowTrack;
|
|
50
50
|
/**
|
|
51
|
-
* Opt-in language rule packs. Each enabled pack materializes a matching
|
|
52
|
-
*
|
|
53
|
-
* meta-skill router loads the pack during review/tdd when the diff touches
|
|
54
|
-
* language in question.
|
|
51
|
+
* Opt-in language rule packs. Each enabled pack materializes a matching rule
|
|
52
|
+
* file under `.cclaw/rules/lang/<id>.md` on the next `cclaw sync`. The
|
|
53
|
+
* meta-skill router loads the pack during review/tdd when the diff touches
|
|
54
|
+
* the language in question. Disabled packs have no on-disk footprint.
|
|
55
55
|
*/
|
|
56
56
|
languageRulePacks?: LanguageRulePack[];
|
|
57
57
|
}
|