@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.
- package/README.md +26 -1
- package/dist/bin/rness.js +6 -40
- package/dist/bin/rness.js.map +1 -1
- package/dist/{chunk-P4YG6P7I.js → chunk-CQ6YD63L.js} +278 -235
- package/dist/chunk-CQ6YD63L.js.map +1 -0
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scaffold/.github/dependabot.yml +8 -0
- package/dist/chunk-P4YG6P7I.js.map +0 -1
|
@@ -2331,12 +2331,227 @@ async function installDependencies(pm, dir, opts = {}) {
|
|
|
2331
2331
|
}
|
|
2332
2332
|
}
|
|
2333
2333
|
|
|
2334
|
-
// src/core/
|
|
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
|
|
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 =
|
|
2382
|
-
const text = await
|
|
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(
|
|
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(
|
|
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(
|
|
2680
|
+
const installed = await readPinnedCli(join14(root, ".rness"));
|
|
2466
2681
|
if (installed === null) return null;
|
|
2467
|
-
const pinned =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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-
|
|
4083
|
+
//# sourceMappingURL=chunk-CQ6YD63L.js.map
|