cclaw-cli 0.10.1 → 0.11.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/config.js +83 -3
- package/dist/content/hooks.js +81 -11
- package/dist/content/meta-skill.d.ts +0 -8
- package/dist/content/meta-skill.js +51 -341
- package/dist/content/next-command.js +2 -1
- package/dist/content/protocols.d.ts +7 -0
- package/dist/content/protocols.js +95 -0
- package/dist/content/skills.js +183 -313
- package/dist/content/stage-common-guidance.d.ts +2 -0
- package/dist/content/stage-common-guidance.js +71 -0
- package/dist/content/stage-schema.d.ts +8 -0
- package/dist/content/stage-schema.js +135 -1
- package/dist/content/start-command.js +19 -13
- package/dist/doctor.js +21 -23
- package/dist/flow-state.d.ts +4 -0
- package/dist/flow-state.js +4 -1
- package/dist/gate-evidence.d.ts +9 -1
- package/dist/gate-evidence.js +121 -17
- package/dist/install.js +10 -0
- package/dist/policy.js +16 -13
- package/dist/runs.js +21 -4
- package/dist/track-heuristics.d.ts +12 -0
- package/dist/track-heuristics.js +144 -0
- package/dist/types.d.ts +26 -3
- package/dist/types.js +6 -3
- package/package.json +1 -1
package/dist/config.js
CHANGED
|
@@ -19,7 +19,8 @@ const ALLOWED_CONFIG_KEYS = new Set([
|
|
|
19
19
|
"promptGuardMode",
|
|
20
20
|
"gitHookGuards",
|
|
21
21
|
"defaultTrack",
|
|
22
|
-
"languageRulePacks"
|
|
22
|
+
"languageRulePacks",
|
|
23
|
+
"trackHeuristics"
|
|
23
24
|
]);
|
|
24
25
|
function configFixExample() {
|
|
25
26
|
return `harnesses:
|
|
@@ -34,6 +35,21 @@ function configValidationError(configFilePath, reason) {
|
|
|
34
35
|
`Example config:\n${configFixExample()}\n` +
|
|
35
36
|
`After fixing, run: cclaw sync`);
|
|
36
37
|
}
|
|
38
|
+
function isRecord(value) {
|
|
39
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40
|
+
}
|
|
41
|
+
function validateStringArray(value, fieldName, configFilePath) {
|
|
42
|
+
if (value === undefined)
|
|
43
|
+
return undefined;
|
|
44
|
+
if (!Array.isArray(value)) {
|
|
45
|
+
throw configValidationError(configFilePath, `"${fieldName}" must be an array of strings`);
|
|
46
|
+
}
|
|
47
|
+
const invalid = value.filter((item) => typeof item !== "string");
|
|
48
|
+
if (invalid.length > 0) {
|
|
49
|
+
throw configValidationError(configFilePath, `"${fieldName}" must contain only strings`);
|
|
50
|
+
}
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
37
53
|
export function configPath(projectRoot) {
|
|
38
54
|
return path.join(projectRoot, CONFIG_PATH);
|
|
39
55
|
}
|
|
@@ -64,7 +80,7 @@ export function createProfileConfig(profile, overrides = {}) {
|
|
|
64
80
|
autoAdvance: false,
|
|
65
81
|
promptGuardMode: "advisory",
|
|
66
82
|
gitHookGuards: false,
|
|
67
|
-
defaultTrack: overrides.defaultTrack ?? "
|
|
83
|
+
defaultTrack: overrides.defaultTrack ?? "medium",
|
|
68
84
|
languageRulePacks: overrides.languageRulePacks ?? []
|
|
69
85
|
};
|
|
70
86
|
case "standard":
|
|
@@ -161,6 +177,69 @@ export async function readConfig(projectRoot) {
|
|
|
161
177
|
throw configValidationError(fullPath, `unknown languageRulePacks id(s): ${formatted}`);
|
|
162
178
|
}
|
|
163
179
|
const languageRulePacks = [...new Set(rawPacks)];
|
|
180
|
+
const trackHeuristicsRaw = parsed.trackHeuristics;
|
|
181
|
+
let trackHeuristics = undefined;
|
|
182
|
+
if (Object.prototype.hasOwnProperty.call(parsed, "trackHeuristics")) {
|
|
183
|
+
if (!isRecord(trackHeuristicsRaw)) {
|
|
184
|
+
throw configValidationError(fullPath, `"trackHeuristics" must be an object`);
|
|
185
|
+
}
|
|
186
|
+
const fallbackRaw = trackHeuristicsRaw.fallback;
|
|
187
|
+
if (fallbackRaw !== undefined && (typeof fallbackRaw !== "string" || !FLOW_TRACK_SET.has(fallbackRaw))) {
|
|
188
|
+
throw configValidationError(fullPath, `"trackHeuristics.fallback" must be one of: ${SUPPORTED_TRACKS_TEXT}`);
|
|
189
|
+
}
|
|
190
|
+
const priorityRaw = trackHeuristicsRaw.priority;
|
|
191
|
+
let priority;
|
|
192
|
+
if (priorityRaw !== undefined) {
|
|
193
|
+
if (!Array.isArray(priorityRaw)) {
|
|
194
|
+
throw configValidationError(fullPath, `"trackHeuristics.priority" must be an array`);
|
|
195
|
+
}
|
|
196
|
+
const invalidPriority = priorityRaw.filter((value) => typeof value !== "string" || !FLOW_TRACK_SET.has(value));
|
|
197
|
+
if (invalidPriority.length > 0) {
|
|
198
|
+
throw configValidationError(fullPath, `"trackHeuristics.priority" must contain only: ${SUPPORTED_TRACKS_TEXT}`);
|
|
199
|
+
}
|
|
200
|
+
priority = [...new Set(priorityRaw)];
|
|
201
|
+
}
|
|
202
|
+
const tracksRaw = trackHeuristicsRaw.tracks;
|
|
203
|
+
let tracks = undefined;
|
|
204
|
+
if (tracksRaw !== undefined) {
|
|
205
|
+
if (!isRecord(tracksRaw)) {
|
|
206
|
+
throw configValidationError(fullPath, `"trackHeuristics.tracks" must be an object`);
|
|
207
|
+
}
|
|
208
|
+
tracks = {};
|
|
209
|
+
for (const [trackName, ruleRaw] of Object.entries(tracksRaw)) {
|
|
210
|
+
if (!FLOW_TRACK_SET.has(trackName)) {
|
|
211
|
+
throw configValidationError(fullPath, `"trackHeuristics.tracks" contains unknown track "${trackName}". Supported: ${SUPPORTED_TRACKS_TEXT}`);
|
|
212
|
+
}
|
|
213
|
+
if (!isRecord(ruleRaw)) {
|
|
214
|
+
throw configValidationError(fullPath, `"trackHeuristics.tracks.${trackName}" must be an object`);
|
|
215
|
+
}
|
|
216
|
+
const triggers = validateStringArray(ruleRaw.triggers, `trackHeuristics.tracks.${trackName}.triggers`, fullPath);
|
|
217
|
+
const patterns = validateStringArray(ruleRaw.patterns, `trackHeuristics.tracks.${trackName}.patterns`, fullPath);
|
|
218
|
+
const veto = validateStringArray(ruleRaw.veto, `trackHeuristics.tracks.${trackName}.veto`, fullPath);
|
|
219
|
+
if (patterns) {
|
|
220
|
+
for (const pattern of patterns) {
|
|
221
|
+
try {
|
|
222
|
+
// eslint-disable-next-line no-new
|
|
223
|
+
new RegExp(pattern, "iu");
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
throw configValidationError(fullPath, `"trackHeuristics.tracks.${trackName}.patterns" contains invalid regex "${pattern}"`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
tracks[trackName] = {
|
|
231
|
+
triggers,
|
|
232
|
+
patterns,
|
|
233
|
+
veto
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
trackHeuristics = {
|
|
238
|
+
fallback: fallbackRaw,
|
|
239
|
+
priority,
|
|
240
|
+
tracks
|
|
241
|
+
};
|
|
242
|
+
}
|
|
164
243
|
return {
|
|
165
244
|
version: parsed.version ?? CCLAW_VERSION,
|
|
166
245
|
flowVersion: parsed.flowVersion ?? FLOW_VERSION,
|
|
@@ -169,7 +248,8 @@ export async function readConfig(projectRoot) {
|
|
|
169
248
|
promptGuardMode,
|
|
170
249
|
gitHookGuards,
|
|
171
250
|
defaultTrack,
|
|
172
|
-
languageRulePacks
|
|
251
|
+
languageRulePacks,
|
|
252
|
+
trackHeuristics
|
|
173
253
|
};
|
|
174
254
|
}
|
|
175
255
|
export async function writeConfig(projectRoot, config) {
|
package/dist/content/hooks.js
CHANGED
|
@@ -39,7 +39,7 @@ export const RUNTIME_SHELL_DETECT_ROOT = DETECT_ROOT;
|
|
|
39
39
|
export function sessionStartScript(_options = {}) {
|
|
40
40
|
return `#!/usr/bin/env bash
|
|
41
41
|
# cclaw session-start hook — generated by cclaw sync
|
|
42
|
-
# Injects using-cclaw + flow status + active artifacts + knowledge
|
|
42
|
+
# Injects using-cclaw + flow status + active artifacts + compact knowledge digest + checkpoint/activity summary.
|
|
43
43
|
set -euo pipefail
|
|
44
44
|
|
|
45
45
|
${DETECT_ROOT}
|
|
@@ -52,6 +52,7 @@ 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
54
|
KNOWLEDGE_FILE="$ROOT/${RUNTIME_ROOT}/knowledge.jsonl"
|
|
55
|
+
KNOWLEDGE_DIGEST_FILE="$ROOT/${RUNTIME_ROOT}/state/knowledge-digest.md"
|
|
55
56
|
META_SKILL="$ROOT/${RUNTIME_ROOT}/skills/${META_SKILL_NAME}/SKILL.md"
|
|
56
57
|
|
|
57
58
|
# --- Read flow state ---
|
|
@@ -309,12 +310,72 @@ if [ -f "$META_SKILL" ]; then
|
|
|
309
310
|
META_CONTENT=$(cat "$META_SKILL" 2>/dev/null || echo "")
|
|
310
311
|
fi
|
|
311
312
|
|
|
312
|
-
# ---
|
|
313
|
-
|
|
313
|
+
# --- Build compact knowledge digest (stage-biased, top entries only) ---
|
|
314
|
+
KNOWLEDGE_DIGEST=""
|
|
314
315
|
LEARNINGS_COUNT=0
|
|
315
316
|
if [ -f "$KNOWLEDGE_FILE" ] && [ -s "$KNOWLEDGE_FILE" ]; then
|
|
316
|
-
KNOWLEDGE_SUMMARY=$(tail -n 30 "$KNOWLEDGE_FILE" 2>/dev/null || echo "")
|
|
317
317
|
LEARNINGS_COUNT=$(grep -c '^{' "$KNOWLEDGE_FILE" 2>/dev/null || echo "0")
|
|
318
|
+
if command -v jq >/dev/null 2>&1; then
|
|
319
|
+
KNOWLEDGE_DIGEST=$(tail -n 200 "$KNOWLEDGE_FILE" 2>/dev/null | jq -Rsc --arg stage "$STAGE" '
|
|
320
|
+
split("\\n")
|
|
321
|
+
| map(select(length > 0))
|
|
322
|
+
| map(try fromjson catch null)
|
|
323
|
+
| map(select(type == "object"))
|
|
324
|
+
| map(select((.stage // null) == $stage or (.stage // null) == null))
|
|
325
|
+
| reverse
|
|
326
|
+
| .[0:8]
|
|
327
|
+
| map("- [" + ((.confidence // "unknown")|tostring) + " • " + ((.stage // "global")|tostring) + " • " + ((.domain // "general")|tostring) + "] " + ((.trigger // "trigger")|tostring) + " -> " + ((.action // "action")|tostring))
|
|
328
|
+
| join("\\n")
|
|
329
|
+
' 2>/dev/null || echo "")
|
|
330
|
+
elif command -v python3 >/dev/null 2>&1; then
|
|
331
|
+
KNOWLEDGE_DIGEST=$(python3 - "$KNOWLEDGE_FILE" "$STAGE" <<'PY'
|
|
332
|
+
import json
|
|
333
|
+
import sys
|
|
334
|
+
|
|
335
|
+
path = sys.argv[1]
|
|
336
|
+
stage = sys.argv[2]
|
|
337
|
+
entries = []
|
|
338
|
+
try:
|
|
339
|
+
with open(path, "r", encoding="utf-8") as fh:
|
|
340
|
+
lines = fh.readlines()[-200:]
|
|
341
|
+
for raw in lines:
|
|
342
|
+
raw = raw.strip()
|
|
343
|
+
if not raw:
|
|
344
|
+
continue
|
|
345
|
+
try:
|
|
346
|
+
obj = json.loads(raw)
|
|
347
|
+
except Exception:
|
|
348
|
+
continue
|
|
349
|
+
if not isinstance(obj, dict):
|
|
350
|
+
continue
|
|
351
|
+
row_stage = obj.get("stage")
|
|
352
|
+
if row_stage not in (stage, None):
|
|
353
|
+
continue
|
|
354
|
+
entries.append(obj)
|
|
355
|
+
except Exception:
|
|
356
|
+
entries = []
|
|
357
|
+
|
|
358
|
+
entries = list(reversed(entries))[:8]
|
|
359
|
+
out = []
|
|
360
|
+
for obj in entries:
|
|
361
|
+
conf = str(obj.get("confidence", "unknown"))
|
|
362
|
+
row_stage = str(obj.get("stage", "global"))
|
|
363
|
+
domain = str(obj.get("domain", "general"))
|
|
364
|
+
trigger = str(obj.get("trigger", "trigger"))
|
|
365
|
+
action = str(obj.get("action", "action"))
|
|
366
|
+
out.append(f"- [{conf} • {row_stage} • {domain}] {trigger} -> {action}")
|
|
367
|
+
print("\\n".join(out))
|
|
368
|
+
PY
|
|
369
|
+
)
|
|
370
|
+
else
|
|
371
|
+
KNOWLEDGE_DIGEST=$(tail -n 8 "$KNOWLEDGE_FILE" 2>/dev/null || echo "")
|
|
372
|
+
fi
|
|
373
|
+
fi
|
|
374
|
+
|
|
375
|
+
if [ -n "$KNOWLEDGE_DIGEST" ]; then
|
|
376
|
+
printf '# Knowledge digest (auto-generated)\\n\\n%s\\n' "$KNOWLEDGE_DIGEST" > "$KNOWLEDGE_DIGEST_FILE" 2>/dev/null || true
|
|
377
|
+
elif [ -f "$KNOWLEDGE_DIGEST_FILE" ]; then
|
|
378
|
+
printf '# Knowledge digest (auto-generated)\\n\\n(no matching entries for current stage)\\n' > "$KNOWLEDGE_DIGEST_FILE" 2>/dev/null || true
|
|
318
379
|
fi
|
|
319
380
|
|
|
320
381
|
# --- Installed cclaw-cli version vs. project's recorded version (one-block
|
|
@@ -391,10 +452,10 @@ if [ -n "$STAGE_SUGGESTION" ]; then
|
|
|
391
452
|
$STAGE_SUGGESTION
|
|
392
453
|
To disable suggestions persistently set ${RUNTIME_ROOT}/state/suggestion-memory.json -> enabled=false."
|
|
393
454
|
fi
|
|
394
|
-
if [ -n "$
|
|
455
|
+
if [ -n "$KNOWLEDGE_DIGEST" ]; then
|
|
395
456
|
CTX="$CTX
|
|
396
|
-
Knowledge
|
|
397
|
-
$
|
|
457
|
+
Knowledge digest (top relevant entries):
|
|
458
|
+
$KNOWLEDGE_DIGEST"
|
|
398
459
|
fi
|
|
399
460
|
if [ -n "$META_CONTENT" ]; then
|
|
400
461
|
CTX="$CTX
|
|
@@ -833,6 +894,7 @@ export default function cclawPlugin(ctx) {
|
|
|
833
894
|
const contextsDir = join(runtimeDir, "contexts");
|
|
834
895
|
const sessionDigestPath = join(stateDir, "session-digest.md");
|
|
835
896
|
const knowledgePath = join(runtimeDir, "knowledge.jsonl");
|
|
897
|
+
const knowledgeDigestPath = join(stateDir, "knowledge-digest.md");
|
|
836
898
|
const metaSkillPath = join(runtimeDir, "skills/${META_SKILL_NAME}/SKILL.md");
|
|
837
899
|
|
|
838
900
|
function ensureRuntimeDirs() {
|
|
@@ -937,8 +999,16 @@ export default function cclawPlugin(ctx) {
|
|
|
937
999
|
}
|
|
938
1000
|
}
|
|
939
1001
|
|
|
940
|
-
function
|
|
941
|
-
|
|
1002
|
+
function readKnowledgeDigest() {
|
|
1003
|
+
const digest = readFileText(knowledgeDigestPath).trim();
|
|
1004
|
+
if (!digest) {
|
|
1005
|
+
return readTailLines(knowledgePath, 12);
|
|
1006
|
+
}
|
|
1007
|
+
return digest
|
|
1008
|
+
.split(/\\r?\\n/)
|
|
1009
|
+
.map((line) => line.trim())
|
|
1010
|
+
.filter((line) => line.length > 0)
|
|
1011
|
+
.filter((line) => !line.startsWith("#"));
|
|
942
1012
|
}
|
|
943
1013
|
|
|
944
1014
|
function buildBootstrap() {
|
|
@@ -965,8 +1035,8 @@ export default function cclawPlugin(ctx) {
|
|
|
965
1035
|
const warning = readLatestContextWarning();
|
|
966
1036
|
if (warning) parts.push("Latest context warning:", warning);
|
|
967
1037
|
|
|
968
|
-
const knowledge =
|
|
969
|
-
if (knowledge.length > 0) parts.push("Knowledge
|
|
1038
|
+
const knowledge = readKnowledgeDigest();
|
|
1039
|
+
if (knowledge.length > 0) parts.push("Knowledge digest (top relevant entries):", ...knowledge);
|
|
970
1040
|
|
|
971
1041
|
parts.push(
|
|
972
1042
|
"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."
|
|
@@ -1,10 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* using-cclaw meta-skill — injected at SessionStart via hooks.
|
|
3
|
-
*
|
|
4
|
-
* Like agent-skills' using-agent-skills, this teaches the agent HOW to use
|
|
5
|
-
* cclaw: skill discovery flowchart, activation rules, skill behaviors.
|
|
6
|
-
* The full text is injected by session-start.sh so the agent always has
|
|
7
|
-
* routing context without needing to read files first.
|
|
8
|
-
*/
|
|
9
1
|
export declare const META_SKILL_NAME = "using-cclaw";
|
|
10
2
|
export declare function usingCclawSkillMarkdown(): string;
|