@przeprogramowani/10x-cli 1.16.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.
Files changed (2) hide show
  1. package/dist/index.mjs +85 -6
  2. 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.16.0",
10176
+ version: "1.17.0",
10177
10177
  description: "Open-source CLI for 10xDevs course content",
10178
10178
  repository: {
10179
10179
  type: "git",
@@ -11512,15 +11512,27 @@ async function runBenchKitInit(ctx, dirArg, options, deps = defaultDeps) {
11512
11512
  const skills = syncDir(join4(scratch, skillSource), join4(targetDir, skillRootFor(toolId)), { overwrite: !repair });
11513
11513
  installWorkflows(targetDir, { skipExisting: repair });
11514
11514
  let baseRepo = null;
11515
+ let demoTasksPinned = 0;
11515
11516
  if (!repair) {
11516
11517
  const detected = await deps.detectBaseRepo(process.cwd());
11517
11518
  if (detected !== null && resolve(detected.rootDir) !== targetDir) {
11518
- if (await registerBaseRepo(join4(targetDir, "bench.config.yaml"), detected)) {
11519
- baseRepo = detected;
11520
- verbose(ctx, `registered base repo ${detected.name} (${detected.url})`);
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
+ }
11521
11532
  }
11522
11533
  }
11523
11534
  }
11535
+ const runnerDeps = await installRunnerDependencies(ctx, deps, targetDir);
11524
11536
  const manifest = {
11525
11537
  templateVersion,
11526
11538
  templateRef: requestedRef ?? "latest",
@@ -11543,6 +11555,8 @@ async function runBenchKitInit(ctx, dirArg, options, deps = defaultDeps) {
11543
11555
  `Created a benchmark instance in '${targetDir}' from template ${templateVersion}.`,
11544
11556
  `Agent skills installed for ${toolName} under ${skillRootFor(toolId)}/.`,
11545
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)."] : [],
11546
11560
  committed ? "Initialized a fresh git repository with an initial commit." : "Initialized a fresh git repository (initial commit skipped — commit the files yourself).",
11547
11561
  "Next: wire up secrets, then run 'bench validate' before the first run."
11548
11562
  ];
@@ -11556,6 +11570,8 @@ async function runBenchKitInit(ctx, dirArg, options, deps = defaultDeps) {
11556
11570
  skillRoot: skillRootFor(toolId),
11557
11571
  filesCopied: copied + skills.added,
11558
11572
  baseRepo,
11573
+ demoTasksPinned,
11574
+ runnerDeps,
11559
11575
  gitInitialized: !repair,
11560
11576
  committed
11561
11577
  });
@@ -11623,9 +11639,11 @@ async function runBenchKitUpdate(ctx, dirArg, options, deps = defaultDeps) {
11623
11639
  for (const file of SHARED_ROOT_FILES) {
11624
11640
  addSync(shared, syncFile(join4(scratch, file), join4(targetDir, file)));
11625
11641
  }
11642
+ const runnerDeps = await installRunnerDependencies(ctx, deps, targetDir);
11626
11643
  output(ctx, [
11627
11644
  `Updated the benchmark instance from template ${currentVersion} to ${newVersion}.`,
11628
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)"] : [],
11629
11647
  ` .github/workflows/ ${describeSync(workflows)}`,
11630
11648
  ` ${`${skillRootFor(toolId)}/`.padEnd(23)}${describeSync(skills)} — proposal, review before committing`,
11631
11649
  ` ${SHARED_ROOT_FILES.join(", ").padEnd(23)}${describeSync(shared)} — proposal, review before committing`,
@@ -11641,6 +11659,7 @@ async function runBenchKitUpdate(ctx, dirArg, options, deps = defaultDeps) {
11641
11659
  templateRef: updatedManifest.templateRef,
11642
11660
  tool: toolId,
11643
11661
  skillRoot: skillRootFor(toolId),
11662
+ runnerDeps,
11644
11663
  zones: { benchKit: "replaced", workflows, skills, shared }
11645
11664
  });
11646
11665
  } finally {
@@ -11831,6 +11850,53 @@ async function registerBaseRepo(configPath, repo) {
11831
11850
  writeFileSync3(configPath, doc.toString());
11832
11851
  return true;
11833
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
+ }
11834
11900
  async function freshGitInit(ctx, deps, dir, templateVersion) {
11835
11901
  const init = await deps.runGit(["init"], dir);
11836
11902
  if (!init.ok) {
@@ -11844,9 +11910,13 @@ async function freshGitInit(ctx, deps, dir, templateVersion) {
11844
11910
  }
11845
11911
  return true;
11846
11912
  }
11847
- function run(cmd, args, cwd) {
11913
+ function run(cmd, args, cwd, env) {
11848
11914
  return new Promise((resolvePromise) => {
11849
- const child = spawn(cmd, args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
11915
+ const child = spawn(cmd, args, {
11916
+ cwd,
11917
+ stdio: ["ignore", "pipe", "pipe"],
11918
+ ...env === undefined ? {} : { env: { ...process.env, ...env } }
11919
+ });
11850
11920
  let stdout = "";
11851
11921
  let stderr = "";
11852
11922
  child.stdout?.on("data", (chunk) => {
@@ -11893,6 +11963,15 @@ var defaultDeps = {
11893
11963
  return null;
11894
11964
  return { rootDir, name: basename(rootDir), url, headCommit };
11895
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
+ },
11896
11975
  detectToolSignals(cwd) {
11897
11976
  return detectTools(cwd);
11898
11977
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@przeprogramowani/10x-cli",
3
- "version": "1.16.0",
3
+ "version": "1.17.0",
4
4
  "description": "Open-source CLI for 10xDevs course content",
5
5
  "repository": {
6
6
  "type": "git",