cclaw-cli 0.1.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/LICENSE +21 -0
- package/README.md +100 -0
- package/dist/cli.d.ts +10 -0
- package/dist/cli.js +101 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +70 -0
- package/dist/constants.d.ts +12 -0
- package/dist/constants.js +50 -0
- package/dist/content/agents.d.ts +39 -0
- package/dist/content/agents.js +244 -0
- package/dist/content/autoplan.d.ts +7 -0
- package/dist/content/autoplan.js +297 -0
- package/dist/content/contracts.d.ts +2 -0
- package/dist/content/contracts.js +50 -0
- package/dist/content/examples.d.ts +2 -0
- package/dist/content/examples.js +327 -0
- package/dist/content/hooks.d.ts +16 -0
- package/dist/content/hooks.js +753 -0
- package/dist/content/learnings.d.ts +5 -0
- package/dist/content/learnings.js +265 -0
- package/dist/content/meta-skill.d.ts +10 -0
- package/dist/content/meta-skill.js +137 -0
- package/dist/content/observe.d.ts +21 -0
- package/dist/content/observe.js +1110 -0
- package/dist/content/session-hooks.d.ts +7 -0
- package/dist/content/session-hooks.js +137 -0
- package/dist/content/skills.d.ts +3 -0
- package/dist/content/skills.js +257 -0
- package/dist/content/stage-schema.d.ts +78 -0
- package/dist/content/stage-schema.js +1453 -0
- package/dist/content/subagents.d.ts +13 -0
- package/dist/content/subagents.js +616 -0
- package/dist/content/templates.d.ts +3 -0
- package/dist/content/templates.js +272 -0
- package/dist/content/utility-skills.d.ts +12 -0
- package/dist/content/utility-skills.js +467 -0
- package/dist/doctor.d.ts +7 -0
- package/dist/doctor.js +610 -0
- package/dist/flow-state.d.ts +19 -0
- package/dist/flow-state.js +41 -0
- package/dist/fs-utils.d.ts +5 -0
- package/dist/fs-utils.js +28 -0
- package/dist/gitignore.d.ts +3 -0
- package/dist/gitignore.js +43 -0
- package/dist/harness-adapters.d.ts +12 -0
- package/dist/harness-adapters.js +175 -0
- package/dist/install.d.ts +9 -0
- package/dist/install.js +562 -0
- package/dist/learnings-summarizer.d.ts +25 -0
- package/dist/learnings-summarizer.js +201 -0
- package/dist/logger.d.ts +3 -0
- package/dist/logger.js +6 -0
- package/dist/policy.d.ts +6 -0
- package/dist/policy.js +179 -0
- package/dist/runs.d.ts +18 -0
- package/dist/runs.js +446 -0
- package/dist/types.d.ts +19 -0
- package/dist/types.js +12 -0
- package/package.json +47 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
const ERROR_PATTERN = /(error|fail|timeout|exception)/iu;
|
|
2
|
+
const KEY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/u;
|
|
3
|
+
function parseJsonLine(line) {
|
|
4
|
+
const trimmed = line.trim();
|
|
5
|
+
if (!trimmed)
|
|
6
|
+
return null;
|
|
7
|
+
try {
|
|
8
|
+
const parsed = JSON.parse(trimmed);
|
|
9
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
10
|
+
return null;
|
|
11
|
+
return parsed;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function toText(value) {
|
|
18
|
+
if (typeof value === "string")
|
|
19
|
+
return value;
|
|
20
|
+
try {
|
|
21
|
+
return JSON.stringify(value);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return "";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function asValidLearning(value) {
|
|
28
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
29
|
+
return null;
|
|
30
|
+
const obj = value;
|
|
31
|
+
const ts = obj.ts;
|
|
32
|
+
const skill = obj.skill;
|
|
33
|
+
const type = obj.type;
|
|
34
|
+
const key = obj.key;
|
|
35
|
+
const insight = obj.insight;
|
|
36
|
+
const confidence = obj.confidence;
|
|
37
|
+
const source = obj.source;
|
|
38
|
+
if (typeof ts !== "string" || !ts)
|
|
39
|
+
return null;
|
|
40
|
+
if (typeof skill !== "string" || !skill)
|
|
41
|
+
return null;
|
|
42
|
+
if (type !== "pitfall" && type !== "pattern" && type !== "preference")
|
|
43
|
+
return null;
|
|
44
|
+
if (typeof key !== "string" || !KEY_PATTERN.test(key))
|
|
45
|
+
return null;
|
|
46
|
+
if (typeof insight !== "string" || insight.trim().length < 16)
|
|
47
|
+
return null;
|
|
48
|
+
if (typeof confidence !== "number" || !Number.isInteger(confidence) || confidence < 1 || confidence > 10)
|
|
49
|
+
return null;
|
|
50
|
+
if (source !== "observed" && source !== "user-stated" && source !== "inferred")
|
|
51
|
+
return null;
|
|
52
|
+
return {
|
|
53
|
+
ts,
|
|
54
|
+
skill,
|
|
55
|
+
type,
|
|
56
|
+
key,
|
|
57
|
+
insight,
|
|
58
|
+
confidence,
|
|
59
|
+
source
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function normalizeToken(value) {
|
|
63
|
+
const normalized = value.trim().replace(/[^A-Za-z0-9._-]+/gu, "-");
|
|
64
|
+
return normalized.replace(/^-+/u, "").replace(/-+$/u, "") || "unknown";
|
|
65
|
+
}
|
|
66
|
+
function maybeObservation(value) {
|
|
67
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
68
|
+
return null;
|
|
69
|
+
const obj = value;
|
|
70
|
+
return {
|
|
71
|
+
ts: typeof obj.ts === "string" ? obj.ts : undefined,
|
|
72
|
+
event: typeof obj.event === "string" ? obj.event : undefined,
|
|
73
|
+
tool: typeof obj.tool === "string" ? obj.tool : undefined,
|
|
74
|
+
phase: typeof obj.phase === "string" ? obj.phase : undefined,
|
|
75
|
+
stage: typeof obj.stage === "string" ? obj.stage : undefined,
|
|
76
|
+
runId: typeof obj.runId === "string" ? obj.runId : undefined,
|
|
77
|
+
data: obj.data
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function bestByConfidence(candidates) {
|
|
81
|
+
const table = new Map();
|
|
82
|
+
for (const candidate of candidates) {
|
|
83
|
+
const token = `${candidate.key}:${candidate.type}`;
|
|
84
|
+
const current = table.get(token);
|
|
85
|
+
if (!current || candidate.confidence > current.confidence) {
|
|
86
|
+
table.set(token, candidate);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return Array.from(table.values());
|
|
90
|
+
}
|
|
91
|
+
function buildCandidates(observations, timestamp) {
|
|
92
|
+
const toolUsage = new Map();
|
|
93
|
+
const toolErrors = new Map();
|
|
94
|
+
const stageErrors = new Map();
|
|
95
|
+
const longPayload = new Map();
|
|
96
|
+
for (const obs of observations) {
|
|
97
|
+
const tool = normalizeToken(obs.tool ?? "unknown");
|
|
98
|
+
const stage = normalizeToken(obs.stage ?? "none");
|
|
99
|
+
const payload = toText(obs.data);
|
|
100
|
+
toolUsage.set(tool, (toolUsage.get(tool) ?? 0) + 1);
|
|
101
|
+
if (payload.length >= 1500) {
|
|
102
|
+
longPayload.set(tool, (longPayload.get(tool) ?? 0) + 1);
|
|
103
|
+
}
|
|
104
|
+
if ((obs.event ?? "") === "tool_complete" && ERROR_PATTERN.test(payload)) {
|
|
105
|
+
toolErrors.set(tool, (toolErrors.get(tool) ?? 0) + 1);
|
|
106
|
+
stageErrors.set(stage, (stageErrors.get(stage) ?? 0) + 1);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const candidates = [];
|
|
110
|
+
for (const [tool, errors] of toolErrors.entries()) {
|
|
111
|
+
if (errors < 3)
|
|
112
|
+
continue;
|
|
113
|
+
candidates.push({
|
|
114
|
+
ts: timestamp,
|
|
115
|
+
skill: "observation",
|
|
116
|
+
type: "pitfall",
|
|
117
|
+
key: `frequent-errors-${tool}`,
|
|
118
|
+
insight: `Tool ${tool} produced ${errors} error-like completions in a single session; add a preflight checklist before using it.`,
|
|
119
|
+
confidence: Math.min(9, 4 + Math.floor(errors / 2)),
|
|
120
|
+
source: "observed"
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
for (const [tool, total] of toolUsage.entries()) {
|
|
124
|
+
if (total < 8)
|
|
125
|
+
continue;
|
|
126
|
+
const errors = toolErrors.get(tool) ?? 0;
|
|
127
|
+
if (errors > Math.max(1, Math.floor(total * 0.15)))
|
|
128
|
+
continue;
|
|
129
|
+
candidates.push({
|
|
130
|
+
ts: timestamp,
|
|
131
|
+
skill: "observation",
|
|
132
|
+
type: "pattern",
|
|
133
|
+
key: `reliable-tool-${tool}`,
|
|
134
|
+
insight: `Tool ${tool} was used ${total} times with low failure rate; prefer it as a first option for similar tasks.`,
|
|
135
|
+
confidence: Math.min(8, 3 + Math.floor(total / 3)),
|
|
136
|
+
source: "observed"
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
for (const [stage, errors] of stageErrors.entries()) {
|
|
140
|
+
if (stage === "none" || errors < 4)
|
|
141
|
+
continue;
|
|
142
|
+
candidates.push({
|
|
143
|
+
ts: timestamp,
|
|
144
|
+
skill: "observation",
|
|
145
|
+
type: "pitfall",
|
|
146
|
+
key: `stage-hotspot-${stage}`,
|
|
147
|
+
insight: `Stage ${stage} produced ${errors} error-like tool completions in one session; add stage-specific checks before execution.`,
|
|
148
|
+
confidence: Math.min(8, 3 + Math.floor(errors / 2)),
|
|
149
|
+
source: "observed"
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
for (const [tool, count] of longPayload.entries()) {
|
|
153
|
+
if (count < 3)
|
|
154
|
+
continue;
|
|
155
|
+
candidates.push({
|
|
156
|
+
ts: timestamp,
|
|
157
|
+
skill: "observation",
|
|
158
|
+
type: "preference",
|
|
159
|
+
key: `truncate-heavy-payloads-${tool}`,
|
|
160
|
+
insight: `Tool ${tool} produced large payloads repeatedly; summarize outputs earlier to avoid context pressure.`,
|
|
161
|
+
confidence: Math.min(7, 3 + Math.floor(count / 2)),
|
|
162
|
+
source: "observed"
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
return bestByConfidence(candidates).filter((entry) => asValidLearning(entry) !== null);
|
|
166
|
+
}
|
|
167
|
+
function appendableCandidates(existing, candidates) {
|
|
168
|
+
const bestExisting = new Map();
|
|
169
|
+
for (const entry of existing) {
|
|
170
|
+
const token = `${entry.key}:${entry.type}`;
|
|
171
|
+
const current = bestExisting.get(token) ?? 0;
|
|
172
|
+
if (entry.confidence > current)
|
|
173
|
+
bestExisting.set(token, entry.confidence);
|
|
174
|
+
}
|
|
175
|
+
const appendable = [];
|
|
176
|
+
for (const candidate of candidates) {
|
|
177
|
+
const token = `${candidate.key}:${candidate.type}`;
|
|
178
|
+
const current = bestExisting.get(token) ?? 0;
|
|
179
|
+
if (candidate.confidence > current) {
|
|
180
|
+
appendable.push(candidate);
|
|
181
|
+
bestExisting.set(token, candidate.confidence);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return appendable;
|
|
185
|
+
}
|
|
186
|
+
export function summarizeObservationLearnings(observationJsonl, existingLearningsJsonl, timestamp) {
|
|
187
|
+
const observations = observationJsonl
|
|
188
|
+
.split(/\r?\n/gu)
|
|
189
|
+
.map(parseJsonLine)
|
|
190
|
+
.filter((value) => value !== null)
|
|
191
|
+
.map(maybeObservation)
|
|
192
|
+
.filter((value) => value !== null);
|
|
193
|
+
const existing = existingLearningsJsonl
|
|
194
|
+
.split(/\r?\n/gu)
|
|
195
|
+
.map(parseJsonLine)
|
|
196
|
+
.map((value) => (value ? asValidLearning(value) : null))
|
|
197
|
+
.filter((value) => value !== null);
|
|
198
|
+
const candidates = buildCandidates(observations, timestamp);
|
|
199
|
+
const appendable = appendableCandidates(existing, candidates);
|
|
200
|
+
return { candidates, appendable };
|
|
201
|
+
}
|
package/dist/logger.d.ts
ADDED
package/dist/logger.js
ADDED
package/dist/policy.d.ts
ADDED
package/dist/policy.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { COMMAND_FILE_ORDER, RUNTIME_ROOT } from "./constants.js";
|
|
4
|
+
import { stageSchema, stagePolicyNeedles } from "./content/stage-schema.js";
|
|
5
|
+
import { stageSkillFolder } from "./content/skills.js";
|
|
6
|
+
import { exists } from "./fs-utils.js";
|
|
7
|
+
const POLICY_RULES = [];
|
|
8
|
+
export async function policyChecks(projectRoot) {
|
|
9
|
+
const checks = [];
|
|
10
|
+
const rules = [...POLICY_RULES];
|
|
11
|
+
for (const stage of COMMAND_FILE_ORDER) {
|
|
12
|
+
const folder = stageSkillFolder(stage);
|
|
13
|
+
const schema = stageSchema(stage);
|
|
14
|
+
const commandFile = `${RUNTIME_ROOT}/commands/${stage}.md`;
|
|
15
|
+
const skillFile = `${RUNTIME_ROOT}/skills/${folder}/SKILL.md`;
|
|
16
|
+
// --- thin command mandatory sections ---
|
|
17
|
+
for (const heading of [
|
|
18
|
+
"## HARD-GATE",
|
|
19
|
+
"## Gates",
|
|
20
|
+
"## Exit",
|
|
21
|
+
"## Anchors",
|
|
22
|
+
"## Context Hydration"
|
|
23
|
+
]) {
|
|
24
|
+
rules.push({
|
|
25
|
+
filePath: commandFile,
|
|
26
|
+
needle: heading,
|
|
27
|
+
name: `command:${stage}:section:${heading.replace(/^## /, "").toLowerCase().replace(/[^a-z0-9]+/g, "_")}`
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
// --- command must reference the skill ---
|
|
31
|
+
rules.push({
|
|
32
|
+
filePath: commandFile,
|
|
33
|
+
needle: `${folder}/SKILL.md`,
|
|
34
|
+
name: `command:${stage}:skill_ref`
|
|
35
|
+
});
|
|
36
|
+
// --- skill mandatory sections ---
|
|
37
|
+
for (const heading of [
|
|
38
|
+
"## Process",
|
|
39
|
+
"## Verification",
|
|
40
|
+
"## Interaction Protocol",
|
|
41
|
+
"## Common Rationalizations",
|
|
42
|
+
"## Red Flags",
|
|
43
|
+
"## HARD-GATE",
|
|
44
|
+
"## Checklist",
|
|
45
|
+
"## Context Loading",
|
|
46
|
+
"## Automatic Subagent Dispatch",
|
|
47
|
+
"## Cognitive Patterns",
|
|
48
|
+
"## Cross-Stage Traceability",
|
|
49
|
+
"## Completion Status",
|
|
50
|
+
"## Artifact Validation"
|
|
51
|
+
]) {
|
|
52
|
+
rules.push({
|
|
53
|
+
filePath: skillFile,
|
|
54
|
+
needle: heading,
|
|
55
|
+
name: `skill:${stage}:section:${heading.replace(/^## /, "").toLowerCase().replace(/[^a-z0-9]+/g, "_")}`
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// --- gate IDs in skills ---
|
|
59
|
+
for (const gate of schema.requiredGates) {
|
|
60
|
+
rules.push({
|
|
61
|
+
filePath: skillFile,
|
|
62
|
+
needle: `\`${gate.id}\``,
|
|
63
|
+
name: `skill:${stage}:gate:${gate.id}`
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
// --- verification section for build/review/ship skills ---
|
|
67
|
+
if (["build", "review", "ship"].includes(stage)) {
|
|
68
|
+
rules.push({
|
|
69
|
+
filePath: skillFile,
|
|
70
|
+
needle: "## Verification Before Completion",
|
|
71
|
+
name: `skill:${stage}:section:verification_before_completion`
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
// --- policy needles in commands ---
|
|
75
|
+
for (const needle of stagePolicyNeedles(stage)) {
|
|
76
|
+
rules.push({
|
|
77
|
+
filePath: commandFile,
|
|
78
|
+
needle,
|
|
79
|
+
name: `command:${stage}:anchor:${needle.toLowerCase().replace(/[^a-z0-9]+/g, "_")}`
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// --- utility skill checks ---
|
|
84
|
+
const runtimeFile = (relativePath) => `${RUNTIME_ROOT}/${relativePath}`;
|
|
85
|
+
const utilitySkillChecks = [
|
|
86
|
+
{ file: runtimeFile("skills/learnings/SKILL.md"), needle: "## Learning Entry Schema", name: "utility_skill:learnings:schema" },
|
|
87
|
+
{ file: runtimeFile("skills/learnings/SKILL.md"), needle: "## Subcommands", name: "utility_skill:learnings:subcommands" },
|
|
88
|
+
{ file: runtimeFile("skills/learnings/SKILL.md"), needle: "## Confidence Decay", name: "utility_skill:learnings:decay" },
|
|
89
|
+
{ file: runtimeFile("skills/learnings/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:learnings:hard_gate" },
|
|
90
|
+
{ file: runtimeFile("skills/autoplan/SKILL.md"), needle: "## Phase Sequence", name: "utility_skill:autoplan:phases" },
|
|
91
|
+
{ file: runtimeFile("skills/autoplan/SKILL.md"), needle: "Decision Principles", name: "utility_skill:autoplan:principles" },
|
|
92
|
+
{ file: runtimeFile("skills/autoplan/SKILL.md"), needle: "## Decision Taxonomy", name: "utility_skill:autoplan:taxonomy" },
|
|
93
|
+
{ file: runtimeFile("skills/autoplan/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:autoplan:hard_gate" },
|
|
94
|
+
{ file: runtimeFile("skills/autoplan/SKILL.md"), needle: "## Restore Points", name: "utility_skill:autoplan:restore_points" },
|
|
95
|
+
{ file: runtimeFile("commands/learn.md"), needle: "## Subcommands", name: "utility_command:learn:subcommands" },
|
|
96
|
+
{ file: runtimeFile("commands/autoplan.md"), needle: "## Phase Sequence", name: "utility_command:autoplan:phases" },
|
|
97
|
+
{ file: runtimeFile("commands/autoplan.md"), needle: "## Decision Principles", name: "utility_command:autoplan:principles" },
|
|
98
|
+
{ file: runtimeFile("skills/subagent-dev/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:sdd:hard_gate" },
|
|
99
|
+
{ file: runtimeFile("skills/subagent-dev/SKILL.md"), needle: "## Status Contract", name: "utility_skill:sdd:status_contract" },
|
|
100
|
+
{ file: runtimeFile("skills/subagent-dev/SKILL.md"), needle: "Implementer", name: "utility_skill:sdd:implementer_template" },
|
|
101
|
+
{ file: runtimeFile("skills/parallel-dispatch/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:parallel:hard_gate" },
|
|
102
|
+
{ file: runtimeFile("skills/parallel-dispatch/SKILL.md"), needle: "Review Army", name: "utility_skill:parallel:review_army" },
|
|
103
|
+
{ file: runtimeFile("skills/parallel-dispatch/SKILL.md"), needle: "Reconciliation", name: "utility_skill:parallel:reconciliation" },
|
|
104
|
+
{ file: runtimeFile("skills/session/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:session:hard_gate" },
|
|
105
|
+
{ file: runtimeFile("skills/session/SKILL.md"), needle: "## Session Start Protocol", name: "utility_skill:session:start" },
|
|
106
|
+
{ file: runtimeFile("skills/session/SKILL.md"), needle: "## Session Stop Protocol", name: "utility_skill:session:stop" },
|
|
107
|
+
{ file: runtimeFile("skills/using-cclaw/SKILL.md"), needle: "## Skill Discovery Flowchart", name: "meta_skill:discovery" },
|
|
108
|
+
{ file: runtimeFile("skills/using-cclaw/SKILL.md"), needle: "## Activation Rules", name: "meta_skill:activation" },
|
|
109
|
+
{ file: runtimeFile("skills/using-cclaw/SKILL.md"), needle: "## Stage Quick Reference", name: "meta_skill:reference" },
|
|
110
|
+
{ file: runtimeFile("skills/using-cclaw/SKILL.md"), needle: "## Failure Modes", name: "meta_skill:failure_modes" },
|
|
111
|
+
{ file: runtimeFile("skills/using-cclaw/SKILL.md"), needle: "## Contextual Skills", name: "meta_skill:contextual_skills" },
|
|
112
|
+
{ file: runtimeFile("skills/using-cclaw/SKILL.md"), needle: "## Decision Protocol", name: "meta_skill:decision_protocol" },
|
|
113
|
+
{ file: runtimeFile("skills/session/SKILL.md"), needle: "## Session Resume Protocol", name: "utility_skill:session:resume" },
|
|
114
|
+
{ file: runtimeFile("skills/security/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:security:hard_gate" },
|
|
115
|
+
{ file: runtimeFile("skills/security/SKILL.md"), needle: "## Checklist", name: "utility_skill:security:checklist" },
|
|
116
|
+
{ file: runtimeFile("skills/security/SKILL.md"), needle: "## Severity Classification", name: "utility_skill:security:severity" },
|
|
117
|
+
{ file: runtimeFile("skills/debugging/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:debugging:hard_gate" },
|
|
118
|
+
{ file: runtimeFile("skills/debugging/SKILL.md"), needle: "## The Protocol", name: "utility_skill:debugging:protocol" },
|
|
119
|
+
{ file: runtimeFile("skills/debugging/SKILL.md"), needle: "Step 1 — Reproduce", name: "utility_skill:debugging:reproduce" },
|
|
120
|
+
{ file: runtimeFile("skills/performance/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:performance:hard_gate" },
|
|
121
|
+
{ file: runtimeFile("skills/performance/SKILL.md"), needle: "## Workflow", name: "utility_skill:performance:workflow" },
|
|
122
|
+
{ file: runtimeFile("skills/performance/SKILL.md"), needle: "## Core Web Vitals Reference", name: "utility_skill:performance:cwv" },
|
|
123
|
+
{ file: runtimeFile("skills/ci-cd/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:cicd:hard_gate" },
|
|
124
|
+
{ file: runtimeFile("skills/ci-cd/SKILL.md"), needle: "## Quality Gate Pipeline", name: "utility_skill:cicd:pipeline" },
|
|
125
|
+
{ file: runtimeFile("skills/ci-cd/SKILL.md"), needle: "## CI Debugging Protocol", name: "utility_skill:cicd:debugging" },
|
|
126
|
+
{ file: runtimeFile("skills/docs/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:docs:hard_gate" },
|
|
127
|
+
{ file: runtimeFile("skills/docs/SKILL.md"), needle: "## ADR (Architecture Decision Record)", name: "utility_skill:docs:adr" },
|
|
128
|
+
{ file: runtimeFile("skills/docs/SKILL.md"), needle: "## README Guidance", name: "utility_skill:docs:readme" },
|
|
129
|
+
{ file: runtimeFile("hooks/session-start.sh"), needle: "ACTIVE_RUN=", name: "hooks:session_start:active_run" },
|
|
130
|
+
{ file: runtimeFile("hooks/session-start.sh"), needle: "checkpoint.json", name: "hooks:session_start:checkpoint_ref" },
|
|
131
|
+
{ file: runtimeFile("hooks/session-start.sh"), needle: "stage-activity.jsonl", name: "hooks:session_start:activity_ref" },
|
|
132
|
+
{ file: runtimeFile("hooks/session-start.sh"), needle: "suggestion-memory.json", name: "hooks:session_start:suggestion_memory" },
|
|
133
|
+
{ file: runtimeFile("hooks/session-start.sh"), needle: "context-warnings.jsonl", name: "hooks:session_start:context_warning_ref" },
|
|
134
|
+
{ file: runtimeFile("hooks/stop-checkpoint.sh"), needle: "checkpoint.json", name: "hooks:stop:checkpoint_write" },
|
|
135
|
+
{ file: runtimeFile("hooks/prompt-guard.sh"), needle: "write_to_cclaw_runtime", name: "hooks:guard:risky_write_advisory" },
|
|
136
|
+
{ file: runtimeFile("hooks/context-monitor.sh"), needle: "remaining is", name: "hooks:context:threshold_warning" },
|
|
137
|
+
{ file: runtimeFile("hooks/observe.sh"), needle: "stage-activity.jsonl", name: "hooks:observe:activity_write" },
|
|
138
|
+
{ file: runtimeFile("hooks/summarize-observations.mjs"), needle: "frequent-errors-", name: "hooks:summarize:runtime_module" },
|
|
139
|
+
{ file: runtimeFile("hooks/opencode-plugin.mjs"), needle: "activeRunId", name: "hooks:opencode:active_run" }
|
|
140
|
+
];
|
|
141
|
+
for (const check of utilitySkillChecks) {
|
|
142
|
+
rules.push({
|
|
143
|
+
filePath: check.file,
|
|
144
|
+
needle: check.needle,
|
|
145
|
+
name: check.name
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
const contentCache = new Map();
|
|
149
|
+
const readCached = async (filePath) => {
|
|
150
|
+
if (contentCache.has(filePath)) {
|
|
151
|
+
return contentCache.get(filePath) ?? null;
|
|
152
|
+
}
|
|
153
|
+
if (!(await exists(filePath))) {
|
|
154
|
+
contentCache.set(filePath, null);
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
const content = await fs.readFile(filePath, "utf8");
|
|
158
|
+
contentCache.set(filePath, content);
|
|
159
|
+
return content;
|
|
160
|
+
};
|
|
161
|
+
for (const rule of rules) {
|
|
162
|
+
const filePath = path.join(projectRoot, rule.filePath);
|
|
163
|
+
const content = await readCached(filePath);
|
|
164
|
+
if (content === null) {
|
|
165
|
+
checks.push({
|
|
166
|
+
name: rule.name,
|
|
167
|
+
ok: false,
|
|
168
|
+
details: `${filePath} not found`
|
|
169
|
+
});
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
checks.push({
|
|
173
|
+
name: rule.name,
|
|
174
|
+
ok: content.includes(rule.needle),
|
|
175
|
+
details: `expect "${rule.needle}" in ${filePath}`
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return checks;
|
|
179
|
+
}
|
package/dist/runs.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type FlowState } from "./flow-state.js";
|
|
2
|
+
export interface CclawRunMeta {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
createdAt: string;
|
|
6
|
+
archivedAt?: string;
|
|
7
|
+
stateSnapshot?: Omit<FlowState, "activeRunId">;
|
|
8
|
+
}
|
|
9
|
+
export declare function readFlowState(projectRoot: string): Promise<FlowState>;
|
|
10
|
+
export declare function writeFlowState(projectRoot: string, state: FlowState): Promise<void>;
|
|
11
|
+
export declare function listRuns(projectRoot: string): Promise<CclawRunMeta[]>;
|
|
12
|
+
export declare function ensureRunSystem(projectRoot: string): Promise<FlowState>;
|
|
13
|
+
export declare function startNewFeatureRun(projectRoot: string, title?: string): Promise<CclawRunMeta>;
|
|
14
|
+
export declare function resumeRun(projectRoot: string, runId: string): Promise<CclawRunMeta>;
|
|
15
|
+
export declare function archiveRun(projectRoot: string, runId?: string): Promise<{
|
|
16
|
+
archived: CclawRunMeta;
|
|
17
|
+
active: CclawRunMeta;
|
|
18
|
+
}>;
|