cclaw-cli 0.10.0 → 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/examples.js +88 -0
- 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/examples.js
CHANGED
|
@@ -714,6 +714,72 @@ const DOMAIN_LABELS = {
|
|
|
714
714
|
"data-pipeline": "Data pipeline / ETL"
|
|
715
715
|
};
|
|
716
716
|
const STAGE_DOMAIN_SAMPLES = {
|
|
717
|
+
brainstorm: [
|
|
718
|
+
{
|
|
719
|
+
domain: "web",
|
|
720
|
+
label: "Direction",
|
|
721
|
+
body: "Problem: admin dashboard orders table requires manual refresh to see new orders. Success: admins see new rows within 2s of server-side status change, no full navigation. Anti-success: WebSocket rewrite of the whole table stack when only one view needs live updates."
|
|
722
|
+
},
|
|
723
|
+
{
|
|
724
|
+
domain: "cli",
|
|
725
|
+
label: "Direction",
|
|
726
|
+
body: "Problem: `cclaw archive` silently deletes 30+ day runs with no preview. Success: a `--dry-run` flag prints would-be-archived run IDs to stdout and exits 0; current behavior is unchanged without the flag. Anti-success: adding an interactive confirmation prompt that breaks CI scripts."
|
|
727
|
+
},
|
|
728
|
+
{
|
|
729
|
+
domain: "library",
|
|
730
|
+
label: "Direction",
|
|
731
|
+
body: "Problem: consumers cannot validate hook JSON without importing internal modules. Success: `validateHookDocument(obj)` exported from the package root with typed result `{ ok, errors? }`. Anti-success: exposing the full Zod schema and forcing consumers to depend on Zod."
|
|
732
|
+
},
|
|
733
|
+
{
|
|
734
|
+
domain: "data-pipeline",
|
|
735
|
+
label: "Direction",
|
|
736
|
+
body: "Problem: reruns of the orders job create duplicate `fact_orders` rows. Success: running the job twice on the same input leaves row count unchanged and `dbt test --select fact_orders` green. Anti-success: introducing a nightly dedup job that hides the underlying non-idempotency."
|
|
737
|
+
}
|
|
738
|
+
],
|
|
739
|
+
scope: [
|
|
740
|
+
{
|
|
741
|
+
domain: "web",
|
|
742
|
+
label: "Scope line",
|
|
743
|
+
body: "In: live-update `/dashboard/orders` table via SSE; out: notification drawer, mobile PWA, dashboards other than `orders`. Discretion: choice of SSE vs long-polling for legacy Safari. NOT in scope: rewriting the auth layer or the existing REST endpoints."
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
domain: "cli",
|
|
747
|
+
label: "Scope line",
|
|
748
|
+
body: "In: add `--dry-run` to `cclaw archive`; out: redesigning archive formats, adding retention flags, or changing the default. Discretion: exact wording of stdout lines. NOT in scope: touching `init` / `sync` / `doctor` subcommands."
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
domain: "library",
|
|
752
|
+
label: "Scope line",
|
|
753
|
+
body: "In: expose `validateHookDocument` + types from package root; out: rewriting hook schema, adding new hook kinds, dropping old ones. Discretion: whether to re-export `HookDocument` as type-only. NOT in scope: migrating consumers."
|
|
754
|
+
},
|
|
755
|
+
{
|
|
756
|
+
domain: "data-pipeline",
|
|
757
|
+
label: "Scope line",
|
|
758
|
+
body: "In: dedup step between `raw.orders` and `fact_orders` keyed on `(order_id, event_ts)`; out: redesigning ingestion, adding new partitions, or touching downstream marts. Discretion: `row_number()` vs `qualify`-style dedup. NOT in scope: backfilling historical partitions."
|
|
759
|
+
}
|
|
760
|
+
],
|
|
761
|
+
design: [
|
|
762
|
+
{
|
|
763
|
+
domain: "web",
|
|
764
|
+
label: "Architecture note",
|
|
765
|
+
body: "Data flow: server-side order update → publish to `orders-updates` channel → SSE endpoint `/api/orders/stream` → `useOrderFeed` hook merges into React state → row rerenders. Failure mode: SSE connection drop → exponential-backoff reconnect + on-reconnect REST snapshot fallback. Trade-off accepted: no client→server channel (SSE one-way); existing REST mutations cover it."
|
|
766
|
+
},
|
|
767
|
+
{
|
|
768
|
+
domain: "cli",
|
|
769
|
+
label: "Architecture note",
|
|
770
|
+
body: "Flag is parsed by the existing Zod CLI parser; `--dry-run` short-circuits before any filesystem mutation, shares formatter `src/cli/format.ts` with `status`. Failure mode: formatter output differs between `status` and `archive --dry-run` → centralize format. Trade-off: we print run IDs unsorted to keep the code path identical to the real archive path."
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
domain: "library",
|
|
774
|
+
label: "Architecture note",
|
|
775
|
+
body: "Re-export `validateHookDocument` from package root; rename internal `__validate` to match the exported name so callsites and the export converge. Failure mode: consumers importing from `/dist/internal` break on the rename → add a deprecation re-export shim for one minor. Trade-off: slightly wider public surface today buys us a smaller public surface tomorrow."
|
|
776
|
+
},
|
|
777
|
+
{
|
|
778
|
+
domain: "data-pipeline",
|
|
779
|
+
label: "Architecture note",
|
|
780
|
+
body: "Insert `int_orders_deduped` CTE between staging and fact, keyed on `(order_id, event_ts)` with `row_number() = 1` per key; `fact_orders` reads from the deduped model only. Failure mode: late-arriving events with an earlier `event_ts` would flap the chosen row → tiebreak on `ingest_ts DESC`. Trade-off: the job now does one extra pass; measured +8% runtime, within budget."
|
|
781
|
+
}
|
|
782
|
+
],
|
|
717
783
|
spec: [
|
|
718
784
|
{
|
|
719
785
|
domain: "web",
|
|
@@ -780,6 +846,28 @@ const STAGE_DOMAIN_SAMPLES = {
|
|
|
780
846
|
body: "RED: `dbt test --select fact_orders` → `unique test on (order_id, event_ts)` fails on re-run. GREEN: added `row_number()` dedup in the staging model. REFACTOR: extracted the dedup CTE into `int_orders_deduped` for reuse by `fact_returns`."
|
|
781
847
|
}
|
|
782
848
|
],
|
|
849
|
+
review: [
|
|
850
|
+
{
|
|
851
|
+
domain: "web",
|
|
852
|
+
label: "Finding",
|
|
853
|
+
body: "R-W-1 (Critical, correctness): `useOrderFeed` does not unsubscribe from the SSE channel on unmount — two mounts on the same page double-count rows. Evidence: `tests/unit/order-feed-hook.test.ts > unmount` fails. Fix owner: frontend; blocks ship."
|
|
854
|
+
},
|
|
855
|
+
{
|
|
856
|
+
domain: "cli",
|
|
857
|
+
label: "Finding",
|
|
858
|
+
body: "R-C-2 (Suggestion, UX): `cclaw archive --dry-run` prints run IDs without a trailing newline, breaking downstream `xargs` pipelines. Evidence: `echo '' | xargs -I{} printf '%s\\n' {}` contrast. Fix owner: CLI; non-blocking."
|
|
859
|
+
},
|
|
860
|
+
{
|
|
861
|
+
domain: "library",
|
|
862
|
+
label: "Finding",
|
|
863
|
+
body: "R-L-1 (Important, surface-area): the new `validateHookDocument` export is documented in README but missing from `src/index.ts` — `import { validateHookDocument } from 'cclaw'` fails despite the docs. Evidence: `pnpm build && node -e \"require('./dist').validateHookDocument\"` prints `undefined`. Fix owner: library; blocks ship."
|
|
864
|
+
},
|
|
865
|
+
{
|
|
866
|
+
domain: "data-pipeline",
|
|
867
|
+
label: "Finding",
|
|
868
|
+
body: "R-D-1 (Critical, correctness): dedup CTE orders by `event_ts ASC` instead of `event_ts DESC` — on duplicate events we keep the older row. Evidence: `dbt test --select fact_orders` green but fixture `tests/fixtures/orders-dupes.csv` shows wrong survivor. Fix owner: analytics-eng; blocks ship."
|
|
869
|
+
}
|
|
870
|
+
],
|
|
783
871
|
ship: [
|
|
784
872
|
{
|
|
785
873
|
domain: "web",
|
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;
|