@przeprogramowani/10x-cli 1.15.0 → 1.17.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/dist/index.mjs +112 -7
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -10173,7 +10173,7 @@ var cac = (name = "") => new CAC(name);
|
|
|
10173
10173
|
// package.json
|
|
10174
10174
|
var package_default = {
|
|
10175
10175
|
name: "@przeprogramowani/10x-cli",
|
|
10176
|
-
version: "1.
|
|
10176
|
+
version: "1.17.0",
|
|
10177
10177
|
description: "Open-source CLI for 10xDevs course content",
|
|
10178
10178
|
repository: {
|
|
10179
10179
|
type: "git",
|
|
@@ -11459,6 +11459,7 @@ function topDetectedProfile(signals) {
|
|
|
11459
11459
|
|
|
11460
11460
|
// src/commands/bench-kit.ts
|
|
11461
11461
|
var TEMPLATE_REPO_URL = "https://github.com/przeprogramowani/10x-bench-kit";
|
|
11462
|
+
var SHARED_ROOT_FILES = ["AGENTS.md"];
|
|
11462
11463
|
var PLACEHOLDER_BASE_REPO = "demo-app";
|
|
11463
11464
|
function registerBenchKitCommand(cli) {
|
|
11464
11465
|
if (!experimentalEnabled())
|
|
@@ -11511,15 +11512,27 @@ async function runBenchKitInit(ctx, dirArg, options, deps = defaultDeps) {
|
|
|
11511
11512
|
const skills = syncDir(join4(scratch, skillSource), join4(targetDir, skillRootFor(toolId)), { overwrite: !repair });
|
|
11512
11513
|
installWorkflows(targetDir, { skipExisting: repair });
|
|
11513
11514
|
let baseRepo = null;
|
|
11515
|
+
let demoTasksPinned = 0;
|
|
11514
11516
|
if (!repair) {
|
|
11515
11517
|
const detected = await deps.detectBaseRepo(process.cwd());
|
|
11516
11518
|
if (detected !== null && resolve(detected.rootDir) !== targetDir) {
|
|
11517
|
-
|
|
11518
|
-
|
|
11519
|
-
|
|
11519
|
+
let repo = detected;
|
|
11520
|
+
const https = toHttpsUrl(detected.url);
|
|
11521
|
+
if (https !== null && await deps.remoteReachable(https)) {
|
|
11522
|
+
repo = { ...detected, url: https };
|
|
11523
|
+
verbose(ctx, `repo answers over https — using ${https} instead of SSH`);
|
|
11524
|
+
}
|
|
11525
|
+
if (await registerBaseRepo(join4(targetDir, "bench.config.yaml"), repo)) {
|
|
11526
|
+
baseRepo = repo;
|
|
11527
|
+
verbose(ctx, `registered base repo ${repo.name} (${repo.url})`);
|
|
11528
|
+
demoTasksPinned = await pinPlaceholderTasks(join4(targetDir, "tasks"), repo);
|
|
11529
|
+
if (demoTasksPinned > 0) {
|
|
11530
|
+
verbose(ctx, `pinned ${demoTasksPinned} demo task(s) to ${repo.headCommit.slice(0, 12)}`);
|
|
11531
|
+
}
|
|
11520
11532
|
}
|
|
11521
11533
|
}
|
|
11522
11534
|
}
|
|
11535
|
+
const runnerDeps = await installRunnerDependencies(ctx, deps, targetDir);
|
|
11523
11536
|
const manifest = {
|
|
11524
11537
|
templateVersion,
|
|
11525
11538
|
templateRef: requestedRef ?? "latest",
|
|
@@ -11542,6 +11555,8 @@ async function runBenchKitInit(ctx, dirArg, options, deps = defaultDeps) {
|
|
|
11542
11555
|
`Created a benchmark instance in '${targetDir}' from template ${templateVersion}.`,
|
|
11543
11556
|
`Agent skills installed for ${toolName} under ${skillRootFor(toolId)}/.`,
|
|
11544
11557
|
baseRepo === null ? "No product repo detected here — add your base repos to bench.config.yaml." : `Registered '${baseRepo.name}' (${baseRepo.url}) as the first base repo in bench.config.yaml.`,
|
|
11558
|
+
...demoTasksPinned > 0 ? [`Pinned the demo task to ${baseRepo?.headCommit.slice(0, 12)} (current HEAD of the base repo).`] : [],
|
|
11559
|
+
...runnerDeps === "failed" ? ["Runner dependencies did not install — run 'npm ci --prefix .bench-kit/runner' yourself."] : runnerDeps === "installed" ? ["Runner dependencies installed (.bench-kit/runner/node_modules)."] : [],
|
|
11545
11560
|
committed ? "Initialized a fresh git repository with an initial commit." : "Initialized a fresh git repository (initial commit skipped — commit the files yourself).",
|
|
11546
11561
|
"Next: wire up secrets, then run 'bench validate' before the first run."
|
|
11547
11562
|
];
|
|
@@ -11555,6 +11570,8 @@ async function runBenchKitInit(ctx, dirArg, options, deps = defaultDeps) {
|
|
|
11555
11570
|
skillRoot: skillRootFor(toolId),
|
|
11556
11571
|
filesCopied: copied + skills.added,
|
|
11557
11572
|
baseRepo,
|
|
11573
|
+
demoTasksPinned,
|
|
11574
|
+
runnerDeps,
|
|
11558
11575
|
gitInitialized: !repair,
|
|
11559
11576
|
committed
|
|
11560
11577
|
});
|
|
@@ -11618,11 +11635,18 @@ async function runBenchKitUpdate(ctx, dirArg, options, deps = defaultDeps) {
|
|
|
11618
11635
|
const skills = syncDir(join4(scratch, skillSource), join4(targetDir, skillRootFor(toolId)), {
|
|
11619
11636
|
overwrite: true
|
|
11620
11637
|
});
|
|
11638
|
+
const shared = { added: 0, updated: 0, unchanged: 0 };
|
|
11639
|
+
for (const file of SHARED_ROOT_FILES) {
|
|
11640
|
+
addSync(shared, syncFile(join4(scratch, file), join4(targetDir, file)));
|
|
11641
|
+
}
|
|
11642
|
+
const runnerDeps = await installRunnerDependencies(ctx, deps, targetDir);
|
|
11621
11643
|
output(ctx, [
|
|
11622
11644
|
`Updated the benchmark instance from template ${currentVersion} to ${newVersion}.`,
|
|
11623
11645
|
" .bench-kit/ replaced wholesale (runtime zone)",
|
|
11646
|
+
...runnerDeps === "failed" ? [" .bench-kit/runner/ npm ci FAILED — run 'npm ci --prefix .bench-kit/runner' yourself"] : runnerDeps === "installed" ? [" .bench-kit/runner/ dependencies reinstalled (npm ci)"] : [],
|
|
11624
11647
|
` .github/workflows/ ${describeSync(workflows)}`,
|
|
11625
11648
|
` ${`${skillRootFor(toolId)}/`.padEnd(23)}${describeSync(skills)} — proposal, review before committing`,
|
|
11649
|
+
` ${SHARED_ROOT_FILES.join(", ").padEnd(23)}${describeSync(shared)} — proposal, review before committing`,
|
|
11626
11650
|
" tasks/, evaluation-pool/, bench.config.yaml untouched (company zone)",
|
|
11627
11651
|
"Next: review 'git diff', run 'bench validate' (it flags any schema changes to fix), then commit via PR."
|
|
11628
11652
|
].join(`
|
|
@@ -11635,7 +11659,8 @@ async function runBenchKitUpdate(ctx, dirArg, options, deps = defaultDeps) {
|
|
|
11635
11659
|
templateRef: updatedManifest.templateRef,
|
|
11636
11660
|
tool: toolId,
|
|
11637
11661
|
skillRoot: skillRootFor(toolId),
|
|
11638
|
-
|
|
11662
|
+
runnerDeps,
|
|
11663
|
+
zones: { benchKit: "replaced", workflows, skills, shared }
|
|
11639
11664
|
});
|
|
11640
11665
|
} finally {
|
|
11641
11666
|
rmSync3(scratch, { recursive: true, force: true });
|
|
@@ -11758,6 +11783,26 @@ function syncDir(srcDir, destDir, opts) {
|
|
|
11758
11783
|
function describeSync(counts) {
|
|
11759
11784
|
return `${counts.added} added, ${counts.updated} updated, ${counts.unchanged} unchanged`;
|
|
11760
11785
|
}
|
|
11786
|
+
function syncFile(from, to) {
|
|
11787
|
+
const counts = { added: 0, updated: 0, unchanged: 0 };
|
|
11788
|
+
if (!existsSync4(from))
|
|
11789
|
+
return counts;
|
|
11790
|
+
if (!existsSync4(to)) {
|
|
11791
|
+
cpSync(from, to);
|
|
11792
|
+
counts.added++;
|
|
11793
|
+
} else if (readFileSync3(from).equals(readFileSync3(to))) {
|
|
11794
|
+
counts.unchanged++;
|
|
11795
|
+
} else {
|
|
11796
|
+
cpSync(from, to);
|
|
11797
|
+
counts.updated++;
|
|
11798
|
+
}
|
|
11799
|
+
return counts;
|
|
11800
|
+
}
|
|
11801
|
+
function addSync(into, counts) {
|
|
11802
|
+
into.added += counts.added;
|
|
11803
|
+
into.updated += counts.updated;
|
|
11804
|
+
into.unchanged += counts.unchanged;
|
|
11805
|
+
}
|
|
11761
11806
|
function materialize(srcDir, destDir, opts) {
|
|
11762
11807
|
let copied = 0;
|
|
11763
11808
|
const walk = (rel) => {
|
|
@@ -11805,6 +11850,53 @@ async function registerBaseRepo(configPath, repo) {
|
|
|
11805
11850
|
writeFileSync3(configPath, doc.toString());
|
|
11806
11851
|
return true;
|
|
11807
11852
|
}
|
|
11853
|
+
function toHttpsUrl(url) {
|
|
11854
|
+
const scp = url.match(/^git@([^:/]+):(.+)$/);
|
|
11855
|
+
if (scp !== null)
|
|
11856
|
+
return `https://${scp[1]}/${scp[2]}`;
|
|
11857
|
+
const ssh = url.match(/^ssh:\/\/(?:[^@/]+@)?([^:/]+)(?::\d+)?\/(.+)$/);
|
|
11858
|
+
if (ssh !== null)
|
|
11859
|
+
return `https://${ssh[1]}/${ssh[2]}`;
|
|
11860
|
+
return null;
|
|
11861
|
+
}
|
|
11862
|
+
var PLACEHOLDER_COMMIT = /^0{40}$/;
|
|
11863
|
+
async function pinPlaceholderTasks(tasksDir, repo) {
|
|
11864
|
+
if (!existsSync4(tasksDir) || !/^[0-9a-f]{40}$/.test(repo.headCommit))
|
|
11865
|
+
return 0;
|
|
11866
|
+
const { parseDocument } = await Promise.resolve().then(() => __toESM(require_dist(), 1));
|
|
11867
|
+
let pinned = 0;
|
|
11868
|
+
for (const entry of readdirSync(tasksDir, { withFileTypes: true })) {
|
|
11869
|
+
if (!entry.isDirectory())
|
|
11870
|
+
continue;
|
|
11871
|
+
const taskYaml = join4(tasksDir, entry.name, "task.yaml");
|
|
11872
|
+
if (!existsSync4(taskYaml))
|
|
11873
|
+
continue;
|
|
11874
|
+
const doc = parseDocument(readFileSync3(taskYaml, "utf8"));
|
|
11875
|
+
if (doc.getIn(["repo"]) !== PLACEHOLDER_BASE_REPO)
|
|
11876
|
+
continue;
|
|
11877
|
+
const commit = doc.getIn(["commit"]);
|
|
11878
|
+
doc.setIn(["repo"], repo.name);
|
|
11879
|
+
if (typeof commit === "string" && PLACEHOLDER_COMMIT.test(commit)) {
|
|
11880
|
+
doc.setIn(["commit"], repo.headCommit);
|
|
11881
|
+
}
|
|
11882
|
+
writeFileSync3(taskYaml, doc.toString());
|
|
11883
|
+
pinned++;
|
|
11884
|
+
}
|
|
11885
|
+
return pinned;
|
|
11886
|
+
}
|
|
11887
|
+
async function installRunnerDependencies(ctx, deps, targetDir) {
|
|
11888
|
+
const runnerDir = join4(targetDir, ".bench-kit", "runner");
|
|
11889
|
+
if (!existsSync4(join4(runnerDir, "package.json")))
|
|
11890
|
+
return "skipped";
|
|
11891
|
+
verbose(ctx, "installing runner dependencies (npm ci in .bench-kit/runner)");
|
|
11892
|
+
const result = await deps.installRunnerDeps(runnerDir);
|
|
11893
|
+
if (!result.ok) {
|
|
11894
|
+
verbose(ctx, `npm ci failed (${result.error.trim().split(`
|
|
11895
|
+
`).pop() ?? ""})`);
|
|
11896
|
+
return "failed";
|
|
11897
|
+
}
|
|
11898
|
+
return "installed";
|
|
11899
|
+
}
|
|
11808
11900
|
async function freshGitInit(ctx, deps, dir, templateVersion) {
|
|
11809
11901
|
const init = await deps.runGit(["init"], dir);
|
|
11810
11902
|
if (!init.ok) {
|
|
@@ -11818,9 +11910,13 @@ async function freshGitInit(ctx, deps, dir, templateVersion) {
|
|
|
11818
11910
|
}
|
|
11819
11911
|
return true;
|
|
11820
11912
|
}
|
|
11821
|
-
function run(cmd, args, cwd) {
|
|
11913
|
+
function run(cmd, args, cwd, env) {
|
|
11822
11914
|
return new Promise((resolvePromise) => {
|
|
11823
|
-
const child = spawn(cmd, args, {
|
|
11915
|
+
const child = spawn(cmd, args, {
|
|
11916
|
+
cwd,
|
|
11917
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
11918
|
+
...env === undefined ? {} : { env: { ...process.env, ...env } }
|
|
11919
|
+
});
|
|
11824
11920
|
let stdout = "";
|
|
11825
11921
|
let stderr = "";
|
|
11826
11922
|
child.stdout?.on("data", (chunk) => {
|
|
@@ -11867,6 +11963,15 @@ var defaultDeps = {
|
|
|
11867
11963
|
return null;
|
|
11868
11964
|
return { rootDir, name: basename(rootDir), url, headCommit };
|
|
11869
11965
|
},
|
|
11966
|
+
async remoteReachable(url) {
|
|
11967
|
+
const result = await run("git", ["ls-remote", "--heads", url], undefined, {
|
|
11968
|
+
GIT_TERMINAL_PROMPT: "0"
|
|
11969
|
+
});
|
|
11970
|
+
return result.ok;
|
|
11971
|
+
},
|
|
11972
|
+
installRunnerDeps(runnerDir) {
|
|
11973
|
+
return run("npm", ["ci", "--no-audit", "--no-fund"], runnerDir);
|
|
11974
|
+
},
|
|
11870
11975
|
detectToolSignals(cwd) {
|
|
11871
11976
|
return detectTools(cwd);
|
|
11872
11977
|
},
|