cclaw-cli 0.36.0 → 0.37.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/content/compound-command.js +44 -11
- package/dist/doctor.js +23 -0
- package/package.json +1 -1
|
@@ -35,20 +35,24 @@ the user can approve individual lifts, accept-all, or skip.
|
|
|
35
35
|
- set \`closeout.compoundPromoted = 0\`,
|
|
36
36
|
- set \`closeout.shipSubstate = "ready_to_archive"\`,
|
|
37
37
|
- emit \`compound: no candidates | next: /cc-next\` and stop.
|
|
38
|
-
5.
|
|
38
|
+
5. **Drift check** each surviving candidate before presenting it (see
|
|
39
|
+
"Drift check" section in the skill): confirm the lift target file is
|
|
40
|
+
current, spot-check the repo for contradictions, demote stale clusters
|
|
41
|
+
into a new superseding entry instead of a lift.
|
|
42
|
+
6. Otherwise, present **one** structured ask (AskUserQuestion / AskQuestion /
|
|
39
43
|
plain text) summarising all candidates at once:
|
|
40
44
|
- \`apply-all\` (default) — apply every listed lift,
|
|
41
45
|
- \`apply-selected\` — prompt per-candidate,
|
|
42
46
|
- \`skip\` — record a skip reason and advance without changes.
|
|
43
|
-
|
|
47
|
+
7. Apply approved lifts to the target file(s). Each lift also appends a
|
|
44
48
|
\`type: "compound"\` entry back to \`${RUNTIME_ROOT}/knowledge.jsonl\`
|
|
45
49
|
summarising what was lifted.
|
|
46
|
-
|
|
50
|
+
8. Update flow-state:
|
|
47
51
|
- \`closeout.compoundCompletedAt = <ISO>\`,
|
|
48
52
|
- \`closeout.compoundPromoted = <count>\`,
|
|
49
53
|
- \`closeout.compoundSkipped = true\` if user picked skip,
|
|
50
54
|
- \`closeout.shipSubstate = "ready_to_archive"\`.
|
|
51
|
-
|
|
55
|
+
9. Emit one-line summary: \`compound: promoted=<N> skipped=<bool> | next: /cc-next\`.
|
|
52
56
|
|
|
53
57
|
## Primary skill
|
|
54
58
|
|
|
@@ -83,27 +87,53 @@ empty pass is allowed and must advance \`closeout.shipSubstate\` to
|
|
|
83
87
|
- \`closeout.compoundPromoted = 0\`,
|
|
84
88
|
- \`closeout.shipSubstate = "ready_to_archive"\`,
|
|
85
89
|
- announce \`compound: no candidates\` and stop.
|
|
86
|
-
4.
|
|
90
|
+
4. **Drift check — run before presenting any candidate.** Knowledge lines
|
|
91
|
+
are append-only, so textual repetition alone does not prove the rule is
|
|
92
|
+
still true. For every cluster that survives the recurrence filter:
|
|
93
|
+
|
|
94
|
+
- **Read the lift target.** Open the rule/protocol/skill file you would
|
|
95
|
+
edit. If the current contents already encode a stronger version of
|
|
96
|
+
the cluster's \`action\`, drop the candidate (nothing to lift).
|
|
97
|
+
- **Grep for contradictions.** Run a quick repo search on the cluster's
|
|
98
|
+
\`trigger\` keywords. If recent code or docs contradict the cluster,
|
|
99
|
+
treat the cluster as stale.
|
|
100
|
+
- **Check age.** Inspect \`last_seen_ts\` across the cluster's lines. If
|
|
101
|
+
every contributing line is older than ~90 days with no fresh
|
|
102
|
+
observation, treat the cluster as stale.
|
|
103
|
+
- **Handle stale clusters correctly.** Do **not** silently skip them.
|
|
104
|
+
Append a new superseding \`type: "lesson"\` line to
|
|
105
|
+
\`.cclaw/knowledge.jsonl\` whose \`trigger\` explicitly references the
|
|
106
|
+
old pattern (e.g. \`"when previous rule about X no longer holds: ..."\`)
|
|
107
|
+
and whose \`action\` documents the replacement or archive reason.
|
|
108
|
+
Then drop the candidate from the lift list.
|
|
109
|
+
- **Cite line IDs.** Every surviving candidate must list the concrete
|
|
110
|
+
knowledge line indices (1-based) that back it, not just a
|
|
111
|
+
summary string. This is what makes the lift auditable.
|
|
112
|
+
- Optionally invoke the \`knowledge-curation\` utility skill's
|
|
113
|
+
stale/duplicate/supersede heuristics if you want a second pass.
|
|
114
|
+
|
|
115
|
+
5. Otherwise, render each candidate as:
|
|
87
116
|
|
|
88
117
|
\`\`\`
|
|
89
118
|
Candidate: <short title>
|
|
90
|
-
Evidence: <knowledge
|
|
119
|
+
Evidence: <knowledge line-ids>
|
|
120
|
+
Freshness: <newest last_seen_ts among evidence lines>
|
|
91
121
|
Lift target: <rule/protocol/skill file>
|
|
92
122
|
Change type: <add/update/remove>
|
|
93
123
|
Expected benefit: <what regressions this prevents>
|
|
94
124
|
\`\`\`
|
|
95
125
|
|
|
96
|
-
|
|
126
|
+
6. Present **one** structured question with three options:
|
|
97
127
|
- \`apply-all\` (default) — apply every candidate,
|
|
98
128
|
- \`apply-selected\` — prompt per-candidate approval next,
|
|
99
129
|
- \`skip\` — record a skip reason and advance.
|
|
100
130
|
|
|
101
|
-
|
|
131
|
+
7. For approved candidates:
|
|
102
132
|
- edit the target file(s) with the lift,
|
|
103
133
|
- append a \`type: "compound"\` entry to \`.cclaw/knowledge.jsonl\`
|
|
104
|
-
describing what was promoted.
|
|
134
|
+
describing what was promoted, including the source line IDs.
|
|
105
135
|
|
|
106
|
-
|
|
136
|
+
8. Update flow-state \`closeout\`:
|
|
107
137
|
- \`compoundCompletedAt\`,
|
|
108
138
|
- \`compoundPromoted\` (count),
|
|
109
139
|
- \`compoundSkipped\` (boolean) + \`compoundSkipReason\` when applicable,
|
|
@@ -122,6 +152,9 @@ closeout chain's perspective.
|
|
|
122
152
|
- \`closeout.compoundCompletedAt\` is set.
|
|
123
153
|
- \`closeout.shipSubstate === "ready_to_archive"\`.
|
|
124
154
|
- If lifts were applied, the target files show the edit and at least one
|
|
125
|
-
new \`compound\` line exists in \`.cclaw/knowledge.jsonl
|
|
155
|
+
new \`compound\` line exists in \`.cclaw/knowledge.jsonl\`, and the new
|
|
156
|
+
line references the source knowledge line IDs.
|
|
157
|
+
- If drift check demoted any cluster, a new superseding \`lesson\` line
|
|
158
|
+
exists on the same run documenting the replacement.
|
|
126
159
|
`;
|
|
127
160
|
}
|
package/dist/doctor.js
CHANGED
|
@@ -873,7 +873,13 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
873
873
|
let missingSchemaV2Fields = 0;
|
|
874
874
|
let parsedKnowledgeLines = 0;
|
|
875
875
|
let lowConfidenceLines = 0;
|
|
876
|
+
let staleRawEntries = 0;
|
|
876
877
|
const triggerActionCounts = new Map();
|
|
878
|
+
// Stale threshold for raw entries: ~90 days with no re-observation.
|
|
879
|
+
// Chosen to match the compound drift checklist language; anything newer is
|
|
880
|
+
// recent enough to trust, anything older deserves a curate/supersede pass.
|
|
881
|
+
const STALE_RAW_THRESHOLD_MS = 90 * 24 * 60 * 60 * 1000;
|
|
882
|
+
const now = Date.now();
|
|
877
883
|
const requiredV2Fields = [
|
|
878
884
|
"type",
|
|
879
885
|
"trigger",
|
|
@@ -919,6 +925,14 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
919
925
|
if (missing) {
|
|
920
926
|
missingSchemaV2Fields += 1;
|
|
921
927
|
}
|
|
928
|
+
const maturity = typeof parsed.maturity === "string" ? parsed.maturity.toLowerCase() : "";
|
|
929
|
+
const lastSeenRaw = typeof parsed.last_seen_ts === "string" ? parsed.last_seen_ts : "";
|
|
930
|
+
if (maturity === "raw" && lastSeenRaw.length > 0) {
|
|
931
|
+
const lastSeenMs = Date.parse(lastSeenRaw);
|
|
932
|
+
if (Number.isFinite(lastSeenMs) && now - lastSeenMs > STALE_RAW_THRESHOLD_MS) {
|
|
933
|
+
staleRawEntries += 1;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
922
936
|
}
|
|
923
937
|
catch {
|
|
924
938
|
malformedKnowledgeLines += 1;
|
|
@@ -962,6 +976,15 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
962
976
|
? "no high-frequency repeated trigger/action clusters detected"
|
|
963
977
|
: `warning: ${repeatedClusters.length} repeated learning cluster(s) detected (>=3 repeats). Consider /cc-ops compound to lift them into rules/skills.`
|
|
964
978
|
});
|
|
979
|
+
checks.push({
|
|
980
|
+
name: "warning:knowledge:stale_raw_entries",
|
|
981
|
+
ok: true,
|
|
982
|
+
details: parsedKnowledgeLines === 0
|
|
983
|
+
? "knowledge.jsonl is empty"
|
|
984
|
+
: staleRawEntries === 0
|
|
985
|
+
? `no raw knowledge entries older than 90 days`
|
|
986
|
+
: `warning: ${staleRawEntries} raw knowledge entry(ies) have last_seen_ts older than 90 days. Run /cc-learn curate or append a superseding entry before the next /cc-ops compound pass.`
|
|
987
|
+
});
|
|
965
988
|
}
|
|
966
989
|
checks.push({
|
|
967
990
|
name: "state:checkpoint_exists",
|