cclaw-cli 0.6.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/cli.d.ts +4 -2
- package/dist/cli.js +33 -7
- package/dist/config.d.ts +11 -1
- package/dist/config.js +64 -4
- package/dist/content/contracts.js +1 -1
- package/dist/content/hooks.js +6 -6
- package/dist/content/learnings.d.ts +5 -0
- package/dist/content/learnings.js +95 -58
- package/dist/content/meta-skill.js +55 -9
- package/dist/content/session-hooks.js +2 -2
- package/dist/content/skills.js +2 -2
- package/dist/content/stage-schema.d.ts +18 -1
- package/dist/content/stage-schema.js +26 -10
- package/dist/content/start-command.js +30 -7
- package/dist/content/status-command.js +29 -7
- package/dist/content/templates.js +29 -7
- package/dist/content/utility-skills.d.ts +28 -1
- package/dist/content/utility-skills.js +342 -29
- package/dist/delegation.d.ts +6 -1
- package/dist/delegation.js +3 -2
- package/dist/doctor.js +65 -4
- package/dist/install.d.ts +3 -1
- package/dist/install.js +98 -21
- package/dist/policy.js +3 -1
- package/dist/runs.d.ts +14 -0
- package/dist/runs.js +43 -1
- package/dist/types.d.ts +29 -0
- package/dist/types.js +20 -0
- package/package.json +1 -1
package/dist/cli.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import type { FlowTrack, HarnessId } from "./types.js";
|
|
2
|
+
import type { FlowTrack, HarnessId, InitProfile } from "./types.js";
|
|
3
3
|
type CommandName = "init" | "sync" | "doctor" | "upgrade" | "uninstall" | "archive";
|
|
4
4
|
interface ParsedArgs {
|
|
5
5
|
command?: CommandName;
|
|
6
6
|
harnesses?: HarnessId[];
|
|
7
7
|
track?: FlowTrack;
|
|
8
|
+
profile?: InitProfile;
|
|
8
9
|
reconcileGates?: boolean;
|
|
9
10
|
archiveName?: string;
|
|
10
11
|
showHelp?: boolean;
|
|
@@ -13,5 +14,6 @@ interface ParsedArgs {
|
|
|
13
14
|
export declare function usage(): string;
|
|
14
15
|
declare function parseHarnesses(raw: string): HarnessId[];
|
|
15
16
|
declare function parseTrack(raw: string): FlowTrack;
|
|
17
|
+
declare function parseProfile(raw: string): InitProfile;
|
|
16
18
|
declare function parseArgs(argv: string[]): ParsedArgs;
|
|
17
|
-
export { parseArgs, parseHarnesses, parseTrack };
|
|
19
|
+
export { parseArgs, parseHarnesses, parseTrack, parseProfile };
|
package/dist/cli.js
CHANGED
|
@@ -3,11 +3,12 @@ import { readFileSync, realpathSync } from "node:fs";
|
|
|
3
3
|
import process from "node:process";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { FLOW_TRACKS, HARNESS_IDS } from "./types.js";
|
|
6
|
+
import { FLOW_TRACKS, HARNESS_IDS, INIT_PROFILES } from "./types.js";
|
|
7
7
|
import { doctorChecks, doctorSucceeded } from "./doctor.js";
|
|
8
8
|
import { initCclaw, syncCclaw, uninstallCclaw, upgradeCclaw } from "./install.js";
|
|
9
9
|
import { error, info } from "./logger.js";
|
|
10
10
|
import { archiveRun } from "./runs.js";
|
|
11
|
+
import { RUNTIME_ROOT } from "./constants.js";
|
|
11
12
|
const INSTALLER_COMMANDS = ["init", "sync", "doctor", "upgrade", "uninstall", "archive"];
|
|
12
13
|
export function usage() {
|
|
13
14
|
return `cclaw - installer-first flow toolkit
|
|
@@ -19,8 +20,9 @@ Usage:
|
|
|
19
20
|
|
|
20
21
|
Commands:
|
|
21
22
|
init Bootstrap .cclaw runtime, state, and harness shims in this project.
|
|
22
|
-
Flags: --
|
|
23
|
-
--
|
|
23
|
+
Flags: --profile=<id> Pre-fill defaults. One of: minimal | standard | full. Default: standard.
|
|
24
|
+
--harnesses=<list> Comma list of harnesses (claude,cursor,opencode,codex). Overrides the profile default.
|
|
25
|
+
--track=<id> Flow track for new runs (standard | quick). Overrides the profile default.
|
|
24
26
|
sync Regenerate harness shim files from the current .cclaw config (non-destructive).
|
|
25
27
|
doctor Run health checks against the local .cclaw runtime. Exit code 2 on failure.
|
|
26
28
|
Flags: --reconcile-gates Recompute current-stage gate evidence before checks.
|
|
@@ -85,6 +87,13 @@ function parseTrack(raw) {
|
|
|
85
87
|
}
|
|
86
88
|
return trimmed;
|
|
87
89
|
}
|
|
90
|
+
function parseProfile(raw) {
|
|
91
|
+
const trimmed = raw.trim();
|
|
92
|
+
if (!INIT_PROFILES.includes(trimmed)) {
|
|
93
|
+
throw new Error(`Unknown profile: ${trimmed}. Supported: ${INIT_PROFILES.join(", ")}`);
|
|
94
|
+
}
|
|
95
|
+
return trimmed;
|
|
96
|
+
}
|
|
88
97
|
function parseArgs(argv) {
|
|
89
98
|
const parsed = {};
|
|
90
99
|
const helpFlag = argv.find((arg) => arg === "--help" || arg === "-h");
|
|
@@ -108,6 +117,10 @@ function parseArgs(argv) {
|
|
|
108
117
|
parsed.track = parseTrack(flag.replace("--track=", ""));
|
|
109
118
|
continue;
|
|
110
119
|
}
|
|
120
|
+
if (flag.startsWith("--profile=")) {
|
|
121
|
+
parsed.profile = parseProfile(flag.replace("--profile=", ""));
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
111
124
|
if (flag === "--reconcile-gates") {
|
|
112
125
|
parsed.reconcileGates = true;
|
|
113
126
|
continue;
|
|
@@ -136,10 +149,13 @@ async function runCommand(parsed, ctx) {
|
|
|
136
149
|
await initCclaw({
|
|
137
150
|
projectRoot: ctx.cwd,
|
|
138
151
|
harnesses: parsed.harnesses,
|
|
139
|
-
track: parsed.track
|
|
152
|
+
track: parsed.track,
|
|
153
|
+
profile: parsed.profile
|
|
140
154
|
});
|
|
141
|
-
const
|
|
142
|
-
|
|
155
|
+
const profileNote = parsed.profile ? ` profile=${parsed.profile}` : "";
|
|
156
|
+
const trackNote = parsed.track ? ` track=${parsed.track}` : "";
|
|
157
|
+
const suffix = profileNote || trackNote ? ` (${(profileNote + trackNote).trim()})` : "";
|
|
158
|
+
info(ctx, `Initialized .cclaw runtime and generated harness shims${suffix}`);
|
|
143
159
|
return 0;
|
|
144
160
|
}
|
|
145
161
|
if (command === "sync") {
|
|
@@ -167,6 +183,16 @@ async function runCommand(parsed, ctx) {
|
|
|
167
183
|
? ` Snapshotted ${archived.snapshottedStateFiles.length} state file(s) under ${archived.archivePath}/state and wrote archive-manifest.json.`
|
|
168
184
|
: "";
|
|
169
185
|
info(ctx, `Archived active artifacts to ${archived.archivePath}. Flow state reset to brainstorm.${snapshotSummary}`);
|
|
186
|
+
const k = archived.knowledge;
|
|
187
|
+
if (k.overThreshold) {
|
|
188
|
+
info(ctx, `Knowledge curation recommended: ${k.knowledgePath} now has ${k.activeEntryCount} active entries (soft threshold ${k.softThreshold}). Run \`/cc-learn curate\` to plan a soft-archive of stale/duplicate entries to ${RUNTIME_ROOT}/knowledge.archive.md.`);
|
|
189
|
+
}
|
|
190
|
+
else if (k.activeEntryCount > 0) {
|
|
191
|
+
info(ctx, `Knowledge: ${k.activeEntryCount}/${k.softThreshold} active entries. Run \`/cc-learn curate\` if you want a sweep before the next run.`);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
info(ctx, `Knowledge: 0 active entries in ${k.knowledgePath}. Capture lessons from this run with \`/cc-learn add\` before they fade.`);
|
|
195
|
+
}
|
|
170
196
|
return 0;
|
|
171
197
|
}
|
|
172
198
|
await uninstallCclaw(ctx.cwd);
|
|
@@ -204,4 +230,4 @@ function isDirectExecution() {
|
|
|
204
230
|
if (isDirectExecution()) {
|
|
205
231
|
void main();
|
|
206
232
|
}
|
|
207
|
-
export { parseArgs, parseHarnesses, parseTrack };
|
|
233
|
+
export { parseArgs, parseHarnesses, parseTrack, parseProfile };
|
package/dist/config.d.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
-
import type { FlowTrack, HarnessId, VibyConfig } from "./types.js";
|
|
1
|
+
import type { FlowTrack, HarnessId, InitProfile, LanguageRulePack, VibyConfig } from "./types.js";
|
|
2
2
|
export declare function configPath(projectRoot: string): string;
|
|
3
3
|
export declare function createDefaultConfig(harnesses?: HarnessId[], defaultTrack?: FlowTrack): VibyConfig;
|
|
4
|
+
/**
|
|
5
|
+
* Build a VibyConfig for a named init profile. Profile defaults are applied
|
|
6
|
+
* first, then any explicit overrides (CLI flags) win. This keeps the profile
|
|
7
|
+
* contract deterministic and testable.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createProfileConfig(profile: InitProfile, overrides?: {
|
|
10
|
+
harnesses?: HarnessId[];
|
|
11
|
+
defaultTrack?: FlowTrack;
|
|
12
|
+
languageRulePacks?: LanguageRulePack[];
|
|
13
|
+
}): VibyConfig;
|
|
4
14
|
export declare function readConfig(projectRoot: string): Promise<VibyConfig>;
|
|
5
15
|
export declare function writeConfig(projectRoot: string, config: VibyConfig): Promise<void>;
|
package/dist/config.js
CHANGED
|
@@ -3,12 +3,14 @@ import path from "node:path";
|
|
|
3
3
|
import { parse, stringify } from "yaml";
|
|
4
4
|
import { CCLAW_VERSION, DEFAULT_HARNESSES, FLOW_VERSION, RUNTIME_ROOT } from "./constants.js";
|
|
5
5
|
import { exists, writeFileSafe } from "./fs-utils.js";
|
|
6
|
-
import { FLOW_TRACKS, HARNESS_IDS } from "./types.js";
|
|
6
|
+
import { FLOW_TRACKS, HARNESS_IDS, LANGUAGE_RULE_PACKS } from "./types.js";
|
|
7
7
|
const CONFIG_PATH = `${RUNTIME_ROOT}/config.yaml`;
|
|
8
8
|
const HARNESS_ID_SET = new Set(HARNESS_IDS);
|
|
9
9
|
const FLOW_TRACK_SET = new Set(FLOW_TRACKS);
|
|
10
|
+
const LANGUAGE_RULE_PACK_SET = new Set(LANGUAGE_RULE_PACKS);
|
|
10
11
|
const SUPPORTED_HARNESSES_TEXT = HARNESS_IDS.join(", ");
|
|
11
12
|
const SUPPORTED_TRACKS_TEXT = FLOW_TRACKS.join(", ");
|
|
13
|
+
const SUPPORTED_LANGUAGE_RULE_PACKS_TEXT = LANGUAGE_RULE_PACKS.join(", ");
|
|
12
14
|
const ALLOWED_CONFIG_KEYS = new Set([
|
|
13
15
|
"version",
|
|
14
16
|
"flowVersion",
|
|
@@ -16,7 +18,8 @@ const ALLOWED_CONFIG_KEYS = new Set([
|
|
|
16
18
|
"autoAdvance",
|
|
17
19
|
"promptGuardMode",
|
|
18
20
|
"gitHookGuards",
|
|
19
|
-
"defaultTrack"
|
|
21
|
+
"defaultTrack",
|
|
22
|
+
"languageRulePacks"
|
|
20
23
|
]);
|
|
21
24
|
function configFixExample() {
|
|
22
25
|
return `harnesses:
|
|
@@ -27,6 +30,7 @@ function configValidationError(configFilePath, reason) {
|
|
|
27
30
|
return new Error(`Invalid cclaw config at ${configFilePath}: ${reason}\n` +
|
|
28
31
|
`Supported harnesses: ${SUPPORTED_HARNESSES_TEXT}\n` +
|
|
29
32
|
`Supported tracks: ${SUPPORTED_TRACKS_TEXT}\n` +
|
|
33
|
+
`Supported languageRulePacks: ${SUPPORTED_LANGUAGE_RULE_PACKS_TEXT}\n` +
|
|
30
34
|
`Example config:\n${configFixExample()}\n` +
|
|
31
35
|
`After fixing, run: cclaw sync`);
|
|
32
36
|
}
|
|
@@ -41,9 +45,50 @@ export function createDefaultConfig(harnesses = DEFAULT_HARNESSES, defaultTrack
|
|
|
41
45
|
autoAdvance: false,
|
|
42
46
|
promptGuardMode: "advisory",
|
|
43
47
|
gitHookGuards: false,
|
|
44
|
-
defaultTrack
|
|
48
|
+
defaultTrack,
|
|
49
|
+
languageRulePacks: []
|
|
45
50
|
};
|
|
46
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Build a VibyConfig for a named init profile. Profile defaults are applied
|
|
54
|
+
* first, then any explicit overrides (CLI flags) win. This keeps the profile
|
|
55
|
+
* contract deterministic and testable.
|
|
56
|
+
*/
|
|
57
|
+
export function createProfileConfig(profile, overrides = {}) {
|
|
58
|
+
const base = createDefaultConfig();
|
|
59
|
+
switch (profile) {
|
|
60
|
+
case "minimal":
|
|
61
|
+
return {
|
|
62
|
+
...base,
|
|
63
|
+
harnesses: overrides.harnesses ?? ["claude"],
|
|
64
|
+
autoAdvance: false,
|
|
65
|
+
promptGuardMode: "advisory",
|
|
66
|
+
gitHookGuards: false,
|
|
67
|
+
defaultTrack: overrides.defaultTrack ?? "quick",
|
|
68
|
+
languageRulePacks: overrides.languageRulePacks ?? []
|
|
69
|
+
};
|
|
70
|
+
case "standard":
|
|
71
|
+
return {
|
|
72
|
+
...base,
|
|
73
|
+
harnesses: overrides.harnesses ?? DEFAULT_HARNESSES,
|
|
74
|
+
autoAdvance: false,
|
|
75
|
+
promptGuardMode: "advisory",
|
|
76
|
+
gitHookGuards: false,
|
|
77
|
+
defaultTrack: overrides.defaultTrack ?? "standard",
|
|
78
|
+
languageRulePacks: overrides.languageRulePacks ?? []
|
|
79
|
+
};
|
|
80
|
+
case "full":
|
|
81
|
+
return {
|
|
82
|
+
...base,
|
|
83
|
+
harnesses: overrides.harnesses ?? DEFAULT_HARNESSES,
|
|
84
|
+
autoAdvance: false,
|
|
85
|
+
promptGuardMode: "strict",
|
|
86
|
+
gitHookGuards: true,
|
|
87
|
+
defaultTrack: overrides.defaultTrack ?? "standard",
|
|
88
|
+
languageRulePacks: overrides.languageRulePacks ?? [...LANGUAGE_RULE_PACKS]
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
47
92
|
export async function readConfig(projectRoot) {
|
|
48
93
|
const fullPath = configPath(projectRoot);
|
|
49
94
|
if (!(await exists(fullPath))) {
|
|
@@ -102,6 +147,20 @@ export async function readConfig(projectRoot) {
|
|
|
102
147
|
const defaultTrack = typeof defaultTrackRaw === "string" && FLOW_TRACK_SET.has(defaultTrackRaw)
|
|
103
148
|
? defaultTrackRaw
|
|
104
149
|
: "standard";
|
|
150
|
+
const languageRulePacksRaw = parsed.languageRulePacks;
|
|
151
|
+
const hasLanguageRulePacksField = Object.prototype.hasOwnProperty.call(parsed, "languageRulePacks");
|
|
152
|
+
if (hasLanguageRulePacksField && !Array.isArray(languageRulePacksRaw)) {
|
|
153
|
+
throw configValidationError(fullPath, `"languageRulePacks" must be an array`);
|
|
154
|
+
}
|
|
155
|
+
const rawPacks = (languageRulePacksRaw ?? []);
|
|
156
|
+
const invalidPacks = rawPacks.filter((pack) => typeof pack !== "string" || !LANGUAGE_RULE_PACK_SET.has(pack));
|
|
157
|
+
if (invalidPacks.length > 0) {
|
|
158
|
+
const formatted = invalidPacks
|
|
159
|
+
.map((item) => (typeof item === "string" ? item : JSON.stringify(item)))
|
|
160
|
+
.join(", ");
|
|
161
|
+
throw configValidationError(fullPath, `unknown languageRulePacks id(s): ${formatted}`);
|
|
162
|
+
}
|
|
163
|
+
const languageRulePacks = [...new Set(rawPacks)];
|
|
105
164
|
return {
|
|
106
165
|
version: parsed.version ?? CCLAW_VERSION,
|
|
107
166
|
flowVersion: parsed.flowVersion ?? FLOW_VERSION,
|
|
@@ -109,7 +168,8 @@ export async function readConfig(projectRoot) {
|
|
|
109
168
|
autoAdvance,
|
|
110
169
|
promptGuardMode,
|
|
111
170
|
gitHookGuards,
|
|
112
|
-
defaultTrack
|
|
171
|
+
defaultTrack,
|
|
172
|
+
languageRulePacks
|
|
113
173
|
};
|
|
114
174
|
}
|
|
115
175
|
export async function writeConfig(projectRoot, config) {
|
|
@@ -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,9 +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.
|
|
8
|
+
const KNOWLEDGE_PATH = ".cclaw/knowledge.jsonl";
|
|
9
|
+
const KNOWLEDGE_ARCHIVE_PATH = ".cclaw/knowledge.archive.jsonl";
|
|
5
10
|
const LEARN_SKILL_NAME = "learnings";
|
|
6
|
-
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
|
+
];
|
|
7
26
|
export function learnSkillMarkdown() {
|
|
8
27
|
return `---
|
|
9
28
|
name: ${LEARN_SKILL_NAME}
|
|
@@ -14,65 +33,81 @@ description: "${LEARN_SKILL_DESCRIPTION}"
|
|
|
14
33
|
|
|
15
34
|
## Overview
|
|
16
35
|
|
|
17
|
-
|
|
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.
|
|
18
38
|
|
|
19
|
-
Use
|
|
20
|
-
- **rule**: hard constraint to follow every time
|
|
21
|
-
- **pattern**: repeatable way that works well in this project
|
|
22
|
-
- **lesson**: non-obvious outcome from a failure or trade-off
|
|
23
|
-
- **compound**: post-ship insight about how to make the *next* feature faster (process accelerator, not domain rule)
|
|
39
|
+
Use the store to keep durable knowledge that should survive sessions:
|
|
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).
|
|
24
44
|
|
|
25
45
|
## HARD-GATE
|
|
26
46
|
|
|
27
|
-
Under \`/cc-learn\`, only modify
|
|
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).
|
|
28
50
|
|
|
29
|
-
## Entry format
|
|
51
|
+
## Entry format — strict JSONL schema
|
|
30
52
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
- Reuse: one short line
|
|
37
|
-
- Confidence: high | medium | low (optional)
|
|
38
|
-
- Domain: api | infra | ui | testing | … (optional)
|
|
39
|
-
- Project: <repo or scope name> (optional)
|
|
53
|
+
Exactly one JSON object per line. Fields must appear in the order:
|
|
54
|
+
\`type, trigger, action, confidence, domain, stage, created, project\`.
|
|
55
|
+
|
|
56
|
+
\`\`\`json
|
|
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"}
|
|
40
58
|
\`\`\`
|
|
41
59
|
|
|
60
|
+
| field | type | required | notes |
|
|
61
|
+
|---|---|---|---|
|
|
62
|
+
| \`type\` | \`"rule" \\| "pattern" \\| "lesson" \\| "compound"\` | yes | Lowercase. |
|
|
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. |
|
|
70
|
+
|
|
42
71
|
Rules:
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
|
|
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.
|
|
47
77
|
|
|
48
78
|
## Curation policy (target: ≤ 50 active entries)
|
|
49
79
|
|
|
50
|
-
The
|
|
51
|
-
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
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.
|
|
56
85
|
|
|
57
86
|
## Subcommands
|
|
58
87
|
|
|
59
88
|
### \`/cc-learn\` (default)
|
|
60
|
-
-
|
|
61
|
-
|
|
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\`.
|
|
62
92
|
|
|
63
93
|
### \`/cc-learn search <query>\`
|
|
64
|
-
-
|
|
65
|
-
|
|
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).
|
|
66
97
|
|
|
67
98
|
### \`/cc-learn add\`
|
|
68
|
-
- Ask for: \`type\`, \`
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
-
|
|
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.
|
|
72
105
|
|
|
73
106
|
### \`/cc-learn curate\`
|
|
74
107
|
- Hand off to the **knowledge-curation** skill (read-only audit + soft-archive plan).
|
|
75
|
-
- 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.
|
|
76
111
|
`;
|
|
77
112
|
}
|
|
78
113
|
export function learnCommandContract() {
|
|
@@ -80,20 +115,23 @@ export function learnCommandContract() {
|
|
|
80
115
|
|
|
81
116
|
## Purpose
|
|
82
117
|
|
|
83
|
-
Manage the project knowledge store
|
|
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.
|
|
84
121
|
|
|
85
122
|
## HARD-GATE
|
|
86
123
|
|
|
87
|
-
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.
|
|
88
126
|
|
|
89
127
|
## Subcommands
|
|
90
128
|
|
|
91
129
|
| subcommand | args | description |
|
|
92
130
|
|---|---|---|
|
|
93
|
-
| (default) | — | Show recent knowledge entries (tail
|
|
94
|
-
| \`search\` | \`<query>\` |
|
|
95
|
-
| \`add\` | — | Append
|
|
96
|
-
| \`curate\` | — | Hand off to the **knowledge-curation** skill: read-only audit + soft-archive plan when the
|
|
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. |
|
|
97
135
|
`;
|
|
98
136
|
}
|
|
99
137
|
export function selfImprovementBlock(stageName) {
|
|
@@ -103,35 +141,34 @@ After this stage, ask:
|
|
|
103
141
|
- Did I discover a non-obvious reusable **rule** or **pattern**?
|
|
104
142
|
- Did a failure reveal a reusable **lesson**?
|
|
105
143
|
|
|
106
|
-
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:
|
|
107
146
|
|
|
108
147
|
\`\`\`bash
|
|
109
148
|
TS="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
110
|
-
|
|
111
|
-
### $TS [pattern] short-title
|
|
112
|
-
- Stage: ${stageName}
|
|
113
|
-
- Context: what situation triggered this
|
|
114
|
-
- Insight: what should be remembered
|
|
115
|
-
- Reuse: how to apply this next time
|
|
116
|
-
EOF
|
|
149
|
+
printf '%s\\n' '{"type":"pattern","trigger":"when <situation>","action":"<concrete move>","confidence":"medium","domain":null,"stage":"${stageName}","created":"'"$TS"'","project":null}' >> ${KNOWLEDGE_PATH}
|
|
117
150
|
\`\`\`
|
|
118
151
|
|
|
119
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.
|
|
120
155
|
`;
|
|
121
156
|
}
|
|
122
157
|
export function learningsSearchPreamble(stage) {
|
|
123
158
|
return `## Prior Knowledge (load at stage start)
|
|
124
159
|
|
|
125
|
-
Before stage work,
|
|
126
|
-
|
|
127
|
-
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.
|
|
128
163
|
`;
|
|
129
164
|
}
|
|
130
165
|
export function learningsAgentsMdBlock() {
|
|
131
166
|
return `### Knowledge Store
|
|
132
167
|
|
|
133
|
-
\`${KNOWLEDGE_PATH}\` — append-only
|
|
134
|
-
|
|
135
|
-
|
|
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).
|
|
136
173
|
`;
|
|
137
174
|
}
|