@rness/cli 0.5.2 → 0.5.3

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.
@@ -2331,12 +2331,227 @@ async function installDependencies(pm, dir, opts = {}) {
2331
2331
  }
2332
2332
  }
2333
2333
 
2334
- // src/core/pinned.ts
2334
+ // src/core/scaffold.ts
2335
+ import { statSync } from "fs";
2336
+ import { dirname as dirname4, join as join12 } from "path";
2337
+ import { fileURLToPath } from "url";
2338
+ var SCAFFOLD_FILES = [
2339
+ "AGENTS.md",
2340
+ "CONVENTIONS.md",
2341
+ "README.md",
2342
+ "WORKSPACE.md",
2343
+ "rness.json",
2344
+ "package.json",
2345
+ "_gitignore",
2346
+ ".githooks/pre-commit",
2347
+ ".github/workflows/validate.yml",
2348
+ ".github/dependabot.yml",
2349
+ "pnpm-workspace.yaml",
2350
+ "adr/0000-template.md",
2351
+ "standards/.gitkeep",
2352
+ "specs/.gitkeep",
2353
+ "plans/.gitkeep",
2354
+ "skills/.gitkeep",
2355
+ "docs/.gitkeep"
2356
+ ];
2357
+ function scaffoldDir() {
2358
+ let dir = dirname4(fileURLToPath(import.meta.url));
2359
+ for (let i = 0; i < 4; i += 1) {
2360
+ const candidate = join12(dir, "scaffold");
2361
+ try {
2362
+ if (statSync(join12(candidate, "rness.json")).isFile()) return candidate;
2363
+ } catch {
2364
+ }
2365
+ dir = dirname4(dir);
2366
+ }
2367
+ throw new Error("scaffold directory not found next to the @rness/cli package");
2368
+ }
2369
+
2370
+ // src/core/scaffold-copy.ts
2371
+ import { chmod as chmod2, mkdir as mkdir2, readFile as readFile7, stat as stat2, writeFile as writeFile2 } from "fs/promises";
2372
+ import { dirname as dirname5, join as join13 } from "path";
2373
+ var TOKENISED = /* @__PURE__ */ new Set(["package.json"]);
2374
+ async function copyScaffold(dest, tokens) {
2375
+ const source = scaffoldDir();
2376
+ for (const rel of SCAFFOLD_FILES) {
2377
+ if (rel === "rness.json") continue;
2378
+ const from = join13(source, ...rel.split("/"));
2379
+ const targetRel = rel === "_gitignore" ? ".gitignore" : rel;
2380
+ const to = join13(dest, ...targetRel.split("/"));
2381
+ await mkdir2(dirname5(to), { recursive: true });
2382
+ let content = await readFile7(from, "utf8");
2383
+ if (TOKENISED.has(rel)) {
2384
+ content = content.replaceAll("__RNESS_VERSION__", tokens.version).replaceAll("__RNESS_PM__", tokens.packageManager);
2385
+ }
2386
+ await writeFile2(to, content, "utf8");
2387
+ const mode = (await stat2(from)).mode & 511;
2388
+ if (mode & 73) await chmod2(to, mode);
2389
+ }
2390
+ }
2391
+
2392
+ // src/version.ts
2393
+ var VERSION = "0.5.3";
2394
+
2395
+ // src/commands/login.ts
2396
+ import { spawn as spawn3 } from "child_process";
2397
+ import { realpath } from "fs/promises";
2398
+
2399
+ // src/core/setup-git.ts
2335
2400
  import { execFile as execFile3 } from "child_process";
2336
- import { readFile as readFile7 } from "fs/promises";
2337
- import { basename as basename4, join as join12 } from "path";
2338
2401
  import { promisify as promisify3 } from "util";
2339
2402
  var execFileP3 = promisify3(execFile3);
2403
+ var KEY = "credential.https://github.com.helper";
2404
+ function helperValue(node, bin) {
2405
+ return `!'${node}' '${bin}' git-credential`;
2406
+ }
2407
+ var isOurs = (value) => /^!'[^']+' '[^']*rness[^']*' git-credential$/.test(value);
2408
+ async function config(args) {
2409
+ const { stdout } = await execFileP3("git", ["config", "--global", ...args]);
2410
+ return stdout;
2411
+ }
2412
+ async function values() {
2413
+ try {
2414
+ const out = await config(["--get-all", KEY]);
2415
+ return out.replace(/\n$/, "").split("\n");
2416
+ } catch {
2417
+ return [];
2418
+ }
2419
+ }
2420
+ function isStableInstall(bin) {
2421
+ return !/[\\/]_npx[\\/]/.test(bin);
2422
+ }
2423
+ async function setupGit(node, bin) {
2424
+ const ours = helperValue(node, bin);
2425
+ if ((await values()).includes(ours)) return false;
2426
+ await removeGitSetup();
2427
+ await config(["--add", KEY, ""]);
2428
+ await config(["--add", KEY, ours]);
2429
+ return true;
2430
+ }
2431
+ async function removeGitSetup() {
2432
+ const current = await values();
2433
+ if (!current.some(isOurs)) return false;
2434
+ const kept = current.filter(
2435
+ (value, i) => !isOurs(value) && !(value === "" && isOurs(current[i + 1] ?? ""))
2436
+ );
2437
+ await config(["--unset-all", KEY]);
2438
+ for (const value of kept) await config(["--add", KEY, value]);
2439
+ return true;
2440
+ }
2441
+
2442
+ // src/commands/login.ts
2443
+ function openInBrowser(url) {
2444
+ const [command, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
2445
+ try {
2446
+ const child = spawn3(command, args, { stdio: "ignore", detached: true });
2447
+ child.on("error", () => void 0);
2448
+ child.unref();
2449
+ } catch {
2450
+ }
2451
+ }
2452
+ async function offerSetupGit(opts, terminal, bin, ui) {
2453
+ if (opts.setupGit === false) return;
2454
+ if (!isStableInstall(bin)) {
2455
+ ui.hint(
2456
+ "install rness globally to let git use your login: npm i -g @rness/cli"
2457
+ );
2458
+ return;
2459
+ }
2460
+ if (opts.setupGit !== true) {
2461
+ if (!terminal.isTty()) return;
2462
+ const p = await terminal.prompts();
2463
+ const ok = await p.confirm({
2464
+ message: "Use rness to authenticate git over HTTPS for github.com?",
2465
+ initialValue: true
2466
+ });
2467
+ if (p.isCancel(ok) || ok !== true) return;
2468
+ }
2469
+ const changed = await setupGit(process.execPath, bin);
2470
+ ui.line(
2471
+ changed ? "updated" : "unchanged",
2472
+ "git: rness answers for https://github.com (rness logout undoes it)",
2473
+ "git now asks rness for your github.com login over HTTPS (rness logout undoes it)"
2474
+ );
2475
+ }
2476
+ async function loginCommand(opts, deps = {}) {
2477
+ const terminal = deps.terminal ?? defaultTerminal;
2478
+ const own = deps.ui === void 0;
2479
+ const ui = deps.ui ?? await makeUi(terminal);
2480
+ if (own) ui.intro("Log in to GitHub");
2481
+ try {
2482
+ const bin = deps.bin ?? await realpath(process.argv[1] ?? "").catch(() => "");
2483
+ const env = envToken();
2484
+ if (env !== null)
2485
+ ui.hint(`${env.source} is set and wins over a stored login`);
2486
+ const stored = await readAuth();
2487
+ if (stored !== null && await resolveToken() !== null) {
2488
+ ui.line(
2489
+ "logged in",
2490
+ `as ${stored.login} (github.com); rness logout to switch`
2491
+ );
2492
+ await offerSetupGit(opts, terminal, bin, ui);
2493
+ if (own) ui.outro("Nothing to do", "idle");
2494
+ return 0;
2495
+ }
2496
+ const code = await requestDeviceCode();
2497
+ if (ui.session)
2498
+ ui.line(
2499
+ "open",
2500
+ code.verificationUri,
2501
+ `Open ${code.verificationUri} and enter the code ${code.userCode}`
2502
+ );
2503
+ else {
2504
+ ui.line("open", code.verificationUri);
2505
+ ui.line("code", code.userCode);
2506
+ }
2507
+ if (terminal.isTty() && process.env["SSH_CONNECTION"] === void 0)
2508
+ (deps.open ?? openInBrowser)(code.verificationUri);
2509
+ if (!ui.session)
2510
+ ui.line("waiting", "for you to approve rness on github.com\u2026");
2511
+ const login = await ui.step(
2512
+ {
2513
+ doing: "waiting for you to approve rness on github.com",
2514
+ sentence: "Waiting for your approval on github.com",
2515
+ quiet: true
2516
+ },
2517
+ async () => {
2518
+ const tokens = await pollForToken(code, deps);
2519
+ const user = await getUser({
2520
+ token: tokens.accessToken,
2521
+ apiBase: opts.githubApi ?? DEFAULT_GITHUB_API
2522
+ });
2523
+ await writeAuth({ login: user.login, tokens });
2524
+ return user.login;
2525
+ },
2526
+ (name) => ["logged in", `as ${name} (github.com)`]
2527
+ );
2528
+ if (!ui.session) ui.line("logged in", `as ${login} (github.com)`);
2529
+ await offerSetupGit(opts, terminal, bin, ui);
2530
+ if (own) ui.outro(`You are logged in as ${login}`);
2531
+ return 0;
2532
+ } catch (e) {
2533
+ if (e instanceof LoginError) {
2534
+ ui.error(e.message);
2535
+ return 1;
2536
+ }
2537
+ return reportError(e);
2538
+ }
2539
+ }
2540
+ function revokeUrl() {
2541
+ return `https://github.com/settings/connections/applications/${clientId()}`;
2542
+ }
2543
+
2544
+ // src/commands/create.ts
2545
+ import { mkdir as mkdir3, mkdtemp, readdir as readdir2, rename as rename2, rm as rm4, stat as stat3 } from "fs/promises";
2546
+ import { tmpdir } from "os";
2547
+ import { dirname as dirname6, join as join15, relative as relative2, resolve as resolve3 } from "path";
2548
+
2549
+ // src/core/pinned.ts
2550
+ import { execFile as execFile4 } from "child_process";
2551
+ import { readFile as readFile8 } from "fs/promises";
2552
+ import { basename as basename4, join as join14 } from "path";
2553
+ import { promisify as promisify4 } from "util";
2554
+ var execFileP4 = promisify4(execFile4);
2340
2555
  var PACKAGE = "@rness/cli";
2341
2556
  var EXACT_VERSION = /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/;
2342
2557
  function compareVersions(a, b) {
@@ -2359,7 +2574,7 @@ function compareVersions(a, b) {
2359
2574
  async function readPackageJson(rnessDir) {
2360
2575
  try {
2361
2576
  const parsed = JSON.parse(
2362
- await readFile7(join12(rnessDir, "package.json"), "utf8")
2577
+ await readFile8(join14(rnessDir, "package.json"), "utf8")
2363
2578
  );
2364
2579
  return parsed !== null && typeof parsed === "object" ? parsed : null;
2365
2580
  } catch {
@@ -2378,8 +2593,8 @@ async function readPin(rnessDir) {
2378
2593
  return null;
2379
2594
  }
2380
2595
  async function writePin(rnessDir, from, to) {
2381
- const file = join12(rnessDir, "package.json");
2382
- const text = await readFile7(file, "utf8");
2596
+ const file = join14(rnessDir, "package.json");
2597
+ const text = await readFile8(file, "utf8");
2383
2598
  const entry = new RegExp(
2384
2599
  `("${PACKAGE}"\\s*:\\s*")${from.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(")`
2385
2600
  );
@@ -2401,12 +2616,12 @@ async function workspacePackageManager(rnessDir) {
2401
2616
  if (isPackageManager(name)) return name;
2402
2617
  }
2403
2618
  for (const [lockfile, pm] of LOCKFILES)
2404
- if (await exists(join12(rnessDir, lockfile))) return pm;
2619
+ if (await exists(join14(rnessDir, lockfile))) return pm;
2405
2620
  return "npm";
2406
2621
  }
2407
2622
  async function hasLockfile(rnessDir, pm) {
2408
2623
  for (const [lockfile, owner] of LOCKFILES)
2409
- if (owner === pm && await exists(join12(rnessDir, lockfile))) return true;
2624
+ if (owner === pm && await exists(join14(rnessDir, lockfile))) return true;
2410
2625
  return false;
2411
2626
  }
2412
2627
  async function pinDrift(rnessDir) {
@@ -2462,9 +2677,9 @@ async function ensureInstalled(rnessDir, opts = {}) {
2462
2677
  }
2463
2678
  }
2464
2679
  async function runPinnedSync(root) {
2465
- const installed = await readPinnedCli(join12(root, ".rness"));
2680
+ const installed = await readPinnedCli(join14(root, ".rness"));
2466
2681
  if (installed === null) return null;
2467
- const pinned = join12(installed.dir, ...installed.bin.split("/"));
2682
+ const pinned = join14(installed.dir, ...installed.bin.split("/"));
2468
2683
  if (!await exists(pinned))
2469
2684
  return {
2470
2685
  code: 1,
@@ -2473,7 +2688,7 @@ async function runPinnedSync(root) {
2473
2688
  `
2474
2689
  };
2475
2690
  try {
2476
- const { stdout, stderr } = await execFileP3(
2691
+ const { stdout, stderr } = await execFileP4(
2477
2692
  process.execPath,
2478
2693
  [pinned, "sync", "--yes"],
2479
2694
  {
@@ -2526,7 +2741,7 @@ function syncOutcome(result, opts = {}) {
2526
2741
  };
2527
2742
  }
2528
2743
  async function syncPinned(root, shown, fallback) {
2529
- const rnessDir = join12(root, ".rness");
2744
+ const rnessDir = join14(root, ".rness");
2530
2745
  const installed = await readPinnedCli(rnessDir);
2531
2746
  if (installed === null) {
2532
2747
  if (fallback !== void 0) return fallback();
@@ -2536,7 +2751,7 @@ async function syncPinned(root, shown, fallback) {
2536
2751
  );
2537
2752
  return 1;
2538
2753
  }
2539
- const pinned = join12(installed.dir, ...installed.bin.split("/"));
2754
+ const pinned = join14(installed.dir, ...installed.bin.split("/"));
2540
2755
  if (!await exists(pinned)) {
2541
2756
  process.stderr.write(
2542
2757
  `@rness/cli in ${shown}/.rness is not installed correctly (missing ${installed.bin}); reinstall in .rness/
@@ -2545,7 +2760,7 @@ async function syncPinned(root, shown, fallback) {
2545
2760
  return 1;
2546
2761
  }
2547
2762
  try {
2548
- const { stdout, stderr } = await execFileP3(
2763
+ const { stdout, stderr } = await execFileP4(
2549
2764
  process.execPath,
2550
2765
  [pinned, "sync", "--yes"],
2551
2766
  {
@@ -2569,221 +2784,6 @@ async function syncPinned(root, shown, fallback) {
2569
2784
  }
2570
2785
  }
2571
2786
 
2572
- // src/core/scaffold.ts
2573
- import { statSync } from "fs";
2574
- import { dirname as dirname4, join as join13 } from "path";
2575
- import { fileURLToPath } from "url";
2576
- var SCAFFOLD_FILES = [
2577
- "AGENTS.md",
2578
- "CONVENTIONS.md",
2579
- "README.md",
2580
- "WORKSPACE.md",
2581
- "rness.json",
2582
- "package.json",
2583
- "_gitignore",
2584
- ".githooks/pre-commit",
2585
- ".github/workflows/validate.yml",
2586
- ".github/dependabot.yml",
2587
- "pnpm-workspace.yaml",
2588
- "adr/0000-template.md",
2589
- "standards/.gitkeep",
2590
- "specs/.gitkeep",
2591
- "plans/.gitkeep",
2592
- "skills/.gitkeep",
2593
- "docs/.gitkeep"
2594
- ];
2595
- function scaffoldDir() {
2596
- let dir = dirname4(fileURLToPath(import.meta.url));
2597
- for (let i = 0; i < 4; i += 1) {
2598
- const candidate = join13(dir, "scaffold");
2599
- try {
2600
- if (statSync(join13(candidate, "rness.json")).isFile()) return candidate;
2601
- } catch {
2602
- }
2603
- dir = dirname4(dir);
2604
- }
2605
- throw new Error("scaffold directory not found next to the @rness/cli package");
2606
- }
2607
-
2608
- // src/core/scaffold-copy.ts
2609
- import { chmod as chmod2, mkdir as mkdir2, readFile as readFile8, stat as stat2, writeFile as writeFile2 } from "fs/promises";
2610
- import { dirname as dirname5, join as join14 } from "path";
2611
- var TOKENISED = /* @__PURE__ */ new Set(["package.json"]);
2612
- async function copyScaffold(dest, tokens) {
2613
- const source = scaffoldDir();
2614
- for (const rel of SCAFFOLD_FILES) {
2615
- if (rel === "rness.json") continue;
2616
- const from = join14(source, ...rel.split("/"));
2617
- const targetRel = rel === "_gitignore" ? ".gitignore" : rel;
2618
- const to = join14(dest, ...targetRel.split("/"));
2619
- await mkdir2(dirname5(to), { recursive: true });
2620
- let content = await readFile8(from, "utf8");
2621
- if (TOKENISED.has(rel)) {
2622
- content = content.replaceAll("__RNESS_VERSION__", tokens.version).replaceAll("__RNESS_PM__", tokens.packageManager);
2623
- }
2624
- await writeFile2(to, content, "utf8");
2625
- const mode = (await stat2(from)).mode & 511;
2626
- if (mode & 73) await chmod2(to, mode);
2627
- }
2628
- }
2629
-
2630
- // src/version.ts
2631
- var VERSION = "0.5.2";
2632
-
2633
- // src/commands/login.ts
2634
- import { spawn as spawn3 } from "child_process";
2635
- import { realpath } from "fs/promises";
2636
-
2637
- // src/core/setup-git.ts
2638
- import { execFile as execFile4 } from "child_process";
2639
- import { promisify as promisify4 } from "util";
2640
- var execFileP4 = promisify4(execFile4);
2641
- var KEY = "credential.https://github.com.helper";
2642
- function helperValue(node, bin) {
2643
- return `!'${node}' '${bin}' git-credential`;
2644
- }
2645
- var isOurs = (value) => /^!'[^']+' '[^']*rness[^']*' git-credential$/.test(value);
2646
- async function config(args) {
2647
- const { stdout } = await execFileP4("git", ["config", "--global", ...args]);
2648
- return stdout;
2649
- }
2650
- async function values() {
2651
- try {
2652
- const out = await config(["--get-all", KEY]);
2653
- return out.replace(/\n$/, "").split("\n");
2654
- } catch {
2655
- return [];
2656
- }
2657
- }
2658
- function isStableInstall(bin) {
2659
- return !/[\\/]_npx[\\/]/.test(bin);
2660
- }
2661
- async function setupGit(node, bin) {
2662
- const ours = helperValue(node, bin);
2663
- if ((await values()).includes(ours)) return false;
2664
- await removeGitSetup();
2665
- await config(["--add", KEY, ""]);
2666
- await config(["--add", KEY, ours]);
2667
- return true;
2668
- }
2669
- async function removeGitSetup() {
2670
- const current = await values();
2671
- if (!current.some(isOurs)) return false;
2672
- const kept = current.filter(
2673
- (value, i) => !isOurs(value) && !(value === "" && isOurs(current[i + 1] ?? ""))
2674
- );
2675
- await config(["--unset-all", KEY]);
2676
- for (const value of kept) await config(["--add", KEY, value]);
2677
- return true;
2678
- }
2679
-
2680
- // src/commands/login.ts
2681
- function openInBrowser(url) {
2682
- const [command, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
2683
- try {
2684
- const child = spawn3(command, args, { stdio: "ignore", detached: true });
2685
- child.on("error", () => void 0);
2686
- child.unref();
2687
- } catch {
2688
- }
2689
- }
2690
- async function offerSetupGit(opts, terminal, bin, ui) {
2691
- if (opts.setupGit === false) return;
2692
- if (!isStableInstall(bin)) {
2693
- ui.hint(
2694
- "install rness globally to let git use your login: npm i -g @rness/cli"
2695
- );
2696
- return;
2697
- }
2698
- if (opts.setupGit !== true) {
2699
- if (!terminal.isTty()) return;
2700
- const p = await terminal.prompts();
2701
- const ok = await p.confirm({
2702
- message: "Use rness to authenticate git over HTTPS for github.com?",
2703
- initialValue: true
2704
- });
2705
- if (p.isCancel(ok) || ok !== true) return;
2706
- }
2707
- const changed = await setupGit(process.execPath, bin);
2708
- ui.line(
2709
- changed ? "updated" : "unchanged",
2710
- "git: rness answers for https://github.com (rness logout undoes it)",
2711
- "git now asks rness for your github.com login over HTTPS (rness logout undoes it)"
2712
- );
2713
- }
2714
- async function loginCommand(opts, deps = {}) {
2715
- const terminal = deps.terminal ?? defaultTerminal;
2716
- const own = deps.ui === void 0;
2717
- const ui = deps.ui ?? await makeUi(terminal);
2718
- if (own) ui.intro("Log in to GitHub");
2719
- try {
2720
- const bin = deps.bin ?? await realpath(process.argv[1] ?? "").catch(() => "");
2721
- const env = envToken();
2722
- if (env !== null)
2723
- ui.hint(`${env.source} is set and wins over a stored login`);
2724
- const stored = await readAuth();
2725
- if (stored !== null && await resolveToken() !== null) {
2726
- ui.line(
2727
- "logged in",
2728
- `as ${stored.login} (github.com); rness logout to switch`
2729
- );
2730
- await offerSetupGit(opts, terminal, bin, ui);
2731
- if (own) ui.outro("Nothing to do", "idle");
2732
- return 0;
2733
- }
2734
- const code = await requestDeviceCode();
2735
- if (ui.session)
2736
- ui.line(
2737
- "open",
2738
- code.verificationUri,
2739
- `Open ${code.verificationUri} and enter the code ${code.userCode}`
2740
- );
2741
- else {
2742
- ui.line("open", code.verificationUri);
2743
- ui.line("code", code.userCode);
2744
- }
2745
- if (terminal.isTty() && process.env["SSH_CONNECTION"] === void 0)
2746
- (deps.open ?? openInBrowser)(code.verificationUri);
2747
- if (!ui.session)
2748
- ui.line("waiting", "for you to approve rness on github.com\u2026");
2749
- const login = await ui.step(
2750
- {
2751
- doing: "waiting for you to approve rness on github.com",
2752
- sentence: "Waiting for your approval on github.com",
2753
- quiet: true
2754
- },
2755
- async () => {
2756
- const tokens = await pollForToken(code, deps);
2757
- const user = await getUser({
2758
- token: tokens.accessToken,
2759
- apiBase: opts.githubApi ?? DEFAULT_GITHUB_API
2760
- });
2761
- await writeAuth({ login: user.login, tokens });
2762
- return user.login;
2763
- },
2764
- (name) => ["logged in", `as ${name} (github.com)`]
2765
- );
2766
- if (!ui.session) ui.line("logged in", `as ${login} (github.com)`);
2767
- await offerSetupGit(opts, terminal, bin, ui);
2768
- if (own) ui.outro(`You are logged in as ${login}`);
2769
- return 0;
2770
- } catch (e) {
2771
- if (e instanceof LoginError) {
2772
- ui.error(e.message);
2773
- return 1;
2774
- }
2775
- return reportError(e);
2776
- }
2777
- }
2778
- function revokeUrl() {
2779
- return `https://github.com/settings/connections/applications/${clientId()}`;
2780
- }
2781
-
2782
- // src/commands/create.ts
2783
- import { mkdir as mkdir3, mkdtemp, readdir as readdir2, rename as rename2, rm as rm4, stat as stat3 } from "fs/promises";
2784
- import { tmpdir } from "os";
2785
- import { dirname as dirname6, join as join15, relative as relative2, resolve as resolve3 } from "path";
2786
-
2787
2787
  // src/core/sync-blocks.ts
2788
2788
  async function syncBlocks(ui, root, shown, inPlace, sshWorks) {
2789
2789
  if (!ui.session)
@@ -3967,6 +3967,51 @@ async function run(argv) {
3967
3967
  return state.code;
3968
3968
  }
3969
3969
 
3970
+ // src/core/catch-up.ts
3971
+ import { spawnSync } from "child_process";
3972
+ var OWN_COMMANDS = [
3973
+ "create",
3974
+ "upgrade",
3975
+ "update",
3976
+ "login",
3977
+ "logout",
3978
+ "git-credential"
3979
+ ];
3980
+ var CATCH_UP_DONE = "RNESS_CATCH_UP_DONE";
3981
+ async function catchUp(argv, deps = {}) {
3982
+ const env = deps.env ?? process.env;
3983
+ const cwd = deps.cwd ?? process.cwd();
3984
+ const command = argv[0];
3985
+ if (command === void 0 || command.startsWith("-") || OWN_COMMANDS.includes(command) || env["RNESS_NO_DELEGATE"] === "1" || env[CATCH_UP_DONE] === "1")
3986
+ return null;
3987
+ const ws = await findWorkspace(cwd).catch(() => null);
3988
+ if (ws === null) return null;
3989
+ env[CATCH_UP_DONE] = "1";
3990
+ const stderr = deps.stderr ?? ((text) => void process.stderr.write(text));
3991
+ const outcome = await ensureInstalled(ws.rnessDir, {
3992
+ env,
3993
+ announce: (pin) => stderr(`installing @rness/cli ${pin} in .rness\u2026
3994
+ `),
3995
+ ...deps.install === void 0 ? {} : { install: deps.install }
3996
+ });
3997
+ if (outcome === null) return null;
3998
+ if (!outcome.installed) {
3999
+ const warning = await driftWarning(cwd);
4000
+ if (warning !== null) stderr(`${warning}
4001
+ `);
4002
+ return null;
4003
+ }
4004
+ if (await pinDrift(ws.rnessDir) !== null) return null;
4005
+ const bin = await pinnedBinPath(ws.rnessDir);
4006
+ if (bin === null) return null;
4007
+ const spawn4 = deps.spawn ?? ((file, args, dir) => spawnSync(process.execPath, [file, ...args], {
4008
+ cwd: dir,
4009
+ env,
4010
+ stdio: "inherit"
4011
+ }).status ?? 1);
4012
+ return spawn4(bin, argv, cwd);
4013
+ }
4014
+
3970
4015
  export {
3971
4016
  exists,
3972
4017
  readOrNull,
@@ -4013,16 +4058,12 @@ export {
4013
4058
  addCommand,
4014
4059
  renderMarkdown,
4015
4060
  contextCommand,
4016
- pinnedBinPath,
4017
4061
  findDelegate,
4018
4062
  PACKAGE_MANAGERS,
4019
4063
  isPackageManager,
4020
4064
  detectPackageManager,
4021
4065
  packageManagerVersion,
4022
4066
  installDependencies,
4023
- pinDrift,
4024
- driftWarning,
4025
- ensureInstalled,
4026
4067
  SCAFFOLD_FILES,
4027
4068
  scaffoldDir,
4028
4069
  copyScaffold,
@@ -4035,6 +4076,8 @@ export {
4035
4076
  STATUSES,
4036
4077
  checkContract,
4037
4078
  validateCommand,
4038
- run
4079
+ run,
4080
+ OWN_COMMANDS,
4081
+ catchUp
4039
4082
  };
4040
- //# sourceMappingURL=chunk-P4YG6P7I.js.map
4083
+ //# sourceMappingURL=chunk-CQ6YD63L.js.map