@rness/cli 0.6.0 → 0.6.2

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.
@@ -45,6 +45,75 @@ async function writeFileAtomic(p, text) {
45
45
  }
46
46
  }
47
47
 
48
+ // src/core/pm.ts
49
+ import { execFile } from "child_process";
50
+ import { promisify } from "util";
51
+ var execFileP = promisify(execFile);
52
+ var PACKAGE_MANAGERS = [
53
+ "npm",
54
+ "pnpm",
55
+ "yarn",
56
+ "bun"
57
+ ];
58
+ function isPackageManager(value) {
59
+ return PACKAGE_MANAGERS.includes(value);
60
+ }
61
+ function detectPackageManager(userAgent = process.env["npm_config_user_agent"] ?? "") {
62
+ const name = userAgent.split("/")[0] ?? "";
63
+ return isPackageManager(name) ? name : "npm";
64
+ }
65
+ function firstLine(text) {
66
+ return text.split("\n").find((l) => l.trim() !== "")?.trim() ?? "unknown error";
67
+ }
68
+ async function packageManagerVersion(pm) {
69
+ try {
70
+ const { stdout } = await execFileP(pm, ["--version"]);
71
+ return stdout.trim();
72
+ } catch (e) {
73
+ throw new Error(`${pm} is not available on PATH`, { cause: e });
74
+ }
75
+ }
76
+ function rnessRunner(pm, version) {
77
+ if (pm === "pnpm") return "pnpm dlx @rness/cli";
78
+ if (pm === "bun") return "bunx @rness/cli";
79
+ if (pm === "yarn" && Number(version?.split(".")[0]) >= 2)
80
+ return "yarn dlx @rness/cli";
81
+ return "npx @rness/cli";
82
+ }
83
+ function rnessCommand(env = process.env) {
84
+ const agent = env["npm_config_user_agent"] ?? "";
85
+ if (agent === "") return "rness";
86
+ const pm = detectPackageManager(agent);
87
+ const [name, version] = (agent.split(" ")[0] ?? "").split("/");
88
+ return rnessRunner(pm, name === pm ? version ?? null : null);
89
+ }
90
+ var BARE_NPM_CODE = /^npm (error|ERR!) code \S+$/;
91
+ function installErrorLine(stderr) {
92
+ const lines = stderr.split("\n").map((l) => l.trim()).filter((l) => l !== "");
93
+ return lines.find((l) => !BARE_NPM_CODE.test(l)) ?? firstLine(stderr);
94
+ }
95
+ var FROZEN = {
96
+ npm: ["ci"],
97
+ pnpm: ["install", "--frozen-lockfile"],
98
+ yarn: ["install", "--immutable"],
99
+ bun: ["install", "--frozen-lockfile"]
100
+ };
101
+ function frozenArgs(pm) {
102
+ return [...FROZEN[pm]];
103
+ }
104
+ async function installDependencies(pm, dir, opts = {}) {
105
+ const args = opts.frozen === true ? frozenArgs(pm) : ["install"];
106
+ try {
107
+ await execFileP(pm, args, { cwd: dir, maxBuffer: 16 * 1024 * 1024 });
108
+ } catch (e) {
109
+ const err = e;
110
+ throw new Error(
111
+ `${pm} ${args.join(" ")} failed in ${dir}: ${installErrorLine(err.stderr ?? err.message)}`,
112
+ { cause: e }
113
+ );
114
+ }
115
+ }
116
+
48
117
  // src/core/auth.ts
49
118
  import { chmod, mkdir, open, readFile as readFile2, rm as rm2, stat } from "fs/promises";
50
119
  import { homedir } from "os";
@@ -298,7 +367,7 @@ async function resolveToken(deps = {}) {
298
367
  await clearAuth();
299
368
  (deps.notify ?? ((l) => process.stderr.write(`${l}
300
369
  `)))(
301
- "your GitHub login expired; run rness login"
370
+ `your GitHub login expired; run ${rnessCommand()} login`
302
371
  );
303
372
  return null;
304
373
  }
@@ -313,7 +382,7 @@ async function resolveToken(deps = {}) {
313
382
  var DEFAULT_GITHUB_API = "https://api.github.com";
314
383
  var MAX_PAGES = 50;
315
384
  var PER_PAGE = 100;
316
- var ADD_LATER = "; add repositories later with rness add <repo>";
385
+ var addLater = () => `; add repositories later with ${rnessCommand()} add <repo>`;
317
386
  var NEXT = /<[^>]*>\s*;\s*rel="next"/;
318
387
  function isRepository(value) {
319
388
  if (value === null || typeof value !== "object") return false;
@@ -357,12 +426,12 @@ function httpError(page, path) {
357
426
  return new Error("GitHub rejected the token (401)", { cause });
358
427
  if (page.status === 429 || page.status === 403 && (page.headers.get("x-ratelimit-remaining") === "0" || page.headers.has("retry-after"))) {
359
428
  return new Error(
360
- "GitHub API rate limit reached; set GITHUB_TOKEN or add repositories later with rness add",
429
+ `GitHub API rate limit reached; set GITHUB_TOKEN or add repositories later with ${rnessCommand()} add`,
361
430
  { cause }
362
431
  );
363
432
  }
364
433
  return new Error(
365
- `GitHub API answered ${page.status} for ${path}${ADD_LATER}`,
434
+ `GitHub API answered ${page.status} for ${path}${addLater()}`,
366
435
  { cause }
367
436
  );
368
437
  }
@@ -403,7 +472,7 @@ async function listRepositories(owner, options) {
403
472
  page = await getPage(url(kind, n), headers, timeoutMs);
404
473
  if (page.status === 404) {
405
474
  throw new Error(
406
- `GitHub has no organization or user named "${owner}" (or it is not visible to you)${ADD_LATER}`,
475
+ `GitHub has no organization or user named "${owner}" (or it is not visible to you)${addLater()}`,
407
476
  { cause: { status: 404, path: kind.path } }
408
477
  );
409
478
  }
@@ -599,10 +668,10 @@ async function githubProvider(apiBase) {
599
668
  import { spawn } from "child_process";
600
669
 
601
670
  // src/core/git.ts
602
- import { execFile } from "child_process";
671
+ import { execFile as execFile2 } from "child_process";
603
672
  import { dirname as dirname2, resolve } from "path";
604
- import { promisify } from "util";
605
- var execFileP = promisify(execFile);
673
+ import { promisify as promisify2 } from "util";
674
+ var execFileP2 = promisify2(execFile2);
606
675
  var ENV_HELPER = '!f() { test "$1" = get && printf "username=%s\\npassword=%s\\n" "$RNESS_GIT_USERNAME" "$RNESS_GIT_TOKEN"; }; f';
607
676
  function withCredentials(credentials) {
608
677
  if (credentials === null || credentials === void 0)
@@ -618,7 +687,7 @@ function withCredentials(credentials) {
618
687
  async function git(args, cwd, credentials) {
619
688
  const auth = withCredentials(credentials);
620
689
  try {
621
- const { stdout } = await execFileP("git", [...auth.args, ...args], {
690
+ const { stdout } = await execFileP2("git", [...auth.args, ...args], {
622
691
  ...cwd === void 0 ? {} : { cwd },
623
692
  env: {
624
693
  ...process.env,
@@ -709,7 +778,7 @@ var NOT_FOUND = [
709
778
  /repository .*not found/i,
710
779
  /does not appear to be a git repository/i
711
780
  ];
712
- function firstLine(text) {
781
+ function firstLine2(text) {
713
782
  return text.split("\n").find((l) => l.trim() !== "")?.trim() ?? "unknown error";
714
783
  }
715
784
  function classifyProbe(url, exitCode, stderr) {
@@ -717,10 +786,10 @@ function classifyProbe(url, exitCode, stderr) {
717
786
  if (AUTH.some((r) => r.test(stderr)))
718
787
  return {
719
788
  kind: "error",
720
- message: `cannot access ${url}: ${firstLine(stderr)}`
789
+ message: `cannot access ${url}: ${firstLine2(stderr)}`
721
790
  };
722
791
  if (NOT_FOUND.some((r) => r.test(stderr))) return { kind: "not-found" };
723
- return { kind: "error", message: `cannot reach ${url}: ${firstLine(stderr)}` };
792
+ return { kind: "error", message: `cannot reach ${url}: ${firstLine2(stderr)}` };
724
793
  }
725
794
  var STDERR_FLUSH_MS = 200;
726
795
  async function probeRemote(url, timeoutMs = 6e4, credentials) {
@@ -1149,7 +1218,7 @@ var GREETING = /^Hi ([^!\s]+)! You've successfully authenticated/m;
1149
1218
  function parseSshGreeting(stderr) {
1150
1219
  return GREETING.exec(stderr)?.[1] ?? null;
1151
1220
  }
1152
- function firstLine2(text) {
1221
+ function firstLine3(text) {
1153
1222
  return text.split("\n").find((l) => l.trim() !== "")?.trim() ?? null;
1154
1223
  }
1155
1224
  var STDERR_FLUSH_MS2 = 200;
@@ -1189,7 +1258,7 @@ async function detectGithubSsh(opts) {
1189
1258
  settle(
1190
1259
  login !== null ? { ok: true, login } : {
1191
1260
  ok: false,
1192
- reason: firstLine2(stderr2) ?? `ssh exited with code ${code ?? "?"}`
1261
+ reason: firstLine3(stderr2) ?? `ssh exited with code ${code ?? "?"}`
1193
1262
  }
1194
1263
  );
1195
1264
  };
@@ -1254,7 +1323,7 @@ var INSTEAD_OF_LINES = [
1254
1323
  ' git config --global url."https://github.com/".insteadOf git@github.com:'
1255
1324
  ];
1256
1325
  function httpsFlagLine(spec) {
1257
- return `or clone this repository over HTTPS: rness add ${spec} --https`;
1326
+ return `or clone this repository over HTTPS: ${rnessCommand()} add ${spec} --https`;
1258
1327
  }
1259
1328
 
1260
1329
  // src/core/workspace.ts
@@ -1568,6 +1637,17 @@ function mergeBlock(existing, block) {
1568
1637
  }
1569
1638
  return { ok: true, text, changed: text !== existing };
1570
1639
  }
1640
+ var POINTER = "@AGENTS.md";
1641
+ function claudeMdAtRoot(existing, block) {
1642
+ if (existing === null) return mergeBlock(null, block);
1643
+ const lines = existing.split(/\r?\n/);
1644
+ if (!lines.some((l) => l.trim() === POINTER))
1645
+ return mergeBlock(existing, block);
1646
+ const eol = existing.includes("\r\n") ? "\r\n" : "\n";
1647
+ const rest = lines.filter((l) => l.trim() !== POINTER).join(eol);
1648
+ const merged = mergeBlock(rest.trim() === "" ? null : rest, block);
1649
+ return merged.ok ? { ...merged, changed: merged.text !== existing } : merged;
1650
+ }
1571
1651
  async function ensureClaudeMd(dir) {
1572
1652
  const file = join8(dir, "CLAUDE.md");
1573
1653
  if (await isSymlink(file)) return "unchanged";
@@ -1780,6 +1860,18 @@ function targetsOf(manifest, root, only) {
1780
1860
  }
1781
1861
  return targets;
1782
1862
  }
1863
+ async function syncBlockFile(file, block, check, rootClaudeMd = false) {
1864
+ const existing = await readOrNull(file);
1865
+ const existingLines = existing === null ? [] : existing.split(/\r?\n/);
1866
+ const span = findBlock(existingLines);
1867
+ const current = span.kind === "one" && isCurrentBlock(existingLines.slice(span.begin, span.end + 1), block.hash) && !(rootClaudeMd && existingLines.some((l) => l.trim() === "@AGENTS.md"));
1868
+ const merged = current ? { ok: true, text: existing ?? "", changed: false } : rootClaudeMd ? claudeMdAtRoot(existing, block.text) : mergeBlock(existing, block.text);
1869
+ if (!merged.ok) return { error: merged.error };
1870
+ if (!merged.changed) return "unchanged";
1871
+ if (check) return "stale";
1872
+ await writeFileAtomic(file, merged.text);
1873
+ return "updated";
1874
+ }
1783
1875
  var SELECT_ALL = "*";
1784
1876
  async function askWhatToSync(input) {
1785
1877
  if (!input.terminal.isTty()) {
@@ -1916,7 +2008,7 @@ async function syncCommand(opts, deps = {}) {
1916
2008
  }
1917
2009
  if (notCloned.size > 0)
1918
2010
  lines.push(
1919
- `not cloned: ${[...notCloned].join(", ")} (rness add <name>, or rness sync --all)`
2011
+ `not cloned: ${[...notCloned].join(", ")} (${rnessCommand()} add <name>, or ${rnessCommand()} sync --all)`
1920
2012
  );
1921
2013
  const scoped = new Set(
1922
2014
  Object.values(manifest.scopes).map((s) => s.path.split("/")[1])
@@ -1926,7 +2018,7 @@ async function syncCommand(opts, deps = {}) {
1926
2018
  );
1927
2019
  if (undeclared.length > 0)
1928
2020
  lines.push(
1929
- `not in rness.json: ${undeclared.join(", ")} (rness add <name> declares it)`
2021
+ `not in rness.json: ${undeclared.join(", ")} (${rnessCommand()} add <name> declares it)`
1930
2022
  );
1931
2023
  if (!await exists(join9(ws.root, "org"))) {
1932
2024
  lines.push(["skipped", "blocks (no org/ directory here)"]);
@@ -1939,10 +2031,11 @@ async function syncCommand(opts, deps = {}) {
1939
2031
  lines.push(["skipped", `${t.label} (directory not present)`]);
1940
2032
  continue;
1941
2033
  }
1942
- const linked = await Promise.all(
2034
+ const [agentsLinked, claudeLinked] = await Promise.all(
1943
2035
  MANAGED_FILES.map((f) => isSymlink(join9(t.dir, f)))
1944
2036
  );
1945
- if (linked.includes(true)) {
2037
+ const atRoot = t.scope === null;
2038
+ if (!atRoot && (agentsLinked === true || claudeLinked === true)) {
1946
2039
  lines.push(["skipped", `${t.label} (symlink)`]);
1947
2040
  continue;
1948
2041
  }
@@ -1962,35 +2055,37 @@ async function syncCommand(opts, deps = {}) {
1962
2055
  `${t.label}: block is ${Math.round(block.bytes / 1024)} KB (over 32 KB)`
1963
2056
  );
1964
2057
  }
1965
- const file = join9(t.dir, "AGENTS.md");
1966
- const existing = await readOrNull(file);
1967
- const existingLines = existing === null ? [] : existing.split(/\r?\n/);
1968
- const span = findBlock(existingLines);
1969
- const current = span.kind === "one" && isCurrentBlock(
1970
- existingLines.slice(span.begin, span.end + 1),
1971
- block.hash
1972
- );
1973
- const merged = current ? { ok: true, text: existing ?? "", changed: false } : mergeBlock(existing, block.text);
1974
- if (!merged.ok) {
1975
- problems.push(`${t.label}: ${merged.error}`);
2058
+ const agents = agentsLinked === true ? "skipped" : await syncBlockFile(join9(t.dir, "AGENTS.md"), block, check);
2059
+ if (typeof agents === "object") {
2060
+ problems.push(`${t.label}: ${agents.error}`);
1976
2061
  continue;
1977
2062
  }
1978
- if (!merged.changed) {
1979
- lines.push(["unchanged", `${t.label}`]);
2063
+ lines.push(
2064
+ agents === "skipped" ? ["skipped", `${t.label} (symlink)`] : [agents, t.label]
2065
+ );
2066
+ if (agents === "stale") differences += 1;
2067
+ if (!atRoot) {
1980
2068
  if (!check) await ensureClaudeMd(t.dir);
1981
2069
  continue;
1982
2070
  }
1983
- if (check) {
1984
- lines.push(["stale", `${t.label}`]);
1985
- differences += 1;
2071
+ if (claudeLinked === true) continue;
2072
+ const claude = await syncBlockFile(
2073
+ join9(t.dir, "CLAUDE.md"),
2074
+ block,
2075
+ check,
2076
+ true
2077
+ );
2078
+ if (typeof claude === "object") {
2079
+ problems.push(`CLAUDE.md: ${claude.error}`);
1986
2080
  continue;
1987
2081
  }
1988
- await writeFileAtomic(file, merged.text);
1989
- await ensureClaudeMd(t.dir);
1990
- lines.push(["updated", `${t.label}`]);
2082
+ if (claude === "stale") differences += 1;
2083
+ if (claude !== agents) lines.push([claude, "CLAUDE.md"]);
1991
2084
  }
1992
2085
  if (check && differences > 0)
1993
- problems.push(`${differences} block(s) out of date \u2014 run rness sync`);
2086
+ problems.push(
2087
+ `${differences} block(s) out of date \u2014 run ${rnessCommand()} sync`
2088
+ );
1994
2089
  }
1995
2090
  return problems.length > 0 ? 1 : 0;
1996
2091
  } finally {
@@ -2230,7 +2325,7 @@ async function contextCommand(opts) {
2230
2325
  }
2231
2326
 
2232
2327
  // src/version.ts
2233
- var VERSION = "0.6.0";
2328
+ var VERSION = "0.6.2";
2234
2329
 
2235
2330
  // src/core/delegate.ts
2236
2331
  import { readFile as readFile6 } from "fs/promises";
@@ -2279,72 +2374,6 @@ async function findDelegate(cwd, ownVersion) {
2279
2374
  return { entry: join11(pinned.dir, "dist", "index.js"), version, root };
2280
2375
  }
2281
2376
 
2282
- // src/core/pm.ts
2283
- import { execFile as execFile2 } from "child_process";
2284
- import { promisify as promisify2 } from "util";
2285
- var execFileP2 = promisify2(execFile2);
2286
- var PACKAGE_MANAGERS = [
2287
- "npm",
2288
- "pnpm",
2289
- "yarn",
2290
- "bun"
2291
- ];
2292
- function isPackageManager(value) {
2293
- return PACKAGE_MANAGERS.includes(value);
2294
- }
2295
- function detectPackageManager(userAgent = process.env["npm_config_user_agent"] ?? "") {
2296
- const name = userAgent.split("/")[0] ?? "";
2297
- return isPackageManager(name) ? name : "npm";
2298
- }
2299
- function firstLine3(text) {
2300
- return text.split("\n").find((l) => l.trim() !== "")?.trim() ?? "unknown error";
2301
- }
2302
- async function packageManagerVersion(pm) {
2303
- try {
2304
- const { stdout } = await execFileP2(pm, ["--version"]);
2305
- return stdout.trim();
2306
- } catch (e) {
2307
- throw new Error(`${pm} is not available on PATH`, { cause: e });
2308
- }
2309
- }
2310
- function rnessRunner(pm, version) {
2311
- if (pm === "pnpm") return "pnpm dlx @rness/cli";
2312
- if (pm === "bun") return "bunx @rness/cli";
2313
- if (pm === "yarn" && Number(version?.split(".")[0]) >= 2)
2314
- return "yarn dlx @rness/cli";
2315
- return "npx @rness/cli";
2316
- }
2317
- async function rnessRunnerFor(pm) {
2318
- const version = pm === "yarn" ? await packageManagerVersion(pm).catch(() => null) : null;
2319
- return rnessRunner(pm, version);
2320
- }
2321
- var BARE_NPM_CODE = /^npm (error|ERR!) code \S+$/;
2322
- function installErrorLine(stderr) {
2323
- const lines = stderr.split("\n").map((l) => l.trim()).filter((l) => l !== "");
2324
- return lines.find((l) => !BARE_NPM_CODE.test(l)) ?? firstLine3(stderr);
2325
- }
2326
- var FROZEN = {
2327
- npm: ["ci"],
2328
- pnpm: ["install", "--frozen-lockfile"],
2329
- yarn: ["install", "--immutable"],
2330
- bun: ["install", "--frozen-lockfile"]
2331
- };
2332
- function frozenArgs(pm) {
2333
- return [...FROZEN[pm]];
2334
- }
2335
- async function installDependencies(pm, dir, opts = {}) {
2336
- const args = opts.frozen === true ? frozenArgs(pm) : ["install"];
2337
- try {
2338
- await execFileP2(pm, args, { cwd: dir, maxBuffer: 16 * 1024 * 1024 });
2339
- } catch (e) {
2340
- const err = e;
2341
- throw new Error(
2342
- `${pm} ${args.join(" ")} failed in ${dir}: ${installErrorLine(err.stderr ?? err.message)}`,
2343
- { cause: e }
2344
- );
2345
- }
2346
- }
2347
-
2348
2377
  // src/core/scaffold.ts
2349
2378
  import { statSync } from "fs";
2350
2379
  import { dirname as dirname4, join as join12 } from "path";
@@ -2480,8 +2509,8 @@ async function offerSetupGit(opts, terminal, bin, ui) {
2480
2509
  const changed = await setupGit(process.execPath, bin);
2481
2510
  ui.line(
2482
2511
  changed ? "updated" : "unchanged",
2483
- "git: rness answers for https://github.com (rness logout undoes it)",
2484
- "git now asks rness for your github.com login over HTTPS (rness logout undoes it)"
2512
+ `git: rness answers for https://github.com (${rnessCommand()} logout undoes it)`,
2513
+ `git now asks rness for your github.com login over HTTPS (${rnessCommand()} logout undoes it)`
2485
2514
  );
2486
2515
  }
2487
2516
  async function loginCommand(opts, deps = {}) {
@@ -2498,7 +2527,7 @@ async function loginCommand(opts, deps = {}) {
2498
2527
  if (stored !== null && await resolveToken() !== null) {
2499
2528
  ui.line(
2500
2529
  "logged in",
2501
- `as ${stored.login} (github.com); rness logout to switch`
2530
+ `as ${stored.login} (github.com); ${rnessCommand()} logout to switch`
2502
2531
  );
2503
2532
  await offerSetupGit(opts, terminal, bin, ui);
2504
2533
  if (own) ui.outro("Nothing to do", "idle");
@@ -2761,7 +2790,7 @@ async function syncPinned(root, shown, fallback) {
2761
2790
  if (installed === null) {
2762
2791
  if (fallback !== void 0) return fallback();
2763
2792
  process.stderr.write(
2764
- `@rness/cli is not installed in ${shown}/.rness; install in .rness/, then rness sync
2793
+ `@rness/cli is not installed in ${shown}/.rness; install in .rness/, then ${rnessCommand()} sync
2765
2794
  `
2766
2795
  );
2767
2796
  return 1;
@@ -2818,8 +2847,8 @@ async function targetProblem(cwd, root, pm) {
2818
2847
  if (!await exists(root)) return null;
2819
2848
  if (await exists(join15(root, ".rness", "rness.json"))) {
2820
2849
  if (!await exists(join15(root, ".rness", "node_modules")))
2821
- return `${shown} holds an rness workspace whose dependencies are not installed; cd ${shown}/.rness && ${pm} install, then rness sync`;
2822
- return `${shown} already holds an rness workspace (.rness/); run rness add inside it to add repositories`;
2850
+ return `${shown} holds an rness workspace whose dependencies are not installed; cd ${shown}/.rness && ${pm} install, then ${rnessCommand()} sync`;
2851
+ return `${shown} already holds an rness workspace (.rness/); run ${rnessCommand()} add inside it to add repositories`;
2823
2852
  }
2824
2853
  if (!(await stat3(root)).isDirectory()) return `${shown} is not a directory`;
2825
2854
  if (!await isEmptyDir(root)) return `${shown} is not empty`;
@@ -2879,6 +2908,8 @@ async function commitContext(input) {
2879
2908
 
2880
2909
  // src/core/sync-blocks.ts
2881
2910
  async function syncBlocks(ui, root, shown, inPlace, sshWorks) {
2911
+ if (process.env["RNESS_NO_DELEGATE"] === "1" && inPlace !== void 0)
2912
+ return inPlace();
2882
2913
  if (!ui.session)
2883
2914
  return ui.step(
2884
2915
  { doing: "syncing the blocks", git: true },
@@ -2895,7 +2926,7 @@ async function syncBlocks(ui, root, shown, inPlace, sshWorks) {
2895
2926
  if (result === null) {
2896
2927
  if (inPlace !== void 0) return inPlace();
2897
2928
  ui.error(
2898
- `@rness/cli is not installed in ${shown}/.rness; install in .rness/, then rness sync`
2929
+ `@rness/cli is not installed in ${shown}/.rness; install in .rness/, then ${rnessCommand()} sync`
2899
2930
  );
2900
2931
  return 1;
2901
2932
  }
@@ -2985,7 +3016,7 @@ async function createBlank(input) {
2985
3016
  const next = [
2986
3017
  `cd ${shown}`,
2987
3018
  "# bring a repository in: <owner>/<repo> on GitHub, or any git URL",
2988
- `${await rnessRunnerFor(pm)} add <owner>/<repo>`,
3019
+ `${rnessCommand()} add <owner>/<repo>`,
2989
3020
  '# to share it: set "org" in .rness/rness.json, then push .rness to github.com/<org>/.rness'
2990
3021
  ];
2991
3022
  if (ui.session) {
@@ -3055,11 +3086,11 @@ async function pickRepositories(input) {
3055
3086
  listed = listing.repositories;
3056
3087
  if (listing.owner === "user")
3057
3088
  ui.hint(
3058
- `only public repositories of ${org} are listed; add private ones later with rness add <repo>`
3089
+ `only public repositories of ${org} are listed; add private ones later with ${rnessCommand()} add <repo>`
3059
3090
  );
3060
3091
  else if (!provider.authenticated)
3061
3092
  ui.hint(
3062
- "only public repositories are listed; rness login lists the private ones you can access"
3093
+ `only public repositories are listed; ${rnessCommand()} login lists the private ones you can access`
3063
3094
  );
3064
3095
  if (listing.truncated)
3065
3096
  ui.hint(`listed the first ${MAX_PAGES * PER_PAGE} repositories of ${org}`);
@@ -3290,7 +3321,6 @@ async function createCommand(opts, deps = {}) {
3290
3321
  return 2;
3291
3322
  }
3292
3323
  let pm = opts.pm !== void 0 && isPackageManager(opts.pm) ? opts.pm : detectPackageManager();
3293
- const launchedWith = pm;
3294
3324
  const interactive = opts.yes !== true && terminal.isTty();
3295
3325
  const ui = interactive ? await makeUi(terminal) : { ...plainUi };
3296
3326
  let sshTest;
@@ -3523,7 +3553,7 @@ async function createCommand(opts, deps = {}) {
3523
3553
  const remaining = Object.keys(catalogue.repos).filter(
3524
3554
  (name2) => !cloned.has(name2)
3525
3555
  );
3526
- const rness2 = await rnessRunnerFor(launchedWith);
3556
+ const rness2 = rnessCommand();
3527
3557
  const next2 = [
3528
3558
  `cd ${shown}`,
3529
3559
  // The comment above its command, as the new-workspace note does: a
@@ -3583,7 +3613,7 @@ ${next2.map((l) => ` ${l}`).join("\n")}
3583
3613
  url: contextUrl
3584
3614
  }) : false;
3585
3615
  if (published === null) return cancelled(ui);
3586
- const rness = await rnessRunnerFor(launchedWith);
3616
+ const rness = rnessCommand();
3587
3617
  const next = [
3588
3618
  `cd ${shown}/.rness`,
3589
3619
  // What was asked for and did not happen, as the command that retries
@@ -3597,7 +3627,9 @@ ${next2.map((l) => ` ${l}`).join("\n")}
3597
3627
  "# or, with the GitHub CLI (gh) installed, in one step:",
3598
3628
  `gh repo create ${org}/.rness --private --source . --push`
3599
3629
  ],
3600
- `# then, for every teammate: ${launchedWith} create rness ${org}`
3630
+ // How this command was launched (npm when rness was typed directly),
3631
+ // whatever --pm installed with.
3632
+ `# then, for every teammate: ${detectPackageManager()} create rness ${org}`
3601
3633
  ];
3602
3634
  if (ui.session) {
3603
3635
  ui.note("Next steps", next);
@@ -3687,7 +3719,7 @@ async function upgradeCommand(version, opts, terminal = defaultTerminal) {
3687
3719
  const pin = await readPin(ws.rnessDir);
3688
3720
  if (pin === null) {
3689
3721
  process.stderr.write(
3690
- `no @rness/cli entry in ${label}/package.json; add it to devDependencies, then run rness upgrade
3722
+ `no @rness/cli entry in ${label}/package.json; add it to devDependencies, then run ${rnessCommand()} upgrade
3691
3723
  `
3692
3724
  );
3693
3725
  return 1;
@@ -3708,7 +3740,8 @@ async function upgradeCommand(version, opts, terminal = defaultTerminal) {
3708
3740
  );
3709
3741
  if (target === null) {
3710
3742
  process.stderr.write(
3711
- "cannot reach the registry; name the version: rness upgrade <version>\n"
3743
+ `cannot reach the registry; name the version: ${rnessCommand()} upgrade <version>
3744
+ `
3712
3745
  );
3713
3746
  return 1;
3714
3747
  }
@@ -3722,7 +3755,7 @@ async function upgradeCommand(version, opts, terminal = defaultTerminal) {
3722
3755
  const downgrading = EXACT_VERSION.test(pin.spec) && compareVersions(target, pin.spec) < 0;
3723
3756
  if (downgrading && version === void 0) {
3724
3757
  process.stderr.write(
3725
- `${label} pins @rness/cli ${pin.spec}, newer than the latest release ${target}; to downgrade: rness upgrade ${target}
3758
+ `${label} pins @rness/cli ${pin.spec}, newer than the latest release ${target}; to downgrade: ${rnessCommand()} upgrade ${target}
3726
3759
  `
3727
3760
  );
3728
3761
  return 1;
@@ -3863,13 +3896,17 @@ async function checkBlocks({
3863
3896
  checks
3864
3897
  });
3865
3898
  if (!await exists(join19(root, "org"))) return derive();
3866
- const targets = [{ scope: null, dir: root, depth: 0, label: "AGENTS.md" }];
3899
+ const targets = [
3900
+ { scope: null, dir: root, depth: 0, file: "AGENTS.md", label: "AGENTS.md" },
3901
+ { scope: null, dir: root, depth: 0, file: "CLAUDE.md", label: "CLAUDE.md" }
3902
+ ];
3867
3903
  for (const [name, entry] of Object.entries(manifest.scopes)) {
3868
3904
  const segments = entry.path.split("/");
3869
3905
  targets.push({
3870
3906
  scope: name,
3871
3907
  dir: join19(root, ...segments),
3872
3908
  depth: segments.length,
3909
+ file: "AGENTS.md",
3873
3910
  label: `${entry.path}/AGENTS.md`
3874
3911
  });
3875
3912
  }
@@ -3882,14 +3919,14 @@ async function checkBlocks({
3882
3919
  );
3883
3920
  continue;
3884
3921
  }
3885
- const text = await readOrNull(join19(t.dir, "AGENTS.md"));
3922
+ const text = await readOrNull(join19(t.dir, t.file));
3886
3923
  const lines = text === null ? [] : text.split(/\r?\n/);
3887
3924
  const found = findBlock(lines);
3888
3925
  if (found.kind === "none") {
3889
3926
  note(
3890
3927
  t.label,
3891
3928
  "no-block",
3892
- `${t.label}: no rness block yet (run rness sync)`
3929
+ `${t.label}: no rness block yet (run ${rnessCommand()} sync)`
3893
3930
  );
3894
3931
  continue;
3895
3932
  }
@@ -3908,10 +3945,15 @@ async function checkBlocks({
3908
3945
  depth: t.depth,
3909
3946
  context
3910
3947
  });
3911
- if (isCurrentBlock(lines.slice(found.begin, found.end + 1), fresh2.hash))
3948
+ const pointerLeft = t.file === "CLAUDE.md" && lines.some((l) => l.trim() === "@AGENTS.md");
3949
+ if (isCurrentBlock(lines.slice(found.begin, found.end + 1), fresh2.hash) && !pointerLeft)
3912
3950
  note(t.label, "current");
3913
3951
  else
3914
- note(t.label, "stale", `${t.label}: stale rness block (run rness sync)`);
3952
+ note(
3953
+ t.label,
3954
+ "stale",
3955
+ `${t.label}: stale rness block (run ${rnessCommand()} sync)`
3956
+ );
3915
3957
  }
3916
3958
  return derive();
3917
3959
  }
@@ -3999,7 +4041,13 @@ async function validateCommand(opts, deps = {}) {
3999
4041
  return 0;
4000
4042
  }
4001
4043
  ui.intro(`Validate ${org}`);
4002
- for (const c of blocks.checks)
4044
+ const rootStatus = blocks.checks.find(
4045
+ (c) => c.label === "AGENTS.md"
4046
+ )?.status;
4047
+ const shown = blocks.checks.filter(
4048
+ (c) => !(c.label === "CLAUDE.md" && c.status === rootStatus)
4049
+ );
4050
+ for (const c of shown)
4003
4051
  if (c.message === null) ui.line("current", c.label);
4004
4052
  else if (c.status === "stale" || c.status === "malformed")
4005
4053
  ui.error(c.message);
@@ -4215,6 +4263,11 @@ export {
4215
4263
  exists,
4216
4264
  readOrNull,
4217
4265
  writeFileAtomic,
4266
+ PACKAGE_MANAGERS,
4267
+ isPackageManager,
4268
+ detectPackageManager,
4269
+ packageManagerVersion,
4270
+ installDependencies,
4218
4271
  GitHubOAuthProvider,
4219
4272
  githubProvider,
4220
4273
  DEFAULT_HOST,
@@ -4259,11 +4312,6 @@ export {
4259
4312
  contextCommand,
4260
4313
  VERSION,
4261
4314
  findDelegate,
4262
- PACKAGE_MANAGERS,
4263
- isPackageManager,
4264
- detectPackageManager,
4265
- packageManagerVersion,
4266
- installDependencies,
4267
4315
  SCAFFOLD_FILES,
4268
4316
  scaffoldDir,
4269
4317
  copyScaffold,
@@ -4279,4 +4327,4 @@ export {
4279
4327
  OWN_COMMANDS,
4280
4328
  catchUp
4281
4329
  };
4282
- //# sourceMappingURL=chunk-NY3WV7X5.js.map
4330
+ //# sourceMappingURL=chunk-7TOHFPW6.js.map