@gobing-ai/superskill 0.1.8 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -3
- package/dist/index.js +572 -159
- package/package.json +1 -1
- 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
|
@@ -9348,6 +9348,11 @@ function resolveContentPath(type, name, opts) {
|
|
|
9348
9348
|
const asIs = join(base, name);
|
|
9349
9349
|
if (existsSync(asIs) && statSync(asIs).isFile())
|
|
9350
9350
|
return asIs;
|
|
9351
|
+
if (type === "skill") {
|
|
9352
|
+
const skillDirForm = join(base, name, "SKILL.md");
|
|
9353
|
+
if (existsSync(skillDirForm))
|
|
9354
|
+
return skillDirForm;
|
|
9355
|
+
}
|
|
9351
9356
|
const direct = join(base, `${name}.md`);
|
|
9352
9357
|
if (existsSync(direct))
|
|
9353
9358
|
return direct;
|
|
@@ -9366,6 +9371,11 @@ function resolveContentPath(type, name, opts) {
|
|
|
9366
9371
|
}
|
|
9367
9372
|
return null;
|
|
9368
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
|
+
}
|
|
9369
9379
|
var init_identity = () => {};
|
|
9370
9380
|
|
|
9371
9381
|
// ../../packages/core/src/content/paths.ts
|
|
@@ -9809,11 +9819,6 @@ function mapPluginToRulesync(pluginPath, pluginName, outputDir) {
|
|
|
9809
9819
|
}
|
|
9810
9820
|
return result;
|
|
9811
9821
|
}
|
|
9812
|
-
function assertSafePathSegment(value, label) {
|
|
9813
|
-
if (!value || value === "." || value === ".." || value.includes("/") || value.includes("\\") || value.includes("\x00")) {
|
|
9814
|
-
throw new Error(`Invalid ${label} '${value}': must be a single path segment`);
|
|
9815
|
-
}
|
|
9816
|
-
}
|
|
9817
9822
|
function deepMergeJsonFile(sourcePath, targetPath) {
|
|
9818
9823
|
const source = readJsonObject(sourcePath);
|
|
9819
9824
|
const target = existsSync3(targetPath) ? readJsonObject(targetPath) : {};
|
|
@@ -9853,6 +9858,7 @@ function copyAndRewriteDirectory(source, destination, pluginName) {
|
|
|
9853
9858
|
}
|
|
9854
9859
|
}
|
|
9855
9860
|
var init_mapper = __esm(() => {
|
|
9861
|
+
init_identity();
|
|
9856
9862
|
init_adapt_command();
|
|
9857
9863
|
init_adapt_subagent();
|
|
9858
9864
|
init_rewrite_references();
|
|
@@ -14084,45 +14090,106 @@ import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as rea
|
|
|
14084
14090
|
import { homedir as homedir2 } from "os";
|
|
14085
14091
|
import { join as join6 } from "path";
|
|
14086
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
|
+
}
|
|
14087
14104
|
function substituteVars(template, vars) {
|
|
14088
|
-
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));
|
|
14106
|
+
}
|
|
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);
|
|
14089
14128
|
}
|
|
14090
|
-
function resolveTemplate(type) {
|
|
14129
|
+
function resolveTemplate(type, tier) {
|
|
14091
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
|
+
}
|
|
14092
14145
|
const userPath = join6(homeDir, ".superskill", "templates", type, "default.md");
|
|
14093
14146
|
if (existsSync7(userPath)) {
|
|
14094
14147
|
return readFileSync5(userPath, "utf-8");
|
|
14095
14148
|
}
|
|
14096
|
-
|
|
14097
|
-
|
|
14098
|
-
|
|
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
|
+
}
|
|
14099
14154
|
}
|
|
14100
|
-
|
|
14101
|
-
return readFileSync5(prodPath, "utf-8");
|
|
14155
|
+
throw new Error(`No built-in default template found for type "${type}".`);
|
|
14102
14156
|
}
|
|
14103
14157
|
async function scaffold(type, name, opts = {}) {
|
|
14104
|
-
const validTypes = ["skill", "command", "agent", "
|
|
14158
|
+
const validTypes = ["skill", "command", "agent", "magent"];
|
|
14105
14159
|
if (!validTypes.includes(type)) {
|
|
14106
14160
|
throw new Error(`Unknown content type: "${type}". Expected one of: ${validTypes.join(", ")}`);
|
|
14107
14161
|
}
|
|
14108
|
-
|
|
14109
|
-
const
|
|
14162
|
+
assertSafePathSegment(name, "content name");
|
|
14163
|
+
const template = resolveTemplate(type, opts.template);
|
|
14164
|
+
let content = substituteVars(template, {
|
|
14110
14165
|
name,
|
|
14111
14166
|
description: opts.description ?? "",
|
|
14112
14167
|
target: opts.target ?? "claude",
|
|
14113
|
-
body: ""
|
|
14168
|
+
body: "",
|
|
14169
|
+
tools: parseList(opts.tools)
|
|
14114
14170
|
});
|
|
14171
|
+
const toolField = type === "agent" ? "tools" : "allowed-tools";
|
|
14172
|
+
content = mergeFrontmatterList(content, toolField, parseList(opts.tools));
|
|
14115
14173
|
const outDir = opts.output ?? cwd4();
|
|
14116
14174
|
mkdirSync4(outDir, { recursive: true });
|
|
14117
|
-
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
|
+
}
|
|
14118
14179
|
if (existsSync7(filePath) && !opts.force) {
|
|
14119
14180
|
throw new Error(`${filePath} already exists \u2014 pass --force to overwrite`);
|
|
14120
14181
|
}
|
|
14121
14182
|
writeFileSync3(filePath, content, "utf-8");
|
|
14122
14183
|
return filePath;
|
|
14123
14184
|
}
|
|
14124
|
-
var PLACEHOLDER_NAME = "<!-- NAME -->", PLACEHOLDER_DESCRIPTION = "<!-- DESCRIPTION -->", PLACEHOLDER_TARGET = "<!-- TARGET -->", PLACEHOLDER_BODY = "<!-- BODY -->";
|
|
14125
|
-
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
|
+
});
|
|
14126
14193
|
|
|
14127
14194
|
// ../../packages/core/src/quality/types.ts
|
|
14128
14195
|
function computeAggregate(dimensions) {
|
|
@@ -14331,8 +14398,16 @@ function scorePatternMatchQuality(entries) {
|
|
|
14331
14398
|
specificMatchers++;
|
|
14332
14399
|
if (e.timeout !== undefined && e.timeout > 0)
|
|
14333
14400
|
hasTimeout++;
|
|
14334
|
-
if (/\$\{CLAUDE_PLUGIN_ROOT\}/.test(e.command)
|
|
14401
|
+
if (/\$\{CLAUDE_PLUGIN_ROOT\}/.test(e.command)) {
|
|
14335
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
|
+
}
|
|
14336
14411
|
}
|
|
14337
14412
|
const n = entries.length || 1;
|
|
14338
14413
|
const matcherScore = specificMatchers / n;
|
|
@@ -14512,10 +14587,23 @@ function _validateContent(type, content, opts) {
|
|
|
14512
14587
|
const findings = [];
|
|
14513
14588
|
let data;
|
|
14514
14589
|
let body;
|
|
14590
|
+
const frontmatterPresent = /^---\s*$/m.test(content);
|
|
14515
14591
|
try {
|
|
14516
|
-
|
|
14517
|
-
|
|
14518
|
-
|
|
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
|
+
}
|
|
14519
14607
|
} catch (e) {
|
|
14520
14608
|
const msg = e instanceof Error ? e.message : String(e);
|
|
14521
14609
|
findings.push({ severity: "error", field: "frontmatter", message: `YAML parse error: ${msg}` });
|
|
@@ -14661,7 +14749,7 @@ function checkLinkValidity(type, data, referenceChecker) {
|
|
|
14661
14749
|
}
|
|
14662
14750
|
return findings;
|
|
14663
14751
|
}
|
|
14664
|
-
function strictChecks(
|
|
14752
|
+
function strictChecks(type, data, body) {
|
|
14665
14753
|
const findings = [];
|
|
14666
14754
|
const desc = data.description;
|
|
14667
14755
|
if (typeof desc === "string" && desc.length < 40) {
|
|
@@ -14698,6 +14786,22 @@ function strictChecks(_type, data, body) {
|
|
|
14698
14786
|
});
|
|
14699
14787
|
}
|
|
14700
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
|
+
}
|
|
14701
14805
|
return findings;
|
|
14702
14806
|
}
|
|
14703
14807
|
function formatValidationResult(result, json) {
|
|
@@ -14716,7 +14820,7 @@ function sentinelResult(message) {
|
|
|
14716
14820
|
findings: [{ severity: "error", field: "_file", message }]
|
|
14717
14821
|
};
|
|
14718
14822
|
}
|
|
14719
|
-
var MODEL_ALIASES, FIELD_TYPES, DEPRECATED_FIELDS;
|
|
14823
|
+
var MODEL_ALIASES, FIELD_TYPES, DEPRECATED_FIELDS, KNOWN_OPTIONAL;
|
|
14720
14824
|
var init_validate = __esm(() => {
|
|
14721
14825
|
init_frontmatter();
|
|
14722
14826
|
init_identity();
|
|
@@ -14757,12 +14861,13 @@ var init_validate = __esm(() => {
|
|
|
14757
14861
|
author: "No longer used; remove.",
|
|
14758
14862
|
version: "Version is derived from the source repository."
|
|
14759
14863
|
};
|
|
14760
|
-
|
|
14761
|
-
|
|
14762
|
-
|
|
14763
|
-
|
|
14764
|
-
|
|
14765
|
-
|
|
14864
|
+
KNOWN_OPTIONAL = {
|
|
14865
|
+
skill: ["license", "metadata"],
|
|
14866
|
+
command: ["argument-hint", "allowed-tools", "target"],
|
|
14867
|
+
agent: [],
|
|
14868
|
+
hook: [],
|
|
14869
|
+
magent: []
|
|
14870
|
+
};
|
|
14766
14871
|
});
|
|
14767
14872
|
|
|
14768
14873
|
// ../../node_modules/.bun/@logtape+logtape@2.1.5/node_modules/@logtape/logtape/dist/context.js
|
|
@@ -89186,7 +89291,6 @@ var init_src = __esm(() => {
|
|
|
89186
89291
|
init_validate();
|
|
89187
89292
|
init_adapt_command();
|
|
89188
89293
|
init_adapt_subagent();
|
|
89189
|
-
init_pi_subagent();
|
|
89190
89294
|
init_pi_tools();
|
|
89191
89295
|
init_rewrite_references();
|
|
89192
89296
|
init_slash_command2();
|
|
@@ -94980,7 +95084,22 @@ async function evaluate3(type, nameOrPath, opts) {
|
|
|
94980
95084
|
report.content = resolveContentName(resolvedPath);
|
|
94981
95085
|
applyRubricWeightingAndVerdict(type, report, opts);
|
|
94982
95086
|
if (opts?.save) {
|
|
94983
|
-
|
|
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
|
+
}
|
|
94984
95103
|
}
|
|
94985
95104
|
return report;
|
|
94986
95105
|
}
|
|
@@ -95087,31 +95206,26 @@ async function ingestScores(type, resolvedPath, resolvedTarget, opts) {
|
|
|
95087
95206
|
dimensions
|
|
95088
95207
|
};
|
|
95089
95208
|
if (opts.save) {
|
|
95090
|
-
|
|
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
|
+
}
|
|
95091
95226
|
}
|
|
95092
95227
|
return report;
|
|
95093
95228
|
}
|
|
95094
|
-
async function persistEvaluation(type, resolvedPath, resolvedTarget, report, opts, scorer, rubricVersion) {
|
|
95095
|
-
try {
|
|
95096
|
-
const fileHash = hashContent(resolvedPath);
|
|
95097
|
-
const adapter = opts.adapter ?? await openStore();
|
|
95098
|
-
const dao = new EvaluationDao(adapter);
|
|
95099
|
-
await dao.insertEvaluation({
|
|
95100
|
-
content_type: type,
|
|
95101
|
-
content_name: resolveContentName(resolvedPath),
|
|
95102
|
-
target_agent: resolvedTarget,
|
|
95103
|
-
operation: opts.operation ?? "evaluate",
|
|
95104
|
-
aggregate: report.aggregate,
|
|
95105
|
-
dimensions: report.dimensions,
|
|
95106
|
-
file_hash: fileHash,
|
|
95107
|
-
scorer: scorer ?? "heuristic",
|
|
95108
|
-
...rubricVersion !== undefined ? { rubric_version: rubricVersion } : {}
|
|
95109
|
-
});
|
|
95110
|
-
} catch (err) {
|
|
95111
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
95112
|
-
echoError(`Warning: failed to save evaluation: ${msg}`);
|
|
95113
|
-
}
|
|
95114
|
-
}
|
|
95115
95229
|
function formatEvaluationReport(report, json3) {
|
|
95116
95230
|
if (json3) {
|
|
95117
95231
|
return JSON.stringify(report);
|
|
@@ -95235,6 +95349,11 @@ function deserializeProposal(row) {
|
|
|
95235
95349
|
init_src();
|
|
95236
95350
|
|
|
95237
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
|
+
}
|
|
95238
95357
|
function computeTrends(evaluations2) {
|
|
95239
95358
|
if (evaluations2.length < 2)
|
|
95240
95359
|
return [];
|
|
@@ -95296,6 +95415,56 @@ function computeTrends(evaluations2) {
|
|
|
95296
95415
|
});
|
|
95297
95416
|
return trends;
|
|
95298
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
|
+
}
|
|
95299
95468
|
function generateProposalId(type, _name, existingProposals) {
|
|
95300
95469
|
const date9 = new Date().toISOString().slice(0, 10);
|
|
95301
95470
|
const seq = String(existingProposals.length + 1).padStart(3, "0");
|
|
@@ -95325,8 +95494,14 @@ function computeAnchorHash(anchor) {
|
|
|
95325
95494
|
return hasher.digest("hex").slice(0, 16);
|
|
95326
95495
|
}
|
|
95327
95496
|
function computeBaselineAnchorHash(content) {
|
|
95328
|
-
|
|
95329
|
-
|
|
95497
|
+
let frontmatter2 = {};
|
|
95498
|
+
if (hasFrontmatter(content)) {
|
|
95499
|
+
try {
|
|
95500
|
+
frontmatter2 = parseFrontmatter(content).data;
|
|
95501
|
+
} catch {
|
|
95502
|
+
frontmatter2 = {};
|
|
95503
|
+
}
|
|
95504
|
+
}
|
|
95330
95505
|
return computeAnchorHash({
|
|
95331
95506
|
frontmatter: frontmatter2,
|
|
95332
95507
|
rubric_criteria: "",
|
|
@@ -95372,8 +95547,14 @@ async function runGate(input) {
|
|
|
95372
95547
|
}
|
|
95373
95548
|
function emitGenerationEnvelope(type, resolvedPath, content, baseline, trends) {
|
|
95374
95549
|
const rubric2 = loadRubric(type);
|
|
95375
|
-
|
|
95376
|
-
|
|
95550
|
+
let frontmatter2 = {};
|
|
95551
|
+
if (hasFrontmatter(content)) {
|
|
95552
|
+
try {
|
|
95553
|
+
frontmatter2 = parseFrontmatter(content).data;
|
|
95554
|
+
} catch {
|
|
95555
|
+
frontmatter2 = {};
|
|
95556
|
+
}
|
|
95557
|
+
}
|
|
95377
95558
|
const description = frontmatter2.description;
|
|
95378
95559
|
const negativeConstraints = extractNegativeConstraints(description);
|
|
95379
95560
|
const contentName = resolveContentName(resolvedPath);
|
|
@@ -95467,6 +95648,9 @@ async function ingestProposal(db2, type, name, resolvedPath, ingestPath, opts, b
|
|
|
95467
95648
|
ingestedAnchorHash: parsed.anchor_hash,
|
|
95468
95649
|
skeptic: parsed.skeptic
|
|
95469
95650
|
});
|
|
95651
|
+
if (!verdict.rejected && verdict.backupPath) {
|
|
95652
|
+
await persistVersionSnapshot(verdict.backupPath, resolvedPath, proposalId);
|
|
95653
|
+
}
|
|
95470
95654
|
return {
|
|
95471
95655
|
baselineScore,
|
|
95472
95656
|
postScore: verdict.postScore,
|
|
@@ -95503,8 +95687,8 @@ async function stepAnalyze(db2, type, name, opts) {
|
|
|
95503
95687
|
const baselineDate = new Date(newest.created_at).toISOString();
|
|
95504
95688
|
return { evaluations: evaluations2, trends, baselineScore, baselineDate };
|
|
95505
95689
|
}
|
|
95506
|
-
async function stepPropose(db2, type, name,
|
|
95507
|
-
const changes =
|
|
95690
|
+
async function stepPropose(db2, type, name, report, trends, evaluations2, baselineScore, baselineDate, content) {
|
|
95691
|
+
const changes = generateChanges(report, trends, content);
|
|
95508
95692
|
const proposalDao = new ProposalDao(db2);
|
|
95509
95693
|
const existingProposals = await proposalDao.getProposals(type, name);
|
|
95510
95694
|
const proposalId = generateProposalId(type, name, existingProposals);
|
|
@@ -95705,12 +95889,58 @@ async function stepVerify(type, name, filePath, baselineScore, proposalDbId, opt
|
|
|
95705
95889
|
} catch {
|
|
95706
95890
|
echoError("Cannot link verify evaluation.");
|
|
95707
95891
|
}
|
|
95708
|
-
|
|
95709
|
-
rmSync3(gate.backupPath, { force: true });
|
|
95710
|
-
}
|
|
95892
|
+
const survivingBackupPath = gate?.backupPath;
|
|
95711
95893
|
const pctStr = baselineScore > 0 ? `, ${delta >= 0 ? "+" : ""}${(delta / baselineScore * 100).toFixed(1)}%` : "";
|
|
95712
95894
|
echo(`Score: ${baselineScore.toFixed(2)} \u2192 ${postScore.toFixed(2)} (${delta >= 0 ? "+" : ""}${delta.toFixed(2)}${pctStr})`);
|
|
95713
|
-
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;
|
|
95714
95944
|
}
|
|
95715
95945
|
async function evolve(type, name, opts) {
|
|
95716
95946
|
const resolvedPath = resolveContentPath(type, name);
|
|
@@ -95719,6 +95949,10 @@ async function evolve(type, name, opts) {
|
|
|
95719
95949
|
return { baselineScore: 0, postScore: 0, delta: 0, changesApplied: 0, proposalPath: "" };
|
|
95720
95950
|
}
|
|
95721
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
|
+
}
|
|
95722
95956
|
let db2;
|
|
95723
95957
|
try {
|
|
95724
95958
|
db2 = await openDb(opts);
|
|
@@ -95727,6 +95961,45 @@ async function evolve(type, name, opts) {
|
|
|
95727
95961
|
echoError(`Could not open the evaluation store. ${msg}`);
|
|
95728
95962
|
return { baselineScore: 0, postScore: 0, delta: 0, changesApplied: 0, proposalPath: "" };
|
|
95729
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
|
+
}
|
|
95730
96003
|
let analysis;
|
|
95731
96004
|
try {
|
|
95732
96005
|
analysis = await stepAnalyze(db2, type, contentName, opts);
|
|
@@ -95736,6 +96009,10 @@ async function evolve(type, name, opts) {
|
|
|
95736
96009
|
return { baselineScore: 0, postScore: 0, delta: 0, changesApplied: 0, proposalPath: "" };
|
|
95737
96010
|
}
|
|
95738
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
|
+
}
|
|
95739
96016
|
if (evaluations2.length < 2) {
|
|
95740
96017
|
echo("Only one evaluation found \u2014 need at least two for trend analysis. Running evaluation-based proposal instead.");
|
|
95741
96018
|
}
|
|
@@ -95793,13 +96070,16 @@ async function evolve(type, name, opts) {
|
|
|
95793
96070
|
} catch {
|
|
95794
96071
|
acceptedFromStore = [];
|
|
95795
96072
|
}
|
|
95796
|
-
const
|
|
96073
|
+
const backupPath2 = await backupFile(resolvedPath);
|
|
95797
96074
|
const appliedCount = await stepApply(acceptedFromStore, resolvedPath, target.id, db2);
|
|
95798
96075
|
const verdict = await stepVerify(type, contentName, resolvedPath, baselineScore, target.id, opts, db2, {
|
|
95799
|
-
backupPath,
|
|
96076
|
+
backupPath: backupPath2,
|
|
95800
96077
|
ingestedAnchorHash: storedAnchorHash,
|
|
95801
96078
|
skeptic: storedSkeptic
|
|
95802
96079
|
});
|
|
96080
|
+
if (!verdict.rejected && verdict.backupPath) {
|
|
96081
|
+
await persistVersionSnapshot(verdict.backupPath, resolvedPath, opts.acceptId);
|
|
96082
|
+
}
|
|
95803
96083
|
return {
|
|
95804
96084
|
baselineScore,
|
|
95805
96085
|
postScore: verdict.postScore,
|
|
@@ -95809,20 +96089,24 @@ async function evolve(type, name, opts) {
|
|
|
95809
96089
|
...verdict.rejected ? { rejected: true, rejectionReason: verdict.reason } : {}
|
|
95810
96090
|
};
|
|
95811
96091
|
}
|
|
95812
|
-
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);
|
|
95813
96094
|
if (opts?.proposeOnly) {
|
|
95814
96095
|
echo(`Proposal written to: ${proposalPath}`);
|
|
95815
96096
|
return { baselineScore, postScore: baselineScore, delta: 0, changesApplied: 0, proposalPath };
|
|
95816
96097
|
}
|
|
95817
96098
|
const { accepted: acceptedChanges } = await interactiveReview(changes, trends);
|
|
96099
|
+
const backupPath = await backupFile(resolvedPath);
|
|
95818
96100
|
const changesApplied = await stepApply(acceptedChanges, resolvedPath, proposalDbId, db2);
|
|
95819
96101
|
const { postScore, delta } = await stepVerify(type, contentName, resolvedPath, baselineScore, proposalDbId, opts, db2);
|
|
96102
|
+
await persistVersionSnapshot(backupPath, resolvedPath, proposalId);
|
|
95820
96103
|
return { baselineScore, postScore, delta, changesApplied, proposalPath };
|
|
95821
96104
|
}
|
|
95822
96105
|
|
|
95823
96106
|
// src/operations/refine.ts
|
|
95824
96107
|
init_src();
|
|
95825
96108
|
init_dist();
|
|
96109
|
+
init_db2();
|
|
95826
96110
|
import { createInterface as createInterface2 } from "readline";
|
|
95827
96111
|
class RefineAbortedError extends Error {
|
|
95828
96112
|
constructor(message = "User quit interactive mode") {
|
|
@@ -95830,6 +96114,11 @@ class RefineAbortedError extends Error {
|
|
|
95830
96114
|
this.name = "RefineAbortedError";
|
|
95831
96115
|
}
|
|
95832
96116
|
}
|
|
96117
|
+
function isHookApplyCapableOpt2(opts) {
|
|
96118
|
+
if (!opts)
|
|
96119
|
+
return false;
|
|
96120
|
+
return Boolean(opts.auto || opts.save);
|
|
96121
|
+
}
|
|
95833
96122
|
function classifyFix(finding) {
|
|
95834
96123
|
if (finding.severity === "error") {
|
|
95835
96124
|
return "auto-apply";
|
|
@@ -95842,17 +96131,59 @@ function classifyFix(finding) {
|
|
|
95842
96131
|
}
|
|
95843
96132
|
return "auto-apply";
|
|
95844
96133
|
}
|
|
95845
|
-
function getDefaultForField(field) {
|
|
95846
|
-
|
|
95847
|
-
|
|
95848
|
-
|
|
95849
|
-
|
|
95850
|
-
|
|
95851
|
-
|
|
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, "");
|
|
95852
96180
|
}
|
|
95853
96181
|
function generateAutoChange(finding, content) {
|
|
95854
96182
|
if (finding.message.toLowerCase().includes("missing")) {
|
|
95855
|
-
|
|
96183
|
+
const value = getDefaultForField(finding.field, content);
|
|
96184
|
+
if (value === null)
|
|
96185
|
+
return null;
|
|
96186
|
+
return { kind: "frontmatter", key: finding.field, value };
|
|
95856
96187
|
}
|
|
95857
96188
|
if (finding.message.includes("must be an array")) {
|
|
95858
96189
|
let currentValue;
|
|
@@ -95998,30 +96329,30 @@ function applyAutoFixes(findings, content) {
|
|
|
95998
96329
|
async function refine3(type, nameOrPath, opts) {
|
|
95999
96330
|
const resolvedPath = resolveContentPath(type, nameOrPath);
|
|
96000
96331
|
const resolvedTarget = opts?.target ?? "claude";
|
|
96001
|
-
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, {
|
|
96002
96338
|
target: resolvedTarget,
|
|
96003
96339
|
strict: opts?.auto === true
|
|
96004
96340
|
});
|
|
96005
|
-
|
|
96006
|
-
|
|
96007
|
-
|
|
96008
|
-
|
|
96009
|
-
|
|
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;
|
|
96010
96348
|
}
|
|
96011
|
-
|
|
96012
|
-
|
|
96013
|
-
}
|
|
96014
|
-
let preScore;
|
|
96015
|
-
let preDimensions;
|
|
96349
|
+
} catch {}
|
|
96350
|
+
let content;
|
|
96016
96351
|
try {
|
|
96017
|
-
|
|
96018
|
-
if (!report)
|
|
96019
|
-
throw new Error("evaluate returned null in heuristic mode");
|
|
96020
|
-
preScore = report.aggregate;
|
|
96021
|
-
preDimensions = report.dimensions;
|
|
96352
|
+
content = await Bun.file(filePath).text();
|
|
96022
96353
|
} catch {
|
|
96023
|
-
echoError("Cannot
|
|
96024
|
-
return { preScore
|
|
96354
|
+
echoError("Cannot read content file for editing.");
|
|
96355
|
+
return { preScore, postScore: preScore, delta: 0, fixesApplied: [], fixesSkipped: [] };
|
|
96025
96356
|
}
|
|
96026
96357
|
const findings = [];
|
|
96027
96358
|
for (const f of validation.findings) {
|
|
@@ -96029,26 +96360,23 @@ async function refine3(type, nameOrPath, opts) {
|
|
|
96029
96360
|
}
|
|
96030
96361
|
for (const [dimName, dimScore] of Object.entries(preDimensions)) {
|
|
96031
96362
|
if (dimScore.score < 0.7 && dimScore.note?.trim()) {
|
|
96032
|
-
|
|
96033
|
-
severity: "warning",
|
|
96034
|
-
|
|
96035
|
-
|
|
96036
|
-
};
|
|
96037
|
-
findings.push({ finding, strategy: "suggest" });
|
|
96363
|
+
findings.push({
|
|
96364
|
+
finding: { severity: "warning", field: dimName, message: dimScore.note },
|
|
96365
|
+
strategy: "suggest"
|
|
96366
|
+
});
|
|
96038
96367
|
}
|
|
96039
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
|
+
}
|
|
96040
96375
|
if (findings.length === 0) {
|
|
96041
96376
|
echo(`No issues found. Score: ${preScore.toFixed(2)}`);
|
|
96042
96377
|
return { preScore, postScore: preScore, delta: 0, fixesApplied: [], fixesSkipped: [] };
|
|
96043
96378
|
}
|
|
96044
|
-
|
|
96045
|
-
try {
|
|
96046
|
-
content = await Bun.file(resolvedPath ?? nameOrPath).text();
|
|
96047
|
-
} catch {
|
|
96048
|
-
echoError("Cannot read content file for editing.");
|
|
96049
|
-
return { preScore, postScore: preScore, delta: 0, fixesApplied: [], fixesSkipped: [] };
|
|
96050
|
-
}
|
|
96051
|
-
const backupPath = await backupFile(resolvedPath ?? nameOrPath);
|
|
96379
|
+
const backupPath = await backupFile(filePath);
|
|
96052
96380
|
let fixesApplied = [];
|
|
96053
96381
|
let fixesSkipped = [];
|
|
96054
96382
|
try {
|
|
@@ -96057,10 +96385,10 @@ async function refine3(type, nameOrPath, opts) {
|
|
|
96057
96385
|
fixesApplied = result.fixesApplied;
|
|
96058
96386
|
fixesSkipped = result.fixesSkipped;
|
|
96059
96387
|
if (fixesApplied.length > 0) {
|
|
96060
|
-
await Bun.write(
|
|
96388
|
+
await Bun.write(filePath, result.content);
|
|
96061
96389
|
}
|
|
96062
96390
|
} else {
|
|
96063
|
-
const result = await runInteractive(findings, content,
|
|
96391
|
+
const result = await runInteractive(findings, content, filePath, backupPath);
|
|
96064
96392
|
fixesApplied = result.fixesApplied;
|
|
96065
96393
|
fixesSkipped = result.fixesSkipped;
|
|
96066
96394
|
}
|
|
@@ -96070,9 +96398,24 @@ async function refine3(type, nameOrPath, opts) {
|
|
|
96070
96398
|
}
|
|
96071
96399
|
throw err;
|
|
96072
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
|
+
}
|
|
96073
96415
|
let postScore;
|
|
96416
|
+
let postReport = null;
|
|
96074
96417
|
try {
|
|
96075
|
-
|
|
96418
|
+
postReport = await evaluate3(type, filePath, { target: resolvedTarget });
|
|
96076
96419
|
if (!postReport)
|
|
96077
96420
|
throw new Error("evaluate returned null in heuristic mode");
|
|
96078
96421
|
postScore = postReport.aggregate;
|
|
@@ -96080,6 +96423,14 @@ async function refine3(type, nameOrPath, opts) {
|
|
|
96080
96423
|
echoError("Cannot re-evaluate after fixes.");
|
|
96081
96424
|
return { preScore, postScore: preScore, delta: 0, fixesApplied, fixesSkipped };
|
|
96082
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
|
+
}
|
|
96083
96434
|
const delta = postScore - preScore;
|
|
96084
96435
|
if (delta === 0 && preScore === postScore) {
|
|
96085
96436
|
echo(`Score: ${preScore.toFixed(2)} (no change)`);
|
|
@@ -96087,12 +96438,20 @@ async function refine3(type, nameOrPath, opts) {
|
|
|
96087
96438
|
const pctStr = preScore > 0 ? `, +${(delta / preScore * 100).toFixed(1)}%` : "";
|
|
96088
96439
|
echo(`Score: ${preScore.toFixed(2)} \u2192 ${postScore.toFixed(2)} (${delta >= 0 ? "+" : ""}${delta.toFixed(2)}${pctStr})`);
|
|
96089
96440
|
}
|
|
96090
|
-
if (opts?.save) {
|
|
96441
|
+
if (opts?.save && postReport) {
|
|
96091
96442
|
try {
|
|
96092
|
-
|
|
96093
|
-
|
|
96094
|
-
|
|
96095
|
-
|
|
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"
|
|
96096
96455
|
});
|
|
96097
96456
|
} catch {
|
|
96098
96457
|
echoError("Warning: failed to save evaluation results.");
|
|
@@ -96100,6 +96459,48 @@ async function refine3(type, nameOrPath, opts) {
|
|
|
96100
96459
|
}
|
|
96101
96460
|
return { preScore, postScore, delta, fixesApplied, fixesSkipped };
|
|
96102
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
|
+
}
|
|
96103
96504
|
|
|
96104
96505
|
// src/operations/scaffold.ts
|
|
96105
96506
|
init_src();
|
|
@@ -96111,10 +96512,16 @@ function addTargetOption(cmd) {
|
|
|
96111
96512
|
return cmd.option("-t, --target <agent>", "Target agent platform", "claude");
|
|
96112
96513
|
}
|
|
96113
96514
|
function addScaffoldOptions(cmd) {
|
|
96114
|
-
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");
|
|
96115
96516
|
}
|
|
96116
96517
|
function addEvolveOptions(cmd) {
|
|
96117
|
-
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");
|
|
96118
96525
|
}
|
|
96119
96526
|
function addJsonOption(cmd) {
|
|
96120
96527
|
return cmd.option("--json", "Output machine-readable JSON");
|
|
@@ -96131,6 +96538,9 @@ function addStrictOption(cmd) {
|
|
|
96131
96538
|
function addAutoOption(cmd) {
|
|
96132
96539
|
return cmd.option("--auto", "Apply low-risk fixes automatically");
|
|
96133
96540
|
}
|
|
96541
|
+
function addDryRunOption(cmd) {
|
|
96542
|
+
return cmd.option("--dry-run", "Preview classified fixes and projected delta without writing");
|
|
96543
|
+
}
|
|
96134
96544
|
function resolveTarget(opts) {
|
|
96135
96545
|
const raw = opts.target || "claude";
|
|
96136
96546
|
if (!TARGETS.includes(raw)) {
|
|
@@ -96164,7 +96574,9 @@ async function agentScaffold(opts) {
|
|
|
96164
96574
|
description: opts.description,
|
|
96165
96575
|
target,
|
|
96166
96576
|
output: opts.output,
|
|
96167
|
-
force: opts.force
|
|
96577
|
+
force: opts.force,
|
|
96578
|
+
template: opts.template,
|
|
96579
|
+
tools: opts.tools
|
|
96168
96580
|
});
|
|
96169
96581
|
echo(`Created: ${createdPath}`);
|
|
96170
96582
|
return;
|
|
@@ -96195,7 +96607,7 @@ async function agentEvaluate(opts) {
|
|
|
96195
96607
|
}
|
|
96196
96608
|
async function agentRefine(opts) {
|
|
96197
96609
|
const target = resolveTarget(opts);
|
|
96198
|
-
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 });
|
|
96199
96611
|
return;
|
|
96200
96612
|
}
|
|
96201
96613
|
async function agentEvolve(opts) {
|
|
@@ -96208,7 +96620,11 @@ async function agentEvolve(opts) {
|
|
|
96208
96620
|
rejectId: opts.reject,
|
|
96209
96621
|
json: opts.json,
|
|
96210
96622
|
ingest: opts.ingest,
|
|
96211
|
-
margin: opts.margin
|
|
96623
|
+
margin: opts.margin,
|
|
96624
|
+
analyze: opts.analyze,
|
|
96625
|
+
history: opts.history,
|
|
96626
|
+
rollback: opts.rollback,
|
|
96627
|
+
confirm: opts.confirm
|
|
96212
96628
|
});
|
|
96213
96629
|
return;
|
|
96214
96630
|
}
|
|
@@ -96238,7 +96654,7 @@ function registerAgent(program2) {
|
|
|
96238
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) => {
|
|
96239
96655
|
await handleAgentEvaluate({ nameOrPath, ...opts });
|
|
96240
96656
|
});
|
|
96241
|
-
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) => {
|
|
96242
96658
|
await handleAgentRefine({ nameOrPath, ...opts });
|
|
96243
96659
|
});
|
|
96244
96660
|
addEvolveOptions(cmd.command("evolve <name>").description("Longitudinal improvement from evaluation history")).action(async (name, opts) => {
|
|
@@ -96254,7 +96670,9 @@ async function commandScaffold(opts) {
|
|
|
96254
96670
|
description: opts.description,
|
|
96255
96671
|
target,
|
|
96256
96672
|
output: opts.output,
|
|
96257
|
-
force: opts.force
|
|
96673
|
+
force: opts.force,
|
|
96674
|
+
template: opts.template,
|
|
96675
|
+
tools: opts.tools
|
|
96258
96676
|
});
|
|
96259
96677
|
echo(`Created: ${createdPath}`);
|
|
96260
96678
|
return;
|
|
@@ -96285,7 +96703,7 @@ async function commandEvaluate(opts) {
|
|
|
96285
96703
|
}
|
|
96286
96704
|
async function commandRefine(opts) {
|
|
96287
96705
|
const target = resolveTarget(opts);
|
|
96288
|
-
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 });
|
|
96289
96707
|
return;
|
|
96290
96708
|
}
|
|
96291
96709
|
async function commandEvolve(opts) {
|
|
@@ -96298,7 +96716,11 @@ async function commandEvolve(opts) {
|
|
|
96298
96716
|
rejectId: opts.reject,
|
|
96299
96717
|
json: opts.json,
|
|
96300
96718
|
ingest: opts.ingest,
|
|
96301
|
-
margin: opts.margin
|
|
96719
|
+
margin: opts.margin,
|
|
96720
|
+
analyze: opts.analyze,
|
|
96721
|
+
history: opts.history,
|
|
96722
|
+
rollback: opts.rollback,
|
|
96723
|
+
confirm: opts.confirm
|
|
96302
96724
|
});
|
|
96303
96725
|
return;
|
|
96304
96726
|
}
|
|
@@ -96328,7 +96750,7 @@ function registerCommand(program2) {
|
|
|
96328
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) => {
|
|
96329
96751
|
await handleCommandEvaluate({ nameOrPath, ...opts });
|
|
96330
96752
|
});
|
|
96331
|
-
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) => {
|
|
96332
96754
|
await handleCommandRefine({ nameOrPath, ...opts });
|
|
96333
96755
|
});
|
|
96334
96756
|
addEvolveOptions(cmd.command("evolve <name>").description("Longitudinal improvement from evaluation history")).action(async (name, opts) => {
|
|
@@ -96747,15 +97169,6 @@ function copyDirectory(source, destination, options2 = {}) {
|
|
|
96747
97169
|
}
|
|
96748
97170
|
|
|
96749
97171
|
// src/commands/hook.ts
|
|
96750
|
-
async function scaffoldHook(name, opts) {
|
|
96751
|
-
const target = resolveTarget(opts);
|
|
96752
|
-
return scaffold("hook", name, {
|
|
96753
|
-
description: opts.description,
|
|
96754
|
-
target,
|
|
96755
|
-
output: opts.output,
|
|
96756
|
-
force: opts.force
|
|
96757
|
-
});
|
|
96758
|
-
}
|
|
96759
97172
|
async function validateHook(nameOrPath, opts) {
|
|
96760
97173
|
const target = resolveTarget(opts);
|
|
96761
97174
|
return validate("hook", nameOrPath, { target, strict: opts.strict });
|
|
@@ -96771,19 +97184,15 @@ async function evaluateHook2(nameOrPath, opts) {
|
|
|
96771
97184
|
}
|
|
96772
97185
|
async function refineHook(nameOrPath, opts) {
|
|
96773
97186
|
const target = resolveTarget(opts);
|
|
96774
|
-
return refine3("hook", nameOrPath, { target,
|
|
97187
|
+
return refine3("hook", nameOrPath, { target, dryRun: opts.dryRun });
|
|
96775
97188
|
}
|
|
96776
97189
|
async function evolveHook(name, opts) {
|
|
96777
97190
|
const target = resolveTarget(opts);
|
|
96778
97191
|
return evolve("hook", name, {
|
|
96779
97192
|
target,
|
|
96780
97193
|
from: opts.from,
|
|
96781
|
-
proposeOnly: opts.proposeOnly,
|
|
96782
|
-
acceptId: opts.accept,
|
|
96783
|
-
rejectId: opts.reject,
|
|
96784
97194
|
json: opts.json,
|
|
96785
|
-
|
|
96786
|
-
margin: opts.margin
|
|
97195
|
+
analyze: opts.analyze
|
|
96787
97196
|
});
|
|
96788
97197
|
}
|
|
96789
97198
|
async function emitHook(name, opts) {
|
|
@@ -96811,11 +97220,6 @@ async function emitHook(name, opts) {
|
|
|
96811
97220
|
}
|
|
96812
97221
|
return { count: hookResult.count, message: hookResult.message };
|
|
96813
97222
|
}
|
|
96814
|
-
async function hookScaffold(opts) {
|
|
96815
|
-
const createdPath = await scaffoldHook(opts.name, opts);
|
|
96816
|
-
echo(`Created: ${createdPath}`);
|
|
96817
|
-
return;
|
|
96818
|
-
}
|
|
96819
97223
|
async function hookValidate(opts) {
|
|
96820
97224
|
const result = await validateHook(opts.nameOrPath, opts);
|
|
96821
97225
|
const output2 = formatValidationResult(result, opts.json);
|
|
@@ -96848,19 +97252,16 @@ async function hookEmit(opts) {
|
|
|
96848
97252
|
}
|
|
96849
97253
|
function registerHook(program2) {
|
|
96850
97254
|
const cmd = program2.command("hook").description("Manage hook definitions");
|
|
96851
|
-
addScaffoldOptions(cmd.command("scaffold <name>").description("Create a new hook from template")).action(async (name, opts) => {
|
|
96852
|
-
await runOperation(() => hookScaffold({ name, ...opts }));
|
|
96853
|
-
});
|
|
96854
97255
|
addStrictOption(addTargetOption(addJsonOption(cmd.command("validate <nameOrPath>").description("Validate a hook file")))).action(async (nameOrPath, opts) => {
|
|
96855
97256
|
await runOperation(() => hookValidate({ nameOrPath, ...opts }));
|
|
96856
97257
|
});
|
|
96857
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) => {
|
|
96858
97259
|
await runOperation(() => hookEvaluate({ nameOrPath, ...opts }));
|
|
96859
97260
|
});
|
|
96860
|
-
|
|
97261
|
+
addHookRefineOptions(cmd.command("refine <nameOrPath>").description("Surface hook quality findings as suggestions (suggest-only, no auto-apply)")).action(async (nameOrPath, opts) => {
|
|
96861
97262
|
await runOperation(() => hookRefine({ nameOrPath, ...opts }));
|
|
96862
97263
|
});
|
|
96863
|
-
|
|
97264
|
+
addHookEvolveOptions(cmd.command("evolve <name>").description("Analyze hook evaluation trends (analyze-only, no apply)")).action(async (name, opts) => {
|
|
96864
97265
|
await runOperation(() => hookEvolve({ name, ...opts }));
|
|
96865
97266
|
});
|
|
96866
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) => {
|
|
@@ -96876,7 +97277,9 @@ async function magentScaffold(opts) {
|
|
|
96876
97277
|
description: opts.description,
|
|
96877
97278
|
target,
|
|
96878
97279
|
output: opts.output,
|
|
96879
|
-
force: opts.force
|
|
97280
|
+
force: opts.force,
|
|
97281
|
+
template: opts.template,
|
|
97282
|
+
tools: opts.tools
|
|
96880
97283
|
});
|
|
96881
97284
|
echo(`Created: ${createdPath}`);
|
|
96882
97285
|
return;
|
|
@@ -96907,7 +97310,7 @@ async function magentEvaluate(opts) {
|
|
|
96907
97310
|
}
|
|
96908
97311
|
async function magentRefine(opts) {
|
|
96909
97312
|
const target = resolveTarget(opts);
|
|
96910
|
-
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 });
|
|
96911
97314
|
return;
|
|
96912
97315
|
}
|
|
96913
97316
|
async function magentEvolve(opts) {
|
|
@@ -96920,7 +97323,11 @@ async function magentEvolve(opts) {
|
|
|
96920
97323
|
rejectId: opts.reject,
|
|
96921
97324
|
json: opts.json,
|
|
96922
97325
|
ingest: opts.ingest,
|
|
96923
|
-
margin: opts.margin
|
|
97326
|
+
margin: opts.margin,
|
|
97327
|
+
analyze: opts.analyze,
|
|
97328
|
+
history: opts.history,
|
|
97329
|
+
rollback: opts.rollback,
|
|
97330
|
+
confirm: opts.confirm
|
|
96924
97331
|
});
|
|
96925
97332
|
return;
|
|
96926
97333
|
}
|
|
@@ -96950,7 +97357,7 @@ function registerMagent(program2) {
|
|
|
96950
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) => {
|
|
96951
97358
|
await handleMagentEvaluate({ nameOrPath, ...opts });
|
|
96952
97359
|
});
|
|
96953
|
-
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) => {
|
|
96954
97361
|
await handleMagentRefine({ nameOrPath, ...opts });
|
|
96955
97362
|
});
|
|
96956
97363
|
addEvolveOptions(cmd.command("evolve <name>").description("Longitudinal improvement from evaluation history")).action(async (name, opts) => {
|
|
@@ -97020,7 +97427,9 @@ async function skillScaffold(opts) {
|
|
|
97020
97427
|
description: opts.description,
|
|
97021
97428
|
target,
|
|
97022
97429
|
output: opts.output,
|
|
97023
|
-
force: opts.force
|
|
97430
|
+
force: opts.force,
|
|
97431
|
+
template: opts.template,
|
|
97432
|
+
tools: opts.tools
|
|
97024
97433
|
});
|
|
97025
97434
|
echo(`Created: ${createdPath}`);
|
|
97026
97435
|
return;
|
|
@@ -97052,7 +97461,7 @@ async function skillEvaluate(opts) {
|
|
|
97052
97461
|
}
|
|
97053
97462
|
async function skillRefine(opts) {
|
|
97054
97463
|
const target = resolveTarget(opts);
|
|
97055
|
-
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 });
|
|
97056
97465
|
return;
|
|
97057
97466
|
}
|
|
97058
97467
|
async function skillEvolve(opts) {
|
|
@@ -97065,7 +97474,11 @@ async function skillEvolve(opts) {
|
|
|
97065
97474
|
rejectId: opts.reject,
|
|
97066
97475
|
json: opts.json,
|
|
97067
97476
|
ingest: opts.ingest,
|
|
97068
|
-
margin: opts.margin
|
|
97477
|
+
margin: opts.margin,
|
|
97478
|
+
analyze: opts.analyze,
|
|
97479
|
+
history: opts.history,
|
|
97480
|
+
rollback: opts.rollback,
|
|
97481
|
+
confirm: opts.confirm
|
|
97069
97482
|
});
|
|
97070
97483
|
return;
|
|
97071
97484
|
}
|
|
@@ -97117,7 +97530,7 @@ function registerSkill(program2) {
|
|
|
97117
97530
|
addScaffoldOptions(cmd.command("scaffold <name>").description("Create a new skill from template")).action(handleSkillScaffold);
|
|
97118
97531
|
addStrictOption(addTargetOption(addJsonOption(cmd.command("validate <nameOrPath>").description("Validate a skill file")))).action(handleSkillValidate);
|
|
97119
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);
|
|
97120
|
-
addSaveOption(addTargetOption(addAutoOption(cmd.command("refine <nameOrPath>").description("Evaluate and auto-fix a skill")))).action(handleSkillRefine);
|
|
97533
|
+
addDryRunOption(addSaveOption(addTargetOption(addAutoOption(cmd.command("refine <nameOrPath>").description("Evaluate and auto-fix a skill"))))).action(handleSkillRefine);
|
|
97121
97534
|
addEvolveOptions(cmd.command("evolve <name>").description("Longitudinal improvement from evaluation history")).action(handleSkillEvolve);
|
|
97122
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);
|
|
97123
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);
|