kc-beta 0.1.1 → 0.1.2
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/package.json +1 -1
- package/src/agent/context.js +58 -88
- package/src/agent/engine.js +71 -39
- package/src/agent/pipelines/_archive_v1/distillation.js +113 -0
- package/src/agent/pipelines/_archive_v1/extraction.js +92 -0
- package/src/agent/pipelines/_archive_v1/initializer.js +163 -0
- package/src/agent/pipelines/_archive_v1/production-qc.js +99 -0
- package/src/agent/pipelines/_archive_v1/skill-authoring.js +83 -0
- package/src/agent/pipelines/_archive_v1/skill-testing.js +111 -0
- package/src/agent/pipelines/distillation.js +7 -11
- package/src/agent/pipelines/extraction.js +5 -7
- package/src/agent/pipelines/initializer.js +8 -14
- package/src/agent/pipelines/production-qc.js +3 -5
- package/src/agent/pipelines/skill-authoring.js +5 -8
- package/src/agent/pipelines/skill-testing.js +6 -8
- package/src/agent/skill-loader.js +139 -0
- package/src/agent/tools/tier-downgrade.js +11 -2
- package/src/cli/onboard.js +12 -0
- package/src/config.js +5 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const BUNDLED_SKILLS_DIR = path.resolve(__dirname, "../../template/skills");
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Discover and index meta skills from template/skills/.
|
|
10
|
+
* Follows Claude Code's pattern: skills are NOT dumped into the system prompt.
|
|
11
|
+
* Instead, a brief index (name + description) is injected into context.
|
|
12
|
+
* The agent reads full SKILL.md content on demand via workspace_file or sandbox_exec.
|
|
13
|
+
*
|
|
14
|
+
* Skills are organized as:
|
|
15
|
+
* template/skills/{lang}/meta-meta/ — System architecture methodology
|
|
16
|
+
* template/skills/{lang}/meta/ — Verification domain methodology
|
|
17
|
+
* template/skills/{lang}/skill-creator/ — Anthropic's official skill creation toolkit
|
|
18
|
+
*/
|
|
19
|
+
export class SkillLoader {
|
|
20
|
+
/**
|
|
21
|
+
* @param {string} [language] - "en" or "zh"
|
|
22
|
+
* @param {string} [skillsDir] - Override skills directory (default: bundled template)
|
|
23
|
+
*/
|
|
24
|
+
constructor(language = "en", skillsDir) {
|
|
25
|
+
this._lang = language;
|
|
26
|
+
this._skillsDir = skillsDir || BUNDLED_SKILLS_DIR;
|
|
27
|
+
this._index = null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Build the skill index by scanning SKILL.md frontmatter.
|
|
32
|
+
* Cached after first call.
|
|
33
|
+
* @returns {Array<{name: string, description: string, category: string, path: string}>}
|
|
34
|
+
*/
|
|
35
|
+
getIndex() {
|
|
36
|
+
if (this._index) return this._index;
|
|
37
|
+
|
|
38
|
+
this._index = [];
|
|
39
|
+
const langDir = path.join(this._skillsDir, this._lang);
|
|
40
|
+
if (!fs.existsSync(langDir)) return this._index;
|
|
41
|
+
|
|
42
|
+
for (const category of ["meta-meta", "meta", "skill-creator"]) {
|
|
43
|
+
const catDir = path.join(langDir, category);
|
|
44
|
+
if (!fs.existsSync(catDir)) continue;
|
|
45
|
+
|
|
46
|
+
// skill-creator is a single skill, not a directory of skills
|
|
47
|
+
const skillMd = path.join(catDir, "SKILL.md");
|
|
48
|
+
if (fs.existsSync(skillMd)) {
|
|
49
|
+
const { name, description } = this._parseFrontmatter(skillMd);
|
|
50
|
+
if (name) {
|
|
51
|
+
this._index.push({
|
|
52
|
+
name: name || category,
|
|
53
|
+
description: description || "",
|
|
54
|
+
category,
|
|
55
|
+
path: path.relative(this._skillsDir, catDir),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Check subdirectories (meta-meta/bootstrap-workspace/, etc.)
|
|
61
|
+
for (const entry of fs.readdirSync(catDir, { withFileTypes: true })) {
|
|
62
|
+
if (!entry.isDirectory()) continue;
|
|
63
|
+
const subSkillMd = path.join(catDir, entry.name, "SKILL.md");
|
|
64
|
+
if (!fs.existsSync(subSkillMd)) continue;
|
|
65
|
+
|
|
66
|
+
const { name, description } = this._parseFrontmatter(subSkillMd);
|
|
67
|
+
this._index.push({
|
|
68
|
+
name: name || entry.name,
|
|
69
|
+
description: description || "",
|
|
70
|
+
category,
|
|
71
|
+
path: path.relative(this._skillsDir, path.join(catDir, entry.name)),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return this._index;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Format the skill index for injection into agent context.
|
|
81
|
+
* Brief listing — agent reads full content on demand.
|
|
82
|
+
* @returns {string}
|
|
83
|
+
*/
|
|
84
|
+
formatForContext() {
|
|
85
|
+
const index = this.getIndex();
|
|
86
|
+
if (index.length === 0) return "";
|
|
87
|
+
|
|
88
|
+
const metaMeta = index.filter((s) => s.category === "meta-meta");
|
|
89
|
+
const meta = index.filter((s) => s.category === "meta");
|
|
90
|
+
const other = index.filter((s) => s.category !== "meta-meta" && s.category !== "meta");
|
|
91
|
+
|
|
92
|
+
const lines = ["## Available Methodology Skills",
|
|
93
|
+
"Read full skill content from the skills/ directory when needed.\n"];
|
|
94
|
+
|
|
95
|
+
if (metaMeta.length) {
|
|
96
|
+
lines.push("**System Architecture (meta-meta):**");
|
|
97
|
+
for (const s of metaMeta) {
|
|
98
|
+
lines.push(`- **${s.name}**: ${s.description.slice(0, 120)}`);
|
|
99
|
+
}
|
|
100
|
+
lines.push("");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (meta.length) {
|
|
104
|
+
lines.push("**Verification Methodology (meta):**");
|
|
105
|
+
for (const s of meta) {
|
|
106
|
+
lines.push(`- **${s.name}**: ${s.description.slice(0, 120)}`);
|
|
107
|
+
}
|
|
108
|
+
lines.push("");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (other.length) {
|
|
112
|
+
lines.push("**Toolkits:**");
|
|
113
|
+
for (const s of other) {
|
|
114
|
+
lines.push(`- **${s.name}**: ${s.description.slice(0, 120)}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return lines.join("\n");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Parse YAML frontmatter from a SKILL.md file.
|
|
123
|
+
* Only extracts name and description — lightweight.
|
|
124
|
+
*/
|
|
125
|
+
_parseFrontmatter(filePath) {
|
|
126
|
+
try {
|
|
127
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
128
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
129
|
+
if (!match) return {};
|
|
130
|
+
|
|
131
|
+
const frontmatter = match[1];
|
|
132
|
+
const name = frontmatter.match(/^name:\s*(.+)$/m)?.[1]?.trim() || "";
|
|
133
|
+
const description = frontmatter.match(/^description:\s*(.+)$/m)?.[1]?.trim() || "";
|
|
134
|
+
return { name, description };
|
|
135
|
+
} catch {
|
|
136
|
+
return {};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -72,14 +72,23 @@ export class TierDowngradeTool extends BaseTool {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
// Read tier tolerance from .env (default from onboarding config)
|
|
76
|
+
let tolerance = 0.05;
|
|
77
|
+
if (fs.existsSync(envPath)) {
|
|
78
|
+
for (const line of fs.readFileSync(envPath, "utf-8").split("\n")) {
|
|
79
|
+
if (line.startsWith("TIER_TOLERANCE=")) {
|
|
80
|
+
try { tolerance = parseFloat(line.split("=")[1].trim()); }
|
|
81
|
+
catch { /* ignore */ }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
76
85
|
|
|
77
86
|
const report = {
|
|
78
87
|
rule_id: ruleId, current_tier: currentTier, target_tier: targetTier,
|
|
79
88
|
current_accuracy: Math.round(currentAcc * 1000) / 1000,
|
|
80
89
|
target_accuracy: Math.round(targetAcc * 1000) / 1000,
|
|
81
90
|
accuracy_delta: Math.round(delta * 1000) / 1000,
|
|
82
|
-
threshold,
|
|
91
|
+
threshold, tolerance, test_count: testInputs.length,
|
|
83
92
|
};
|
|
84
93
|
return new ToolResult(JSON.stringify(report, null, 2));
|
|
85
94
|
}
|
package/src/cli/onboard.js
CHANGED
|
@@ -160,6 +160,15 @@ export async function onboard() {
|
|
|
160
160
|
const accuracy = parseFloat(await ask(rl, ` ${CYAN}${t.accuracy}${RESET}`, defaultAcc));
|
|
161
161
|
console.log();
|
|
162
162
|
|
|
163
|
+
// Advanced thresholds (Enter to keep defaults)
|
|
164
|
+
const advLabel = lang === "zh" ? "高级阈值" : "Advanced Thresholds";
|
|
165
|
+
const skipHint = lang === "zh" ? "回车使用默认值" : "Enter to keep defaults";
|
|
166
|
+
console.log(` ${CYAN}${advLabel}${RESET} ${DIM}(${skipHint})${RESET}`);
|
|
167
|
+
const systemicThreshold = parseFloat(await ask(rl, ` ${lang === "zh" ? "系统性问题阈值" : "Systemic threshold"}`, existing.systemic_threshold?.toString() || "0.10"));
|
|
168
|
+
const spotCheckRate = parseFloat(await ask(rl, ` ${lang === "zh" ? "抽查比率" : "Spot-check rate"}`, existing.spot_check_rate?.toString() || "0.10"));
|
|
169
|
+
const tierTolerance = parseFloat(await ask(rl, ` ${lang === "zh" ? "降级容差" : "Tier downgrade tolerance"}`, existing.tier_tolerance?.toString() || "0.05"));
|
|
170
|
+
console.log();
|
|
171
|
+
|
|
163
172
|
rl.close();
|
|
164
173
|
|
|
165
174
|
const config = {
|
|
@@ -170,6 +179,9 @@ export async function onboard() {
|
|
|
170
179
|
conductor_model: model,
|
|
171
180
|
tiers,
|
|
172
181
|
accuracy_threshold: accuracy,
|
|
182
|
+
systemic_threshold: systemicThreshold,
|
|
183
|
+
spot_check_rate: spotCheckRate,
|
|
184
|
+
tier_tolerance: tierTolerance,
|
|
173
185
|
};
|
|
174
186
|
|
|
175
187
|
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
package/src/config.js
CHANGED
|
@@ -81,6 +81,11 @@ export function loadSettings(workspacePath) {
|
|
|
81
81
|
skillAccuracy: parseFloat(env.SKILL_ACCURACY || gc.accuracy_threshold?.toString() || "0.9"),
|
|
82
82
|
workflowAccuracy: parseFloat(env.WORKFLOW_ACCURACY || "0.9"),
|
|
83
83
|
|
|
84
|
+
// Advanced thresholds (from onboarding or .env)
|
|
85
|
+
systemicThreshold: parseFloat(env.SYSTEMIC_THRESHOLD || gc.systemic_threshold?.toString() || "0.10"),
|
|
86
|
+
spotCheckRate: parseFloat(env.SPOT_CHECK_RATE || gc.spot_check_rate?.toString() || "0.10"),
|
|
87
|
+
tierTolerance: parseFloat(env.TIER_TOLERANCE || gc.tier_tolerance?.toString() || "0.05"),
|
|
88
|
+
|
|
84
89
|
// Evolution
|
|
85
90
|
maxIterations: parseInt(env.MAX_ITERATIONS || "20", 10),
|
|
86
91
|
monitorFrequency: env.MONITOR_FREQUENCY || "mid",
|