@gobing-ai/superskill 0.1.7 → 0.2.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/README.md +2 -3
- package/dist/index.js +1080 -321
- package/package.json +1 -1
- package/rubrics/command.yaml +12 -12
- package/rubrics/hook.yaml +28 -24
- package/rubrics/magent.yaml +7 -6
- package/templates/agent/default.md +27 -2
- package/templates/agent/minimal.md +10 -0
- package/templates/agent/specialist.md +47 -0
- package/templates/agent/standard.md +35 -0
- package/templates/command/default.md +27 -5
- package/templates/command/plugin.md +53 -0
- package/templates/command/simple.md +47 -0
- package/templates/command/workflow.md +51 -0
- package/templates/magent/default.md +53 -10
- package/templates/skill/default.md +63 -1
- package/templates/skill/pattern.md +95 -0
- package/templates/skill/reference.md +102 -0
- package/templates/skill/technique.md +107 -0
- package/templates/hook/default.md +0 -8
package/dist/index.js
CHANGED
|
@@ -9317,7 +9317,7 @@ function hashContent(filePath) {
|
|
|
9317
9317
|
var init_hash = () => {};
|
|
9318
9318
|
|
|
9319
9319
|
// ../../packages/core/src/content/identity.ts
|
|
9320
|
-
import { existsSync } from "fs";
|
|
9320
|
+
import { existsSync, statSync } from "fs";
|
|
9321
9321
|
import { basename, dirname, extname, join } from "path";
|
|
9322
9322
|
import { cwd } from "process";
|
|
9323
9323
|
function resolveContentName(path) {
|
|
@@ -9333,10 +9333,26 @@ function resolveContentName(path) {
|
|
|
9333
9333
|
}
|
|
9334
9334
|
function resolveContentPath(type, name, opts) {
|
|
9335
9335
|
if (name.includes("/") || name.includes("\\")) {
|
|
9336
|
-
if (existsSync(name))
|
|
9337
|
-
|
|
9336
|
+
if (existsSync(name)) {
|
|
9337
|
+
const st = statSync(name);
|
|
9338
|
+
if (st.isDirectory()) {
|
|
9339
|
+
const skillMd = join(name, "SKILL.md");
|
|
9340
|
+
if (existsSync(skillMd))
|
|
9341
|
+
return skillMd;
|
|
9342
|
+
} else {
|
|
9343
|
+
return name;
|
|
9344
|
+
}
|
|
9345
|
+
}
|
|
9338
9346
|
}
|
|
9339
9347
|
const base = opts?.baseDir ?? cwd();
|
|
9348
|
+
const asIs = join(base, name);
|
|
9349
|
+
if (existsSync(asIs) && statSync(asIs).isFile())
|
|
9350
|
+
return asIs;
|
|
9351
|
+
if (type === "skill") {
|
|
9352
|
+
const skillDirForm = join(base, name, "SKILL.md");
|
|
9353
|
+
if (existsSync(skillDirForm))
|
|
9354
|
+
return skillDirForm;
|
|
9355
|
+
}
|
|
9340
9356
|
const direct = join(base, `${name}.md`);
|
|
9341
9357
|
if (existsSync(direct))
|
|
9342
9358
|
return direct;
|
|
@@ -9355,6 +9371,11 @@ function resolveContentPath(type, name, opts) {
|
|
|
9355
9371
|
}
|
|
9356
9372
|
return null;
|
|
9357
9373
|
}
|
|
9374
|
+
function assertSafePathSegment(value, label) {
|
|
9375
|
+
if (!value || value === "." || value === ".." || value.includes("/") || value.includes("\\") || value.includes("\x00")) {
|
|
9376
|
+
throw new Error(`Invalid ${label} '${value}': must be a single path segment`);
|
|
9377
|
+
}
|
|
9378
|
+
}
|
|
9358
9379
|
var init_identity = () => {};
|
|
9359
9380
|
|
|
9360
9381
|
// ../../packages/core/src/content/paths.ts
|
|
@@ -9710,7 +9731,7 @@ var init_adapt_subagent = __esm(() => {
|
|
|
9710
9731
|
});
|
|
9711
9732
|
|
|
9712
9733
|
// ../../packages/core/src/mapper.ts
|
|
9713
|
-
import { existsSync as existsSync3, mkdirSync, readdirSync, readFileSync as readFileSync2, statSync, writeFileSync } from "fs";
|
|
9734
|
+
import { existsSync as existsSync3, mkdirSync, readdirSync, readFileSync as readFileSync2, statSync as statSync2, writeFileSync } from "fs";
|
|
9714
9735
|
import { join as join3 } from "path";
|
|
9715
9736
|
function mapPluginToRulesync(pluginPath, pluginName, outputDir) {
|
|
9716
9737
|
assertSafePathSegment(pluginName, "plugin name");
|
|
@@ -9798,11 +9819,6 @@ function mapPluginToRulesync(pluginPath, pluginName, outputDir) {
|
|
|
9798
9819
|
}
|
|
9799
9820
|
return result;
|
|
9800
9821
|
}
|
|
9801
|
-
function assertSafePathSegment(value, label) {
|
|
9802
|
-
if (!value || value === "." || value === ".." || value.includes("/") || value.includes("\\") || value.includes("\x00")) {
|
|
9803
|
-
throw new Error(`Invalid ${label} '${value}': must be a single path segment`);
|
|
9804
|
-
}
|
|
9805
|
-
}
|
|
9806
9822
|
function deepMergeJsonFile(sourcePath, targetPath) {
|
|
9807
9823
|
const source = readJsonObject(sourcePath);
|
|
9808
9824
|
const target = existsSync3(targetPath) ? readJsonObject(targetPath) : {};
|
|
@@ -9833,7 +9849,7 @@ function copyAndRewriteDirectory(source, destination, pluginName) {
|
|
|
9833
9849
|
for (const entry of readdirSync(source)) {
|
|
9834
9850
|
const srcPath = join3(source, entry);
|
|
9835
9851
|
const destPath = join3(destination, entry);
|
|
9836
|
-
if (
|
|
9852
|
+
if (statSync2(srcPath).isDirectory()) {
|
|
9837
9853
|
copyAndRewriteDirectory(srcPath, destPath, pluginName);
|
|
9838
9854
|
} else {
|
|
9839
9855
|
const content = readFileSync2(srcPath, "utf-8");
|
|
@@ -9842,6 +9858,7 @@ function copyAndRewriteDirectory(source, destination, pluginName) {
|
|
|
9842
9858
|
}
|
|
9843
9859
|
}
|
|
9844
9860
|
var init_mapper = __esm(() => {
|
|
9861
|
+
init_identity();
|
|
9845
9862
|
init_adapt_command();
|
|
9846
9863
|
init_adapt_subagent();
|
|
9847
9864
|
init_rewrite_references();
|
|
@@ -13814,7 +13831,7 @@ var init_zod = __esm(() => {
|
|
|
13814
13831
|
});
|
|
13815
13832
|
|
|
13816
13833
|
// ../../packages/core/src/marketplace.ts
|
|
13817
|
-
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
13834
|
+
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
|
|
13818
13835
|
import { join as join4, resolve } from "path";
|
|
13819
13836
|
function resolvePlugin(marketplacePath, pluginName) {
|
|
13820
13837
|
let manifestPath = null;
|
|
@@ -13861,8 +13878,19 @@ function resolvePlugin(marketplacePath, pluginName) {
|
|
|
13861
13878
|
const marketplaceRoot = resolve(manifestPath, "..", "..");
|
|
13862
13879
|
const pluginRootBase = manifest.metadata?.pluginRoot ?? "";
|
|
13863
13880
|
const pluginRoot = resolve(marketplaceRoot, pluginRootBase, source);
|
|
13864
|
-
|
|
13865
|
-
|
|
13881
|
+
let dirents;
|
|
13882
|
+
try {
|
|
13883
|
+
dirents = readdirSync2(pluginRoot);
|
|
13884
|
+
} catch {
|
|
13885
|
+
throw new Error(`Plugin root not found: ${pluginRoot}`);
|
|
13886
|
+
}
|
|
13887
|
+
const hasSkills = dirents.includes("skills");
|
|
13888
|
+
const hasCommands = dirents.includes("commands");
|
|
13889
|
+
const hasAgents = dirents.includes("agents");
|
|
13890
|
+
const hasHooksDir = dirents.includes("hooks");
|
|
13891
|
+
const hasHooksFile = dirents.includes("hooks.json");
|
|
13892
|
+
if (!(hasSkills || hasCommands || hasAgents || hasHooksDir || hasHooksFile)) {
|
|
13893
|
+
throw new Error(`No recognizable plugin content (skills/, commands/, agents/, hooks/, hooks.json) in: ${pluginRoot}`);
|
|
13866
13894
|
}
|
|
13867
13895
|
return { pluginRoot, marketplaceRoot, source };
|
|
13868
13896
|
}
|
|
@@ -14013,7 +14041,7 @@ var init_migrate = __esm(() => {
|
|
|
14013
14041
|
});
|
|
14014
14042
|
|
|
14015
14043
|
// ../../packages/core/src/operations/package.ts
|
|
14016
|
-
import { cpSync, existsSync as existsSync6, mkdirSync as mkdirSync3, statSync as
|
|
14044
|
+
import { cpSync, existsSync as existsSync6, mkdirSync as mkdirSync3, statSync as statSync3 } from "fs";
|
|
14017
14045
|
import { basename as basename2, dirname as dirname3, join as join5 } from "path";
|
|
14018
14046
|
import { cwd as cwd3 } from "process";
|
|
14019
14047
|
function resolveSkillDir(name) {
|
|
@@ -14021,7 +14049,7 @@ function resolveSkillDir(name) {
|
|
|
14021
14049
|
if (!skillPath) {
|
|
14022
14050
|
throw Object.assign(new Error(`Skill not found: ${name}`), { code: "ENOENT" });
|
|
14023
14051
|
}
|
|
14024
|
-
const dir =
|
|
14052
|
+
const dir = statSync3(skillPath).isDirectory() ? skillPath : dirname3(skillPath);
|
|
14025
14053
|
return { dir, name: basename2(dir) };
|
|
14026
14054
|
}
|
|
14027
14055
|
function copyDirIfExists(src, dest) {
|
|
@@ -14062,45 +14090,106 @@ import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as rea
|
|
|
14062
14090
|
import { homedir as homedir2 } from "os";
|
|
14063
14091
|
import { join as join6 } from "path";
|
|
14064
14092
|
import { cwd as cwd4 } from "process";
|
|
14093
|
+
function parseList(value) {
|
|
14094
|
+
if (value === undefined)
|
|
14095
|
+
return [];
|
|
14096
|
+
if (Array.isArray(value)) {
|
|
14097
|
+
return value.map((v) => v.trim()).filter((v) => v.length > 0);
|
|
14098
|
+
}
|
|
14099
|
+
return value.split(",").map((v) => v.trim()).filter((v) => v.length > 0);
|
|
14100
|
+
}
|
|
14101
|
+
function toYamlArray(items) {
|
|
14102
|
+
return `[${items.join(", ")}]`;
|
|
14103
|
+
}
|
|
14065
14104
|
function substituteVars(template, vars) {
|
|
14066
|
-
return template.replaceAll(PLACEHOLDER_NAME, vars.name).replaceAll(PLACEHOLDER_DESCRIPTION, vars.description).replaceAll(PLACEHOLDER_TARGET, vars.target).replaceAll(PLACEHOLDER_BODY, vars.body);
|
|
14105
|
+
return template.replaceAll(PLACEHOLDER_NAME, vars.name).replaceAll(PLACEHOLDER_DESCRIPTION, vars.description).replaceAll(PLACEHOLDER_TARGET, vars.target).replaceAll(PLACEHOLDER_BODY, vars.body).replaceAll(PLACEHOLDER_TOOLS, toYamlArray(vars.tools));
|
|
14067
14106
|
}
|
|
14068
|
-
function
|
|
14107
|
+
function mergeFrontmatterList(content, key, items) {
|
|
14108
|
+
if (items.length === 0)
|
|
14109
|
+
return content;
|
|
14110
|
+
const fenceRe = /^---$/gm;
|
|
14111
|
+
const matches = [...content.matchAll(fenceRe)];
|
|
14112
|
+
if (matches.length < 2)
|
|
14113
|
+
return content;
|
|
14114
|
+
const openPos = matches[0]?.index ?? 0;
|
|
14115
|
+
const closePos = matches[1]?.index ?? 0;
|
|
14116
|
+
const fmStart = openPos + 3;
|
|
14117
|
+
const fmBody = content.slice(fmStart, closePos);
|
|
14118
|
+
const yamlValue = toYamlArray(items);
|
|
14119
|
+
const pattern = new RegExp(`^${key}:.*$`, "m");
|
|
14120
|
+
let newFmBody;
|
|
14121
|
+
if (pattern.test(fmBody)) {
|
|
14122
|
+
newFmBody = fmBody.replace(pattern, `${key}: ${yamlValue}`);
|
|
14123
|
+
} else {
|
|
14124
|
+
newFmBody = `${fmBody}${key}: ${yamlValue}
|
|
14125
|
+
`;
|
|
14126
|
+
}
|
|
14127
|
+
return content.slice(0, fmStart) + newFmBody + content.slice(closePos);
|
|
14128
|
+
}
|
|
14129
|
+
function resolveTemplate(type, tier) {
|
|
14069
14130
|
const homeDir = process.env.HOME ?? homedir2();
|
|
14131
|
+
const tierName = tier?.trim();
|
|
14132
|
+
if (tierName && tierName !== "default") {
|
|
14133
|
+
const userTierPath = join6(homeDir, ".superskill", "templates", type, `${tierName}.md`);
|
|
14134
|
+
if (existsSync7(userTierPath)) {
|
|
14135
|
+
return readFileSync5(userTierPath, "utf-8");
|
|
14136
|
+
}
|
|
14137
|
+
for (const base of TEMPLATE_BASE_DIRS) {
|
|
14138
|
+
const path = join6(base, type, `${tierName}.md`);
|
|
14139
|
+
if (existsSync7(path)) {
|
|
14140
|
+
return readFileSync5(path, "utf-8");
|
|
14141
|
+
}
|
|
14142
|
+
}
|
|
14143
|
+
throw new Error(`Unknown template tier "${tierName}" for type "${type}". ` + `No user override (~/.superskill/templates/${type}/${tierName}.md) ` + `or built-in template found. Omit --template to use the default tier.`);
|
|
14144
|
+
}
|
|
14070
14145
|
const userPath = join6(homeDir, ".superskill", "templates", type, "default.md");
|
|
14071
14146
|
if (existsSync7(userPath)) {
|
|
14072
14147
|
return readFileSync5(userPath, "utf-8");
|
|
14073
14148
|
}
|
|
14074
|
-
|
|
14075
|
-
|
|
14076
|
-
|
|
14149
|
+
for (const base of TEMPLATE_BASE_DIRS) {
|
|
14150
|
+
const path = join6(base, type, "default.md");
|
|
14151
|
+
if (existsSync7(path)) {
|
|
14152
|
+
return readFileSync5(path, "utf-8");
|
|
14153
|
+
}
|
|
14077
14154
|
}
|
|
14078
|
-
|
|
14079
|
-
return readFileSync5(prodPath, "utf-8");
|
|
14155
|
+
throw new Error(`No built-in default template found for type "${type}".`);
|
|
14080
14156
|
}
|
|
14081
14157
|
async function scaffold(type, name, opts = {}) {
|
|
14082
|
-
const validTypes = ["skill", "command", "agent", "
|
|
14158
|
+
const validTypes = ["skill", "command", "agent", "magent"];
|
|
14083
14159
|
if (!validTypes.includes(type)) {
|
|
14084
14160
|
throw new Error(`Unknown content type: "${type}". Expected one of: ${validTypes.join(", ")}`);
|
|
14085
14161
|
}
|
|
14086
|
-
|
|
14087
|
-
const
|
|
14162
|
+
assertSafePathSegment(name, "content name");
|
|
14163
|
+
const template = resolveTemplate(type, opts.template);
|
|
14164
|
+
let content = substituteVars(template, {
|
|
14088
14165
|
name,
|
|
14089
14166
|
description: opts.description ?? "",
|
|
14090
14167
|
target: opts.target ?? "claude",
|
|
14091
|
-
body: ""
|
|
14168
|
+
body: "",
|
|
14169
|
+
tools: parseList(opts.tools)
|
|
14092
14170
|
});
|
|
14171
|
+
const toolField = type === "agent" ? "tools" : "allowed-tools";
|
|
14172
|
+
content = mergeFrontmatterList(content, toolField, parseList(opts.tools));
|
|
14093
14173
|
const outDir = opts.output ?? cwd4();
|
|
14094
14174
|
mkdirSync4(outDir, { recursive: true });
|
|
14095
|
-
const filePath = join6(outDir, `${name}.md`);
|
|
14175
|
+
const filePath = type === "skill" ? join6(outDir, name, "SKILL.md") : join6(outDir, `${name}.md`);
|
|
14176
|
+
if (type === "skill") {
|
|
14177
|
+
mkdirSync4(join6(outDir, name), { recursive: true });
|
|
14178
|
+
}
|
|
14096
14179
|
if (existsSync7(filePath) && !opts.force) {
|
|
14097
14180
|
throw new Error(`${filePath} already exists \u2014 pass --force to overwrite`);
|
|
14098
14181
|
}
|
|
14099
14182
|
writeFileSync3(filePath, content, "utf-8");
|
|
14100
14183
|
return filePath;
|
|
14101
14184
|
}
|
|
14102
|
-
var PLACEHOLDER_NAME = "<!-- NAME -->", PLACEHOLDER_DESCRIPTION = "<!-- DESCRIPTION -->", PLACEHOLDER_TARGET = "<!-- TARGET -->", PLACEHOLDER_BODY = "<!-- BODY -->";
|
|
14103
|
-
var init_scaffold = () => {
|
|
14185
|
+
var PLACEHOLDER_NAME = "<!-- NAME -->", PLACEHOLDER_DESCRIPTION = "<!-- DESCRIPTION -->", PLACEHOLDER_TARGET = "<!-- TARGET -->", PLACEHOLDER_BODY = "<!-- BODY -->", PLACEHOLDER_TOOLS = "<!-- TOOLS -->", TEMPLATE_BASE_DIRS;
|
|
14186
|
+
var init_scaffold = __esm(() => {
|
|
14187
|
+
init_identity();
|
|
14188
|
+
TEMPLATE_BASE_DIRS = [
|
|
14189
|
+
join6(import.meta.dir, "..", "..", "..", "..", "apps", "cli", "src", "templates"),
|
|
14190
|
+
join6(import.meta.dir, "..", "templates")
|
|
14191
|
+
];
|
|
14192
|
+
});
|
|
14104
14193
|
|
|
14105
14194
|
// ../../packages/core/src/quality/types.ts
|
|
14106
14195
|
function computeAggregate(dimensions) {
|
|
@@ -14122,10 +14211,10 @@ var init_types2 = __esm(() => {
|
|
|
14122
14211
|
VAGUE_KEYWORDS = ["maybe", "perhaps", "might", "could be", "probably"];
|
|
14123
14212
|
REQUIRED_FIELDS = {
|
|
14124
14213
|
skill: ["name", "description"],
|
|
14125
|
-
command: ["
|
|
14214
|
+
command: ["description"],
|
|
14126
14215
|
agent: ["name", "description", "model", "tools"],
|
|
14127
|
-
hook: [
|
|
14128
|
-
magent: [
|
|
14216
|
+
hook: [],
|
|
14217
|
+
magent: []
|
|
14129
14218
|
};
|
|
14130
14219
|
});
|
|
14131
14220
|
|
|
@@ -14224,89 +14313,180 @@ var init_heuristics = __esm(() => {
|
|
|
14224
14313
|
});
|
|
14225
14314
|
|
|
14226
14315
|
// ../../packages/core/src/quality/hook.ts
|
|
14227
|
-
function
|
|
14228
|
-
|
|
14229
|
-
|
|
14230
|
-
|
|
14231
|
-
|
|
14232
|
-
|
|
14233
|
-
|
|
14234
|
-
|
|
14235
|
-
|
|
14236
|
-
|
|
14237
|
-
|
|
14238
|
-
|
|
14316
|
+
function parseHookEntries(raw) {
|
|
14317
|
+
if (typeof raw !== "object" || raw === null)
|
|
14318
|
+
return null;
|
|
14319
|
+
const data = raw;
|
|
14320
|
+
const hooks = data.hooks;
|
|
14321
|
+
if (typeof hooks !== "object" || hooks === null)
|
|
14322
|
+
return null;
|
|
14323
|
+
const entries = [];
|
|
14324
|
+
for (const [event, matcherBlocks] of Object.entries(hooks)) {
|
|
14325
|
+
if (!Array.isArray(matcherBlocks))
|
|
14326
|
+
continue;
|
|
14327
|
+
for (const block of matcherBlocks) {
|
|
14328
|
+
if (typeof block !== "object" || block === null)
|
|
14329
|
+
continue;
|
|
14330
|
+
const subHooks = block.hooks;
|
|
14331
|
+
if (!Array.isArray(subHooks))
|
|
14332
|
+
continue;
|
|
14333
|
+
for (const h of subHooks) {
|
|
14334
|
+
if (typeof h !== "object" || h === null)
|
|
14335
|
+
continue;
|
|
14336
|
+
entries.push({
|
|
14337
|
+
event,
|
|
14338
|
+
matcher: typeof block.matcher === "string" ? block.matcher : "",
|
|
14339
|
+
command: typeof h.command === "string" ? h.command : "",
|
|
14340
|
+
type: typeof h.type === "string" ? h.type : "",
|
|
14341
|
+
timeout: typeof h.timeout === "number" ? h.timeout : undefined
|
|
14342
|
+
});
|
|
14343
|
+
}
|
|
14239
14344
|
}
|
|
14240
|
-
} else {
|
|
14241
|
-
base = 0;
|
|
14242
|
-
note = "Missing event field";
|
|
14243
14345
|
}
|
|
14244
|
-
|
|
14245
|
-
base = clamp(base + 0.1);
|
|
14246
|
-
}
|
|
14247
|
-
return { score: clamp(base), note };
|
|
14248
|
-
}
|
|
14249
|
-
function scoreEventCoverage(data, body) {
|
|
14250
|
-
const eventName = typeof data.event === "string" ? data.event.trim() : "";
|
|
14251
|
-
const mentionsEventName = eventName.length > 0 && body.toLowerCase().includes(eventName.toLowerCase()) ? 1 : 0;
|
|
14252
|
-
const density = keywordDensity(body, ["event", "intercept", "trigger", "when", "condition", "match"]);
|
|
14253
|
-
const score = 0.5 * mentionsEventName + 0.5 * density;
|
|
14254
|
-
const note = score >= 0.5 ? "Event coverage described" : "Minimal event description";
|
|
14255
|
-
return { score: clamp(score), note };
|
|
14346
|
+
return entries.length > 0 ? entries : null;
|
|
14256
14347
|
}
|
|
14257
|
-
function
|
|
14258
|
-
|
|
14259
|
-
|
|
14260
|
-
"
|
|
14261
|
-
|
|
14262
|
-
"approval",
|
|
14263
|
-
"explicit",
|
|
14264
|
-
"dangerous",
|
|
14265
|
-
"destructive",
|
|
14266
|
-
"block"
|
|
14267
|
-
]);
|
|
14268
|
-
const note = density >= 0.2 ? "Includes safety considerations" : "No safety gates described";
|
|
14269
|
-
return { score: clamp(density), note };
|
|
14270
|
-
}
|
|
14271
|
-
function scorePatternMatchQuality(body) {
|
|
14272
|
-
const hasSpecificGlob = /\*\.[a-z]+\b/i.test(body);
|
|
14273
|
-
const patternDensity = keywordDensity(body, ["match", "pattern", "regex", "glob"]);
|
|
14274
|
-
let score;
|
|
14275
|
-
let note;
|
|
14276
|
-
if (hasSpecificGlob) {
|
|
14277
|
-
score = 0.9;
|
|
14278
|
-
note = "Specific match patterns";
|
|
14279
|
-
} else if (patternDensity > 0) {
|
|
14280
|
-
score = 0.3;
|
|
14281
|
-
note = "Broad/unspecific patterns";
|
|
14282
|
-
} else {
|
|
14283
|
-
score = 0;
|
|
14284
|
-
note = "No match patterns";
|
|
14348
|
+
function scoreCorrectness(entries) {
|
|
14349
|
+
let valid = 0;
|
|
14350
|
+
for (const e of entries) {
|
|
14351
|
+
if (e.type === "command" && e.command.length > 0 && e.matcher.length > 0)
|
|
14352
|
+
valid++;
|
|
14285
14353
|
}
|
|
14354
|
+
const score = entries.length > 0 ? clamp(valid / entries.length) : 0;
|
|
14355
|
+
const note = `${valid}/${entries.length} entries valid`;
|
|
14286
14356
|
return { score, note };
|
|
14287
14357
|
}
|
|
14358
|
+
function scoreEventCoverage(entries) {
|
|
14359
|
+
const events = new Set(entries.map((e) => e.event));
|
|
14360
|
+
const covered = KNOWN_HOOK_EVENTS.filter((e) => events.has(e)).length;
|
|
14361
|
+
const score = clamp(Math.min(events.size / 3, 1));
|
|
14362
|
+
const note = `${covered} of ${KNOWN_HOOK_EVENTS.length} known events covered (${events.size} total)`;
|
|
14363
|
+
return { score, note };
|
|
14364
|
+
}
|
|
14365
|
+
function scoreSafety(entries) {
|
|
14366
|
+
const dangerousPatterns = [
|
|
14367
|
+
{ re: /rm\s+-rf/i, label: "rm -rf" },
|
|
14368
|
+
{ re: /\b(?:curl|wget|fetch)\b.*\|\s*(?:ba|z)?sh\b/i, label: "download pipe to shell" },
|
|
14369
|
+
{ re: /--no-verify/i, label: "--no-verify bypass" },
|
|
14370
|
+
{ re: /\beval\b/i, label: "eval" },
|
|
14371
|
+
{ re: /sudo\b/i, label: "sudo" },
|
|
14372
|
+
{ re: /chmod\s+777/i, label: "chmod 777" },
|
|
14373
|
+
{ re: /\$\([^)]*\)/, label: "unquoted command substitution" },
|
|
14374
|
+
{ re: /`[^`]+`/, label: "backtick execution" }
|
|
14375
|
+
];
|
|
14376
|
+
const findings = [];
|
|
14377
|
+
let dangerous = 0;
|
|
14378
|
+
for (const e of entries) {
|
|
14379
|
+
for (const { re, label } of dangerousPatterns) {
|
|
14380
|
+
if (re.test(e.command)) {
|
|
14381
|
+
dangerous++;
|
|
14382
|
+
findings.push(`[${e.event}] ${label}: ${e.command.slice(0, 60)}`);
|
|
14383
|
+
}
|
|
14384
|
+
}
|
|
14385
|
+
}
|
|
14386
|
+
const base = entries.length > 0 ? 1 - dangerous / (entries.length * 2) : 0;
|
|
14387
|
+
const score = clamp(Math.max(base, 0.1));
|
|
14388
|
+
const note = dangerous === 0 ? "No dangerous command patterns found" : `${dangerous} dangerous pattern(s) found`;
|
|
14389
|
+
const recs = dangerous > 0 ? ["Replace dangerous patterns with safe alternatives; add explicit approval gates"] : undefined;
|
|
14390
|
+
return { score, note, findings: findings.length > 0 ? findings : undefined, recommendations: recs };
|
|
14391
|
+
}
|
|
14392
|
+
function scorePatternMatchQuality(entries) {
|
|
14393
|
+
let specificMatchers = 0;
|
|
14394
|
+
let hasTimeout = 0;
|
|
14395
|
+
let portable = 0;
|
|
14396
|
+
for (const e of entries) {
|
|
14397
|
+
if (e.matcher !== "*" && e.matcher.length > 0)
|
|
14398
|
+
specificMatchers++;
|
|
14399
|
+
if (e.timeout !== undefined && e.timeout > 0)
|
|
14400
|
+
hasTimeout++;
|
|
14401
|
+
if (/\$\{CLAUDE_PLUGIN_ROOT\}/.test(e.command)) {
|
|
14402
|
+
portable++;
|
|
14403
|
+
} else {
|
|
14404
|
+
const tokens = e.command.trim().split(/\s+/);
|
|
14405
|
+
const firstToken = tokens[0] ?? "";
|
|
14406
|
+
const bareBinary = firstToken.length > 0 && !firstToken.includes("/") && !firstToken.startsWith(".");
|
|
14407
|
+
const noPathTokens = tokens.every((t) => !t.includes("/") || /\$\{CLAUDE_PLUGIN_ROOT\}/.test(t));
|
|
14408
|
+
if (bareBinary && noPathTokens)
|
|
14409
|
+
portable++;
|
|
14410
|
+
}
|
|
14411
|
+
}
|
|
14412
|
+
const n = entries.length || 1;
|
|
14413
|
+
const matcherScore = specificMatchers / n;
|
|
14414
|
+
const timeoutScore = hasTimeout / n;
|
|
14415
|
+
const portableScore = portable / n;
|
|
14416
|
+
const score = clamp(0.3 * matcherScore + 0.4 * timeoutScore + 0.3 * portableScore);
|
|
14417
|
+
const noteParts = [];
|
|
14418
|
+
if (specificMatchers < n)
|
|
14419
|
+
noteParts.push(`${n - specificMatchers} broad matcher(s)`);
|
|
14420
|
+
if (hasTimeout < n)
|
|
14421
|
+
noteParts.push(`${n - hasTimeout} missing timeout`);
|
|
14422
|
+
if (portable < n)
|
|
14423
|
+
noteParts.push(`${n - portable} non-portable path(s)`);
|
|
14424
|
+
const findings = noteParts.length > 0 ? noteParts.map((p) => p) : undefined;
|
|
14425
|
+
const recs = noteParts.length > 0 ? [
|
|
14426
|
+
"Use specific matchers instead of *; add timeout to every hook; use CLAUDE_PLUGIN_ROOT env var for paths"
|
|
14427
|
+
] : undefined;
|
|
14428
|
+
return {
|
|
14429
|
+
score,
|
|
14430
|
+
note: noteParts.length > 0 ? noteParts.join("; ") : "All entries specific, timed, and portable",
|
|
14431
|
+
findings,
|
|
14432
|
+
recommendations: recs
|
|
14433
|
+
};
|
|
14434
|
+
}
|
|
14288
14435
|
function evaluateHook(content, target) {
|
|
14289
|
-
const
|
|
14290
|
-
|
|
14291
|
-
|
|
14292
|
-
|
|
14293
|
-
|
|
14294
|
-
|
|
14295
|
-
const errNote = parseErrorNote(content, "Frontmatter parse error");
|
|
14436
|
+
const isJson = target.endsWith(".json") || /^\s*\{/.test(content);
|
|
14437
|
+
if (isJson) {
|
|
14438
|
+
let parsed;
|
|
14439
|
+
try {
|
|
14440
|
+
parsed = JSON.parse(content);
|
|
14441
|
+
} catch {
|
|
14296
14442
|
return {
|
|
14297
|
-
|
|
14298
|
-
|
|
14299
|
-
|
|
14300
|
-
|
|
14443
|
+
type: "hook",
|
|
14444
|
+
target,
|
|
14445
|
+
content: "",
|
|
14446
|
+
aggregate: 0,
|
|
14447
|
+
dimensions: {
|
|
14448
|
+
correctness: { score: 0, note: "Invalid JSON: parse error" },
|
|
14449
|
+
"event-coverage": { score: 0, note: "Invalid JSON: parse error" },
|
|
14450
|
+
safety: { score: 0, note: "Invalid JSON: parse error" },
|
|
14451
|
+
"pattern-match-quality": { score: 0, note: "Invalid JSON: parse error" }
|
|
14452
|
+
}
|
|
14301
14453
|
};
|
|
14302
14454
|
}
|
|
14455
|
+
const entries = parseHookEntries(parsed);
|
|
14456
|
+
if (!entries || entries.length === 0) {
|
|
14457
|
+
return {
|
|
14458
|
+
type: "hook",
|
|
14459
|
+
target,
|
|
14460
|
+
content: "",
|
|
14461
|
+
aggregate: 0,
|
|
14462
|
+
dimensions: {
|
|
14463
|
+
correctness: { score: 0, note: "No hook entries found in JSON" },
|
|
14464
|
+
"event-coverage": { score: 0, note: "No hook entries found in JSON" },
|
|
14465
|
+
safety: { score: 0, note: "No hook entries found in JSON" },
|
|
14466
|
+
"pattern-match-quality": { score: 0, note: "No hook entries found in JSON" }
|
|
14467
|
+
}
|
|
14468
|
+
};
|
|
14469
|
+
}
|
|
14470
|
+
const dimensions2 = {
|
|
14471
|
+
correctness: scoreCorrectness(entries),
|
|
14472
|
+
"event-coverage": scoreEventCoverage(entries),
|
|
14473
|
+
safety: scoreSafety(entries),
|
|
14474
|
+
"pattern-match-quality": scorePatternMatchQuality(entries)
|
|
14475
|
+
};
|
|
14303
14476
|
return {
|
|
14304
|
-
|
|
14305
|
-
|
|
14306
|
-
|
|
14307
|
-
|
|
14477
|
+
type: "hook",
|
|
14478
|
+
target,
|
|
14479
|
+
content: "",
|
|
14480
|
+
aggregate: computeAggregate(dimensions2),
|
|
14481
|
+
dimensions: dimensions2
|
|
14308
14482
|
};
|
|
14309
|
-
}
|
|
14483
|
+
}
|
|
14484
|
+
const dimensions = {
|
|
14485
|
+
correctness: { score: 0, note: "Markdown hook definitions not supported; use hooks.json" },
|
|
14486
|
+
"event-coverage": { score: 0, note: "Markdown hook definitions not supported; use hooks.json" },
|
|
14487
|
+
safety: { score: 0, note: "Markdown hook definitions not supported; use hooks.json" },
|
|
14488
|
+
"pattern-match-quality": { score: 0, note: "Markdown hook definitions not supported; use hooks.json" }
|
|
14489
|
+
};
|
|
14310
14490
|
return {
|
|
14311
14491
|
type: "hook",
|
|
14312
14492
|
target,
|
|
@@ -14333,8 +14513,34 @@ var init_hook = __esm(() => {
|
|
|
14333
14513
|
});
|
|
14334
14514
|
|
|
14335
14515
|
// ../../packages/core/src/operations/validate.ts
|
|
14336
|
-
import { existsSync as existsSync8, statSync as
|
|
14337
|
-
import { dirname as dirname4 } from "path";
|
|
14516
|
+
import { existsSync as existsSync8, statSync as statSync4 } from "fs";
|
|
14517
|
+
import { dirname as dirname4, join as join7 } from "path";
|
|
14518
|
+
function checkBodyLinks(body, baseDir) {
|
|
14519
|
+
const findings = [];
|
|
14520
|
+
const linkRe = /\[([^\]]*)\]\(([^)]+)\)/g;
|
|
14521
|
+
for (const match of body.matchAll(linkRe)) {
|
|
14522
|
+
const linkText = match[1];
|
|
14523
|
+
const target = match[2];
|
|
14524
|
+
if (!target)
|
|
14525
|
+
continue;
|
|
14526
|
+
if (/^#/.test(target))
|
|
14527
|
+
continue;
|
|
14528
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(target))
|
|
14529
|
+
continue;
|
|
14530
|
+
const filePart = target.split(/[#?]/)[0];
|
|
14531
|
+
if (!filePart)
|
|
14532
|
+
continue;
|
|
14533
|
+
const resolved = join7(baseDir, filePart);
|
|
14534
|
+
if (!existsSync8(resolved)) {
|
|
14535
|
+
findings.push({
|
|
14536
|
+
severity: "warning",
|
|
14537
|
+
field: "_links",
|
|
14538
|
+
message: `Broken body link: [${linkText}](${target}) \u2192 target not found: ${resolved}`
|
|
14539
|
+
});
|
|
14540
|
+
}
|
|
14541
|
+
}
|
|
14542
|
+
return findings;
|
|
14543
|
+
}
|
|
14338
14544
|
async function validate(type, nameOrPath, opts) {
|
|
14339
14545
|
const resolvedPath = resolveContentPath(type, nameOrPath);
|
|
14340
14546
|
if (!resolvedPath) {
|
|
@@ -14345,7 +14551,7 @@ async function validate(type, nameOrPath, opts) {
|
|
|
14345
14551
|
}
|
|
14346
14552
|
let stat;
|
|
14347
14553
|
try {
|
|
14348
|
-
stat =
|
|
14554
|
+
stat = statSync4(resolvedPath);
|
|
14349
14555
|
} catch {
|
|
14350
14556
|
return sentinelResult(`File not found: ${resolvedPath}`);
|
|
14351
14557
|
}
|
|
@@ -14365,19 +14571,39 @@ async function validate(type, nameOrPath, opts) {
|
|
|
14365
14571
|
return sentinelResult(`Cannot read file: ${resolvedPath}`);
|
|
14366
14572
|
}
|
|
14367
14573
|
const baseDir = dirname4(resolvedPath);
|
|
14368
|
-
|
|
14574
|
+
const result = _validateContent(type, content, {
|
|
14369
14575
|
...opts,
|
|
14370
14576
|
referenceChecker: (refType, refName) => resolveContentPath(refType, refName, { baseDir }) !== null
|
|
14371
14577
|
});
|
|
14578
|
+
const bodyStart = content.indexOf(`
|
|
14579
|
+
---
|
|
14580
|
+
`);
|
|
14581
|
+
const body = bodyStart >= 0 ? content.slice(bodyStart + 5) : content;
|
|
14582
|
+
const linkFindings = checkBodyLinks(body, baseDir);
|
|
14583
|
+
result.findings.push(...linkFindings);
|
|
14584
|
+
return result;
|
|
14372
14585
|
}
|
|
14373
14586
|
function _validateContent(type, content, opts) {
|
|
14374
14587
|
const findings = [];
|
|
14375
14588
|
let data;
|
|
14376
14589
|
let body;
|
|
14590
|
+
const frontmatterPresent = /^---\s*$/m.test(content);
|
|
14377
14591
|
try {
|
|
14378
|
-
|
|
14379
|
-
|
|
14380
|
-
|
|
14592
|
+
if (frontmatterPresent) {
|
|
14593
|
+
const parsed = parseFrontmatter(content);
|
|
14594
|
+
data = parsed.data;
|
|
14595
|
+
body = parsed.body;
|
|
14596
|
+
} else if (type === "magent") {
|
|
14597
|
+
data = {};
|
|
14598
|
+
body = content;
|
|
14599
|
+
} else {
|
|
14600
|
+
findings.push({
|
|
14601
|
+
severity: "error",
|
|
14602
|
+
field: "frontmatter",
|
|
14603
|
+
message: "YAML parse error: Missing frontmatter: content must start with ---"
|
|
14604
|
+
});
|
|
14605
|
+
return { valid: false, findings };
|
|
14606
|
+
}
|
|
14381
14607
|
} catch (e) {
|
|
14382
14608
|
const msg = e instanceof Error ? e.message : String(e);
|
|
14383
14609
|
findings.push({ severity: "error", field: "frontmatter", message: `YAML parse error: ${msg}` });
|
|
@@ -14523,7 +14749,7 @@ function checkLinkValidity(type, data, referenceChecker) {
|
|
|
14523
14749
|
}
|
|
14524
14750
|
return findings;
|
|
14525
14751
|
}
|
|
14526
|
-
function strictChecks(
|
|
14752
|
+
function strictChecks(type, data, body) {
|
|
14527
14753
|
const findings = [];
|
|
14528
14754
|
const desc = data.description;
|
|
14529
14755
|
if (typeof desc === "string" && desc.length < 40) {
|
|
@@ -14560,6 +14786,22 @@ function strictChecks(_type, data, body) {
|
|
|
14560
14786
|
});
|
|
14561
14787
|
}
|
|
14562
14788
|
}
|
|
14789
|
+
const recognized = new Set([
|
|
14790
|
+
...Object.keys(FIELD_TYPES[type] ?? {}),
|
|
14791
|
+
...REQUIRED_FIELDS[type],
|
|
14792
|
+
...KNOWN_OPTIONAL[type] ?? []
|
|
14793
|
+
]);
|
|
14794
|
+
for (const key of Object.keys(data)) {
|
|
14795
|
+
if (recognized.has(key))
|
|
14796
|
+
continue;
|
|
14797
|
+
if (DEPRECATED_FIELDS[key] !== undefined)
|
|
14798
|
+
continue;
|
|
14799
|
+
findings.push({
|
|
14800
|
+
severity: "warning",
|
|
14801
|
+
field: key,
|
|
14802
|
+
message: `Unknown frontmatter key '${key}'`
|
|
14803
|
+
});
|
|
14804
|
+
}
|
|
14563
14805
|
return findings;
|
|
14564
14806
|
}
|
|
14565
14807
|
function formatValidationResult(result, json) {
|
|
@@ -14578,7 +14820,7 @@ function sentinelResult(message) {
|
|
|
14578
14820
|
findings: [{ severity: "error", field: "_file", message }]
|
|
14579
14821
|
};
|
|
14580
14822
|
}
|
|
14581
|
-
var MODEL_ALIASES, FIELD_TYPES, DEPRECATED_FIELDS;
|
|
14823
|
+
var MODEL_ALIASES, FIELD_TYPES, DEPRECATED_FIELDS, KNOWN_OPTIONAL;
|
|
14582
14824
|
var init_validate = __esm(() => {
|
|
14583
14825
|
init_frontmatter();
|
|
14584
14826
|
init_identity();
|
|
@@ -14619,12 +14861,13 @@ var init_validate = __esm(() => {
|
|
|
14619
14861
|
author: "No longer used; remove.",
|
|
14620
14862
|
version: "Version is derived from the source repository."
|
|
14621
14863
|
};
|
|
14622
|
-
|
|
14623
|
-
|
|
14624
|
-
|
|
14625
|
-
|
|
14626
|
-
|
|
14627
|
-
|
|
14864
|
+
KNOWN_OPTIONAL = {
|
|
14865
|
+
skill: ["license", "metadata"],
|
|
14866
|
+
command: ["argument-hint", "allowed-tools", "target"],
|
|
14867
|
+
agent: [],
|
|
14868
|
+
hook: [],
|
|
14869
|
+
magent: []
|
|
14870
|
+
};
|
|
14628
14871
|
});
|
|
14629
14872
|
|
|
14630
14873
|
// ../../node_modules/.bun/@logtape+logtape@2.1.5/node_modules/@logtape/logtape/dist/context.js
|
|
@@ -32208,7 +32451,7 @@ var init_config = __esm(() => {
|
|
|
32208
32451
|
});
|
|
32209
32452
|
|
|
32210
32453
|
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.3.21/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
|
|
32211
|
-
import { appendFileSync, cpSync as cpSync2, createWriteStream, existsSync as existsSync9, mkdirSync as mkdirSync5, readdirSync as
|
|
32454
|
+
import { appendFileSync, cpSync as cpSync2, createWriteStream, existsSync as existsSync9, mkdirSync as mkdirSync5, readdirSync as readdirSync3, readFileSync as readFileSync6, renameSync, rmSync as rmSync2, statSync as statSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
32212
32455
|
import { dirname as dirname5, resolve as resolvePath } from "path";
|
|
32213
32456
|
function createNodeFileSystem(root) {
|
|
32214
32457
|
const projectRoot = root ?? findProjectRoot(process.cwd());
|
|
@@ -32228,7 +32471,7 @@ function createNodeFileSystem(root) {
|
|
|
32228
32471
|
ensureDir: (path) => {
|
|
32229
32472
|
mkdirSync5(path, { recursive: true });
|
|
32230
32473
|
},
|
|
32231
|
-
readDir: (path) =>
|
|
32474
|
+
readDir: (path) => readdirSync3(path),
|
|
32232
32475
|
deleteFile: (path) => {
|
|
32233
32476
|
rmSync2(path, { recursive: true, force: true });
|
|
32234
32477
|
},
|
|
@@ -32244,7 +32487,7 @@ function createNodeFileSystem(root) {
|
|
|
32244
32487
|
},
|
|
32245
32488
|
stat: (path) => {
|
|
32246
32489
|
try {
|
|
32247
|
-
const s =
|
|
32490
|
+
const s = statSync5(path);
|
|
32248
32491
|
return {
|
|
32249
32492
|
isFile: () => s.isFile(),
|
|
32250
32493
|
isDirectory: () => s.isDirectory(),
|
|
@@ -34872,7 +35115,7 @@ var init_encoding_option = __esm(() => {
|
|
|
34872
35115
|
});
|
|
34873
35116
|
|
|
34874
35117
|
// ../../node_modules/.bun/execa@9.6.1/node_modules/execa/lib/arguments/cwd.js
|
|
34875
|
-
import { statSync as
|
|
35118
|
+
import { statSync as statSync6 } from "fs";
|
|
34876
35119
|
import path4 from "path";
|
|
34877
35120
|
import process6 from "process";
|
|
34878
35121
|
var normalizeCwd = (cwd5 = getDefaultCwd()) => {
|
|
@@ -34892,7 +35135,7 @@ ${error51.message}`;
|
|
|
34892
35135
|
}
|
|
34893
35136
|
let cwdStat;
|
|
34894
35137
|
try {
|
|
34895
|
-
cwdStat =
|
|
35138
|
+
cwdStat = statSync6(cwd5);
|
|
34896
35139
|
} catch (error51) {
|
|
34897
35140
|
return `The "cwd" option is invalid: ${cwd5}.
|
|
34898
35141
|
${error51.message}
|
|
@@ -40376,8 +40619,14 @@ function scoreCompleteness(data) {
|
|
|
40376
40619
|
const required2 = REQUIRED_FIELDS.agent;
|
|
40377
40620
|
const score = scorePresence(fieldsPresent, required2);
|
|
40378
40621
|
const missing = required2.filter((f) => !fieldsPresent.includes(f));
|
|
40379
|
-
const
|
|
40380
|
-
|
|
40622
|
+
const findings = missing.length > 0 ? [`Missing required fields: ${missing.join(", ")}`] : undefined;
|
|
40623
|
+
const recs = missing.length > 0 ? ["Add the missing frontmatter fields"] : undefined;
|
|
40624
|
+
return {
|
|
40625
|
+
score: clamp(score),
|
|
40626
|
+
note: missing.length > 0 ? `Missing: ${missing.join(", ")}` : "All required fields present",
|
|
40627
|
+
findings,
|
|
40628
|
+
recommendations: recs
|
|
40629
|
+
};
|
|
40381
40630
|
}
|
|
40382
40631
|
function scoreRoleClarity(body) {
|
|
40383
40632
|
const patterns = [/you are/i, /role/i, /specialist/i, /persona/i];
|
|
@@ -40404,7 +40653,9 @@ function scoreRoleClarity(body) {
|
|
|
40404
40653
|
}
|
|
40405
40654
|
const score = specificity ? clamp(base2 + 0.2) : base2;
|
|
40406
40655
|
const note = matchCount >= 2 ? "Clear role defined" : matchCount === 1 ? "Role definition vague/generic" : "No role definition found";
|
|
40407
|
-
|
|
40656
|
+
const findings = matchCount < 2 ? ["Role definition is vague, generic, or absent"] : undefined;
|
|
40657
|
+
const recs = matchCount === 0 ? ['Add a role statement (e.g. "You are a ... specialist")'] : matchCount === 1 ? ["Add more role signals (specialist, persona, role scope)"] : undefined;
|
|
40658
|
+
return { score, note, findings, recommendations: recs };
|
|
40408
40659
|
}
|
|
40409
40660
|
function scoreToolSelection(data) {
|
|
40410
40661
|
const tools = data.tools;
|
|
@@ -40417,7 +40668,9 @@ function scoreToolSelection(data) {
|
|
|
40417
40668
|
} else {
|
|
40418
40669
|
score = 0.1;
|
|
40419
40670
|
}
|
|
40420
|
-
|
|
40671
|
+
const findings = count2 < 3 ? [`Only ${count2} tool(s) selected \u2014 3+ recommended`] : undefined;
|
|
40672
|
+
const recs = count2 === 0 ? ["Add at least 3 tools to the agent frontmatter"] : count2 < 3 ? ["Add more tools to cover the agent workflow"] : undefined;
|
|
40673
|
+
return { score, note: `${count2} tools selected`, findings, recommendations: recs };
|
|
40421
40674
|
}
|
|
40422
40675
|
function scoreSkillLinkage(body) {
|
|
40423
40676
|
const patterns = [/skill:/i, /skills:/i, /skill/i];
|
|
@@ -40437,7 +40690,13 @@ function scoreSkillLinkage(body) {
|
|
|
40437
40690
|
score = 0;
|
|
40438
40691
|
note = "No skill references";
|
|
40439
40692
|
}
|
|
40440
|
-
|
|
40693
|
+
let findings;
|
|
40694
|
+
let recs;
|
|
40695
|
+
if (score < 1) {
|
|
40696
|
+
findings = ["Skill linkage is weak or missing"];
|
|
40697
|
+
recs = score === 0.5 ? ["Use structured skill references (skill: or skills:) in the agent body"] : ["Add skill references to the agent body for delegated workflows"];
|
|
40698
|
+
}
|
|
40699
|
+
return { score, note, findings, recommendations: recs };
|
|
40441
40700
|
}
|
|
40442
40701
|
function scoreModelFit(data) {
|
|
40443
40702
|
const model = data.model;
|
|
@@ -40460,7 +40719,16 @@ function scoreModelFit(data) {
|
|
|
40460
40719
|
score = 0;
|
|
40461
40720
|
note = "Model: missing";
|
|
40462
40721
|
}
|
|
40463
|
-
|
|
40722
|
+
let findings;
|
|
40723
|
+
let recs;
|
|
40724
|
+
if (score < 0.5) {
|
|
40725
|
+
findings = ["Model field is missing or unrecognized"];
|
|
40726
|
+
recs = ["Specify a valid model (e.g. inherit, claude-sonnet-4, claude-opus-4)"];
|
|
40727
|
+
} else if (score === 0.5) {
|
|
40728
|
+
findings = ["Model name appears ambiguous"];
|
|
40729
|
+
recs = ["Use a recognized model alias (inherit, sonnet, opus, haiku) or well-formed name (claude-sonnet-4)"];
|
|
40730
|
+
}
|
|
40731
|
+
return { score, note, findings, recommendations: recs };
|
|
40464
40732
|
}
|
|
40465
40733
|
function evaluateAgent(content, target) {
|
|
40466
40734
|
const data = parseFrontmatterSafe(content) ?? {};
|
|
@@ -40489,53 +40757,99 @@ var init_agent = __esm(() => {
|
|
|
40489
40757
|
function scoreCompleteness2(data) {
|
|
40490
40758
|
const fieldsPresent = Object.keys(data);
|
|
40491
40759
|
const base2 = scorePresence(fieldsPresent, REQUIRED_FIELDS.command);
|
|
40492
|
-
const
|
|
40493
|
-
const
|
|
40760
|
+
const hasArgHint = typeof data["argument-hint"] === "string" && data["argument-hint"].length > 0;
|
|
40761
|
+
const hasAllowedTools = Array.isArray(data["allowed-tools"]) && data["allowed-tools"].length > 0;
|
|
40762
|
+
const optBonus = (hasArgHint ? 0.1 : 0) + (hasAllowedTools ? 0.1 : 0);
|
|
40763
|
+
const score = clamp(Math.min(base2 + optBonus, 1));
|
|
40494
40764
|
const missing = [];
|
|
40495
40765
|
for (const f of REQUIRED_FIELDS.command) {
|
|
40496
40766
|
if (!(f in data))
|
|
40497
40767
|
missing.push(f);
|
|
40498
40768
|
}
|
|
40499
40769
|
const note = missing.length > 0 ? `Missing fields: ${missing.join(", ")}` : "All required fields present";
|
|
40500
|
-
|
|
40770
|
+
const findings = missing.length > 0 ? [`Missing required fields: ${missing.join(", ")}`] : undefined;
|
|
40771
|
+
const recs = missing.includes("description") ? ["Add a description field to the command frontmatter"] : undefined;
|
|
40772
|
+
return { score, note, findings, recommendations: recs };
|
|
40501
40773
|
}
|
|
40502
40774
|
function scoreClarity(body) {
|
|
40503
40775
|
return scoreClarityFromDensities(body);
|
|
40504
40776
|
}
|
|
40505
40777
|
function scoreArgumentHints(data) {
|
|
40506
|
-
const
|
|
40507
|
-
|
|
40508
|
-
|
|
40509
|
-
|
|
40510
|
-
if (args.length === 0) {
|
|
40511
|
-
return { score: 0, note: "0/0 arguments have hints" };
|
|
40778
|
+
const hasKey = "argument-hint" in data;
|
|
40779
|
+
const argHint = data["argument-hint"];
|
|
40780
|
+
if (!hasKey) {
|
|
40781
|
+
return { score: 1, note: "No argument-hint (command takes no parameters)" };
|
|
40512
40782
|
}
|
|
40513
|
-
|
|
40514
|
-
|
|
40515
|
-
|
|
40516
|
-
|
|
40517
|
-
|
|
40783
|
+
if (typeof argHint !== "string" || argHint.trim().length === 0) {
|
|
40784
|
+
return {
|
|
40785
|
+
score: 0.4,
|
|
40786
|
+
note: "Argument-hint declared but empty",
|
|
40787
|
+
findings: ["Argument-hint is declared but empty"],
|
|
40788
|
+
recommendations: [
|
|
40789
|
+
"Add a descriptive argument-hint string with placeholder syntax, or remove the empty field"
|
|
40790
|
+
]
|
|
40791
|
+
};
|
|
40518
40792
|
}
|
|
40519
|
-
const
|
|
40520
|
-
|
|
40521
|
-
|
|
40522
|
-
|
|
40793
|
+
const hint = argHint.trim();
|
|
40794
|
+
const hasPositional = /<[a-z][^>]*>/i.test(hint);
|
|
40795
|
+
const hasFlags = /\[?--[a-z][^\s\]]*\]?/i.test(hint);
|
|
40796
|
+
let score;
|
|
40797
|
+
let note;
|
|
40798
|
+
if (hasPositional && hasFlags) {
|
|
40799
|
+
score = 1;
|
|
40800
|
+
note = "Rich argument-hint with positional args and flags";
|
|
40801
|
+
} else if (hasPositional || hasFlags) {
|
|
40802
|
+
score = 0.75;
|
|
40803
|
+
note = "Argument-hint present but could be more descriptive";
|
|
40804
|
+
} else {
|
|
40805
|
+
score = 0.4;
|
|
40806
|
+
note = "Argument-hint is vague or placeholder-only";
|
|
40807
|
+
}
|
|
40808
|
+
let findings;
|
|
40809
|
+
let recs;
|
|
40810
|
+
if (score < 1 && score > 0.5) {
|
|
40811
|
+
findings = ["Argument-hint could be more descriptive"];
|
|
40812
|
+
recs = ["Add both positional args (<name>) and flags ([--flag <value>]) to the argument-hint"];
|
|
40813
|
+
} else if (score <= 0.5) {
|
|
40814
|
+
findings = ["Argument-hint is vague or missing for a parameterized command"];
|
|
40815
|
+
recs = ["Add a descriptive argument-hint string with placeholder syntax"];
|
|
40816
|
+
}
|
|
40817
|
+
return { score, note, findings, recommendations: recs };
|
|
40818
|
+
}
|
|
40819
|
+
function scoreToolReferences(body, data) {
|
|
40820
|
+
const allowedTools = data["allowed-tools"];
|
|
40821
|
+
const toolCount = Array.isArray(allowedTools) ? allowedTools.length : 0;
|
|
40523
40822
|
const structuredCount = (body.match(/\btools?:/gi) ?? []).length;
|
|
40524
40823
|
const backtickCount = (body.match(/`[a-z][a-z0-9_-]*`/g) ?? []).length;
|
|
40525
|
-
const
|
|
40824
|
+
const bodyWeighted = structuredCount + Math.min(backtickCount, 1);
|
|
40526
40825
|
let score;
|
|
40527
40826
|
let note;
|
|
40528
|
-
if (
|
|
40827
|
+
if (toolCount >= 5) {
|
|
40529
40828
|
score = 1;
|
|
40530
|
-
note =
|
|
40531
|
-
} else if (
|
|
40532
|
-
score = 0.
|
|
40829
|
+
note = `${toolCount} allowed-tools declared`;
|
|
40830
|
+
} else if (toolCount >= 3) {
|
|
40831
|
+
score = 0.9;
|
|
40832
|
+
note = `${toolCount} allowed-tools declared`;
|
|
40833
|
+
} else if (toolCount >= 1 || structuredCount >= 1 || bodyWeighted >= 2) {
|
|
40834
|
+
score = 0.7;
|
|
40835
|
+
note = toolCount > 0 ? `${toolCount} allowed-tools declared` : "Uses tool references";
|
|
40836
|
+
} else if (bodyWeighted === 1) {
|
|
40837
|
+
score = 0.4;
|
|
40533
40838
|
note = "Limited tool references";
|
|
40534
40839
|
} else {
|
|
40535
40840
|
score = 0.1;
|
|
40536
40841
|
note = "No tool references found";
|
|
40537
40842
|
}
|
|
40538
|
-
|
|
40843
|
+
let findings;
|
|
40844
|
+
let recs;
|
|
40845
|
+
if (score < 0.5) {
|
|
40846
|
+
findings = ["No tool references found"];
|
|
40847
|
+
recs = ["Add allowed-tools to frontmatter or reference tools in the command body"];
|
|
40848
|
+
} else if (score < 0.8) {
|
|
40849
|
+
findings = ["Limited tool references"];
|
|
40850
|
+
recs = ["Declare all required tools in the allowed-tools frontmatter array"];
|
|
40851
|
+
}
|
|
40852
|
+
return { score, note, findings, recommendations: recs };
|
|
40539
40853
|
}
|
|
40540
40854
|
function scoreSlashSyntax(body, target) {
|
|
40541
40855
|
const slashPattern = /\/[a-z][a-z-]*/g;
|
|
@@ -40562,7 +40876,7 @@ function evaluateCommand(content, target) {
|
|
|
40562
40876
|
completeness: scoreCompleteness2(data),
|
|
40563
40877
|
clarity: scoreClarity(body),
|
|
40564
40878
|
"argument-hints": scoreArgumentHints(data),
|
|
40565
|
-
"tool-references": scoreToolReferences(body),
|
|
40879
|
+
"tool-references": scoreToolReferences(body, data),
|
|
40566
40880
|
"slash-syntax": scoreSlashSyntax(body, target)
|
|
40567
40881
|
};
|
|
40568
40882
|
return {
|
|
@@ -40581,16 +40895,21 @@ var init_command3 = __esm(() => {
|
|
|
40581
40895
|
// ../../packages/core/src/quality/magent.ts
|
|
40582
40896
|
function scoreCompleteness3(body) {
|
|
40583
40897
|
let found = 0;
|
|
40584
|
-
for (const re of MAGENT_SECTIONS) {
|
|
40898
|
+
for (const { re } of MAGENT_SECTIONS) {
|
|
40585
40899
|
if (re.test(body))
|
|
40586
40900
|
found++;
|
|
40587
40901
|
}
|
|
40902
|
+
const score = clamp(found / MAGENT_SECTIONS.length);
|
|
40903
|
+
const findings = found < MAGENT_SECTIONS.length / 2 ? ["Config is missing key governance sections"] : undefined;
|
|
40904
|
+
const recs = found < MAGENT_SECTIONS.length ? ["Add more governance sections (commands, verification, conventions, safety, docs)"] : undefined;
|
|
40588
40905
|
return {
|
|
40589
|
-
score
|
|
40590
|
-
note: `${found}/${MAGENT_SECTIONS.length} sections present
|
|
40906
|
+
score,
|
|
40907
|
+
note: `${found}/${MAGENT_SECTIONS.length} governance sections present`,
|
|
40908
|
+
findings,
|
|
40909
|
+
recommendations: recs
|
|
40591
40910
|
};
|
|
40592
40911
|
}
|
|
40593
|
-
function scorePlatformCoverage(data) {
|
|
40912
|
+
function scorePlatformCoverage(data, body) {
|
|
40594
40913
|
const raw = data.platforms;
|
|
40595
40914
|
let platforms = [];
|
|
40596
40915
|
if (Array.isArray(raw)) {
|
|
@@ -40598,8 +40917,29 @@ function scorePlatformCoverage(data) {
|
|
|
40598
40917
|
} else if (typeof raw === "string") {
|
|
40599
40918
|
platforms = raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
40600
40919
|
}
|
|
40920
|
+
if (platforms.length === 0) {
|
|
40921
|
+
const detected = [];
|
|
40922
|
+
const platformPatterns = [
|
|
40923
|
+
[/claude.?code/i, "claude-code"],
|
|
40924
|
+
[/codex/i, "codex"],
|
|
40925
|
+
[/gemini/i, "gemini"],
|
|
40926
|
+
[/cursor/i, "cursor"],
|
|
40927
|
+
[/windsurf/i, "windsurf"],
|
|
40928
|
+
[/opencode/i, "opencode"],
|
|
40929
|
+
[/openclaw/i, "openclaw"],
|
|
40930
|
+
[/antigravity/i, "antigravity"],
|
|
40931
|
+
[/pi\b/i, "pi"]
|
|
40932
|
+
];
|
|
40933
|
+
for (const [re, name] of platformPatterns) {
|
|
40934
|
+
if (re.test(body))
|
|
40935
|
+
detected.push(name);
|
|
40936
|
+
}
|
|
40937
|
+
platforms = detected;
|
|
40938
|
+
}
|
|
40601
40939
|
const score = clamp(Math.min(platforms.length / 5, 1));
|
|
40602
|
-
|
|
40940
|
+
const findings = platforms.length === 0 ? ["No platforms declared or detected"] : platforms.length < 3 ? ["Limited platform coverage"] : undefined;
|
|
40941
|
+
const recs = platforms.length < 3 ? ["Declare supported platforms in frontmatter (platforms:) or mention them in prose"] : undefined;
|
|
40942
|
+
return { score, note: `${platforms.length} platforms covered`, findings, recommendations: recs };
|
|
40603
40943
|
}
|
|
40604
40944
|
function scoreConciseness(body) {
|
|
40605
40945
|
return {
|
|
@@ -40627,16 +40967,19 @@ function scoreSafety2(body) {
|
|
|
40627
40967
|
if (lower.includes(kw.toLowerCase()))
|
|
40628
40968
|
count2++;
|
|
40629
40969
|
}
|
|
40630
|
-
|
|
40970
|
+
const findings = count2 < 3 ? ["Limited safety markers in config"] : undefined;
|
|
40971
|
+
const recs = count2 < 3 ? ["Add [CRITICAL] markers, safety rules, NEVER directives, and security validation"] : undefined;
|
|
40972
|
+
return { score: density, note: `${count2} safety markers found`, findings, recommendations: recs };
|
|
40631
40973
|
}
|
|
40632
40974
|
function evaluateMagent(content, target) {
|
|
40633
|
-
const fmResult = parseFrontmatterSafe(content);
|
|
40634
|
-
const data = fmResult ?? {};
|
|
40635
|
-
const fmNote = fmResult === null ? parseErrorNote(content, "unknown parse error") : null;
|
|
40636
40975
|
const body = extractBody(content);
|
|
40976
|
+
const hasFrontmatter = /^---\s*$/m.test(content);
|
|
40977
|
+
const fmResult = hasFrontmatter ? parseFrontmatterSafe(content) : undefined;
|
|
40978
|
+
const data = fmResult ?? {};
|
|
40979
|
+
const fmNote = hasFrontmatter && fmResult === null ? parseErrorNote(content, "Frontmatter parse error") : null;
|
|
40637
40980
|
const dimensions = {
|
|
40638
40981
|
completeness: scoreCompleteness3(body),
|
|
40639
|
-
"platform-coverage": scorePlatformCoverage(data),
|
|
40982
|
+
"platform-coverage": scorePlatformCoverage(data, body),
|
|
40640
40983
|
conciseness: scoreConciseness(body),
|
|
40641
40984
|
"tone-consistency": scoreToneConsistency(body),
|
|
40642
40985
|
safety: scoreSafety2(body)
|
|
@@ -40659,7 +41002,14 @@ var MAGENT_SECTIONS;
|
|
|
40659
41002
|
var init_magent = __esm(() => {
|
|
40660
41003
|
init_heuristics();
|
|
40661
41004
|
init_types2();
|
|
40662
|
-
MAGENT_SECTIONS = [
|
|
41005
|
+
MAGENT_SECTIONS = [
|
|
41006
|
+
{ re: /^## .*[Pp]roject|^## .*[Ss]tack/m, label: "project" },
|
|
41007
|
+
{ re: /^## .*[Cc]ommand|^## .*[Tt]ool/m, label: "commands" },
|
|
41008
|
+
{ re: /^## .*[Vv]erif|^## .*[Tt]est|^## .*[Gg]ate/m, label: "verification" },
|
|
41009
|
+
{ re: /^## .*[Cc]onvention|^## .*[Ss]tyle|^## .*[Bb]oundar/m, label: "conventions" },
|
|
41010
|
+
{ re: /^## .*[Ss]afety|^## .*[Ss]ecurity|^## .*[Cc]ritical/m, label: "safety" },
|
|
41011
|
+
{ re: /^## .*[Dd]oc|^## .*[Rr]eference|^## .*[Rr]outing/m, label: "docs" }
|
|
41012
|
+
];
|
|
40663
41013
|
});
|
|
40664
41014
|
|
|
40665
41015
|
// ../../packages/core/src/quality/skill.ts
|
|
@@ -40694,7 +41044,17 @@ function scoreCompleteness4(content, data, body) {
|
|
|
40694
41044
|
const keySet = new Set(presentKeys);
|
|
40695
41045
|
const missing = required2.filter((f) => !keySet.has(f));
|
|
40696
41046
|
const note = missing.length > 0 ? `Missing fields: ${missing.join(", ")}` : "All required fields present";
|
|
40697
|
-
|
|
41047
|
+
const findings = [];
|
|
41048
|
+
const recommendations = [];
|
|
41049
|
+
if (missing.length > 0) {
|
|
41050
|
+
findings.push(`Missing required frontmatter: ${missing.join(", ")}`);
|
|
41051
|
+
recommendations.push(`Add \`${missing.join("`, `")}\` to YAML frontmatter`);
|
|
41052
|
+
}
|
|
41053
|
+
if (structure < 1) {
|
|
41054
|
+
findings.push("Body lacks section headings (# / ## / ###). Structure aids navigation.");
|
|
41055
|
+
recommendations.push("Organize content with markdown headings for progressive disclosure");
|
|
41056
|
+
}
|
|
41057
|
+
return { score, note, findings, recommendations };
|
|
40698
41058
|
}
|
|
40699
41059
|
function scoreClarity2(body) {
|
|
40700
41060
|
return scoreClarityFromDensities(body);
|
|
@@ -40709,7 +41069,16 @@ function scoreTriggerAccuracy(body) {
|
|
|
40709
41069
|
} else {
|
|
40710
41070
|
score = clamp(1 - (count2 - 10) / 10);
|
|
40711
41071
|
}
|
|
40712
|
-
|
|
41072
|
+
const findings = [];
|
|
41073
|
+
const recommendations = [];
|
|
41074
|
+
if (count2 < 3) {
|
|
41075
|
+
findings.push(`Only ${count2} trigger phrase(s) found; aim for 3\u201310 for reliable skill activation.`);
|
|
41076
|
+
recommendations.push("Add 1\u20132 more When-to-Use scenarios or trigger phrase patterns to the description.");
|
|
41077
|
+
} else if (count2 > 10) {
|
|
41078
|
+
findings.push(`${count2} trigger phrases may cause overlap with adjacent skills.`);
|
|
41079
|
+
recommendations.push("Consolidate overlapping triggers or narrow the activation scope.");
|
|
41080
|
+
}
|
|
41081
|
+
return { score, note: `${count2} trigger phrases found`, findings, recommendations };
|
|
40713
41082
|
}
|
|
40714
41083
|
function scoreAntiHallucination(body) {
|
|
40715
41084
|
const density = keywordDensity(body, [
|
|
@@ -40723,10 +41092,16 @@ function scoreAntiHallucination(body) {
|
|
|
40723
41092
|
"evidence"
|
|
40724
41093
|
]);
|
|
40725
41094
|
const note = density > 0 ? "Includes verification language" : "Missing verification instructions";
|
|
40726
|
-
|
|
41095
|
+
const findings = [];
|
|
41096
|
+
const recommendations = [];
|
|
41097
|
+
if (density < 0.3) {
|
|
41098
|
+
findings.push("Verification/citation language sparse or absent. Skill may invite fabrication.");
|
|
41099
|
+
recommendations.push('Add explicit "verify with source", "cross-check against docs", or "cite the reference" instructions.');
|
|
41100
|
+
}
|
|
41101
|
+
return { score: density, note, findings, recommendations };
|
|
40727
41102
|
}
|
|
40728
41103
|
function scoreConciseness2(body) {
|
|
40729
|
-
const score = scoreLength(body, 500,
|
|
41104
|
+
const score = scoreLength(body, 500, 15000);
|
|
40730
41105
|
return { score, note: `Body length: ${body.length} chars` };
|
|
40731
41106
|
}
|
|
40732
41107
|
function countTriggerPhrases(body) {
|
|
@@ -40791,7 +41166,7 @@ var init_evaluate = __esm(() => {
|
|
|
40791
41166
|
// ../../packages/core/src/quality/rubric.ts
|
|
40792
41167
|
import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
|
|
40793
41168
|
import { homedir as homedir3 } from "os";
|
|
40794
|
-
import { join as
|
|
41169
|
+
import { join as join8 } from "path";
|
|
40795
41170
|
function resolveRubricContent(type, opts) {
|
|
40796
41171
|
if (opts?.path) {
|
|
40797
41172
|
if (!existsSync10(opts.path)) {
|
|
@@ -40800,15 +41175,15 @@ function resolveRubricContent(type, opts) {
|
|
|
40800
41175
|
return readFileSync9(opts.path, "utf-8");
|
|
40801
41176
|
}
|
|
40802
41177
|
const homeDir = process.env.HOME ?? homedir3();
|
|
40803
|
-
const userPath =
|
|
41178
|
+
const userPath = join8(homeDir, ".superskill", "rubrics", `${type}.yaml`);
|
|
40804
41179
|
if (existsSync10(userPath)) {
|
|
40805
41180
|
return readFileSync9(userPath, "utf-8");
|
|
40806
41181
|
}
|
|
40807
|
-
const devPath =
|
|
41182
|
+
const devPath = join8(import.meta.dir, "..", "rubrics", `${type}.yaml`);
|
|
40808
41183
|
if (existsSync10(devPath)) {
|
|
40809
41184
|
return readFileSync9(devPath, "utf-8");
|
|
40810
41185
|
}
|
|
40811
|
-
const prodPath =
|
|
41186
|
+
const prodPath = join8(import.meta.dir, "..", "..", "rubrics", `${type}.yaml`);
|
|
40812
41187
|
if (existsSync10(prodPath)) {
|
|
40813
41188
|
return readFileSync9(prodPath, "utf-8");
|
|
40814
41189
|
}
|
|
@@ -46639,11 +47014,11 @@ var require_out = __commonJS((exports) => {
|
|
|
46639
47014
|
async.read(path7, getSettings(optionsOrSettingsOrCallback), callback);
|
|
46640
47015
|
}
|
|
46641
47016
|
exports.stat = stat;
|
|
46642
|
-
function
|
|
47017
|
+
function statSync7(path7, optionsOrSettings) {
|
|
46643
47018
|
const settings = getSettings(optionsOrSettings);
|
|
46644
47019
|
return sync.read(path7, settings);
|
|
46645
47020
|
}
|
|
46646
|
-
exports.statSync =
|
|
47021
|
+
exports.statSync = statSync7;
|
|
46647
47022
|
function getSettings(settingsOrOptions = {}) {
|
|
46648
47023
|
if (settingsOrOptions instanceof settings_1.default) {
|
|
46649
47024
|
return settingsOrOptions;
|
|
@@ -57813,7 +58188,7 @@ import { join as join52 } from "path";
|
|
|
57813
58188
|
import path10, { relative as relative2, resolve as resolve4 } from "path";
|
|
57814
58189
|
import { basename as basename4, join as join9 } from "path";
|
|
57815
58190
|
import { join as join72 } from "path";
|
|
57816
|
-
import { join as
|
|
58191
|
+
import { join as join82 } from "path";
|
|
57817
58192
|
import { join as join10 } from "path";
|
|
57818
58193
|
import { basename as basename22, join as join11 } from "path";
|
|
57819
58194
|
import { join as join13 } from "path";
|
|
@@ -57886,7 +58261,7 @@ import { join as join79 } from "path";
|
|
|
57886
58261
|
import { join as join81 } from "path";
|
|
57887
58262
|
import { join as join80 } from "path";
|
|
57888
58263
|
import { join as join84 } from "path";
|
|
57889
|
-
import { join as
|
|
58264
|
+
import { join as join822 } from "path";
|
|
57890
58265
|
import { join as join83 } from "path";
|
|
57891
58266
|
import { join as join85 } from "path";
|
|
57892
58267
|
import { join as join86 } from "path";
|
|
@@ -63432,7 +63807,7 @@ var init_chunk_QKQNZ6C3 = __esm(() => {
|
|
|
63432
63807
|
constructor({ frontmatter, body, ...rest2 }) {
|
|
63433
63808
|
const parseResult = RulesyncCommandFrontmatterSchema.safeParse(frontmatter);
|
|
63434
63809
|
if (!parseResult.success && rest2.validate) {
|
|
63435
|
-
throw new Error(`Invalid frontmatter in ${
|
|
63810
|
+
throw new Error(`Invalid frontmatter in ${join82(rest2.outputRoot ?? process.cwd(), rest2.relativeDirPath, rest2.relativeFilePath)}: ${formatError2(parseResult.error)}`);
|
|
63436
63811
|
}
|
|
63437
63812
|
const parsedFrontmatter = parseResult.success ? { ...frontmatter, ...parseResult.data } : { ...frontmatter, targets: frontmatter.targets ?? ["*"] };
|
|
63438
63813
|
super({
|
|
@@ -63473,7 +63848,7 @@ var init_chunk_QKQNZ6C3 = __esm(() => {
|
|
|
63473
63848
|
} else {
|
|
63474
63849
|
return {
|
|
63475
63850
|
success: false,
|
|
63476
|
-
error: new Error(`Invalid frontmatter in ${
|
|
63851
|
+
error: new Error(`Invalid frontmatter in ${join82(this.relativeDirPath, this.relativeFilePath)}: ${formatError2(result.error)}`)
|
|
63477
63852
|
};
|
|
63478
63853
|
}
|
|
63479
63854
|
}
|
|
@@ -63481,7 +63856,7 @@ var init_chunk_QKQNZ6C3 = __esm(() => {
|
|
|
63481
63856
|
outputRoot = process.cwd(),
|
|
63482
63857
|
relativeFilePath
|
|
63483
63858
|
}) {
|
|
63484
|
-
const filePath =
|
|
63859
|
+
const filePath = join82(outputRoot, _RulesyncCommand.getSettablePaths().relativeDirPath, relativeFilePath);
|
|
63485
63860
|
const fileContent = await readFileContent(filePath);
|
|
63486
63861
|
const { frontmatter, body: content } = parseFrontmatter2(fileContent, filePath);
|
|
63487
63862
|
const result = RulesyncCommandFrontmatterSchema.safeParse(frontmatter);
|
|
@@ -69803,9 +70178,9 @@ prompt = ""`;
|
|
|
69803
70178
|
return ignoreProcessorToolTargets;
|
|
69804
70179
|
}
|
|
69805
70180
|
};
|
|
69806
|
-
AMP_GLOBAL_DIR =
|
|
69807
|
-
AMP_SKILLS_PROJECT_DIR =
|
|
69808
|
-
AMP_SKILLS_GLOBAL_DIR =
|
|
70181
|
+
AMP_GLOBAL_DIR = join822(".config", "amp");
|
|
70182
|
+
AMP_SKILLS_PROJECT_DIR = join822(AMP_AGENTS_DIR, "skills");
|
|
70183
|
+
AMP_SKILLS_GLOBAL_DIR = join822(".config", "agents", "skills");
|
|
69809
70184
|
EnvVarNameSchema = exports_external3.string().check(refine2((value) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(value), "envVars entries must be valid environment variable names"));
|
|
69810
70185
|
McpServerSchema = exports_external3.looseObject({
|
|
69811
70186
|
type: exports_external3.optional(exports_external3.enum(["local", "stdio", "sse", "http", "ws", "streamable-http"])),
|
|
@@ -88916,7 +89291,6 @@ var init_src = __esm(() => {
|
|
|
88916
89291
|
init_validate();
|
|
88917
89292
|
init_adapt_command();
|
|
88918
89293
|
init_adapt_subagent();
|
|
88919
|
-
init_pi_subagent();
|
|
88920
89294
|
init_pi_tools();
|
|
88921
89295
|
init_rewrite_references();
|
|
88922
89296
|
init_slash_command2();
|
|
@@ -94660,11 +95034,39 @@ function deserializeEvaluation(row) {
|
|
|
94660
95034
|
}
|
|
94661
95035
|
|
|
94662
95036
|
// src/operations/evaluate.ts
|
|
95037
|
+
async function showHistory(type, contentName, opts) {
|
|
95038
|
+
const adapter = opts.adapter ?? await openStore();
|
|
95039
|
+
const dao = new EvaluationDao(adapter);
|
|
95040
|
+
const rows = await dao.getEvaluations(type, contentName);
|
|
95041
|
+
if (rows.length === 0)
|
|
95042
|
+
return;
|
|
95043
|
+
const cols = { date: 19, agg: 9, verdict: 7 };
|
|
95044
|
+
const lines = [];
|
|
95045
|
+
lines.push(`Evaluation history for ${contentName} (${rows.length} entries):`);
|
|
95046
|
+
lines.push("");
|
|
95047
|
+
const header = `${"Date".padEnd(cols.date)} ${"Aggregate".padEnd(cols.agg)} ${"Verdict".padEnd(cols.verdict)} Scorer`;
|
|
95048
|
+
lines.push(header);
|
|
95049
|
+
lines.push("-".repeat(header.length));
|
|
95050
|
+
for (const row of rows) {
|
|
95051
|
+
const date9 = new Date(row.created_at).toISOString().slice(0, 19).replace("T", " ");
|
|
95052
|
+
const agg = row.aggregate.toFixed(2).padEnd(cols.agg);
|
|
95053
|
+
const verdict = (row.aggregate >= 0.7 ? "PASS" : "FAIL").padEnd(cols.verdict);
|
|
95054
|
+
const scorer = row.scorer ?? "heuristic";
|
|
95055
|
+
const rv = row.rubric_version ? ` v${row.rubric_version}` : "";
|
|
95056
|
+
lines.push(`${date9.padEnd(cols.date)} ${agg} ${verdict} ${scorer}${rv}`);
|
|
95057
|
+
}
|
|
95058
|
+
echo(lines.join(`
|
|
95059
|
+
`));
|
|
95060
|
+
}
|
|
94663
95061
|
async function evaluate3(type, nameOrPath, opts) {
|
|
94664
95062
|
const resolvedPath = resolveContentPath(type, nameOrPath);
|
|
94665
95063
|
if (!resolvedPath) {
|
|
94666
95064
|
throw Object.assign(new Error(`File not found: ${nameOrPath}`), { code: 2 });
|
|
94667
95065
|
}
|
|
95066
|
+
if (opts?.history) {
|
|
95067
|
+
await showHistory(type, resolveContentName(resolvedPath), opts);
|
|
95068
|
+
return null;
|
|
95069
|
+
}
|
|
94668
95070
|
let content;
|
|
94669
95071
|
try {
|
|
94670
95072
|
content = await Bun.file(resolvedPath).text();
|
|
@@ -94680,8 +95082,24 @@ async function evaluate3(type, nameOrPath, opts) {
|
|
|
94680
95082
|
}
|
|
94681
95083
|
const report = evaluate(type, content, resolvedTarget);
|
|
94682
95084
|
report.content = resolveContentName(resolvedPath);
|
|
95085
|
+
applyRubricWeightingAndVerdict(type, report, opts);
|
|
94683
95086
|
if (opts?.save) {
|
|
94684
|
-
|
|
95087
|
+
try {
|
|
95088
|
+
const adapter = opts.adapter ?? await openStore();
|
|
95089
|
+
await new EvaluationDao(adapter).insertEvaluation({
|
|
95090
|
+
content_type: type,
|
|
95091
|
+
content_name: resolveContentName(resolvedPath),
|
|
95092
|
+
target_agent: resolvedTarget,
|
|
95093
|
+
operation: opts.operation ?? "evaluate",
|
|
95094
|
+
aggregate: report.aggregate,
|
|
95095
|
+
dimensions: report.dimensions,
|
|
95096
|
+
file_hash: hashContent(resolvedPath),
|
|
95097
|
+
scorer: "heuristic"
|
|
95098
|
+
});
|
|
95099
|
+
} catch (err) {
|
|
95100
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
95101
|
+
echoError(`Warning: failed to save evaluation: ${msg}`);
|
|
95102
|
+
}
|
|
94685
95103
|
}
|
|
94686
95104
|
return report;
|
|
94687
95105
|
}
|
|
@@ -94695,11 +95113,30 @@ function computeWeightedAggregate(scores, rubric2) {
|
|
|
94695
95113
|
}
|
|
94696
95114
|
return sum2;
|
|
94697
95115
|
}
|
|
95116
|
+
function applyRubricWeightingAndVerdict(type, report, opts) {
|
|
95117
|
+
try {
|
|
95118
|
+
const rubric2 = loadRubric(type, opts?.rubric ? { path: opts.rubric } : undefined);
|
|
95119
|
+
report.aggregate = computeWeightedAggregate(report.dimensions, rubric2);
|
|
95120
|
+
} catch {}
|
|
95121
|
+
const agg = report.aggregate;
|
|
95122
|
+
report.verdict = agg >= 0.7 ? "PASS" : "FAIL";
|
|
95123
|
+
if (agg >= 0.9)
|
|
95124
|
+
report.grade = "A";
|
|
95125
|
+
else if (agg >= 0.75)
|
|
95126
|
+
report.grade = "B";
|
|
95127
|
+
else if (agg >= 0.6)
|
|
95128
|
+
report.grade = "C";
|
|
95129
|
+
else if (agg >= 0.45)
|
|
95130
|
+
report.grade = "D";
|
|
95131
|
+
else
|
|
95132
|
+
report.grade = "F";
|
|
95133
|
+
}
|
|
94698
95134
|
function emitEnvelope(type, resolvedPath, content, resolvedTarget, opts) {
|
|
94699
95135
|
const rubric2 = loadRubric(type, { path: opts.rubric });
|
|
94700
95136
|
const contentName = resolveContentName(resolvedPath);
|
|
94701
95137
|
const baseline = evaluate(type, content, resolvedTarget);
|
|
94702
95138
|
baseline.content = contentName;
|
|
95139
|
+
applyRubricWeightingAndVerdict(type, baseline, opts);
|
|
94703
95140
|
const envelope = {
|
|
94704
95141
|
type,
|
|
94705
95142
|
content_name: contentName,
|
|
@@ -94769,31 +95206,26 @@ async function ingestScores(type, resolvedPath, resolvedTarget, opts) {
|
|
|
94769
95206
|
dimensions
|
|
94770
95207
|
};
|
|
94771
95208
|
if (opts.save) {
|
|
94772
|
-
|
|
95209
|
+
try {
|
|
95210
|
+
const adapter = opts.adapter ?? await openStore();
|
|
95211
|
+
await new EvaluationDao(adapter).insertEvaluation({
|
|
95212
|
+
content_type: type,
|
|
95213
|
+
content_name: resolveContentName(resolvedPath),
|
|
95214
|
+
target_agent: resolvedTarget,
|
|
95215
|
+
operation: opts.operation ?? "evaluate",
|
|
95216
|
+
aggregate: report.aggregate,
|
|
95217
|
+
dimensions: report.dimensions,
|
|
95218
|
+
file_hash: hashContent(resolvedPath),
|
|
95219
|
+
scorer: "rubric",
|
|
95220
|
+
rubric_version: rubric2.version
|
|
95221
|
+
});
|
|
95222
|
+
} catch (err) {
|
|
95223
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
95224
|
+
echoError(`Warning: failed to save evaluation: ${msg}`);
|
|
95225
|
+
}
|
|
94773
95226
|
}
|
|
94774
95227
|
return report;
|
|
94775
95228
|
}
|
|
94776
|
-
async function persistEvaluation(type, resolvedPath, resolvedTarget, report, opts, scorer, rubricVersion) {
|
|
94777
|
-
try {
|
|
94778
|
-
const fileHash = hashContent(resolvedPath);
|
|
94779
|
-
const adapter = opts.adapter ?? await openStore();
|
|
94780
|
-
const dao = new EvaluationDao(adapter);
|
|
94781
|
-
await dao.insertEvaluation({
|
|
94782
|
-
content_type: type,
|
|
94783
|
-
content_name: resolveContentName(resolvedPath),
|
|
94784
|
-
target_agent: resolvedTarget,
|
|
94785
|
-
operation: opts.operation ?? "evaluate",
|
|
94786
|
-
aggregate: report.aggregate,
|
|
94787
|
-
dimensions: report.dimensions,
|
|
94788
|
-
file_hash: fileHash,
|
|
94789
|
-
scorer: scorer ?? "heuristic",
|
|
94790
|
-
...rubricVersion !== undefined ? { rubric_version: rubricVersion } : {}
|
|
94791
|
-
});
|
|
94792
|
-
} catch (err) {
|
|
94793
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
94794
|
-
echoError(`Warning: failed to save evaluation: ${msg}`);
|
|
94795
|
-
}
|
|
94796
|
-
}
|
|
94797
95229
|
function formatEvaluationReport(report, json3) {
|
|
94798
95230
|
if (json3) {
|
|
94799
95231
|
return JSON.stringify(report);
|
|
@@ -94811,6 +95243,33 @@ function formatEvaluationReport(report, json3) {
|
|
|
94811
95243
|
}
|
|
94812
95244
|
lines.push(` ${"\u2500".repeat(maxNameLen)}${"\u2500".repeat(30)}`);
|
|
94813
95245
|
lines.push(` ${"AGGREGATE".padEnd(maxNameLen)} ${report.aggregate.toFixed(2)}`);
|
|
95246
|
+
if (report.verdict || report.grade) {
|
|
95247
|
+
lines.push("");
|
|
95248
|
+
lines.push(` Verdict: ${report.verdict ?? ""} Grade: ${report.grade ?? ""}`);
|
|
95249
|
+
}
|
|
95250
|
+
const findings = [];
|
|
95251
|
+
const recommendations = [];
|
|
95252
|
+
for (const name of dimNames) {
|
|
95253
|
+
const dim2 = report.dimensions[name];
|
|
95254
|
+
if (!dim2)
|
|
95255
|
+
continue;
|
|
95256
|
+
if (dim2.findings)
|
|
95257
|
+
findings.push(...dim2.findings.map((f) => `[${name}] ${f}`));
|
|
95258
|
+
if (dim2.recommendations)
|
|
95259
|
+
recommendations.push(...dim2.recommendations.map((r) => `[${name}] ${r}`));
|
|
95260
|
+
}
|
|
95261
|
+
if (findings.length > 0) {
|
|
95262
|
+
lines.push("");
|
|
95263
|
+
lines.push("Findings:");
|
|
95264
|
+
for (const f of findings)
|
|
95265
|
+
lines.push(` \u2022 ${f}`);
|
|
95266
|
+
}
|
|
95267
|
+
if (recommendations.length > 0) {
|
|
95268
|
+
lines.push("");
|
|
95269
|
+
lines.push("Recommendations:");
|
|
95270
|
+
for (const r of recommendations)
|
|
95271
|
+
lines.push(` \u2192 ${r}`);
|
|
95272
|
+
}
|
|
94814
95273
|
return lines.join(`
|
|
94815
95274
|
`);
|
|
94816
95275
|
}
|
|
@@ -94890,6 +95349,11 @@ function deserializeProposal(row) {
|
|
|
94890
95349
|
init_src();
|
|
94891
95350
|
|
|
94892
95351
|
// src/operations/evolve.ts
|
|
95352
|
+
function isHookApplyCapableOpt(opts) {
|
|
95353
|
+
if (!opts)
|
|
95354
|
+
return false;
|
|
95355
|
+
return Boolean(opts.proposeOnly || opts.acceptId || opts.rejectId || opts.ingest || opts.history || opts.rollback);
|
|
95356
|
+
}
|
|
94893
95357
|
function computeTrends(evaluations2) {
|
|
94894
95358
|
if (evaluations2.length < 2)
|
|
94895
95359
|
return [];
|
|
@@ -94951,6 +95415,56 @@ function computeTrends(evaluations2) {
|
|
|
94951
95415
|
});
|
|
94952
95416
|
return trends;
|
|
94953
95417
|
}
|
|
95418
|
+
function hasFrontmatter(content) {
|
|
95419
|
+
if (!content.startsWith(`---
|
|
95420
|
+
`))
|
|
95421
|
+
return false;
|
|
95422
|
+
return /\n---(?=\n|$)/.test(content.slice(4));
|
|
95423
|
+
}
|
|
95424
|
+
function firstBodyLine(content) {
|
|
95425
|
+
for (const line of content.split(`
|
|
95426
|
+
`)) {
|
|
95427
|
+
const trimmed = line.trim();
|
|
95428
|
+
if (trimmed)
|
|
95429
|
+
return trimmed;
|
|
95430
|
+
}
|
|
95431
|
+
return "";
|
|
95432
|
+
}
|
|
95433
|
+
function generateChanges(report, trends, content) {
|
|
95434
|
+
const changes = [];
|
|
95435
|
+
const dimMap = new Map(Object.entries(report.dimensions));
|
|
95436
|
+
const withFrontmatter = content === undefined ? true : hasFrontmatter(content);
|
|
95437
|
+
const bodyAnchor = withFrontmatter ? "" : firstBodyLine(content ?? "");
|
|
95438
|
+
for (const trend of trends) {
|
|
95439
|
+
if (trend.trend === "declining" || trend.trend === "flat" && trend.latest < 0.7) {
|
|
95440
|
+
const dimData = dimMap.get(trend.dimension);
|
|
95441
|
+
const note = dimData?.note ?? "";
|
|
95442
|
+
const scoreLine = `Score: ${trend.latest.toFixed(2)} (trend: ${trend.trend}, \u0394${trend.delta >= 0 ? "+" : ""}${trend.delta.toFixed(2)}).`;
|
|
95443
|
+
if (withFrontmatter) {
|
|
95444
|
+
const suggestion = note ? `[Improve ${trend.dimension}]: ${note}` : `[Improve ${trend.dimension}]: review and enhance the description for better ${trend.dimension}.`;
|
|
95445
|
+
changes.push({
|
|
95446
|
+
dimension: trend.dimension,
|
|
95447
|
+
location: "frontmatter.description",
|
|
95448
|
+
current: `${trend.dimension} score: ${trend.latest.toFixed(2)}`,
|
|
95449
|
+
proposed: suggestion,
|
|
95450
|
+
reason: note ? `${scoreLine} Note: "${note}".` : `${scoreLine} Score below threshold.`
|
|
95451
|
+
});
|
|
95452
|
+
} else {
|
|
95453
|
+
const suggestion = note ? `[Improve ${trend.dimension}]: ${note}` : `[Improve ${trend.dimension}]: review and enhance this config for better ${trend.dimension}.`;
|
|
95454
|
+
changes.push({
|
|
95455
|
+
dimension: trend.dimension,
|
|
95456
|
+
location: "body",
|
|
95457
|
+
current: bodyAnchor,
|
|
95458
|
+
proposed: bodyAnchor ? `${bodyAnchor}
|
|
95459
|
+
|
|
95460
|
+
${suggestion}` : suggestion,
|
|
95461
|
+
reason: `${scoreLine} Config has no frontmatter; suggesting a body addition rather than a frontmatter.description edit.`
|
|
95462
|
+
});
|
|
95463
|
+
}
|
|
95464
|
+
}
|
|
95465
|
+
}
|
|
95466
|
+
return changes;
|
|
95467
|
+
}
|
|
94954
95468
|
function generateProposalId(type, _name, existingProposals) {
|
|
94955
95469
|
const date9 = new Date().toISOString().slice(0, 10);
|
|
94956
95470
|
const seq = String(existingProposals.length + 1).padStart(3, "0");
|
|
@@ -94980,8 +95494,14 @@ function computeAnchorHash(anchor) {
|
|
|
94980
95494
|
return hasher.digest("hex").slice(0, 16);
|
|
94981
95495
|
}
|
|
94982
95496
|
function computeBaselineAnchorHash(content) {
|
|
94983
|
-
|
|
94984
|
-
|
|
95497
|
+
let frontmatter2 = {};
|
|
95498
|
+
if (hasFrontmatter(content)) {
|
|
95499
|
+
try {
|
|
95500
|
+
frontmatter2 = parseFrontmatter(content).data;
|
|
95501
|
+
} catch {
|
|
95502
|
+
frontmatter2 = {};
|
|
95503
|
+
}
|
|
95504
|
+
}
|
|
94985
95505
|
return computeAnchorHash({
|
|
94986
95506
|
frontmatter: frontmatter2,
|
|
94987
95507
|
rubric_criteria: "",
|
|
@@ -95027,8 +95547,14 @@ async function runGate(input) {
|
|
|
95027
95547
|
}
|
|
95028
95548
|
function emitGenerationEnvelope(type, resolvedPath, content, baseline, trends) {
|
|
95029
95549
|
const rubric2 = loadRubric(type);
|
|
95030
|
-
|
|
95031
|
-
|
|
95550
|
+
let frontmatter2 = {};
|
|
95551
|
+
if (hasFrontmatter(content)) {
|
|
95552
|
+
try {
|
|
95553
|
+
frontmatter2 = parseFrontmatter(content).data;
|
|
95554
|
+
} catch {
|
|
95555
|
+
frontmatter2 = {};
|
|
95556
|
+
}
|
|
95557
|
+
}
|
|
95032
95558
|
const description = frontmatter2.description;
|
|
95033
95559
|
const negativeConstraints = extractNegativeConstraints(description);
|
|
95034
95560
|
const contentName = resolveContentName(resolvedPath);
|
|
@@ -95122,6 +95648,9 @@ async function ingestProposal(db2, type, name, resolvedPath, ingestPath, opts, b
|
|
|
95122
95648
|
ingestedAnchorHash: parsed.anchor_hash,
|
|
95123
95649
|
skeptic: parsed.skeptic
|
|
95124
95650
|
});
|
|
95651
|
+
if (!verdict.rejected && verdict.backupPath) {
|
|
95652
|
+
await persistVersionSnapshot(verdict.backupPath, resolvedPath, proposalId);
|
|
95653
|
+
}
|
|
95125
95654
|
return {
|
|
95126
95655
|
baselineScore,
|
|
95127
95656
|
postScore: verdict.postScore,
|
|
@@ -95158,8 +95687,8 @@ async function stepAnalyze(db2, type, name, opts) {
|
|
|
95158
95687
|
const baselineDate = new Date(newest.created_at).toISOString();
|
|
95159
95688
|
return { evaluations: evaluations2, trends, baselineScore, baselineDate };
|
|
95160
95689
|
}
|
|
95161
|
-
async function stepPropose(db2, type, name,
|
|
95162
|
-
const changes =
|
|
95690
|
+
async function stepPropose(db2, type, name, report, trends, evaluations2, baselineScore, baselineDate, content) {
|
|
95691
|
+
const changes = generateChanges(report, trends, content);
|
|
95163
95692
|
const proposalDao = new ProposalDao(db2);
|
|
95164
95693
|
const existingProposals = await proposalDao.getProposals(type, name);
|
|
95165
95694
|
const proposalId = generateProposalId(type, name, existingProposals);
|
|
@@ -95360,12 +95889,58 @@ async function stepVerify(type, name, filePath, baselineScore, proposalDbId, opt
|
|
|
95360
95889
|
} catch {
|
|
95361
95890
|
echoError("Cannot link verify evaluation.");
|
|
95362
95891
|
}
|
|
95363
|
-
|
|
95364
|
-
rmSync3(gate.backupPath, { force: true });
|
|
95365
|
-
}
|
|
95892
|
+
const survivingBackupPath = gate?.backupPath;
|
|
95366
95893
|
const pctStr = baselineScore > 0 ? `, ${delta >= 0 ? "+" : ""}${(delta / baselineScore * 100).toFixed(1)}%` : "";
|
|
95367
95894
|
echo(`Score: ${baselineScore.toFixed(2)} \u2192 ${postScore.toFixed(2)} (${delta >= 0 ? "+" : ""}${delta.toFixed(2)}${pctStr})`);
|
|
95368
|
-
return { postScore, delta };
|
|
95895
|
+
return { postScore, delta, ...survivingBackupPath ? { backupPath: survivingBackupPath } : {} };
|
|
95896
|
+
}
|
|
95897
|
+
function scoreToGrade(score) {
|
|
95898
|
+
if (score >= 0.9)
|
|
95899
|
+
return "A";
|
|
95900
|
+
if (score >= 0.75)
|
|
95901
|
+
return "B";
|
|
95902
|
+
if (score >= 0.6)
|
|
95903
|
+
return "C";
|
|
95904
|
+
if (score >= 0.45)
|
|
95905
|
+
return "D";
|
|
95906
|
+
return "F";
|
|
95907
|
+
}
|
|
95908
|
+
function formatAnalyze(name, analysis) {
|
|
95909
|
+
const { trends, baselineScore, baselineDate, evaluations: evaluations2 } = analysis;
|
|
95910
|
+
const grade = scoreToGrade(baselineScore);
|
|
95911
|
+
const verdict = baselineScore >= 0.7 ? "PASS" : "FAIL";
|
|
95912
|
+
const gitAvailable = existsSync12(join220(process.cwd(), ".git"));
|
|
95913
|
+
const lines = [];
|
|
95914
|
+
lines.push("=== Evolution Analysis ===");
|
|
95915
|
+
lines.push(`Target: ${name} Score: ${(baselineScore * 100).toFixed(0)}% (${grade}) Status: ${verdict}`);
|
|
95916
|
+
lines.push(`Available data sources: evaluation-history (${evaluations2.length}) \xB7 git-history (${gitAvailable ? "\u2713" : "\u2717"})`);
|
|
95917
|
+
if (trends.length > 0) {
|
|
95918
|
+
lines.push("");
|
|
95919
|
+
lines.push("| Dimension | Earliest | Latest | Trend |");
|
|
95920
|
+
lines.push("|-----------|----------|--------|-------|");
|
|
95921
|
+
for (const t of trends) {
|
|
95922
|
+
const arrow = t.trend === "improving" ? "\u2191" : t.trend === "declining" ? "\u2193" : "\u2192";
|
|
95923
|
+
lines.push(`| ${t.dimension} | ${t.earliest.toFixed(2)} | ${t.latest.toFixed(2)} | ${arrow} ${t.trend} |`);
|
|
95924
|
+
}
|
|
95925
|
+
}
|
|
95926
|
+
const declining = trends.filter((t) => t.trend === "declining");
|
|
95927
|
+
const flatLow = trends.filter((t) => t.trend === "flat" && t.latest < 0.7);
|
|
95928
|
+
if (declining.length > 0) {
|
|
95929
|
+
lines.push(`Patterns: [warning] declining dimensions: ${declining.map((t) => t.dimension).join(", ")}`);
|
|
95930
|
+
} else if (flatLow.length > 0) {
|
|
95931
|
+
lines.push(`Patterns: [warning] flat-low dimensions: ${flatLow.map((t) => t.dimension).join(", ")}`);
|
|
95932
|
+
} else {
|
|
95933
|
+
lines.push(`Patterns: [success] ${name} is currently stable at ${(baselineScore * 100).toFixed(0)}%`);
|
|
95934
|
+
}
|
|
95935
|
+
lines.push(`Baseline date: ${baselineDate}`);
|
|
95936
|
+
return lines.join(`
|
|
95937
|
+
`);
|
|
95938
|
+
}
|
|
95939
|
+
async function persistVersionSnapshot(backupPath, resolvedPath, proposalId) {
|
|
95940
|
+
const versionPath = `${resolvedPath}.version-${proposalId}`;
|
|
95941
|
+
await Bun.write(versionPath, Bun.file(backupPath));
|
|
95942
|
+
rmSync3(backupPath, { force: true });
|
|
95943
|
+
return versionPath;
|
|
95369
95944
|
}
|
|
95370
95945
|
async function evolve(type, name, opts) {
|
|
95371
95946
|
const resolvedPath = resolveContentPath(type, name);
|
|
@@ -95374,6 +95949,10 @@ async function evolve(type, name, opts) {
|
|
|
95374
95949
|
return { baselineScore: 0, postScore: 0, delta: 0, changesApplied: 0, proposalPath: "" };
|
|
95375
95950
|
}
|
|
95376
95951
|
const contentName = resolveContentName(resolvedPath);
|
|
95952
|
+
if (type === "hook" && isHookApplyCapableOpt(opts)) {
|
|
95953
|
+
echoError("hook evolve is analyze-only \u2014 apply/history/rollback are not supported for hooks.");
|
|
95954
|
+
return { baselineScore: 0, postScore: 0, delta: 0, changesApplied: 0, proposalPath: "" };
|
|
95955
|
+
}
|
|
95377
95956
|
let db2;
|
|
95378
95957
|
try {
|
|
95379
95958
|
db2 = await openDb(opts);
|
|
@@ -95382,6 +95961,45 @@ async function evolve(type, name, opts) {
|
|
|
95382
95961
|
echoError(`Could not open the evaluation store. ${msg}`);
|
|
95383
95962
|
return { baselineScore: 0, postScore: 0, delta: 0, changesApplied: 0, proposalPath: "" };
|
|
95384
95963
|
}
|
|
95964
|
+
if (opts?.history) {
|
|
95965
|
+
const proposals2 = await new ProposalDao(db2).getProposals(type, contentName);
|
|
95966
|
+
const accepted = proposals2.filter((p) => p.status === "accepted");
|
|
95967
|
+
if (accepted.length === 0) {
|
|
95968
|
+
echo(`No applied versions found for ${type}/${contentName}.`);
|
|
95969
|
+
return { baselineScore: 0, postScore: 0, delta: 0, changesApplied: 0, proposalPath: "" };
|
|
95970
|
+
}
|
|
95971
|
+
const lines = [];
|
|
95972
|
+
lines.push(`=== Version History: ${contentName} ===`);
|
|
95973
|
+
lines.push("");
|
|
95974
|
+
lines.push("| Version | Applied At | Snapshot |");
|
|
95975
|
+
lines.push("|---------|------------|----------|");
|
|
95976
|
+
for (const p of accepted) {
|
|
95977
|
+
const json3 = typeof p.proposal_json === "string" ? JSON.parse(p.proposal_json) : p.proposal_json;
|
|
95978
|
+
const proposalId2 = json3?.proposal_id;
|
|
95979
|
+
const versionId = proposalId2 ?? `#${p.id}`;
|
|
95980
|
+
const appliedAt = p.applied_at ?? "unknown";
|
|
95981
|
+
const versionPath = `${resolvedPath}.version-${versionId}`;
|
|
95982
|
+
const hasSnapshot = existsSync12(versionPath) ? "\u2713" : "\u2717";
|
|
95983
|
+
lines.push(`| ${versionId} | ${appliedAt} | ${hasSnapshot} |`);
|
|
95984
|
+
}
|
|
95985
|
+
echo(lines.join(`
|
|
95986
|
+
`));
|
|
95987
|
+
return { baselineScore: 0, postScore: 0, delta: 0, changesApplied: 0, proposalPath: "" };
|
|
95988
|
+
}
|
|
95989
|
+
if (opts?.rollback) {
|
|
95990
|
+
if (!opts.confirm) {
|
|
95991
|
+
echoError("--rollback requires --confirm to proceed.");
|
|
95992
|
+
return { baselineScore: 0, postScore: 0, delta: 0, changesApplied: 0, proposalPath: "" };
|
|
95993
|
+
}
|
|
95994
|
+
const versionPath = `${resolvedPath}.version-${opts.rollback}`;
|
|
95995
|
+
if (!existsSync12(versionPath)) {
|
|
95996
|
+
echoError(`Version snapshot not found: ${opts.rollback}`);
|
|
95997
|
+
return { baselineScore: 0, postScore: 0, delta: 0, changesApplied: 0, proposalPath: "" };
|
|
95998
|
+
}
|
|
95999
|
+
await Bun.write(resolvedPath, Bun.file(versionPath));
|
|
96000
|
+
echo(`Rolled back ${contentName} to version ${opts.rollback}.`);
|
|
96001
|
+
return { baselineScore: 0, postScore: 0, delta: 0, changesApplied: 0, proposalPath: "" };
|
|
96002
|
+
}
|
|
95385
96003
|
let analysis;
|
|
95386
96004
|
try {
|
|
95387
96005
|
analysis = await stepAnalyze(db2, type, contentName, opts);
|
|
@@ -95391,6 +96009,10 @@ async function evolve(type, name, opts) {
|
|
|
95391
96009
|
return { baselineScore: 0, postScore: 0, delta: 0, changesApplied: 0, proposalPath: "" };
|
|
95392
96010
|
}
|
|
95393
96011
|
const { trends, baselineScore, baselineDate, evaluations: evaluations2 } = analysis;
|
|
96012
|
+
if (opts?.analyze) {
|
|
96013
|
+
echo(formatAnalyze(contentName, analysis));
|
|
96014
|
+
return { baselineScore, postScore: baselineScore, delta: 0, changesApplied: 0, proposalPath: "" };
|
|
96015
|
+
}
|
|
95394
96016
|
if (evaluations2.length < 2) {
|
|
95395
96017
|
echo("Only one evaluation found \u2014 need at least two for trend analysis. Running evaluation-based proposal instead.");
|
|
95396
96018
|
}
|
|
@@ -95448,13 +96070,16 @@ async function evolve(type, name, opts) {
|
|
|
95448
96070
|
} catch {
|
|
95449
96071
|
acceptedFromStore = [];
|
|
95450
96072
|
}
|
|
95451
|
-
const
|
|
96073
|
+
const backupPath2 = await backupFile(resolvedPath);
|
|
95452
96074
|
const appliedCount = await stepApply(acceptedFromStore, resolvedPath, target.id, db2);
|
|
95453
96075
|
const verdict = await stepVerify(type, contentName, resolvedPath, baselineScore, target.id, opts, db2, {
|
|
95454
|
-
backupPath,
|
|
96076
|
+
backupPath: backupPath2,
|
|
95455
96077
|
ingestedAnchorHash: storedAnchorHash,
|
|
95456
96078
|
skeptic: storedSkeptic
|
|
95457
96079
|
});
|
|
96080
|
+
if (!verdict.rejected && verdict.backupPath) {
|
|
96081
|
+
await persistVersionSnapshot(verdict.backupPath, resolvedPath, opts.acceptId);
|
|
96082
|
+
}
|
|
95458
96083
|
return {
|
|
95459
96084
|
baselineScore,
|
|
95460
96085
|
postScore: verdict.postScore,
|
|
@@ -95464,20 +96089,24 @@ async function evolve(type, name, opts) {
|
|
|
95464
96089
|
...verdict.rejected ? { rejected: true, rejectionReason: verdict.reason } : {}
|
|
95465
96090
|
};
|
|
95466
96091
|
}
|
|
95467
|
-
const
|
|
96092
|
+
const proposeContent = await Bun.file(resolvedPath).text();
|
|
96093
|
+
const { proposalId, proposalDbId, proposalPath, changes } = await stepPropose(db2, type, contentName, baselineReport, trends, evaluations2, baselineScore, baselineDate, proposeContent);
|
|
95468
96094
|
if (opts?.proposeOnly) {
|
|
95469
96095
|
echo(`Proposal written to: ${proposalPath}`);
|
|
95470
96096
|
return { baselineScore, postScore: baselineScore, delta: 0, changesApplied: 0, proposalPath };
|
|
95471
96097
|
}
|
|
95472
96098
|
const { accepted: acceptedChanges } = await interactiveReview(changes, trends);
|
|
96099
|
+
const backupPath = await backupFile(resolvedPath);
|
|
95473
96100
|
const changesApplied = await stepApply(acceptedChanges, resolvedPath, proposalDbId, db2);
|
|
95474
96101
|
const { postScore, delta } = await stepVerify(type, contentName, resolvedPath, baselineScore, proposalDbId, opts, db2);
|
|
96102
|
+
await persistVersionSnapshot(backupPath, resolvedPath, proposalId);
|
|
95475
96103
|
return { baselineScore, postScore, delta, changesApplied, proposalPath };
|
|
95476
96104
|
}
|
|
95477
96105
|
|
|
95478
96106
|
// src/operations/refine.ts
|
|
95479
96107
|
init_src();
|
|
95480
96108
|
init_dist();
|
|
96109
|
+
init_db2();
|
|
95481
96110
|
import { createInterface as createInterface2 } from "readline";
|
|
95482
96111
|
class RefineAbortedError extends Error {
|
|
95483
96112
|
constructor(message = "User quit interactive mode") {
|
|
@@ -95485,6 +96114,11 @@ class RefineAbortedError extends Error {
|
|
|
95485
96114
|
this.name = "RefineAbortedError";
|
|
95486
96115
|
}
|
|
95487
96116
|
}
|
|
96117
|
+
function isHookApplyCapableOpt2(opts) {
|
|
96118
|
+
if (!opts)
|
|
96119
|
+
return false;
|
|
96120
|
+
return Boolean(opts.auto || opts.save);
|
|
96121
|
+
}
|
|
95488
96122
|
function classifyFix(finding) {
|
|
95489
96123
|
if (finding.severity === "error") {
|
|
95490
96124
|
return "auto-apply";
|
|
@@ -95497,17 +96131,59 @@ function classifyFix(finding) {
|
|
|
95497
96131
|
}
|
|
95498
96132
|
return "auto-apply";
|
|
95499
96133
|
}
|
|
95500
|
-
function getDefaultForField(field) {
|
|
95501
|
-
|
|
95502
|
-
|
|
95503
|
-
|
|
95504
|
-
|
|
95505
|
-
|
|
95506
|
-
|
|
96134
|
+
function getDefaultForField(field, content) {
|
|
96135
|
+
if (field === "model")
|
|
96136
|
+
return "inherit";
|
|
96137
|
+
if (field === "tools")
|
|
96138
|
+
return [];
|
|
96139
|
+
const name = readFrontmatterName(content);
|
|
96140
|
+
const h1 = extractFirstHeading(content);
|
|
96141
|
+
if (field === "description") {
|
|
96142
|
+
if (name)
|
|
96143
|
+
return humanize(name);
|
|
96144
|
+
if (h1)
|
|
96145
|
+
return h1;
|
|
96146
|
+
return null;
|
|
96147
|
+
}
|
|
96148
|
+
if (field === "name") {
|
|
96149
|
+
if (h1)
|
|
96150
|
+
return slugify2(h1);
|
|
96151
|
+
return null;
|
|
96152
|
+
}
|
|
96153
|
+
return null;
|
|
96154
|
+
}
|
|
96155
|
+
function readFrontmatterName(content) {
|
|
96156
|
+
try {
|
|
96157
|
+
const parsed = parseFrontmatter(content);
|
|
96158
|
+
const name = parsed.data.name;
|
|
96159
|
+
return typeof name === "string" && name.trim() ? name.trim() : null;
|
|
96160
|
+
} catch {
|
|
96161
|
+
return null;
|
|
96162
|
+
}
|
|
96163
|
+
}
|
|
96164
|
+
function extractFirstHeading(content) {
|
|
96165
|
+
let body = content;
|
|
96166
|
+
if (content.startsWith(`---
|
|
96167
|
+
`)) {
|
|
96168
|
+
const closer = content.slice(4).match(/\n---(?=\n|$)/);
|
|
96169
|
+
if (closer?.index !== undefined)
|
|
96170
|
+
body = content.slice(closer.index + 4 + 4);
|
|
96171
|
+
}
|
|
96172
|
+
const headingMatch = /^\s*#\s+(.+?)\s*$/m.exec(body);
|
|
96173
|
+
return headingMatch?.[1] ? headingMatch[1].trim() : null;
|
|
96174
|
+
}
|
|
96175
|
+
function humanize(slug) {
|
|
96176
|
+
return slug.replace(/[-_]+/g, " ").replace(/\b\w/g, (c3) => c3.toUpperCase()).trim();
|
|
96177
|
+
}
|
|
96178
|
+
function slugify2(label) {
|
|
96179
|
+
return label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
95507
96180
|
}
|
|
95508
96181
|
function generateAutoChange(finding, content) {
|
|
95509
96182
|
if (finding.message.toLowerCase().includes("missing")) {
|
|
95510
|
-
|
|
96183
|
+
const value = getDefaultForField(finding.field, content);
|
|
96184
|
+
if (value === null)
|
|
96185
|
+
return null;
|
|
96186
|
+
return { kind: "frontmatter", key: finding.field, value };
|
|
95511
96187
|
}
|
|
95512
96188
|
if (finding.message.includes("must be an array")) {
|
|
95513
96189
|
let currentValue;
|
|
@@ -95653,30 +96329,30 @@ function applyAutoFixes(findings, content) {
|
|
|
95653
96329
|
async function refine3(type, nameOrPath, opts) {
|
|
95654
96330
|
const resolvedPath = resolveContentPath(type, nameOrPath);
|
|
95655
96331
|
const resolvedTarget = opts?.target ?? "claude";
|
|
95656
|
-
const
|
|
96332
|
+
const filePath = resolvedPath ?? nameOrPath;
|
|
96333
|
+
if (type === "hook" && isHookApplyCapableOpt2(opts)) {
|
|
96334
|
+
echoError("hook refine is suggest-only \u2014 auto-apply and save are not supported for hooks. Use --dry-run to preview findings, then hand-fix and `hook validate`.");
|
|
96335
|
+
return { preScore: 0, postScore: 0, delta: 0, fixesApplied: [], fixesSkipped: [] };
|
|
96336
|
+
}
|
|
96337
|
+
const validation = await validate(type, filePath, {
|
|
95657
96338
|
target: resolvedTarget,
|
|
95658
96339
|
strict: opts?.auto === true
|
|
95659
96340
|
});
|
|
95660
|
-
|
|
95661
|
-
|
|
95662
|
-
|
|
95663
|
-
|
|
95664
|
-
|
|
96341
|
+
let preScore = 0;
|
|
96342
|
+
let preDimensions = {};
|
|
96343
|
+
try {
|
|
96344
|
+
const report = await evaluate3(type, filePath, { target: resolvedTarget });
|
|
96345
|
+
if (report) {
|
|
96346
|
+
preScore = report.aggregate;
|
|
96347
|
+
preDimensions = report.dimensions;
|
|
95665
96348
|
}
|
|
95666
|
-
|
|
95667
|
-
|
|
95668
|
-
}
|
|
95669
|
-
let preScore;
|
|
95670
|
-
let preDimensions;
|
|
96349
|
+
} catch {}
|
|
96350
|
+
let content;
|
|
95671
96351
|
try {
|
|
95672
|
-
|
|
95673
|
-
if (!report)
|
|
95674
|
-
throw new Error("evaluate returned null in heuristic mode");
|
|
95675
|
-
preScore = report.aggregate;
|
|
95676
|
-
preDimensions = report.dimensions;
|
|
96352
|
+
content = await Bun.file(filePath).text();
|
|
95677
96353
|
} catch {
|
|
95678
|
-
echoError("Cannot
|
|
95679
|
-
return { preScore
|
|
96354
|
+
echoError("Cannot read content file for editing.");
|
|
96355
|
+
return { preScore, postScore: preScore, delta: 0, fixesApplied: [], fixesSkipped: [] };
|
|
95680
96356
|
}
|
|
95681
96357
|
const findings = [];
|
|
95682
96358
|
for (const f of validation.findings) {
|
|
@@ -95684,26 +96360,23 @@ async function refine3(type, nameOrPath, opts) {
|
|
|
95684
96360
|
}
|
|
95685
96361
|
for (const [dimName, dimScore] of Object.entries(preDimensions)) {
|
|
95686
96362
|
if (dimScore.score < 0.7 && dimScore.note?.trim()) {
|
|
95687
|
-
|
|
95688
|
-
severity: "warning",
|
|
95689
|
-
|
|
95690
|
-
|
|
95691
|
-
};
|
|
95692
|
-
findings.push({ finding, strategy: "suggest" });
|
|
96363
|
+
findings.push({
|
|
96364
|
+
finding: { severity: "warning", field: dimName, message: dimScore.note },
|
|
96365
|
+
strategy: "suggest"
|
|
96366
|
+
});
|
|
95693
96367
|
}
|
|
95694
96368
|
}
|
|
96369
|
+
if (opts?.dryRun || type === "hook") {
|
|
96370
|
+
if (type === "hook") {
|
|
96371
|
+
echo("Hook refine is suggest-only (task 0061 decision C). Findings are recommendations; hooks.json is not modified. Hand-fix, then `hook validate`.");
|
|
96372
|
+
}
|
|
96373
|
+
return dryRunPreview(type, content, resolvedTarget, findings);
|
|
96374
|
+
}
|
|
95695
96375
|
if (findings.length === 0) {
|
|
95696
96376
|
echo(`No issues found. Score: ${preScore.toFixed(2)}`);
|
|
95697
96377
|
return { preScore, postScore: preScore, delta: 0, fixesApplied: [], fixesSkipped: [] };
|
|
95698
96378
|
}
|
|
95699
|
-
|
|
95700
|
-
try {
|
|
95701
|
-
content = await Bun.file(resolvedPath ?? nameOrPath).text();
|
|
95702
|
-
} catch {
|
|
95703
|
-
echoError("Cannot read content file for editing.");
|
|
95704
|
-
return { preScore, postScore: preScore, delta: 0, fixesApplied: [], fixesSkipped: [] };
|
|
95705
|
-
}
|
|
95706
|
-
const backupPath = await backupFile(resolvedPath ?? nameOrPath);
|
|
96379
|
+
const backupPath = await backupFile(filePath);
|
|
95707
96380
|
let fixesApplied = [];
|
|
95708
96381
|
let fixesSkipped = [];
|
|
95709
96382
|
try {
|
|
@@ -95712,10 +96385,10 @@ async function refine3(type, nameOrPath, opts) {
|
|
|
95712
96385
|
fixesApplied = result.fixesApplied;
|
|
95713
96386
|
fixesSkipped = result.fixesSkipped;
|
|
95714
96387
|
if (fixesApplied.length > 0) {
|
|
95715
|
-
await Bun.write(
|
|
96388
|
+
await Bun.write(filePath, result.content);
|
|
95716
96389
|
}
|
|
95717
96390
|
} else {
|
|
95718
|
-
const result = await runInteractive(findings, content,
|
|
96391
|
+
const result = await runInteractive(findings, content, filePath, backupPath);
|
|
95719
96392
|
fixesApplied = result.fixesApplied;
|
|
95720
96393
|
fixesSkipped = result.fixesSkipped;
|
|
95721
96394
|
}
|
|
@@ -95725,9 +96398,24 @@ async function refine3(type, nameOrPath, opts) {
|
|
|
95725
96398
|
}
|
|
95726
96399
|
throw err;
|
|
95727
96400
|
}
|
|
96401
|
+
if (!validation.valid) {
|
|
96402
|
+
const revalidation = await validate(type, filePath, {
|
|
96403
|
+
target: resolvedTarget,
|
|
96404
|
+
strict: opts?.auto === true
|
|
96405
|
+
});
|
|
96406
|
+
if (!revalidation.valid) {
|
|
96407
|
+
for (const f of revalidation.findings) {
|
|
96408
|
+
if (f.severity === "error")
|
|
96409
|
+
echoError(`[ERROR] ${f.field}: ${f.message}`);
|
|
96410
|
+
}
|
|
96411
|
+
echoError("Validation errors remain after structural fixes; refine aborted.");
|
|
96412
|
+
return { preScore, postScore: preScore, delta: 0, fixesApplied, fixesSkipped };
|
|
96413
|
+
}
|
|
96414
|
+
}
|
|
95728
96415
|
let postScore;
|
|
96416
|
+
let postReport = null;
|
|
95729
96417
|
try {
|
|
95730
|
-
|
|
96418
|
+
postReport = await evaluate3(type, filePath, { target: resolvedTarget });
|
|
95731
96419
|
if (!postReport)
|
|
95732
96420
|
throw new Error("evaluate returned null in heuristic mode");
|
|
95733
96421
|
postScore = postReport.aggregate;
|
|
@@ -95735,6 +96423,14 @@ async function refine3(type, nameOrPath, opts) {
|
|
|
95735
96423
|
echoError("Cannot re-evaluate after fixes.");
|
|
95736
96424
|
return { preScore, postScore: preScore, delta: 0, fixesApplied, fixesSkipped };
|
|
95737
96425
|
}
|
|
96426
|
+
if (postScore < preScore) {
|
|
96427
|
+
await restoreFromBackup(backupPath, filePath);
|
|
96428
|
+
echo("Refine skipped: changes would have lowered the score; original restored.");
|
|
96429
|
+
for (const f of fixesApplied)
|
|
96430
|
+
fixesSkipped.push({ ...f, applied: false });
|
|
96431
|
+
fixesApplied = [];
|
|
96432
|
+
postScore = preScore;
|
|
96433
|
+
}
|
|
95738
96434
|
const delta = postScore - preScore;
|
|
95739
96435
|
if (delta === 0 && preScore === postScore) {
|
|
95740
96436
|
echo(`Score: ${preScore.toFixed(2)} (no change)`);
|
|
@@ -95742,12 +96438,20 @@ async function refine3(type, nameOrPath, opts) {
|
|
|
95742
96438
|
const pctStr = preScore > 0 ? `, +${(delta / preScore * 100).toFixed(1)}%` : "";
|
|
95743
96439
|
echo(`Score: ${preScore.toFixed(2)} \u2192 ${postScore.toFixed(2)} (${delta >= 0 ? "+" : ""}${delta.toFixed(2)}${pctStr})`);
|
|
95744
96440
|
}
|
|
95745
|
-
if (opts?.save) {
|
|
96441
|
+
if (opts?.save && postReport) {
|
|
95746
96442
|
try {
|
|
95747
|
-
|
|
95748
|
-
|
|
95749
|
-
|
|
95750
|
-
|
|
96443
|
+
const fileHash = hashContent(filePath);
|
|
96444
|
+
const adapter = await openStore();
|
|
96445
|
+
const dao = new EvaluationDao(adapter);
|
|
96446
|
+
await dao.insertEvaluation({
|
|
96447
|
+
content_type: type,
|
|
96448
|
+
content_name: resolveContentName(filePath),
|
|
96449
|
+
target_agent: resolvedTarget,
|
|
96450
|
+
operation: "refine",
|
|
96451
|
+
aggregate: postReport.aggregate,
|
|
96452
|
+
dimensions: postReport.dimensions,
|
|
96453
|
+
file_hash: fileHash,
|
|
96454
|
+
scorer: "heuristic"
|
|
95751
96455
|
});
|
|
95752
96456
|
} catch {
|
|
95753
96457
|
echoError("Warning: failed to save evaluation results.");
|
|
@@ -95755,6 +96459,48 @@ async function refine3(type, nameOrPath, opts) {
|
|
|
95755
96459
|
}
|
|
95756
96460
|
return { preScore, postScore, delta, fixesApplied, fixesSkipped };
|
|
95757
96461
|
}
|
|
96462
|
+
function dryRunPreview(type, content, target, findings) {
|
|
96463
|
+
let preScore = 0;
|
|
96464
|
+
try {
|
|
96465
|
+
preScore = evaluate(type, content, target).aggregate;
|
|
96466
|
+
} catch {}
|
|
96467
|
+
const autoFindings = findings.filter((f) => f.strategy === "auto-apply");
|
|
96468
|
+
const projected = applyAutoFixes(autoFindings, content);
|
|
96469
|
+
let projectedPost = preScore;
|
|
96470
|
+
try {
|
|
96471
|
+
projectedPost = evaluate(type, projected.content, target).aggregate;
|
|
96472
|
+
} catch {}
|
|
96473
|
+
echo("Dry run \u2014 no changes written.");
|
|
96474
|
+
if (findings.length === 0) {
|
|
96475
|
+
echo(`No issues found. Score: ${preScore.toFixed(2)}`);
|
|
96476
|
+
} else {
|
|
96477
|
+
const hookSuggestOnly2 = type === "hook";
|
|
96478
|
+
for (const { finding, strategy } of findings) {
|
|
96479
|
+
const effectiveStrategy = hookSuggestOnly2 ? "suggest" : strategy;
|
|
96480
|
+
const tag = effectiveStrategy.toUpperCase();
|
|
96481
|
+
const change = strategy === "auto-apply" ? generateAutoChange(finding, content) : null;
|
|
96482
|
+
const proposed = !hookSuggestOnly2 && change && change.kind === "frontmatter" ? ` \u2192 would set ${change.key} = ${formatValue(change.value)}` : "";
|
|
96483
|
+
echo(`[${tag}] ${finding.field}: ${finding.message}${proposed}`);
|
|
96484
|
+
}
|
|
96485
|
+
const delta = projectedPost - preScore;
|
|
96486
|
+
const pctStr = preScore > 0 ? `, +${(delta / preScore * 100).toFixed(1)}%` : "";
|
|
96487
|
+
echo(`Projected: ${preScore.toFixed(2)} \u2192 ${projectedPost.toFixed(2)} (${delta >= 0 ? "+" : ""}${delta.toFixed(2)}${pctStr})`);
|
|
96488
|
+
}
|
|
96489
|
+
const hookSuggestOnly = type === "hook";
|
|
96490
|
+
const fixesSkipped = findings.map(({ finding, strategy }) => ({
|
|
96491
|
+
severity: finding.severity,
|
|
96492
|
+
field: finding.field,
|
|
96493
|
+
message: finding.message,
|
|
96494
|
+
strategy: hookSuggestOnly ? "suggest" : strategy,
|
|
96495
|
+
applied: false
|
|
96496
|
+
}));
|
|
96497
|
+
return { preScore, postScore: projectedPost, delta: projectedPost - preScore, fixesApplied: [], fixesSkipped };
|
|
96498
|
+
}
|
|
96499
|
+
function formatValue(value) {
|
|
96500
|
+
if (Array.isArray(value))
|
|
96501
|
+
return value.length === 0 ? "[]" : `[${value.join(", ")}]`;
|
|
96502
|
+
return String(value);
|
|
96503
|
+
}
|
|
95758
96504
|
|
|
95759
96505
|
// src/operations/scaffold.ts
|
|
95760
96506
|
init_src();
|
|
@@ -95766,10 +96512,16 @@ function addTargetOption(cmd) {
|
|
|
95766
96512
|
return cmd.option("-t, --target <agent>", "Target agent platform", "claude");
|
|
95767
96513
|
}
|
|
95768
96514
|
function addScaffoldOptions(cmd) {
|
|
95769
|
-
return cmd.option("-d, --description <text>", "Content description").option("-t, --target <agent>", "Target agent platform", "claude").option("-o, --output <dir>", "Output directory (default: cwd)").option("--force", "Overwrite existing file if present");
|
|
96515
|
+
return cmd.option("-d, --description <text>", "Content description").option("-t, --target <agent>", "Target agent platform", "claude").option("-o, --output <dir>", "Output directory (default: cwd)").option("--template <tier>", "Template tier (e.g. minimal / standard / specialist)").option("--tools <list>", "Comma-separated tool names to pre-populate frontmatter").option("--force", "Overwrite existing file if present");
|
|
95770
96516
|
}
|
|
95771
96517
|
function addEvolveOptions(cmd) {
|
|
95772
|
-
return cmd.option("-t, --target <agent>", "Target agent platform", "claude").option("--from <date>", "Analyze evaluations since date (ISO 8601)").option("--propose-only", "Generate proposal without applying").option("--accept <id>", "Accept a specific proposal by ID").option("--reject <id>", "Reject a specific proposal").option("--json", "Output machine-readable JSON (envelope-out with --propose-only)").option("--ingest <file>", "Agent-authored proposal JSON (ingest-in mode)").option("--margin <n>", "\u0394-margin gate threshold for accept (default 0.05)", Number.parseFloat, 0.05);
|
|
96518
|
+
return cmd.option("-t, --target <agent>", "Target agent platform", "claude").option("--from <date>", "Analyze evaluations since date (ISO 8601)").option("--propose-only", "Generate proposal without applying").option("--accept <id>", "Accept a specific proposal by ID").option("--reject <id>", "Reject a specific proposal").option("--json", "Output machine-readable JSON (envelope-out with --propose-only)").option("--ingest <file>", "Agent-authored proposal JSON (ingest-in mode)").option("--margin <n>", "\u0394-margin gate threshold for accept (default 0.05)", Number.parseFloat, 0.05).option("--analyze", "Print analysis summary (trends, score, data sources) without writing a proposal").option("--history", "List applied proposal versions from the store").option("--rollback <id>", "Rollback to a prior version by proposal_id (requires --confirm)").option("--confirm", "Confirm a destructive operation (required for --rollback)");
|
|
96519
|
+
}
|
|
96520
|
+
function addHookEvolveOptions(cmd) {
|
|
96521
|
+
return cmd.option("-t, --target <agent>", "Target agent platform", "claude").option("--from <date>", "Analyze evaluations since date (ISO 8601)").option("--analyze", "Print analysis summary (trends, score, data sources) \u2014 analyze-only, no apply").option("--json", "Output machine-readable JSON");
|
|
96522
|
+
}
|
|
96523
|
+
function addHookRefineOptions(cmd) {
|
|
96524
|
+
return cmd.option("-t, --target <agent>", "Target agent platform", "claude").option("--dry-run", "Preview classified findings and recommendations without writing");
|
|
95773
96525
|
}
|
|
95774
96526
|
function addJsonOption(cmd) {
|
|
95775
96527
|
return cmd.option("--json", "Output machine-readable JSON");
|
|
@@ -95786,6 +96538,9 @@ function addStrictOption(cmd) {
|
|
|
95786
96538
|
function addAutoOption(cmd) {
|
|
95787
96539
|
return cmd.option("--auto", "Apply low-risk fixes automatically");
|
|
95788
96540
|
}
|
|
96541
|
+
function addDryRunOption(cmd) {
|
|
96542
|
+
return cmd.option("--dry-run", "Preview classified fixes and projected delta without writing");
|
|
96543
|
+
}
|
|
95789
96544
|
function resolveTarget(opts) {
|
|
95790
96545
|
const raw = opts.target || "claude";
|
|
95791
96546
|
if (!TARGETS.includes(raw)) {
|
|
@@ -95819,7 +96574,9 @@ async function agentScaffold(opts) {
|
|
|
95819
96574
|
description: opts.description,
|
|
95820
96575
|
target,
|
|
95821
96576
|
output: opts.output,
|
|
95822
|
-
force: opts.force
|
|
96577
|
+
force: opts.force,
|
|
96578
|
+
template: opts.template,
|
|
96579
|
+
tools: opts.tools
|
|
95823
96580
|
});
|
|
95824
96581
|
echo(`Created: ${createdPath}`);
|
|
95825
96582
|
return;
|
|
@@ -95850,7 +96607,7 @@ async function agentEvaluate(opts) {
|
|
|
95850
96607
|
}
|
|
95851
96608
|
async function agentRefine(opts) {
|
|
95852
96609
|
const target = resolveTarget(opts);
|
|
95853
|
-
await refine3("agent", opts.nameOrPath, { target, auto: opts.auto, save: opts.save });
|
|
96610
|
+
await refine3("agent", opts.nameOrPath, { target, auto: opts.auto, save: opts.save, dryRun: opts.dryRun });
|
|
95854
96611
|
return;
|
|
95855
96612
|
}
|
|
95856
96613
|
async function agentEvolve(opts) {
|
|
@@ -95863,7 +96620,11 @@ async function agentEvolve(opts) {
|
|
|
95863
96620
|
rejectId: opts.reject,
|
|
95864
96621
|
json: opts.json,
|
|
95865
96622
|
ingest: opts.ingest,
|
|
95866
|
-
margin: opts.margin
|
|
96623
|
+
margin: opts.margin,
|
|
96624
|
+
analyze: opts.analyze,
|
|
96625
|
+
history: opts.history,
|
|
96626
|
+
rollback: opts.rollback,
|
|
96627
|
+
confirm: opts.confirm
|
|
95867
96628
|
});
|
|
95868
96629
|
return;
|
|
95869
96630
|
}
|
|
@@ -95893,7 +96654,7 @@ function registerAgent(program2) {
|
|
|
95893
96654
|
addEvaluateOptions(addSaveOption(addTargetOption(addJsonOption(cmd.command("evaluate <nameOrPath>").description("Evaluate agent quality (use --rubric --json for envelope, --ingest --save to persist scores)"))))).action(async (nameOrPath, opts) => {
|
|
95894
96655
|
await handleAgentEvaluate({ nameOrPath, ...opts });
|
|
95895
96656
|
});
|
|
95896
|
-
addSaveOption(addTargetOption(addAutoOption(cmd.command("refine <nameOrPath>").description("Evaluate and auto-fix an agent")))).action(async (nameOrPath, opts) => {
|
|
96657
|
+
addDryRunOption(addSaveOption(addTargetOption(addAutoOption(cmd.command("refine <nameOrPath>").description("Evaluate and auto-fix an agent"))))).action(async (nameOrPath, opts) => {
|
|
95897
96658
|
await handleAgentRefine({ nameOrPath, ...opts });
|
|
95898
96659
|
});
|
|
95899
96660
|
addEvolveOptions(cmd.command("evolve <name>").description("Longitudinal improvement from evaluation history")).action(async (name, opts) => {
|
|
@@ -95909,7 +96670,9 @@ async function commandScaffold(opts) {
|
|
|
95909
96670
|
description: opts.description,
|
|
95910
96671
|
target,
|
|
95911
96672
|
output: opts.output,
|
|
95912
|
-
force: opts.force
|
|
96673
|
+
force: opts.force,
|
|
96674
|
+
template: opts.template,
|
|
96675
|
+
tools: opts.tools
|
|
95913
96676
|
});
|
|
95914
96677
|
echo(`Created: ${createdPath}`);
|
|
95915
96678
|
return;
|
|
@@ -95940,7 +96703,7 @@ async function commandEvaluate(opts) {
|
|
|
95940
96703
|
}
|
|
95941
96704
|
async function commandRefine(opts) {
|
|
95942
96705
|
const target = resolveTarget(opts);
|
|
95943
|
-
await refine3("command", opts.nameOrPath, { target, auto: opts.auto, save: opts.save });
|
|
96706
|
+
await refine3("command", opts.nameOrPath, { target, auto: opts.auto, save: opts.save, dryRun: opts.dryRun });
|
|
95944
96707
|
return;
|
|
95945
96708
|
}
|
|
95946
96709
|
async function commandEvolve(opts) {
|
|
@@ -95953,7 +96716,11 @@ async function commandEvolve(opts) {
|
|
|
95953
96716
|
rejectId: opts.reject,
|
|
95954
96717
|
json: opts.json,
|
|
95955
96718
|
ingest: opts.ingest,
|
|
95956
|
-
margin: opts.margin
|
|
96719
|
+
margin: opts.margin,
|
|
96720
|
+
analyze: opts.analyze,
|
|
96721
|
+
history: opts.history,
|
|
96722
|
+
rollback: opts.rollback,
|
|
96723
|
+
confirm: opts.confirm
|
|
95957
96724
|
});
|
|
95958
96725
|
return;
|
|
95959
96726
|
}
|
|
@@ -95983,7 +96750,7 @@ function registerCommand(program2) {
|
|
|
95983
96750
|
addEvaluateOptions(addSaveOption(addTargetOption(addJsonOption(cmd.command("evaluate <nameOrPath>").description("Evaluate command quality (use --rubric --json for envelope, --ingest --save to persist scores)"))))).action(async (nameOrPath, opts) => {
|
|
95984
96751
|
await handleCommandEvaluate({ nameOrPath, ...opts });
|
|
95985
96752
|
});
|
|
95986
|
-
addSaveOption(addTargetOption(addAutoOption(cmd.command("refine <nameOrPath>").description("Evaluate and auto-fix a command")))).action(async (nameOrPath, opts) => {
|
|
96753
|
+
addDryRunOption(addSaveOption(addTargetOption(addAutoOption(cmd.command("refine <nameOrPath>").description("Evaluate and auto-fix a command"))))).action(async (nameOrPath, opts) => {
|
|
95987
96754
|
await handleCommandRefine({ nameOrPath, ...opts });
|
|
95988
96755
|
});
|
|
95989
96756
|
addEvolveOptions(cmd.command("evolve <name>").description("Longitudinal improvement from evaluation history")).action(async (name, opts) => {
|
|
@@ -96004,10 +96771,10 @@ import {
|
|
|
96004
96771
|
copyFileSync as copyFileSync2,
|
|
96005
96772
|
existsSync as existsSync14,
|
|
96006
96773
|
mkdirSync as mkdirSync9,
|
|
96007
|
-
readdirSync as
|
|
96774
|
+
readdirSync as readdirSync4,
|
|
96008
96775
|
readFileSync as readFileSync13,
|
|
96009
96776
|
rmSync as rmSync4,
|
|
96010
|
-
statSync as
|
|
96777
|
+
statSync as statSync7,
|
|
96011
96778
|
writeFileSync as writeFileSync8
|
|
96012
96779
|
} from "fs";
|
|
96013
96780
|
import { homedir as homedir5 } from "os";
|
|
@@ -96267,7 +97034,7 @@ async function executeInstall(plugin, targets2, options2, dependencies = {}) {
|
|
|
96267
97034
|
if (existsSync14(agentsDir) && !options2.dryRun) {
|
|
96268
97035
|
const piAgentsDir = join223(outputRoot, ".pi", "agent", "agents");
|
|
96269
97036
|
mkdirSync9(piAgentsDir, { recursive: true });
|
|
96270
|
-
for (const entry of
|
|
97037
|
+
for (const entry of readdirSync4(agentsDir)) {
|
|
96271
97038
|
if (!entry.endsWith(".md"))
|
|
96272
97039
|
continue;
|
|
96273
97040
|
const agentName = entry.replace(/\.md$/, "");
|
|
@@ -96332,7 +97099,7 @@ function resolvePluginRoot(plugin, marketplacePath) {
|
|
|
96332
97099
|
return { pluginRoot: resolved.pluginRoot, marketplaceRoot: manifestRoot, marketplaceName };
|
|
96333
97100
|
}
|
|
96334
97101
|
const fallback = join223("plugins", plugin);
|
|
96335
|
-
if (existsSync14(
|
|
97102
|
+
if (existsSync14(fallback) && readdirSync4(fallback).some((d) => ["skills", "commands", "agents", "hooks", "hooks.json"].includes(d)))
|
|
96336
97103
|
return { pluginRoot: fallback };
|
|
96337
97104
|
const available = listResolvablePlugins(marketplacePath);
|
|
96338
97105
|
const msg = available.length > 0 ? `Available: ${available.join(", ")}` : "No marketplace manifest found and no plugins/<name>/ directory.";
|
|
@@ -96369,9 +97136,9 @@ function transformRulesyncMarkdown(root, target, pluginName) {
|
|
|
96369
97136
|
function transformMarkdownDirectory(dir, target, pluginName) {
|
|
96370
97137
|
if (!existsSync14(dir))
|
|
96371
97138
|
return;
|
|
96372
|
-
for (const entry of
|
|
97139
|
+
for (const entry of readdirSync4(dir)) {
|
|
96373
97140
|
const path11 = join223(dir, entry);
|
|
96374
|
-
const stats =
|
|
97141
|
+
const stats = statSync7(path11);
|
|
96375
97142
|
if (stats.isDirectory()) {
|
|
96376
97143
|
transformMarkdownDirectory(path11, target, pluginName);
|
|
96377
97144
|
continue;
|
|
@@ -96388,12 +97155,12 @@ function copyDirectory(source, destination, options2 = {}) {
|
|
|
96388
97155
|
if (!existsSync14(source))
|
|
96389
97156
|
return;
|
|
96390
97157
|
mkdirSync9(destination, { recursive: true });
|
|
96391
|
-
for (const entry of
|
|
97158
|
+
for (const entry of readdirSync4(source)) {
|
|
96392
97159
|
if (options2.skipDirectoryNames?.has(entry))
|
|
96393
97160
|
continue;
|
|
96394
97161
|
const sourcePath = join223(source, entry);
|
|
96395
97162
|
const destinationPath = join223(destination, entry);
|
|
96396
|
-
if (
|
|
97163
|
+
if (statSync7(sourcePath).isDirectory()) {
|
|
96397
97164
|
copyDirectory(sourcePath, destinationPath, options2);
|
|
96398
97165
|
} else {
|
|
96399
97166
|
copyFileSync2(sourcePath, destinationPath);
|
|
@@ -96402,15 +97169,6 @@ function copyDirectory(source, destination, options2 = {}) {
|
|
|
96402
97169
|
}
|
|
96403
97170
|
|
|
96404
97171
|
// src/commands/hook.ts
|
|
96405
|
-
async function scaffoldHook(name, opts) {
|
|
96406
|
-
const target = resolveTarget(opts);
|
|
96407
|
-
return scaffold("hook", name, {
|
|
96408
|
-
description: opts.description,
|
|
96409
|
-
target,
|
|
96410
|
-
output: opts.output,
|
|
96411
|
-
force: opts.force
|
|
96412
|
-
});
|
|
96413
|
-
}
|
|
96414
97172
|
async function validateHook(nameOrPath, opts) {
|
|
96415
97173
|
const target = resolveTarget(opts);
|
|
96416
97174
|
return validate("hook", nameOrPath, { target, strict: opts.strict });
|
|
@@ -96426,19 +97184,15 @@ async function evaluateHook2(nameOrPath, opts) {
|
|
|
96426
97184
|
}
|
|
96427
97185
|
async function refineHook(nameOrPath, opts) {
|
|
96428
97186
|
const target = resolveTarget(opts);
|
|
96429
|
-
return refine3("hook", nameOrPath, { target,
|
|
97187
|
+
return refine3("hook", nameOrPath, { target, dryRun: opts.dryRun });
|
|
96430
97188
|
}
|
|
96431
97189
|
async function evolveHook(name, opts) {
|
|
96432
97190
|
const target = resolveTarget(opts);
|
|
96433
97191
|
return evolve("hook", name, {
|
|
96434
97192
|
target,
|
|
96435
97193
|
from: opts.from,
|
|
96436
|
-
proposeOnly: opts.proposeOnly,
|
|
96437
|
-
acceptId: opts.accept,
|
|
96438
|
-
rejectId: opts.reject,
|
|
96439
97194
|
json: opts.json,
|
|
96440
|
-
|
|
96441
|
-
margin: opts.margin
|
|
97195
|
+
analyze: opts.analyze
|
|
96442
97196
|
});
|
|
96443
97197
|
}
|
|
96444
97198
|
async function emitHook(name, opts) {
|
|
@@ -96466,11 +97220,6 @@ async function emitHook(name, opts) {
|
|
|
96466
97220
|
}
|
|
96467
97221
|
return { count: hookResult.count, message: hookResult.message };
|
|
96468
97222
|
}
|
|
96469
|
-
async function hookScaffold(opts) {
|
|
96470
|
-
const createdPath = await scaffoldHook(opts.name, opts);
|
|
96471
|
-
echo(`Created: ${createdPath}`);
|
|
96472
|
-
return;
|
|
96473
|
-
}
|
|
96474
97223
|
async function hookValidate(opts) {
|
|
96475
97224
|
const result = await validateHook(opts.nameOrPath, opts);
|
|
96476
97225
|
const output2 = formatValidationResult(result, opts.json);
|
|
@@ -96503,19 +97252,16 @@ async function hookEmit(opts) {
|
|
|
96503
97252
|
}
|
|
96504
97253
|
function registerHook(program2) {
|
|
96505
97254
|
const cmd = program2.command("hook").description("Manage hook definitions");
|
|
96506
|
-
addScaffoldOptions(cmd.command("scaffold <name>").description("Create a new hook from template")).action(async (name, opts) => {
|
|
96507
|
-
await runOperation(() => hookScaffold({ name, ...opts }));
|
|
96508
|
-
});
|
|
96509
97255
|
addStrictOption(addTargetOption(addJsonOption(cmd.command("validate <nameOrPath>").description("Validate a hook file")))).action(async (nameOrPath, opts) => {
|
|
96510
97256
|
await runOperation(() => hookValidate({ nameOrPath, ...opts }));
|
|
96511
97257
|
});
|
|
96512
97258
|
addEvaluateOptions(addSaveOption(addTargetOption(addJsonOption(cmd.command("evaluate <nameOrPath>").description("Evaluate hook quality (use --rubric --json for envelope, --ingest --save to persist scores)"))))).action(async (nameOrPath, opts) => {
|
|
96513
97259
|
await runOperation(() => hookEvaluate({ nameOrPath, ...opts }));
|
|
96514
97260
|
});
|
|
96515
|
-
|
|
97261
|
+
addHookRefineOptions(cmd.command("refine <nameOrPath>").description("Surface hook quality findings as suggestions (suggest-only, no auto-apply)")).action(async (nameOrPath, opts) => {
|
|
96516
97262
|
await runOperation(() => hookRefine({ nameOrPath, ...opts }));
|
|
96517
97263
|
});
|
|
96518
|
-
|
|
97264
|
+
addHookEvolveOptions(cmd.command("evolve <name>").description("Analyze hook evaluation trends (analyze-only, no apply)")).action(async (name, opts) => {
|
|
96519
97265
|
await runOperation(() => hookEvolve({ name, ...opts }));
|
|
96520
97266
|
});
|
|
96521
97267
|
addTargetOption(cmd.command("emit <name>").description("Emit a hook definition to a single target agent (thin wrapper over the install hook path)")).option("--global", "Install to user-level global directory (default)", true).option("--dry-run", "Preview without writing files", false).action(async (name, opts) => {
|
|
@@ -96531,7 +97277,9 @@ async function magentScaffold(opts) {
|
|
|
96531
97277
|
description: opts.description,
|
|
96532
97278
|
target,
|
|
96533
97279
|
output: opts.output,
|
|
96534
|
-
force: opts.force
|
|
97280
|
+
force: opts.force,
|
|
97281
|
+
template: opts.template,
|
|
97282
|
+
tools: opts.tools
|
|
96535
97283
|
});
|
|
96536
97284
|
echo(`Created: ${createdPath}`);
|
|
96537
97285
|
return;
|
|
@@ -96562,7 +97310,7 @@ async function magentEvaluate(opts) {
|
|
|
96562
97310
|
}
|
|
96563
97311
|
async function magentRefine(opts) {
|
|
96564
97312
|
const target = resolveTarget(opts);
|
|
96565
|
-
await refine3("magent", opts.nameOrPath, { target, auto: opts.auto, save: opts.save });
|
|
97313
|
+
await refine3("magent", opts.nameOrPath, { target, auto: opts.auto, save: opts.save, dryRun: opts.dryRun });
|
|
96566
97314
|
return;
|
|
96567
97315
|
}
|
|
96568
97316
|
async function magentEvolve(opts) {
|
|
@@ -96575,7 +97323,11 @@ async function magentEvolve(opts) {
|
|
|
96575
97323
|
rejectId: opts.reject,
|
|
96576
97324
|
json: opts.json,
|
|
96577
97325
|
ingest: opts.ingest,
|
|
96578
|
-
margin: opts.margin
|
|
97326
|
+
margin: opts.margin,
|
|
97327
|
+
analyze: opts.analyze,
|
|
97328
|
+
history: opts.history,
|
|
97329
|
+
rollback: opts.rollback,
|
|
97330
|
+
confirm: opts.confirm
|
|
96579
97331
|
});
|
|
96580
97332
|
return;
|
|
96581
97333
|
}
|
|
@@ -96605,7 +97357,7 @@ function registerMagent(program2) {
|
|
|
96605
97357
|
addEvaluateOptions(addSaveOption(addTargetOption(addJsonOption(cmd.command("evaluate <nameOrPath>").description("Evaluate magent quality (use --rubric --json for envelope, --ingest --save to persist scores)"))))).action(async (nameOrPath, opts) => {
|
|
96606
97358
|
await handleMagentEvaluate({ nameOrPath, ...opts });
|
|
96607
97359
|
});
|
|
96608
|
-
addSaveOption(addTargetOption(addAutoOption(cmd.command("refine <nameOrPath>").description("Evaluate and auto-fix a magent")))).action(async (nameOrPath, opts) => {
|
|
97360
|
+
addDryRunOption(addSaveOption(addTargetOption(addAutoOption(cmd.command("refine <nameOrPath>").description("Evaluate and auto-fix a magent"))))).action(async (nameOrPath, opts) => {
|
|
96609
97361
|
await handleMagentRefine({ nameOrPath, ...opts });
|
|
96610
97362
|
});
|
|
96611
97363
|
addEvolveOptions(cmd.command("evolve <name>").description("Longitudinal improvement from evaluation history")).action(async (name, opts) => {
|
|
@@ -96675,7 +97427,9 @@ async function skillScaffold(opts) {
|
|
|
96675
97427
|
description: opts.description,
|
|
96676
97428
|
target,
|
|
96677
97429
|
output: opts.output,
|
|
96678
|
-
force: opts.force
|
|
97430
|
+
force: opts.force,
|
|
97431
|
+
template: opts.template,
|
|
97432
|
+
tools: opts.tools
|
|
96679
97433
|
});
|
|
96680
97434
|
echo(`Created: ${createdPath}`);
|
|
96681
97435
|
return;
|
|
@@ -96695,10 +97449,11 @@ async function skillEvaluate(opts) {
|
|
|
96695
97449
|
const report = await evaluate3("skill", opts.nameOrPath, {
|
|
96696
97450
|
target,
|
|
96697
97451
|
save: opts.save,
|
|
97452
|
+
history: opts.history,
|
|
96698
97453
|
...opts.rubric ? { rubric: opts.rubric } : {},
|
|
96699
97454
|
...opts.ingest ? { ingest: opts.ingest } : {}
|
|
96700
97455
|
});
|
|
96701
|
-
if (report) {
|
|
97456
|
+
if (report && !opts.history) {
|
|
96702
97457
|
const output2 = formatEvaluationReport(report, opts.json);
|
|
96703
97458
|
echo(`${output2}`);
|
|
96704
97459
|
}
|
|
@@ -96706,7 +97461,7 @@ async function skillEvaluate(opts) {
|
|
|
96706
97461
|
}
|
|
96707
97462
|
async function skillRefine(opts) {
|
|
96708
97463
|
const target = resolveTarget(opts);
|
|
96709
|
-
await refine3("skill", opts.nameOrPath, { target, auto: opts.auto, save: opts.save });
|
|
97464
|
+
await refine3("skill", opts.nameOrPath, { target, auto: opts.auto, save: opts.save, dryRun: opts.dryRun });
|
|
96710
97465
|
return;
|
|
96711
97466
|
}
|
|
96712
97467
|
async function skillEvolve(opts) {
|
|
@@ -96719,7 +97474,11 @@ async function skillEvolve(opts) {
|
|
|
96719
97474
|
rejectId: opts.reject,
|
|
96720
97475
|
json: opts.json,
|
|
96721
97476
|
ingest: opts.ingest,
|
|
96722
|
-
margin: opts.margin
|
|
97477
|
+
margin: opts.margin,
|
|
97478
|
+
analyze: opts.analyze,
|
|
97479
|
+
history: opts.history,
|
|
97480
|
+
rollback: opts.rollback,
|
|
97481
|
+
confirm: opts.confirm
|
|
96723
97482
|
});
|
|
96724
97483
|
return;
|
|
96725
97484
|
}
|
|
@@ -96770,8 +97529,8 @@ function registerSkill(program2) {
|
|
|
96770
97529
|
const cmd = program2.command("skill").description("Manage skill definitions");
|
|
96771
97530
|
addScaffoldOptions(cmd.command("scaffold <name>").description("Create a new skill from template")).action(handleSkillScaffold);
|
|
96772
97531
|
addStrictOption(addTargetOption(addJsonOption(cmd.command("validate <nameOrPath>").description("Validate a skill file")))).action(handleSkillValidate);
|
|
96773
|
-
addEvaluateOptions(addSaveOption(addTargetOption(addJsonOption(cmd.command("evaluate <nameOrPath>").description("Evaluate skill quality (use --rubric --json for envelope, --ingest --save to persist scores)"))))).action(handleSkillEvaluate);
|
|
96774
|
-
addSaveOption(addTargetOption(addAutoOption(cmd.command("refine <nameOrPath>").description("Evaluate and auto-fix a skill")))).action(handleSkillRefine);
|
|
97532
|
+
addEvaluateOptions(addSaveOption(addTargetOption(addJsonOption(cmd.command("evaluate <nameOrPath>").description("Evaluate skill quality (use --rubric --json for envelope, --ingest --save to persist scores)").option("--history", "Show prior evaluation rows from the store"))))).action(handleSkillEvaluate);
|
|
97533
|
+
addDryRunOption(addSaveOption(addTargetOption(addAutoOption(cmd.command("refine <nameOrPath>").description("Evaluate and auto-fix a skill"))))).action(handleSkillRefine);
|
|
96775
97534
|
addEvolveOptions(cmd.command("evolve <name>").description("Longitudinal improvement from evaluation history")).action(handleSkillEvolve);
|
|
96776
97535
|
cmd.command("package <name>").description("Package a skill for distribution").option("-o, --output <dir>", "Output directory (default: cwd)").option("--include-companions", "Include companion configs (metadata.openclaw, agents/)").action(handleSkillPackage);
|
|
96777
97536
|
cmd.command("migrate <sources...>").description("Merge/migrate skills into a destination").option("--refine", "Route through the generation seam (F023) for content refinement").option("--ingest <file>", "Agent-authored proposal JSON (apply through the double-loop gate)").option("-t, --target <agent>", "Target agent platform", "claude").option("--margin <n>", "\u0394-margin gate threshold (default 0.05)", Number.parseFloat, 0.05).action(handleSkillMigrate);
|